|
|
@ -25,24 +25,16 @@ public class ComplexExpression extends Expression { |
|
|
|
|
|
|
|
|
|
|
|
public ComplexExpression(Operator op, Expression[] sub) { |
|
|
|
public ComplexExpression(Operator op, Expression[] sub) { |
|
|
|
super(Type.tUnknown); |
|
|
|
super(Type.tUnknown); |
|
|
|
|
|
|
|
if (sub.length != op.getOperandCount()) |
|
|
|
|
|
|
|
throw new AssertError ("Operand count mismatch: "+ |
|
|
|
|
|
|
|
sub.length + " != " + |
|
|
|
|
|
|
|
op.getOperandCount()); |
|
|
|
operator = op; |
|
|
|
operator = op; |
|
|
|
operator.parent = this; |
|
|
|
operator.parent = this; |
|
|
|
subExpressions = sub; |
|
|
|
subExpressions = sub; |
|
|
|
operator.setExpression(this); |
|
|
|
for (int i=0; i< subExpressions.length; i++) |
|
|
|
if (subExpressions.length != op.getOperandCount()) |
|
|
|
subExpressions[i].parent = this; |
|
|
|
throw new AssertError ("Operand count mismatch: "+ |
|
|
|
updateType(); |
|
|
|
subExpressions.length + " != " + |
|
|
|
|
|
|
|
op.getOperandCount()); |
|
|
|
|
|
|
|
if (subExpressions.length > 0) { |
|
|
|
|
|
|
|
Type types[] = new Type[subExpressions.length]; |
|
|
|
|
|
|
|
for (int i=0; i < types.length; i++) { |
|
|
|
|
|
|
|
subExpressions[i].parent = this; |
|
|
|
|
|
|
|
types[i] = subExpressions[i].getType(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
operator.setOperandType(types); |
|
|
|
|
|
|
|
updateSubTypes(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.type = operator.getType(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public int getOperandCount() { |
|
|
|
public int getOperandCount() { |
|
|
@ -74,8 +66,7 @@ public class ComplexExpression extends Expression { |
|
|
|
|
|
|
|
|
|
|
|
Operator negop = |
|
|
|
Operator negop = |
|
|
|
new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP); |
|
|
|
new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP); |
|
|
|
Expression[] e = { this }; |
|
|
|
return new ComplexExpression(negop, new Expression[] { this }); |
|
|
|
return new ComplexExpression(negop, e); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public Expression tryToCombine(Expression e) { |
|
|
|
public Expression tryToCombine(Expression e) { |
|
|
@ -118,18 +109,49 @@ public class ComplexExpression extends Expression { |
|
|
|
|
|
|
|
|
|
|
|
void updateSubTypes() { |
|
|
|
void updateSubTypes() { |
|
|
|
for (int i=0; i < subExpressions.length; i++) { |
|
|
|
for (int i=0; i < subExpressions.length; i++) { |
|
|
|
subExpressions[i].setType(operator.getOperandType(i)); |
|
|
|
if (i == 0 && operator instanceof ArrayStoreOperator) { |
|
|
|
|
|
|
|
/* No rule without exception: |
|
|
|
|
|
|
|
* We can always use tSubType, except for the |
|
|
|
|
|
|
|
* array operand of an array store instruction. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
subExpressions[i].setType(operator.getOperandType(i)); |
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
subExpressions[i].setType |
|
|
|
|
|
|
|
(Type.tSubType(operator.getOperandType(i))); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void updateType() { |
|
|
|
public void updateType() { |
|
|
|
updateSubTypes(); |
|
|
|
|
|
|
|
if (subExpressions.length > 0) { |
|
|
|
if (subExpressions.length > 0) { |
|
|
|
Type types[] = new Type[subExpressions.length]; |
|
|
|
Type types[] = new Type[subExpressions.length]; |
|
|
|
for (int i=0; i < types.length; i++) { |
|
|
|
while (true) { |
|
|
|
types[i] = subExpressions[i].getType(); |
|
|
|
boolean changed = false; |
|
|
|
|
|
|
|
updateSubTypes(); |
|
|
|
|
|
|
|
for (int i=0; i < types.length; i++) { |
|
|
|
|
|
|
|
if (i == 0 && operator instanceof ArrayStoreOperator) { |
|
|
|
|
|
|
|
/* No rule without exception: |
|
|
|
|
|
|
|
* We can always use tSuperType, except for the |
|
|
|
|
|
|
|
* array operand of an array store instruction. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
types[i] = subExpressions[i].getType(); |
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
types[i] = Type.tSuperType |
|
|
|
|
|
|
|
(subExpressions[i].getType()); |
|
|
|
|
|
|
|
types[i] = |
|
|
|
|
|
|
|
types[i].intersection(operator.getOperandType(i)); |
|
|
|
|
|
|
|
if (!types[i].equals(operator.getOperandType(i))) { |
|
|
|
|
|
|
|
if (Decompiler.isTypeDebugging) |
|
|
|
|
|
|
|
System.err.println("change in "+this+": " |
|
|
|
|
|
|
|
+operator.getOperandType(i) |
|
|
|
|
|
|
|
+"->"+types[i]); |
|
|
|
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (changed) |
|
|
|
|
|
|
|
operator.setOperandType(types); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
operator.setOperandType(types); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
setType(operator.getType()); |
|
|
|
setType(operator.getType()); |
|
|
|
} |
|
|
|
} |
|
|
@ -140,6 +162,8 @@ public class ComplexExpression extends Expression { |
|
|
|
type = newType; |
|
|
|
type = newType; |
|
|
|
operator.setType(type); |
|
|
|
operator.setType(type); |
|
|
|
updateSubTypes(); |
|
|
|
updateSubTypes(); |
|
|
|
|
|
|
|
if (parent != null) |
|
|
|
|
|
|
|
parent.updateType(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -151,14 +175,22 @@ public class ComplexExpression extends Expression { |
|
|
|
String[] expr = new String[subExpressions.length]; |
|
|
|
String[] expr = new String[subExpressions.length]; |
|
|
|
for (int i=0; i<subExpressions.length; i++) { |
|
|
|
for (int i=0; i<subExpressions.length; i++) { |
|
|
|
expr[i] = subExpressions[i]. |
|
|
|
expr[i] = subExpressions[i]. |
|
|
|
toString(operator.getOperandPriority(i)); |
|
|
|
toString(Decompiler.isTypeDebugging |
|
|
|
|
|
|
|
? 700 /* type cast priority */ |
|
|
|
|
|
|
|
: operator.getOperandPriority(i)); |
|
|
|
|
|
|
|
if (Decompiler.isTypeDebugging) { |
|
|
|
|
|
|
|
expr[i] = "("+ |
|
|
|
|
|
|
|
(operator.getOperandType(i) |
|
|
|
|
|
|
|
.equals(subExpressions[i].getType()) |
|
|
|
|
|
|
|
? "" : ""+subExpressions[i].getType()+"->") |
|
|
|
|
|
|
|
+ operator.getOperandType(i)+") "+expr[i]; |
|
|
|
|
|
|
|
if (700 < operator.getOperandPriority(i)) |
|
|
|
|
|
|
|
expr[i] = "(" + expr[i] + ")"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (subExpressions[i].getType() == Type.tError) |
|
|
|
|
|
|
|
expr[i] = "(/*type error */" + expr[i]+")"; |
|
|
|
} |
|
|
|
} |
|
|
|
String result = operator.toString(expr); |
|
|
|
return operator.toString(expr); |
|
|
|
if (Decompiler.isTypeDebugging) |
|
|
|
|
|
|
|
result = "("+operator.getType()+") ("+result+")"; |
|
|
|
|
|
|
|
else if (operator.getType() == Type.tError) |
|
|
|
|
|
|
|
result = "(/*type error */" + result+")"; |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean equals(Object o) { |
|
|
|
public boolean equals(Object o) { |
|
|
@ -186,6 +218,7 @@ public class ComplexExpression extends Expression { |
|
|
|
if (operator instanceof InvokeOperator |
|
|
|
if (operator instanceof InvokeOperator |
|
|
|
&& ((field = ((InvokeOperator)operator).getField()) |
|
|
|
&& ((field = ((InvokeOperator)operator).getField()) |
|
|
|
.getCpoolClass().getName().getString() |
|
|
|
.getCpoolClass().getName().getString() |
|
|
|
|
|
|
|
.replace(java.io.File.separatorChar, '.') |
|
|
|
.equals("java.lang.StringBuffer")) |
|
|
|
.equals("java.lang.StringBuffer")) |
|
|
|
&& !((InvokeOperator)operator).isStatic() && |
|
|
|
&& !((InvokeOperator)operator).isStatic() && |
|
|
|
field.getNameAndType().getName().getString().equals("append") && |
|
|
|
field.getNameAndType().getName().getString().equals("append") && |
|
|
@ -199,9 +232,9 @@ public class ComplexExpression extends Expression { |
|
|
|
subExpressions[1].getType().isOfType(Type.tString)) |
|
|
|
subExpressions[1].getType().isOfType(Type.tString)) |
|
|
|
return subExpressions[1]; |
|
|
|
return subExpressions[1]; |
|
|
|
|
|
|
|
|
|
|
|
Expression[] exprs = { e, |
|
|
|
return new ComplexExpression |
|
|
|
(Expression)subExpressions[1].simplify() }; |
|
|
|
(new StringAddOperator(), new Expression[] |
|
|
|
return new ComplexExpression(new StringAddOperator(), exprs); |
|
|
|
{ e, (Expression)subExpressions[1].simplify() }); |
|
|
|
} |
|
|
|
} |
|
|
|
if (operator instanceof ConstructorOperator && |
|
|
|
if (operator instanceof ConstructorOperator && |
|
|
|
operator.getType().isOfType(Type.tStringBuffer)) { |
|
|
|
operator.getType().isOfType(Type.tStringBuffer)) { |
|
|
@ -224,45 +257,51 @@ public class ComplexExpression extends Expression { |
|
|
|
(ConstOperator) subExpressions[1].getOperator(); |
|
|
|
(ConstOperator) subExpressions[1].getOperator(); |
|
|
|
ConstOperator c2 = |
|
|
|
ConstOperator c2 = |
|
|
|
(ConstOperator) subExpressions[2].getOperator(); |
|
|
|
(ConstOperator) subExpressions[2].getOperator(); |
|
|
|
if (c1.getValue().equals("true") && |
|
|
|
if (c1.getValue().equals("1") && |
|
|
|
c2.getValue().equals("false")) |
|
|
|
c2.getValue().equals("0")) |
|
|
|
return subExpressions[0].simplify(); |
|
|
|
return subExpressions[0].simplify(); |
|
|
|
if (c2.getValue().equals("true") && |
|
|
|
if (c2.getValue().equals("1") && |
|
|
|
c1.getValue().equals("false")) |
|
|
|
c1.getValue().equals("0")) |
|
|
|
return subExpressions[0].negate().simplify(); |
|
|
|
return subExpressions[0].negate().simplify(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// if ((operator instanceof AssignOperator ||
|
|
|
|
else if ((operator instanceof AssignOperator || |
|
|
|
// operator instanceof StoreInstruction) &&
|
|
|
|
operator instanceof StoreInstruction) && |
|
|
|
// subExpressions[subExpressions.length-1]
|
|
|
|
subExpressions[subExpressions.length-1] |
|
|
|
// .operator instanceof ConstOperator) {
|
|
|
|
.getOperator() instanceof ConstOperator) { |
|
|
|
// StoreInstruction store;
|
|
|
|
|
|
|
|
// if (operator instanceof AssignOperator)
|
|
|
|
StoreInstruction store; |
|
|
|
// store = ((AssignOperator)operator).getStore();
|
|
|
|
if (operator instanceof AssignOperator) |
|
|
|
// else
|
|
|
|
store = ((AssignOperator)operator).getStore(); |
|
|
|
// store = (StoreInstruction)operator;
|
|
|
|
else |
|
|
|
|
|
|
|
store = (StoreInstruction)operator; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ConstOperator one = (ConstOperator) |
|
|
|
|
|
|
|
subExpressions[subExpressions.length-1].getOperator(); |
|
|
|
|
|
|
|
|
|
|
|
// ConstOperator one = (ConstOperator)
|
|
|
|
if ((operator.getOperatorIndex() == |
|
|
|
// subExpressions[subExpressions.length-1].operator;
|
|
|
|
operator.OPASSIGN_OP+operator.ADD_OP || |
|
|
|
|
|
|
|
operator.getOperatorIndex() == |
|
|
|
|
|
|
|
operator.OPASSIGN_OP+operator.NEG_OP) && |
|
|
|
|
|
|
|
(one.getValue().equals("1") || |
|
|
|
|
|
|
|
one.getValue().equals("-1"))) { |
|
|
|
|
|
|
|
|
|
|
|
// if ((operator.getOperatorIndex() ==
|
|
|
|
int op = ((operator.getOperatorIndex() == |
|
|
|
// operator.OPASSIGN_OP+operator.ADD_OP ||
|
|
|
|
operator.OPASSIGN_OP+operator.ADD_OP) == |
|
|
|
// operator.getOperatorIndex() ==
|
|
|
|
one.getValue().equals("1"))? |
|
|
|
// operator.OPASSIGN_OP+operator.NEG_OP) &&
|
|
|
|
operator.INC_OP : operator.DEC_OP; |
|
|
|
// (one.getValue().equals("1") ||
|
|
|
|
|
|
|
|
// one.getValue().equals("-1"))) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// int op = ((operator.getOperatorIndex() ==
|
|
|
|
Operator ppfixop = new PrePostFixOperator |
|
|
|
// operator.OPASSIGN_OP+operator.ADD_OP) ==
|
|
|
|
(store.getLValueType(), op, store, |
|
|
|
// one.getValue().equals("1"))?
|
|
|
|
operator instanceof StoreInstruction); |
|
|
|
// operator.INC_OP : operator.DEC_OP;
|
|
|
|
if (subExpressions.length == 1) |
|
|
|
|
|
|
|
return ppfixop.simplify(); |
|
|
|
|
|
|
|
|
|
|
|
// return new PostFixOperator
|
|
|
|
operator = ppfixop; |
|
|
|
// (store.getType(), op, store,
|
|
|
|
ppfixop.parent = this; |
|
|
|
// operator instanceof StoreInstruction).simplify();
|
|
|
|
} |
|
|
|
// }
|
|
|
|
} |
|
|
|
// }
|
|
|
|
else if (operator instanceof CompareUnaryOperator && |
|
|
|
if (operator instanceof CompareUnaryOperator && |
|
|
|
|
|
|
|
subExpressions[0].getOperator() instanceof CompareToIntOperator) { |
|
|
|
subExpressions[0].getOperator() instanceof CompareToIntOperator) { |
|
|
|
|
|
|
|
|
|
|
|
CompareBinaryOperator newOp = new CompareBinaryOperator |
|
|
|
CompareBinaryOperator newOp = new CompareBinaryOperator |
|
|
@ -277,7 +316,7 @@ public class ComplexExpression extends Expression { |
|
|
|
} else |
|
|
|
} else |
|
|
|
return newOp.simplify(); |
|
|
|
return newOp.simplify(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (operator instanceof CompareUnaryOperator && |
|
|
|
else if (operator instanceof CompareUnaryOperator && |
|
|
|
operator.getOperandType(0).isOfType(Type.tBoolean)) { |
|
|
|
operator.getOperandType(0).isOfType(Type.tBoolean)) { |
|
|
|
/* xx == false */ |
|
|
|
/* xx == false */ |
|
|
|
if (operator.getOperatorIndex() == operator.EQUALS_OP) |
|
|
|
if (operator.getOperatorIndex() == operator.EQUALS_OP) |
|
|
@ -286,42 +325,39 @@ public class ComplexExpression extends Expression { |
|
|
|
if (operator.getOperatorIndex() == operator.NOTEQUALS_OP) |
|
|
|
if (operator.getOperatorIndex() == operator.NOTEQUALS_OP) |
|
|
|
return subExpressions[0].simplify(); |
|
|
|
return subExpressions[0].simplify(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else if (operator instanceof InvokeOperator |
|
|
|
if (operator instanceof InvokeOperator |
|
|
|
|
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
.getNameAndType().getName().getString().equals("toString")) |
|
|
|
.getNameAndType().getName().getString().equals("toString")) |
|
|
|
&& !((InvokeOperator)operator).isStatic() |
|
|
|
&& !((InvokeOperator)operator).isStatic() |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
.getCpoolClass().getName().getString() |
|
|
|
.getCpoolClass().getName().getString() |
|
|
|
|
|
|
|
.replace(java.io.File.separatorChar, '.') |
|
|
|
.equals("java.lang.StringBuffer")) |
|
|
|
.equals("java.lang.StringBuffer")) |
|
|
|
&& subExpressions.length == 1) { |
|
|
|
&& subExpressions.length == 1) { |
|
|
|
Instruction simple = subExpressions[0].simplifyStringBuffer(); |
|
|
|
Instruction simple = subExpressions[0].simplifyStringBuffer(); |
|
|
|
if (simple != null) |
|
|
|
if (simple != null) |
|
|
|
return simple; |
|
|
|
return simple; |
|
|
|
} |
|
|
|
} |
|
|
|
if (operator instanceof InvokeOperator |
|
|
|
else if (operator instanceof InvokeOperator |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
.getNameAndType().getName().getString().equals("valueOf")) |
|
|
|
.getNameAndType().getName().getString().equals("valueOf")) |
|
|
|
&& ((InvokeOperator)operator).isStatic() |
|
|
|
&& ((InvokeOperator)operator).isStatic() |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
&& (((InvokeOperator)operator).getField() |
|
|
|
.getCpoolClass().getName().getString() |
|
|
|
.getCpoolClass().getName().getString() |
|
|
|
|
|
|
|
.replace(java.io.File.separatorChar, '.') |
|
|
|
.equals("java.lang.String")) |
|
|
|
.equals("java.lang.String")) |
|
|
|
&& subExpressions.length == 1) { |
|
|
|
&& subExpressions.length == 1) { |
|
|
|
if (subExpressions[0].getType() == Type.tString) |
|
|
|
if (subExpressions[0].getType() == Type.tString) |
|
|
|
return subExpressions[0].simplify(); |
|
|
|
return subExpressions[0].simplify(); |
|
|
|
else { |
|
|
|
|
|
|
|
Expression[] exprs = { |
|
|
|
return new ComplexExpression |
|
|
|
emptyString, |
|
|
|
(new StringAddOperator(), new Expression[] |
|
|
|
(Expression) subExpressions[0].simplify() |
|
|
|
{ emptyString, (Expression) subExpressions[0].simplify() }); |
|
|
|
}; |
|
|
|
|
|
|
|
return new ComplexExpression(new StringAddOperator(), exprs); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
for (int i=0; i< subExpressions.length; i++) { |
|
|
|
for (int i=0; i< subExpressions.length; i++) { |
|
|
|
subExpressions[i] = (Expression) subExpressions[i].simplify(); |
|
|
|
subExpressions[i] = (Expression) subExpressions[i].simplify(); |
|
|
|
subExpressions[i].parent = this; |
|
|
|
subExpressions[i].parent = this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
return this; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|