|
|
|
@ -21,7 +21,29 @@ import java.util.*; |
|
|
|
|
import java.util.Map.Entry; |
|
|
|
|
|
|
|
|
|
public class SimplifyExprentsHelper { |
|
|
|
|
static final MatchEngine class14Builder = new MatchEngine(); |
|
|
|
|
@SuppressWarnings("SpellCheckingInspection") private static final MatchEngine class14Builder = new MatchEngine( |
|
|
|
|
"statement type:if iftype:if exprsize:-1\n" + |
|
|
|
|
" exprent position:head type:if\n" + |
|
|
|
|
" exprent type:function functype:eq\n" + |
|
|
|
|
" exprent type:field name:$fieldname$\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:$fieldname$\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:$fieldname$ ret:$field$\n" + |
|
|
|
|
" exprent type:var index:$var$"); |
|
|
|
|
|
|
|
|
|
private final boolean firstInvocation; |
|
|
|
|
|
|
|
|
@ -29,10 +51,11 @@ public class SimplifyExprentsHelper { |
|
|
|
|
this.firstInvocation = firstInvocation; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public boolean simplifyStackVarsStatement(Statement stat, HashSet<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) { |
|
|
|
|
public boolean simplifyStackVarsStatement(Statement stat, Set<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) { |
|
|
|
|
boolean res = false; |
|
|
|
|
|
|
|
|
|
if (stat.getExprents() == null) { |
|
|
|
|
List<Exprent> expressions = stat.getExprents(); |
|
|
|
|
if (expressions == null) { |
|
|
|
|
boolean processClass14 = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4); |
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
@ -65,7 +88,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
res = simplifyStackVarsExprents(stat.getExprents(), cl); |
|
|
|
|
res = simplifyStackVarsExprents(expressions, cl); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
@ -75,7 +98,6 @@ public class SimplifyExprentsHelper { |
|
|
|
|
boolean res = false; |
|
|
|
|
|
|
|
|
|
int index = 0; |
|
|
|
|
|
|
|
|
|
while (index < list.size()) { |
|
|
|
|
Exprent current = list.get(index); |
|
|
|
|
|
|
|
|
@ -131,9 +153,9 @@ public class SimplifyExprentsHelper { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// direct initialization of an array
|
|
|
|
|
int arrcount = isArrayInitializer(list, index); |
|
|
|
|
if (arrcount > 0) { |
|
|
|
|
for (int i = 0; i < arrcount; i++) { |
|
|
|
|
int arrCount = isArrayInitializer(list, index); |
|
|
|
|
if (arrCount > 0) { |
|
|
|
|
for (int i = 0; i < arrCount; i++) { |
|
|
|
|
list.remove(index + 1); |
|
|
|
|
} |
|
|
|
|
res = true; |
|
|
|
@ -163,13 +185,13 @@ public class SimplifyExprentsHelper { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// assignment on stack
|
|
|
|
|
if (isStackAssignement(current, next)) { |
|
|
|
|
if (isStackAssignment(current, next)) { |
|
|
|
|
list.remove(index + 1); |
|
|
|
|
res = true; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!firstInvocation && isStackAssignement2(current, next)) { |
|
|
|
|
if (!firstInvocation && isStackAssignment2(current, next)) { |
|
|
|
|
list.remove(index + 1); |
|
|
|
|
res = true; |
|
|
|
|
continue; |
|
|
|
@ -186,38 +208,38 @@ public class SimplifyExprentsHelper { |
|
|
|
|
AssignmentExprent as = (AssignmentExprent)first; |
|
|
|
|
|
|
|
|
|
if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) { |
|
|
|
|
NewExprent newex = (NewExprent)as.getRight(); |
|
|
|
|
NewExprent newExpr = (NewExprent)as.getRight(); |
|
|
|
|
|
|
|
|
|
if (!newex.getLstArrayElements().isEmpty()) { |
|
|
|
|
VarExprent arrvar = (VarExprent)as.getLeft(); |
|
|
|
|
if (!newExpr.getLstArrayElements().isEmpty()) { |
|
|
|
|
VarExprent arrVar = (VarExprent)as.getLeft(); |
|
|
|
|
|
|
|
|
|
if (second.type == Exprent.EXPRENT_ASSIGNMENT) { |
|
|
|
|
AssignmentExprent aas = (AssignmentExprent)second; |
|
|
|
|
if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) { |
|
|
|
|
ArrayExprent arrex = (ArrayExprent)aas.getLeft(); |
|
|
|
|
if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray()) |
|
|
|
|
&& arrex.getIndex().type == Exprent.EXPRENT_CONST) { |
|
|
|
|
|
|
|
|
|
int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue(); |
|
|
|
|
|
|
|
|
|
if (constvalue < newex.getLstArrayElements().size()) { |
|
|
|
|
Exprent init = newex.getLstArrayElements().get(constvalue); |
|
|
|
|
ArrayExprent arrExpr = (ArrayExprent)aas.getLeft(); |
|
|
|
|
if (arrExpr.getArray().type == Exprent.EXPRENT_VAR && |
|
|
|
|
arrVar.equals(arrExpr.getArray()) && |
|
|
|
|
arrExpr.getIndex().type == Exprent.EXPRENT_CONST) { |
|
|
|
|
int constValue = ((ConstExprent)arrExpr.getIndex()).getIntValue(); |
|
|
|
|
|
|
|
|
|
if (constValue < newExpr.getLstArrayElements().size()) { |
|
|
|
|
Exprent init = newExpr.getLstArrayElements().get(constValue); |
|
|
|
|
if (init.type == Exprent.EXPRENT_CONST) { |
|
|
|
|
ConstExprent cinit = (ConstExprent)init; |
|
|
|
|
VarType arrtype = newex.getNewType().decreaseArrayDim(); |
|
|
|
|
ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype); |
|
|
|
|
VarType arrType = newExpr.getNewType().decreaseArrayDim(); |
|
|
|
|
ConstExprent defaultVal = ExprProcessor.getDefaultArrayValue(arrType); |
|
|
|
|
|
|
|
|
|
if (cinit.equals(defaultval)) { |
|
|
|
|
Exprent tempexpr = aas.getRight(); |
|
|
|
|
if (cinit.equals(defaultVal)) { |
|
|
|
|
Exprent tempExpr = aas.getRight(); |
|
|
|
|
|
|
|
|
|
if (!tempexpr.containsExprent(arrvar)) { |
|
|
|
|
newex.getLstArrayElements().set(constvalue, tempexpr); |
|
|
|
|
if (!tempExpr.containsExprent(arrVar)) { |
|
|
|
|
newExpr.getLstArrayElements().set(constValue, tempExpr); |
|
|
|
|
|
|
|
|
|
if (tempexpr.type == Exprent.EXPRENT_NEW) { |
|
|
|
|
NewExprent tempnewex = (NewExprent)tempexpr; |
|
|
|
|
int dims = newex.getNewType().arrayDim; |
|
|
|
|
if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) { |
|
|
|
|
tempnewex.setDirectArrayInit(true); |
|
|
|
|
if (tempExpr.type == Exprent.EXPRENT_NEW) { |
|
|
|
|
NewExprent tempNewExpr = (NewExprent)tempExpr; |
|
|
|
|
int dims = newExpr.getNewType().arrayDim; |
|
|
|
|
if (dims > 1 && !tempNewExpr.getLstArrayElements().isEmpty()) { |
|
|
|
|
tempNewExpr.setDirectArrayInit(true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -242,19 +264,18 @@ public class SimplifyExprentsHelper { |
|
|
|
|
AssignmentExprent as = (AssignmentExprent)current; |
|
|
|
|
|
|
|
|
|
if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) { |
|
|
|
|
NewExprent newex = (NewExprent)as.getRight(); |
|
|
|
|
NewExprent newExpr = (NewExprent)as.getRight(); |
|
|
|
|
|
|
|
|
|
if (newex.getExprType().arrayDim > 0 && newex.getLstDims().size() == 1 && newex.getLstArrayElements().isEmpty() && |
|
|
|
|
newex.getLstDims().get(0).type == Exprent.EXPRENT_CONST) { |
|
|
|
|
if (newExpr.getExprType().arrayDim > 0 && newExpr.getLstDims().size() == 1 && newExpr.getLstArrayElements().isEmpty() && |
|
|
|
|
newExpr.getLstDims().get(0).type == Exprent.EXPRENT_CONST) { |
|
|
|
|
|
|
|
|
|
int size = (Integer)((ConstExprent)newex.getLstDims().get(0)).getValue(); |
|
|
|
|
int size = (Integer)((ConstExprent)newExpr.getLstDims().get(0)).getValue(); |
|
|
|
|
if (size == 0) { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VarExprent arrvar = (VarExprent)as.getLeft(); |
|
|
|
|
|
|
|
|
|
HashMap<Integer, Exprent> mapInit = new HashMap<>(); |
|
|
|
|
VarExprent arrVar = (VarExprent)as.getLeft(); |
|
|
|
|
Map<Integer, Exprent> mapInit = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
int i = 1; |
|
|
|
|
while (index + i < list.size() && i <= size) { |
|
|
|
@ -264,17 +285,14 @@ public class SimplifyExprentsHelper { |
|
|
|
|
if (expr.type == Exprent.EXPRENT_ASSIGNMENT) { |
|
|
|
|
AssignmentExprent aas = (AssignmentExprent)expr; |
|
|
|
|
if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) { |
|
|
|
|
ArrayExprent arrex = (ArrayExprent)aas.getLeft(); |
|
|
|
|
if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray()) |
|
|
|
|
&& arrex.getIndex().type == Exprent.EXPRENT_CONST) { |
|
|
|
|
|
|
|
|
|
int constvalue = ((ConstExprent)arrex.getIndex()) |
|
|
|
|
.getIntValue(); // TODO: check for a number type. Failure extremely improbable, but nevertheless...
|
|
|
|
|
|
|
|
|
|
if (constvalue < size && !mapInit.containsKey(constvalue)) { |
|
|
|
|
|
|
|
|
|
if (!aas.getRight().containsExprent(arrvar)) { |
|
|
|
|
mapInit.put(constvalue, aas.getRight()); |
|
|
|
|
ArrayExprent arrExpr = (ArrayExprent)aas.getLeft(); |
|
|
|
|
if (arrExpr.getArray().type == Exprent.EXPRENT_VAR && arrVar.equals(arrExpr.getArray()) && |
|
|
|
|
arrExpr.getIndex().type == Exprent.EXPRENT_CONST) { |
|
|
|
|
// TODO: check for a number type. Failure extremely improbable, but nevertheless...
|
|
|
|
|
int constValue = ((ConstExprent)arrExpr.getIndex()).getIntValue(); |
|
|
|
|
if (constValue < size && !mapInit.containsKey(constValue)) { |
|
|
|
|
if (!aas.getRight().containsExprent(arrVar)) { |
|
|
|
|
mapInit.put(constValue, aas.getRight()); |
|
|
|
|
found = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -291,33 +309,29 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
double fraction = ((double)mapInit.size()) / size; |
|
|
|
|
|
|
|
|
|
if ((arrvar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) || |
|
|
|
|
(size > 7 && fraction >= 0.7)) { |
|
|
|
|
|
|
|
|
|
if ((arrVar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) || (size > 7 && fraction >= 0.7)) { |
|
|
|
|
List<Exprent> lstRet = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
VarType arrtype = newex.getNewType().decreaseArrayDim(); |
|
|
|
|
|
|
|
|
|
ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype); |
|
|
|
|
|
|
|
|
|
VarType arrayType = newExpr.getNewType().decreaseArrayDim(); |
|
|
|
|
ConstExprent defaultVal = ExprProcessor.getDefaultArrayValue(arrayType); |
|
|
|
|
for (int j = 0; j < size; j++) { |
|
|
|
|
lstRet.add(defaultval.copy()); |
|
|
|
|
lstRet.add(defaultVal.copy()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int dims = newex.getNewType().arrayDim; |
|
|
|
|
int dims = newExpr.getNewType().arrayDim; |
|
|
|
|
for (Entry<Integer, Exprent> ent : mapInit.entrySet()) { |
|
|
|
|
Exprent tempexpr = ent.getValue(); |
|
|
|
|
lstRet.set(ent.getKey(), tempexpr); |
|
|
|
|
Exprent tempExpr = ent.getValue(); |
|
|
|
|
lstRet.set(ent.getKey(), tempExpr); |
|
|
|
|
|
|
|
|
|
if (tempexpr.type == Exprent.EXPRENT_NEW) { |
|
|
|
|
NewExprent tempnewex = (NewExprent)tempexpr; |
|
|
|
|
if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) { |
|
|
|
|
tempnewex.setDirectArrayInit(true); |
|
|
|
|
if (tempExpr.type == Exprent.EXPRENT_NEW) { |
|
|
|
|
NewExprent tempNewExpr = (NewExprent)tempExpr; |
|
|
|
|
if (dims > 1 && !tempNewExpr.getLstArrayElements().isEmpty()) { |
|
|
|
|
tempNewExpr.setDirectArrayInit(true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
newex.setLstArrayElements(lstRet); |
|
|
|
|
newExpr.setLstArrayElements(lstRet); |
|
|
|
|
|
|
|
|
|
return mapInit.size(); |
|
|
|
|
} |
|
|
|
@ -333,17 +347,16 @@ public class SimplifyExprentsHelper { |
|
|
|
|
AssignmentExprent asf = (AssignmentExprent)first; |
|
|
|
|
|
|
|
|
|
if (asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) { |
|
|
|
|
VarExprent varleft = (VarExprent)asf.getLeft(); |
|
|
|
|
VarExprent varright = (VarExprent)asf.getRight(); |
|
|
|
|
|
|
|
|
|
return varleft.getIndex() == varright.getIndex() && varleft.isStack() && varright.isStack(); |
|
|
|
|
VarExprent left = (VarExprent)asf.getLeft(); |
|
|
|
|
VarExprent right = (VarExprent)asf.getRight(); |
|
|
|
|
return left.getIndex() == right.getIndex() && left.isStack() && right.isStack(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static boolean isStackAssignement2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
|
|
|
|
|
private static boolean isStackAssignment2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
|
|
|
|
|
if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) { |
|
|
|
|
AssignmentExprent asf = (AssignmentExprent)first; |
|
|
|
|
AssignmentExprent ass = (AssignmentExprent)second; |
|
|
|
@ -360,7 +373,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static boolean isStackAssignement(Exprent first, Exprent second) { |
|
|
|
|
private static boolean isStackAssignment(Exprent first, Exprent second) { |
|
|
|
|
if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) { |
|
|
|
|
AssignmentExprent asf = (AssignmentExprent)first; |
|
|
|
|
AssignmentExprent ass = (AssignmentExprent)second; |
|
|
|
@ -395,8 +408,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
if (as.getRight().type == Exprent.EXPRENT_FUNCTION) { |
|
|
|
|
FunctionExprent func = (FunctionExprent)as.getRight(); |
|
|
|
|
|
|
|
|
|
if (func.getFuncType() == FunctionExprent.FUNCTION_ADD || |
|
|
|
|
func.getFuncType() == FunctionExprent.FUNCTION_SUB) { |
|
|
|
|
if (func.getFuncType() == FunctionExprent.FUNCTION_ADD || func.getFuncType() == FunctionExprent.FUNCTION_SUB) { |
|
|
|
|
Exprent econd = func.getLstOperands().get(0); |
|
|
|
|
Exprent econst = func.getLstOperands().get(1); |
|
|
|
|
|
|
|
|
@ -410,9 +422,8 @@ public class SimplifyExprentsHelper { |
|
|
|
|
Exprent left = as.getLeft(); |
|
|
|
|
|
|
|
|
|
if (left.type != Exprent.EXPRENT_VAR && left.equals(econd)) { |
|
|
|
|
FunctionExprent ret = new FunctionExprent( |
|
|
|
|
func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI, |
|
|
|
|
econd, func.bytecode); |
|
|
|
|
int type = func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI; |
|
|
|
|
FunctionExprent ret = new FunctionExprent(type, econd, func.bytecode); |
|
|
|
|
ret.setImplicitType(VarType.VARTYPE_INT); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
@ -449,10 +460,10 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
private static boolean isMonitorExit(Exprent first) { |
|
|
|
|
if (first.type == Exprent.EXPRENT_MONITOR) { |
|
|
|
|
MonitorExprent monexpr = (MonitorExprent)first; |
|
|
|
|
return monexpr.getMonType() == MonitorExprent.MONITOR_EXIT && |
|
|
|
|
monexpr.getValue().type == Exprent.EXPRENT_VAR && |
|
|
|
|
!((VarExprent)monexpr.getValue()).isStack(); |
|
|
|
|
MonitorExprent expr = (MonitorExprent)first; |
|
|
|
|
return expr.getMonType() == MonitorExprent.MONITOR_EXIT && |
|
|
|
|
expr.getValue().type == Exprent.EXPRENT_VAR && |
|
|
|
|
!((VarExprent)expr.getValue()).isStack(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
@ -460,21 +471,21 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) { |
|
|
|
|
if (first.type == Exprent.EXPRENT_INVOCATION) { |
|
|
|
|
InvocationExprent invexpr = (InvocationExprent)first; |
|
|
|
|
InvocationExprent invocation = (InvocationExprent)first; |
|
|
|
|
|
|
|
|
|
if (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && invexpr.getName().equals("getClass") && |
|
|
|
|
invexpr.getStringDescriptor().equals("()Ljava/lang/Class;")) { |
|
|
|
|
if (!invocation.isStatic() && invocation.getInstance().type == Exprent.EXPRENT_VAR && invocation.getName().equals("getClass") && |
|
|
|
|
invocation.getStringDescriptor().equals("()Ljava/lang/Class;")) { |
|
|
|
|
|
|
|
|
|
List<Exprent> lstExprents = second.getAllExprents(); |
|
|
|
|
lstExprents.add(second); |
|
|
|
|
|
|
|
|
|
for (Exprent expr : lstExprents) { |
|
|
|
|
if (expr.type == Exprent.EXPRENT_NEW) { |
|
|
|
|
NewExprent nexpr = (NewExprent)expr; |
|
|
|
|
if (nexpr.getConstructor() != null && !nexpr.getConstructor().getLstParameters().isEmpty() && |
|
|
|
|
nexpr.getConstructor().getLstParameters().get(0).equals(invexpr.getInstance())) { |
|
|
|
|
NewExprent newExpr = (NewExprent)expr; |
|
|
|
|
if (newExpr.getConstructor() != null && !newExpr.getConstructor().getLstParameters().isEmpty() && |
|
|
|
|
newExpr.getConstructor().getLstParameters().get(0).equals(invocation.getInstance())) { |
|
|
|
|
|
|
|
|
|
String classname = nexpr.getNewType().value; |
|
|
|
|
String classname = newExpr.getNewType().value; |
|
|
|
|
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); |
|
|
|
|
if (node != null && node.type != ClassNode.CLASS_ROOT) { |
|
|
|
|
return true; |
|
|
|
@ -488,7 +499,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// propagate (var = new X) forward to the <init> invokation
|
|
|
|
|
// propagate (var = new X) forward to the <init> invocation
|
|
|
|
|
private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) { |
|
|
|
|
Exprent current = list.get(index); |
|
|
|
|
|
|
|
|
@ -497,12 +508,11 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
if (as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) { |
|
|
|
|
|
|
|
|
|
NewExprent newexpr = (NewExprent)as.getRight(); |
|
|
|
|
VarType newtype = newexpr.getNewType(); |
|
|
|
|
VarVersionPair leftPaar = new VarVersionPair((VarExprent)as.getLeft()); |
|
|
|
|
|
|
|
|
|
if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arrayDim == 0 && newexpr.getConstructor() == null) { |
|
|
|
|
NewExprent newExpr = (NewExprent)as.getRight(); |
|
|
|
|
VarType newType = newExpr.getNewType(); |
|
|
|
|
VarVersionPair leftPair = new VarVersionPair((VarExprent)as.getLeft()); |
|
|
|
|
|
|
|
|
|
if (newType.type == CodeConstants.TYPE_OBJECT && newType.arrayDim == 0 && newExpr.getConstructor() == null) { |
|
|
|
|
for (int i = index + 1; i < list.size(); i++) { |
|
|
|
|
Exprent remote = list.get(i); |
|
|
|
|
|
|
|
|
@ -513,8 +523,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
if (in.getFunctype() == InvocationExprent.TYP_INIT && |
|
|
|
|
in.getInstance().type == Exprent.EXPRENT_VAR && |
|
|
|
|
as.getLeft().equals(in.getInstance())) { |
|
|
|
|
|
|
|
|
|
newexpr.setConstructor(in); |
|
|
|
|
newExpr.setConstructor(in); |
|
|
|
|
in.setInstance(null); |
|
|
|
|
|
|
|
|
|
list.set(i, as.copy()); |
|
|
|
@ -525,7 +534,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
// check for variable in use
|
|
|
|
|
Set<VarVersionPair> setVars = remote.getAllVariables(); |
|
|
|
|
if (setVars.contains(leftPaar)) { // variable used somewhere in between -> exit, need a better reduced code
|
|
|
|
|
if (setVars.contains(leftPair)) { // variable used somewhere in between -> exit, need a better reduced code
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -553,13 +562,13 @@ public class SimplifyExprentsHelper { |
|
|
|
|
ClassNode lambda_class = DecompilerContext.getClassProcessor().getMapRootClasses().get(lambda_class_name); |
|
|
|
|
|
|
|
|
|
if (lambda_class != null) { // real lambda class found, replace invocation with an anonymous class
|
|
|
|
|
NewExprent newexp = new NewExprent(new VarType(lambda_class_name, true), null, 0, in.bytecode); |
|
|
|
|
newexp.setConstructor(in); |
|
|
|
|
// note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invokation
|
|
|
|
|
NewExprent newExpr = new NewExprent(new VarType(lambda_class_name, true), null, 0, in.bytecode); |
|
|
|
|
newExpr.setConstructor(in); |
|
|
|
|
// note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invocation
|
|
|
|
|
// lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);)
|
|
|
|
|
// in this case instance will hold the corresponding object
|
|
|
|
|
|
|
|
|
|
return newexp; |
|
|
|
|
return newExpr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -579,10 +588,10 @@ public class SimplifyExprentsHelper { |
|
|
|
|
if (exprent.type == Exprent.EXPRENT_INVOCATION) { |
|
|
|
|
InvocationExprent in = (InvocationExprent)exprent; |
|
|
|
|
if (in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) { |
|
|
|
|
NewExprent newexp = (NewExprent)in.getInstance(); |
|
|
|
|
newexp.setConstructor(in); |
|
|
|
|
NewExprent newExpr = (NewExprent)in.getInstance(); |
|
|
|
|
newExpr.setConstructor(in); |
|
|
|
|
in.setInstance(null); |
|
|
|
|
return newexp; |
|
|
|
|
return newExpr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -591,37 +600,35 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) { |
|
|
|
|
if (stat.type == Statement.TYPE_IF && stat.getExprents() == null) { |
|
|
|
|
IfStatement stif = (IfStatement)stat; |
|
|
|
|
|
|
|
|
|
Exprent ifheadexpr = stif.getHeadexprent(); |
|
|
|
|
Set<Integer> ifheadexpr_bytecode = (ifheadexpr == null ? null : ifheadexpr.bytecode); |
|
|
|
|
|
|
|
|
|
if (stif.iftype == IfStatement.IFTYPE_IFELSE) { |
|
|
|
|
Statement ifstat = stif.getIfstat(); |
|
|
|
|
Statement elsestat = stif.getElsestat(); |
|
|
|
|
|
|
|
|
|
if (ifstat.getExprents() != null && ifstat.getExprents().size() == 1 |
|
|
|
|
&& elsestat.getExprents() != null && elsestat.getExprents().size() == 1 |
|
|
|
|
&& ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1 |
|
|
|
|
&& ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) { |
|
|
|
|
|
|
|
|
|
Exprent ifexpr = ifstat.getExprents().get(0); |
|
|
|
|
Exprent elseexpr = elsestat.getExprents().get(0); |
|
|
|
|
|
|
|
|
|
if (ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) { |
|
|
|
|
AssignmentExprent ifas = (AssignmentExprent)ifexpr; |
|
|
|
|
AssignmentExprent elseas = (AssignmentExprent)elseexpr; |
|
|
|
|
|
|
|
|
|
if (ifas.getLeft().type == Exprent.EXPRENT_VAR && elseas.getLeft().type == Exprent.EXPRENT_VAR) { |
|
|
|
|
VarExprent ifvar = (VarExprent)ifas.getLeft(); |
|
|
|
|
VarExprent elsevar = (VarExprent)elseas.getLeft(); |
|
|
|
|
|
|
|
|
|
if (ifvar.getIndex() == elsevar.getIndex() && ifvar.isStack()) { // ifvar.getIndex() >= VarExprent.STACK_BASE) {
|
|
|
|
|
IfStatement statement = (IfStatement)stat; |
|
|
|
|
Exprent ifHeadExpr = statement.getHeadexprent(); |
|
|
|
|
Set<Integer> ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode); |
|
|
|
|
|
|
|
|
|
if (statement.iftype == IfStatement.IFTYPE_IFELSE) { |
|
|
|
|
Statement ifStatement = statement.getIfstat(); |
|
|
|
|
Statement elseStatement = statement.getElsestat(); |
|
|
|
|
|
|
|
|
|
if (ifStatement.getExprents() != null && ifStatement.getExprents().size() == 1 && |
|
|
|
|
elseStatement.getExprents() != null && elseStatement.getExprents().size() == 1 && |
|
|
|
|
ifStatement.getAllSuccessorEdges().size() == 1 && elseStatement.getAllSuccessorEdges().size() == 1 && |
|
|
|
|
ifStatement.getAllSuccessorEdges().get(0).getDestination() == elseStatement.getAllSuccessorEdges().get(0).getDestination()) { |
|
|
|
|
Exprent ifExpr = ifStatement.getExprents().get(0); |
|
|
|
|
Exprent elseExpr = elseStatement.getExprents().get(0); |
|
|
|
|
|
|
|
|
|
if (ifExpr.type == Exprent.EXPRENT_ASSIGNMENT && elseExpr.type == Exprent.EXPRENT_ASSIGNMENT) { |
|
|
|
|
AssignmentExprent ifAssign = (AssignmentExprent)ifExpr; |
|
|
|
|
AssignmentExprent elseAssign = (AssignmentExprent)elseExpr; |
|
|
|
|
|
|
|
|
|
if (ifAssign.getLeft().type == Exprent.EXPRENT_VAR && elseAssign.getLeft().type == Exprent.EXPRENT_VAR) { |
|
|
|
|
VarExprent ifVar = (VarExprent)ifAssign.getLeft(); |
|
|
|
|
VarExprent elseVar = (VarExprent)elseAssign.getLeft(); |
|
|
|
|
|
|
|
|
|
if (ifVar.getIndex() == elseVar.getIndex() && ifVar.isStack()) { // ifVar.getIndex() >= VarExprent.STACK_BASE) {
|
|
|
|
|
boolean found = false; |
|
|
|
|
|
|
|
|
|
for (Entry<VarVersionPair, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) { |
|
|
|
|
if (ent.getKey().var == ifvar.getIndex()) { |
|
|
|
|
if (ent.getValue().contains(ifvar.getVersion()) && ent.getValue().contains(elsevar.getVersion())) { |
|
|
|
|
if (ent.getKey().var == ifVar.getIndex()) { |
|
|
|
|
if (ent.getValue().contains(ifVar.getVersion()) && ent.getValue().contains(elseVar.getVersion())) { |
|
|
|
|
found = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
@ -629,65 +636,61 @@ public class SimplifyExprentsHelper { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (found) { |
|
|
|
|
List<Exprent> data = new ArrayList<>(stif.getFirst().getExprents()); |
|
|
|
|
List<Exprent> data = new ArrayList<>(statement.getFirst().getExprents()); |
|
|
|
|
|
|
|
|
|
data.add(new AssignmentExprent(ifvar, new FunctionExprent(FunctionExprent.FUNCTION_IIF, |
|
|
|
|
Arrays.asList( |
|
|
|
|
stif.getHeadexprent().getCondition(), |
|
|
|
|
ifas.getRight(), |
|
|
|
|
elseas.getRight()), ifheadexpr_bytecode), ifheadexpr_bytecode)); |
|
|
|
|
stif.setExprents(data); |
|
|
|
|
List<Exprent> operands = Arrays.asList(statement.getHeadexprent().getCondition(), ifAssign.getRight(), elseAssign.getRight()); |
|
|
|
|
data.add(new AssignmentExprent(ifVar, new FunctionExprent(FunctionExprent.FUNCTION_IIF, operands, ifHeadExprBytecode), ifHeadExprBytecode)); |
|
|
|
|
statement.setExprents(data); |
|
|
|
|
|
|
|
|
|
if (stif.getAllSuccessorEdges().isEmpty()) { |
|
|
|
|
StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0); |
|
|
|
|
StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination()); |
|
|
|
|
if (statement.getAllSuccessorEdges().isEmpty()) { |
|
|
|
|
StatEdge ifEdge = ifStatement.getAllSuccessorEdges().get(0); |
|
|
|
|
StatEdge edge = new StatEdge(ifEdge.getType(), statement, ifEdge.getDestination()); |
|
|
|
|
|
|
|
|
|
stif.addSuccessor(edge); |
|
|
|
|
if (ifedge.closure != null) { |
|
|
|
|
ifedge.closure.addLabeledEdge(edge); |
|
|
|
|
statement.addSuccessor(edge); |
|
|
|
|
if (ifEdge.closure != null) { |
|
|
|
|
ifEdge.closure.addLabeledEdge(edge); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SequenceHelper.destroyAndFlattenStatement(stif); |
|
|
|
|
SequenceHelper.destroyAndFlattenStatement(statement); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (ifexpr.type == Exprent.EXPRENT_EXIT && elseexpr.type == Exprent.EXPRENT_EXIT) { |
|
|
|
|
ExitExprent ifex = (ExitExprent)ifexpr; |
|
|
|
|
ExitExprent elseex = (ExitExprent)elseexpr; |
|
|
|
|
|
|
|
|
|
if (ifex.getExitType() == elseex.getExitType() && ifex.getValue() != null && elseex.getValue() != null && |
|
|
|
|
ifex.getExitType() == ExitExprent.EXIT_RETURN) { |
|
|
|
|
else if (ifExpr.type == Exprent.EXPRENT_EXIT && elseExpr.type == Exprent.EXPRENT_EXIT) { |
|
|
|
|
ExitExprent ifExit = (ExitExprent)ifExpr; |
|
|
|
|
ExitExprent elseExit = (ExitExprent)elseExpr; |
|
|
|
|
|
|
|
|
|
if (ifExit.getExitType() == elseExit.getExitType() && ifExit.getValue() != null && elseExit.getValue() != null && |
|
|
|
|
ifExit.getExitType() == ExitExprent.EXIT_RETURN) { |
|
|
|
|
// throw is dangerous, because of implicit casting to a common superclass
|
|
|
|
|
// e.g. throws IOException and throw true?new RuntimeException():new IOException(); won't work
|
|
|
|
|
if (ifex.getExitType() == ExitExprent.EXIT_THROW && |
|
|
|
|
!ifex.getValue().getExprType().equals(elseex.getValue().getExprType())) { // note: getExprType unreliable at this point!
|
|
|
|
|
if (ifExit.getExitType() == ExitExprent.EXIT_THROW && |
|
|
|
|
!ifExit.getValue().getExprType().equals(elseExit.getValue().getExprType())) { // note: getExprType unreliable at this point!
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// avoid flattening to 'iff' if any of the branches is an 'iff' already
|
|
|
|
|
if (isIff(ifex.getValue()) || isIff(elseex.getValue())) { |
|
|
|
|
if (isIff(ifExit.getValue()) || isIff(elseExit.getValue())) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<Exprent> data = new ArrayList<>(stif.getFirst().getExprents()); |
|
|
|
|
List<Exprent> data = new ArrayList<>(statement.getFirst().getExprents()); |
|
|
|
|
|
|
|
|
|
data.add(new ExitExprent(ifex.getExitType(), new FunctionExprent(FunctionExprent.FUNCTION_IIF, |
|
|
|
|
data.add(new ExitExprent(ifExit.getExitType(), new FunctionExprent(FunctionExprent.FUNCTION_IIF, |
|
|
|
|
Arrays.asList( |
|
|
|
|
stif.getHeadexprent().getCondition(), |
|
|
|
|
ifex.getValue(), |
|
|
|
|
elseex.getValue()), ifheadexpr_bytecode), ifex.getRetType(), ifheadexpr_bytecode)); |
|
|
|
|
stif.setExprents(data); |
|
|
|
|
statement.getHeadexprent().getCondition(), |
|
|
|
|
ifExit.getValue(), |
|
|
|
|
elseExit.getValue()), ifHeadExprBytecode), ifExit.getRetType(), ifHeadExprBytecode)); |
|
|
|
|
statement.setExprents(data); |
|
|
|
|
|
|
|
|
|
StatEdge retedge = ifstat.getAllSuccessorEdges().get(0); |
|
|
|
|
stif.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, stif, retedge.getDestination(), |
|
|
|
|
retedge.closure == stif ? stif.getParent() : retedge.closure)); |
|
|
|
|
StatEdge retEdge = ifStatement.getAllSuccessorEdges().get(0); |
|
|
|
|
Statement closure = retEdge.closure == statement ? statement.getParent() : retEdge.closure; |
|
|
|
|
statement.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, statement, retEdge.getDestination(), closure)); |
|
|
|
|
|
|
|
|
|
SequenceHelper.destroyAndFlattenStatement(stif); |
|
|
|
|
SequenceHelper.destroyAndFlattenStatement(statement); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -703,41 +706,14 @@ public class SimplifyExprentsHelper { |
|
|
|
|
return exp.type == Exprent.EXPRENT_FUNCTION && ((FunctionExprent) exp).getFuncType() == FunctionExprent.FUNCTION_IIF; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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:$fieldname$\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:$fieldname$\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:$fieldname$ ret:$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$"); |
|
|
|
|
FieldExprent fieldexpr = (FieldExprent)class14Builder.getVariableValue("$field$"); |
|
|
|
|
AssignmentExprent assignment = (AssignmentExprent)class14Builder.getVariableValue("$assignfield$"); |
|
|
|
|
FieldExprent fieldExpr = (FieldExprent)class14Builder.getVariableValue("$field$"); |
|
|
|
|
|
|
|
|
|
assfirst.replaceExprent(assfirst.getRight(), new ConstExprent(VarType.VARTYPE_CLASS, class_name, null)); |
|
|
|
|
assignment.replaceExprent(assignment.getRight(), new ConstExprent(VarType.VARTYPE_CLASS, class_name, null)); |
|
|
|
|
|
|
|
|
|
List<Exprent> data = new ArrayList<>(stat.getFirst().getExprents()); |
|
|
|
|
|
|
|
|
@ -747,7 +723,7 @@ public class SimplifyExprentsHelper { |
|
|
|
|
|
|
|
|
|
ClassWrapper wrapper = (ClassWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_WRAPPER); |
|
|
|
|
if (wrapper != null) { |
|
|
|
|
wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fieldexpr.getName(), fieldexpr.getDescriptor().descriptorString)); |
|
|
|
|
wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fieldExpr.getName(), fieldExpr.getDescriptor().descriptorString)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|