Extended option 'dc4' to handle inlined class references (mainly Eclipse). See IDEA-135387 for an example.

This commit is contained in:
Stiver
2015-03-01 13:51:30 +01:00
parent c3b4a23fdb
commit b3962a09ca
14 changed files with 822 additions and 12 deletions

View File

@@ -15,24 +15,41 @@
*/
package org.jetbrains.java.decompiler.modules.decompiler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ArrayExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.MonitorExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
import java.util.*;
import java.util.Map.Entry;
public class SimplifyExprentsHelper {
static MatchEngine class14Builder = new MatchEngine();
private boolean firstInvocation;
public SimplifyExprentsHelper(boolean firstInvocation) {
@@ -45,6 +62,8 @@ public class SimplifyExprentsHelper {
if (stat.getExprents() == null) {
boolean processClass14 = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4);
while (true) {
boolean changed = false;
@@ -61,6 +80,11 @@ public class SimplifyExprentsHelper {
if (changed = buildIff(st, ssa)) {
break;
}
// collapse inlined .class property in version 1.4 and before
if (processClass14 && (changed = collapseInlinedClass14(st))) {
break;
}
}
res |= changed;
@@ -852,4 +876,53 @@ public class SimplifyExprentsHelper {
return false;
}
static {
class14Builder.parse(
"statement type:if iftype:if exprsize:-1\n" +
" exprent position:head type:if\n" +
" exprent type:function functype:eq\n" +
" exprent type:field name:$field$\n" +
" exprent type:constant consttype:null\n" +
" statement type:basicblock\n" +
" exprent position:-1 type:assignment ret:$assignfield$\n" +
" exprent type:var index:$var$\n" +
" exprent type:field name:$field$\n" +
" statement type:sequence statsize:2\n" +
" statement type:trycatch\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:assignment\n" +
" exprent type:var index:$var$\n" +
" exprent type:invocation invclass:java/lang/Class signature:forName(Ljava/lang/String;)Ljava/lang/Class;\n" +
" exprent position:0 type:constant consttype:string constvalue:$classname$\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:exit exittype:throw\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:assignment\n" +
" exprent type:field name:$field$\n" +
" exprent type:var index:$var$"
);
}
private static boolean collapseInlinedClass14(Statement stat) {
boolean ret = class14Builder.match(stat);
if(ret) {
String class_name = (String)class14Builder.getVariableValue("$classname$");
AssignmentExprent assfirst = (AssignmentExprent)class14Builder.getVariableValue("$assignfield$");
assfirst.replaceExprent(assfirst.getRight(), new ConstExprent(VarType.VARTYPE_CLASS, class_name, null));
List<Exprent> data = new ArrayList<Exprent>();
data.addAll(stat.getFirst().getExprents());
stat.setExprents(data);
SequenceHelper.destroyAndFlattenStatement(stat);
}
return ret;
}
}

View File

@@ -23,9 +23,14 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.*;
import java.util.Map.Entry;
public class ConstExprent extends Exprent {
private static final Map<Integer, String> ESCAPES = new HashMap<Integer, String>() {{
@@ -395,4 +400,37 @@ public class ConstExprent extends Exprent {
public boolean isBoolPermitted() {
return boolPermitted;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
for(Entry<MatchProperties, RuleValue> rule : matchNode.getRules().entrySet()) {
RuleValue rule_value = rule.getValue();
switch(rule.getKey()) {
case EXPRENT_CONSTTYPE:
if(!rule_value.value.equals(this.constType)) {
return false;
}
break;
case EXPRENT_CONSTVALUE:
if(rule_value.isVariable()) {
if(!engine.checkAndSetVariableValue(rule_value.value.toString(), this.value)) {
return false;
}
}
break;
}
}
return true;
}
}

View File

@@ -25,11 +25,15 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.struct.attr.StructExceptionsAttribute;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
public class ExitExprent extends Exprent {
@@ -151,4 +155,25 @@ public class ExitExprent extends Exprent {
public VarType getRetType() {
return retType;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
Integer type = (Integer)matchNode.getRuleValue(MatchProperties.EXPRENT_EXITTYPE);
if(type != null) {
if(this.exitType != type.intValue()) {
return false;
}
}
return true;
}
}

View File

@@ -15,6 +15,13 @@
*/
package org.jetbrains.java.decompiler.modules.decompiler.exps;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.TextBuffer;
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
@@ -22,10 +29,12 @@ import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.IMatchable;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import java.util.*;
public class Exprent {
public class Exprent implements IMatchable {
public static final int MULTIPLE_USES = 1;
public static final int SIDE_EFFECTS_FREE = 2;
@@ -131,4 +140,58 @@ public class Exprent {
}
}
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public IMatchable findObject(MatchNode matchNode, int index) {
if(matchNode.getType() != MatchNode.MATCHNODE_EXPRENT) {
return null;
}
List<Exprent> lstAllExprents = getAllExprents();
if(lstAllExprents == null || lstAllExprents.isEmpty()) {
return null;
}
String position = (String)matchNode.getRuleValue(MatchProperties.EXPRENT_POSITION);
if(position != null) {
if(position.matches("-?\\d+")) {
return lstAllExprents.get((lstAllExprents.size() + Integer.parseInt(position)) % lstAllExprents.size()); // care for negative positions
}
} else if(index < lstAllExprents.size()) { // use 'index' parameter
return lstAllExprents.get(index);
}
return null;
}
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(matchNode.getType() != MatchNode.MATCHNODE_EXPRENT) {
return false;
}
for(Entry<MatchProperties, RuleValue> rule : matchNode.getRules().entrySet()) {
switch(rule.getKey()) {
case EXPRENT_TYPE:
if(this.type != ((Integer)rule.getValue().value).intValue()) {
return false;
}
break;
case EXPRENT_RET:
if(!engine.checkAndSetVariableValue((String)rule.getValue().value, this)) {
return false;
}
break;
}
}
return true;
}
}

View File

@@ -26,6 +26,10 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.TextUtil;
@@ -181,4 +185,31 @@ public class FieldExprent extends Exprent {
public String getName() {
return name;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
RuleValue rule = matchNode.getRules().get(MatchProperties.EXPRENT_FIELD_NAME);
if(rule != null) {
if(rule.isVariable()) {
if(!engine.checkAndSetVariableValue((String)rule.value, this.name)) {
return false;
}
} else {
if(!rule.value.equals(this.name)) {
return false;
}
}
}
return true;
}
}

View File

@@ -21,10 +21,15 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.IMatchable;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
import java.util.*;
import java.util.Map.Entry;
public class FunctionExprent extends Exprent {
@@ -604,4 +609,25 @@ public class FunctionExprent extends Exprent {
public void setImplicitType(VarType implicitType) {
this.implicitType = implicitType;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
Integer type = (Integer)matchNode.getRuleValue(MatchProperties.EXPRENT_FUNCTYPE);
if(type != null) {
if(this.funcType != type.intValue()) {
return false;
}
}
return true;
}
}

View File

@@ -15,6 +15,13 @@
*/
package org.jetbrains.java.decompiler.modules.decompiler.exps;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@@ -31,12 +38,13 @@ import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
import org.jetbrains.java.decompiler.util.TextUtil;
import java.util.*;
public class InvocationExprent extends Exprent {
public static final int INVOKE_SPECIAL = 1;
@@ -87,6 +95,7 @@ public class InvocationExprent extends Exprent {
break;
case CodeConstants.opc_invokedynamic:
invocationTyp = INVOKE_DYNAMIC;
classname = "java/lang/Class"; // dummy class name
invokeDynamicClassSuffix = "##Lambda_" + cn.index1 + "_" + cn.index2;
}
@@ -482,4 +491,47 @@ public class InvocationExprent extends Exprent {
public String getInvokeDynamicClassSuffix() {
return invokeDynamicClassSuffix;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
for(Entry<MatchProperties, RuleValue> rule : matchNode.getRules().entrySet()) {
RuleValue value = rule.getValue();
switch(rule.getKey()) {
case EXPRENT_INVOCATION_PARAMETER:
if(value.isVariable()) {
if(value.parameter < lstParameters.size()) {
if(!engine.checkAndSetVariableValue(value.value.toString(), lstParameters.get(value.parameter))) {
return false;
}
} else {
return false;
}
}
break;
case EXPRENT_INVOCATION_CLASS:
if(!value.value.equals(this.classname)) {
return false;
}
break;
case EXPRENT_INVOCATION_SIGNATURE:
if(!value.value.equals(this.name + this.stringDescriptor)) {
return false;
}
break;
}
}
return true;
}
}

View File

@@ -26,6 +26,10 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.ArrayList;
@@ -180,4 +184,31 @@ public class VarExprent extends Exprent {
public void setStack(boolean stack) {
this.stack = stack;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
RuleValue rule = matchNode.getRules().get(MatchProperties.EXPRENT_VAR_INDEX);
if(rule != null) {
if(rule.isVariable()) {
if(!engine.checkAndSetVariableValue((String)rule.value, this.index)) {
return false;
}
} else {
if(this.index != Integer.valueOf((String)rule.value).intValue()) {
return false;
}
}
}
return true;
}
}

View File

@@ -22,10 +22,15 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
import org.jetbrains.java.decompiler.struct.match.IMatchable;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
public class IfStatement extends Statement {
@@ -421,4 +426,42 @@ public class IfStatement extends Statement {
public StatEdge getElseEdge() {
return elseedge;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public IMatchable findObject(MatchNode matchNode, int index) {
IMatchable object = super.findObject(matchNode, index);
if(object != null) {
return object;
}
if(matchNode.getType() == MatchNode.MATCHNODE_EXPRENT) {
String position = (String)matchNode.getRuleValue(MatchProperties.EXPRENT_POSITION);
if("head".equals(position)) {
return getHeadexprent();
}
}
return null;
}
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(!super.match(matchNode, engine)) {
return false;
}
Integer type = (Integer)matchNode.getRuleValue(MatchProperties.STATEMENT_IFTYPE);
if(type != null) {
if(this.iftype != type.intValue()) {
return false;
}
}
return true;
}
}

View File

@@ -15,6 +15,15 @@
*/
package org.jetbrains.java.decompiler.modules.decompiler.stats;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.InstructionSequence;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@@ -24,11 +33,13 @@ import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.struct.match.IMatchable;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.util.*;
public class Statement {
public class Statement implements IMatchable {
public static final int STATEDGE_ALL = 1 << 31;
public static final int STATEDGE_DIRECT_ALL = 1 << 30;
@@ -859,4 +870,78 @@ public class Statement {
public String toString() {
return id.toString();
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
public IMatchable findObject(MatchNode matchNode, int index) {
int node_type = matchNode.getType();
if(node_type == MatchNode.MATCHNODE_STATEMENT) {
String position = (String)matchNode.getRuleValue(MatchProperties.STATEMENT_POSITION);
if(position != null) {
if(position.matches("-?\\d+")) {
return this.stats.get((this.stats.size() + Integer.parseInt(position)) % this.stats.size()); // care for negative positions
}
} else if(index < this.stats.size()) { // use 'index' parameter
return this.stats.get(index);
}
} else if(node_type == MatchNode.MATCHNODE_EXPRENT && this.exprents != null) {
String position = (String)matchNode.getRuleValue(MatchProperties.EXPRENT_POSITION);
if(position != null) {
if(position.matches("-?\\d+")) {
return this.exprents.get((this.exprents.size() + Integer.parseInt(position)) % this.exprents.size()); // care for negative positions
}
} else if(index < this.exprents.size()) { // use 'index' parameter
return this.exprents.get(index);
}
}
return null;
}
public boolean match(MatchNode matchNode, MatchEngine engine) {
if(matchNode.getType() != MatchNode.MATCHNODE_STATEMENT) {
return false;
}
for(Entry<MatchProperties, RuleValue> rule : matchNode.getRules().entrySet()) {
switch(rule.getKey()) {
case STATEMENT_TYPE:
if(this.type != ((Integer)rule.getValue().value).intValue()) {
return false;
}
break;
case STATEMENT_STATSIZE:
if(this.stats.size() != ((Integer)rule.getValue().value).intValue()) {
return false;
}
break;
case STATEMENT_EXPRSIZE:
int exprsize = ((Integer)rule.getValue().value).intValue();
if(exprsize == -1) {
if(this.exprents != null) {
return false;
}
} else {
if(this.exprents == null || this.exprents.size() != exprsize) {
return false;
}
}
break;
case STATEMENT_RET:
if(!engine.checkAndSetVariableValue((String)rule.getValue().value, this)) {
return false;
}
break;
}
}
return true;
}
}