|
|
|
@ -23,11 +23,17 @@ import jode.GlobalOptions; |
|
|
|
|
import jode.Decompiler; |
|
|
|
|
import jode.decompiler.Analyzer; |
|
|
|
|
import jode.decompiler.ClassAnalyzer; |
|
|
|
|
import jode.decompiler.CodeAnalyzer; |
|
|
|
|
import jode.decompiler.MethodAnalyzer; |
|
|
|
|
import jode.expr.*; |
|
|
|
|
import jode.type.MethodType; |
|
|
|
|
import jode.type.Type; |
|
|
|
|
import jode.bytecode.ClassInfo; |
|
|
|
|
import jode.bytecode.InnerClassInfo; |
|
|
|
|
|
|
|
|
|
import java.util.Vector; |
|
|
|
|
import java.util.Enumeration; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* |
|
|
|
|
* @author Jochen Hoenicke |
|
|
|
@ -39,9 +45,215 @@ public class TransformConstructors { |
|
|
|
|
&& (((ThisOperator)thisExpr).getClassInfo() == clazz)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static boolean checkImplicitAnonymousConstructor |
|
|
|
|
(ClassAnalyzer clazzAnalyzer, MethodAnalyzer constr) { |
|
|
|
|
|
|
|
|
|
if (clazzAnalyzer.getName() != null) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
int outerValuesLength = clazzAnalyzer.getOuterValues().length; |
|
|
|
|
MethodType origType = constr.getType(); |
|
|
|
|
/** |
|
|
|
|
* Situation: |
|
|
|
|
* constructor(outerParams, params) { |
|
|
|
|
* super(params); |
|
|
|
|
* } |
|
|
|
|
* |
|
|
|
|
* Mark constructor as anonymous constructor. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
StructuredBlock sb = constr.getMethodHeader().block; |
|
|
|
|
if (!(sb instanceof InstructionBlock)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
InstructionBlock superBlock = (InstructionBlock) sb; |
|
|
|
|
if (!(superBlock.getInstruction() instanceof InvokeOperator)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
InvokeOperator superCall |
|
|
|
|
= (InvokeOperator) superBlock.getInstruction().simplify(); |
|
|
|
|
superBlock.setInstruction(superCall); |
|
|
|
|
|
|
|
|
|
if (superCall.getFreeOperandCount() != 0 |
|
|
|
|
|| !superCall.isConstructor() || !superCall.isSuperOrThis()) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
Expression[] subExpr = superCall.getSubExpressions(); |
|
|
|
|
Expression thisExpr = subExpr[0]; |
|
|
|
|
if (!isThis(thisExpr, clazzAnalyzer.getClazz())) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
Type[] constrParams = constr.getType().getParameterTypes(); |
|
|
|
|
if (subExpr.length - 1 != constrParams.length - outerValuesLength) |
|
|
|
|
return false; |
|
|
|
|
for (int i = 1; i < subExpr.length; i++) { |
|
|
|
|
if (!(subExpr[i] instanceof LocalLoadOperator)) |
|
|
|
|
return false; |
|
|
|
|
LocalLoadOperator llop = (LocalLoadOperator) subExpr[i]; |
|
|
|
|
if (llop.getLocalInfo().getSlot() != i + outerValuesLength) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
constr.setAnonymousConstructor(true); |
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static boolean checkJikesSuperAndFillLoads(Expression expr, |
|
|
|
|
int outerValuesLength, |
|
|
|
|
Vector localLoads) { |
|
|
|
|
if (expr instanceof LocalStoreOperator |
|
|
|
|
|| expr instanceof IIncOperator) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
if (expr instanceof LocalLoadOperator) { |
|
|
|
|
LocalLoadOperator llop = (LocalLoadOperator) expr; |
|
|
|
|
int slot = llop.getLocalInfo().getSlot(); |
|
|
|
|
if (slot < outerValuesLength) |
|
|
|
|
return false; |
|
|
|
|
localLoads.addElement(llop); |
|
|
|
|
} |
|
|
|
|
if (expr instanceof Operator) { |
|
|
|
|
Expression subExpr[] = ((Operator)expr).getSubExpressions(); |
|
|
|
|
for (int i=0; i< subExpr.length; i++) { |
|
|
|
|
if (!checkJikesSuperAndFillLoads(subExpr[i], outerValuesLength, |
|
|
|
|
localLoads)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static boolean checkJikesContinuation |
|
|
|
|
(ClassAnalyzer clazzAnalyzer, MethodAnalyzer constr) { |
|
|
|
|
|
|
|
|
|
Expression[] oVs = clazzAnalyzer.getOuterValues(); |
|
|
|
|
int outerValuesLength = oVs == null ? 0 : oVs.length; |
|
|
|
|
MethodType origType = constr.getType(); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Situation: |
|
|
|
|
* constructor(outerParams, params) { |
|
|
|
|
* [optional: super(this, params, exprs)] |
|
|
|
|
* constructor$?(Outer.this, params); |
|
|
|
|
* } |
|
|
|
|
* |
|
|
|
|
* Move optional super to method constructor$? |
|
|
|
|
* (renaming local variables) and mark constructor and |
|
|
|
|
* constructor$? as Jikes constructor. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
StructuredBlock sb = constr.getMethodHeader().block; |
|
|
|
|
|
|
|
|
|
Vector localLoads = null; |
|
|
|
|
InstructionBlock superBlock = null; |
|
|
|
|
if (sb instanceof SequentialBlock) { |
|
|
|
|
|
|
|
|
|
if (!(sb.getSubBlocks()[0] instanceof InstructionBlock) |
|
|
|
|
|| !(sb.getSubBlocks()[1] instanceof InstructionBlock)) |
|
|
|
|
return false; |
|
|
|
|
superBlock = (InstructionBlock) sb.getSubBlocks()[0]; |
|
|
|
|
sb = sb.getSubBlocks()[1]; |
|
|
|
|
|
|
|
|
|
if (!(superBlock.getInstruction() instanceof InvokeOperator)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
InvokeOperator superCall |
|
|
|
|
= (InvokeOperator) superBlock.getInstruction().simplify(); |
|
|
|
|
superBlock.setInstruction(superCall); |
|
|
|
|
|
|
|
|
|
if (superCall.getFreeOperandCount() != 0 |
|
|
|
|
|| !superCall.isConstructor() || !superCall.isSuperOrThis()) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
Expression[] subExpr = superCall.getSubExpressions(); |
|
|
|
|
Expression thisExpr = subExpr[0]; |
|
|
|
|
if (!isThis(thisExpr, clazzAnalyzer.getClazz())) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
localLoads = new Vector(); |
|
|
|
|
for (int i=1; i< subExpr.length; i++) { |
|
|
|
|
if (!checkJikesSuperAndFillLoads(subExpr[i], outerValuesLength, |
|
|
|
|
localLoads)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else if (!(sb instanceof InstructionBlock)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
/* Now check the constructor$? invocation */ |
|
|
|
|
Expression lastExpr = ((InstructionBlock)sb).getInstruction(); |
|
|
|
|
if (!(lastExpr instanceof InvokeOperator)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
InvokeOperator invoke = (InvokeOperator) lastExpr; |
|
|
|
|
if (!invoke.isThis() |
|
|
|
|
|| invoke.getFreeOperandCount() != 0) |
|
|
|
|
return false; |
|
|
|
|
MethodAnalyzer methodAna = invoke.getMethodAnalyzer(); |
|
|
|
|
if (methodAna == null) |
|
|
|
|
return false; |
|
|
|
|
CodeAnalyzer codeAna = methodAna.getCode(); |
|
|
|
|
if (codeAna == null) |
|
|
|
|
return false; |
|
|
|
|
MethodType type = methodAna.getType(); |
|
|
|
|
|
|
|
|
|
if (!methodAna.getName().startsWith("constructor$") |
|
|
|
|
|| (type.getParameterTypes().length - 1 |
|
|
|
|
!= origType.getParameterTypes().length - outerValuesLength) |
|
|
|
|
|| type.getReturnType() != Type.tVoid) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
if (!isThis(invoke.getSubExpressions()[0], |
|
|
|
|
clazzAnalyzer.getClazz())) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
ClassInfo parent; |
|
|
|
|
if (clazzAnalyzer.getParent() instanceof ClassAnalyzer) |
|
|
|
|
parent = ((ClassAnalyzer) clazzAnalyzer.getParent()) |
|
|
|
|
.getClazz(); |
|
|
|
|
else if (clazzAnalyzer.getParent() instanceof CodeAnalyzer) |
|
|
|
|
parent = ((CodeAnalyzer) clazzAnalyzer.getParent()) |
|
|
|
|
.getClazz(); |
|
|
|
|
else |
|
|
|
|
return false; |
|
|
|
|
if (!isThis(invoke.getSubExpressions()[1], parent)) |
|
|
|
|
return false; |
|
|
|
|
for (int j = 1; j < type.getParameterTypes().length; j++) { |
|
|
|
|
if (!(invoke.getSubExpressions()[j+1] |
|
|
|
|
instanceof LocalLoadOperator)) |
|
|
|
|
return false; |
|
|
|
|
LocalLoadOperator llop |
|
|
|
|
= (LocalLoadOperator) invoke.getSubExpressions()[j+1]; |
|
|
|
|
if (llop.getLocalInfo().getSlot() != j + outerValuesLength) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
constr.getMethodHeader().block.removeBlock(); |
|
|
|
|
|
|
|
|
|
/* Now move the constructor call. |
|
|
|
|
*/ |
|
|
|
|
if (superBlock != null) { |
|
|
|
|
SequentialBlock sequBlock = new SequentialBlock(); |
|
|
|
|
Enumeration enum = localLoads.elements(); |
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
LocalLoadOperator llop |
|
|
|
|
= (LocalLoadOperator) enum.nextElement(); |
|
|
|
|
int newSlot = llop.getLocalInfo().getSlot() |
|
|
|
|
- outerValuesLength + 1; |
|
|
|
|
llop.setCodeAnalyzer(codeAna); |
|
|
|
|
llop.setLocalInfo(codeAna.getLocalInfo(0, newSlot)); |
|
|
|
|
} |
|
|
|
|
codeAna.insertStructuredBlock(superBlock); |
|
|
|
|
} |
|
|
|
|
constr.setJikesConstructor(true); |
|
|
|
|
methodAna.setJikesConstructor(true); |
|
|
|
|
methodAna.analyze(); |
|
|
|
|
checkImplicitAnonymousConstructor(clazzAnalyzer, methodAna); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static void transform(ClassAnalyzer clazzAnalyzer, |
|
|
|
|
boolean isStatic, boolean isMember, |
|
|
|
|
boolean isAnonymous, MethodAnalyzer[] cons) { |
|
|
|
|
boolean isStatic, MethodAnalyzer[] cons) { |
|
|
|
|
if (cons.length == 0) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
@ -73,11 +285,13 @@ public class TransformConstructors { |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
InvokeOperator invoke = (InvokeOperator) instr; |
|
|
|
|
if (!invoke.isConstructor() || !invoke.isSuperOrThis() |
|
|
|
|
|| !isThis(invoke.getSubExpressions()[0], |
|
|
|
|
clazzAnalyzer.getClazz())) |
|
|
|
|
if (!invoke.isConstructor() || !invoke.isSuperOrThis()) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
Expression thisExpr = invoke.getSubExpressions()[0]; |
|
|
|
|
if (!isThis(thisExpr, clazzAnalyzer.getClazz())) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
if (invoke.isThis()) { |
|
|
|
|
/* This constructor calls another constructor, so we |
|
|
|
|
* can skip it. |
|
|
|
@ -89,12 +303,46 @@ public class TransformConstructors { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
/* This constructor begins with a super call, as |
|
|
|
|
* expected. If the super() has no parameters, we |
|
|
|
|
* can remove it as it is implicit. |
|
|
|
|
*/ |
|
|
|
|
* expected. |
|
|
|
|
*/ |
|
|
|
|
InnerClassInfo outer = invoke.getOuterClassInfo(); |
|
|
|
|
/* If the super() has no parameters, we can remove it |
|
|
|
|
*/ |
|
|
|
|
// /* If this is an anonymous class, and the super() gets
|
|
|
|
|
// * the same parameters as this class, remove it, too
|
|
|
|
|
// */
|
|
|
|
|
// if (clazzAnalyzer.getName() == null
|
|
|
|
|
// && (Decompiler.options & Decompiler.OPTION_ANON) != 0
|
|
|
|
|
// && cons.length == 1) {
|
|
|
|
|
// int skipParams = 1;
|
|
|
|
|
// if (outer != null && outer.outer != null
|
|
|
|
|
// && outer.name != null
|
|
|
|
|
// && !Modifier.isStatic(outer.modifiers)
|
|
|
|
|
// && (Decompiler.options
|
|
|
|
|
// & Decompiler.OPTION_INNER) != 0
|
|
|
|
|
// && (invoke.getSubExpressions()[1]
|
|
|
|
|
// instanceof ThisOperator))
|
|
|
|
|
// skipParams++;
|
|
|
|
|
// int length = invoke.getSubExpressions().length
|
|
|
|
|
// - skipParams;
|
|
|
|
|
// Type[] consType = cons[i].getMethodType()
|
|
|
|
|
// .getParameterTypes();
|
|
|
|
|
// int outerValuesLength =
|
|
|
|
|
// clazzAnalyzer.getOuterValues().length;
|
|
|
|
|
// if (length == consType.length - outerValuesLength) {
|
|
|
|
|
// for (int j=0; j< length; j++) {
|
|
|
|
|
// Expression expr =
|
|
|
|
|
// invoke.getSubExpressions()[skipParams+j];
|
|
|
|
|
// /*XXX*/
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// clazzAnalyzer.setSuperParams(params);
|
|
|
|
|
// ib.removeBlock();
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
if (outer != null && outer.outer != null |
|
|
|
|
&& !Modifier.isStatic(outer.modifiers)) { |
|
|
|
|
&& outer.name != null |
|
|
|
|
&& !Modifier.isStatic(outer.modifiers)) { |
|
|
|
|
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0 |
|
|
|
|
&& (invoke.getMethodType().getParameterTypes() |
|
|
|
|
.length == 1) |
|
|
|
@ -119,102 +367,17 @@ public class TransformConstructors { |
|
|
|
|
for (int i=0; i< constrCount; i++) |
|
|
|
|
start[i] = sb[i]; |
|
|
|
|
|
|
|
|
|
if (isMember || isAnonymous) { |
|
|
|
|
this_loop: |
|
|
|
|
for (;;) { |
|
|
|
|
StructuredBlock ib = |
|
|
|
|
(sb[0] instanceof SequentialBlock) |
|
|
|
|
? sb[0].getSubBlocks()[0] |
|
|
|
|
: sb[0]; |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("isMember: "+ib); |
|
|
|
|
|
|
|
|
|
if (!(ib instanceof InstructionBlock)) |
|
|
|
|
break this_loop; |
|
|
|
|
|
|
|
|
|
Expression instr |
|
|
|
|
= ((InstructionBlock) ib).getInstruction().simplify(); |
|
|
|
|
if (!(instr instanceof StoreInstruction) |
|
|
|
|
|| instr.getFreeOperandCount() != 0) |
|
|
|
|
break this_loop; |
|
|
|
|
|
|
|
|
|
StoreInstruction store = (StoreInstruction) instr; |
|
|
|
|
if (!(store.getLValue() instanceof PutFieldOperator)) |
|
|
|
|
break this_loop; |
|
|
|
|
|
|
|
|
|
PutFieldOperator pfo = (PutFieldOperator) store.getLValue(); |
|
|
|
|
if (pfo.isStatic() || !pfo.isThis()) |
|
|
|
|
break this_loop; |
|
|
|
|
|
|
|
|
|
Expression expr = store.getSubExpressions()[1]; |
|
|
|
|
|
|
|
|
|
if (isMember) { |
|
|
|
|
if (!(expr instanceof ThisOperator)) |
|
|
|
|
break this_loop; |
|
|
|
|
} else { |
|
|
|
|
if (!(expr instanceof LocalLoadOperator)) |
|
|
|
|
break this_loop; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("field "+pfo.getFieldName() |
|
|
|
|
+ " = " + expr); |
|
|
|
|
if (!isThis(pfo.getSubExpressions()[0], |
|
|
|
|
clazzAnalyzer.getClazz())) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("not this: "+instr); |
|
|
|
|
break this_loop; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int i=1; i< constrCount; i++) { |
|
|
|
|
ib = (sb[i] instanceof SequentialBlock) |
|
|
|
|
? sb[i].getSubBlocks()[0] |
|
|
|
|
: sb[i]; |
|
|
|
|
if (!(ib instanceof InstructionBlock) |
|
|
|
|
|| !(((InstructionBlock)ib).getInstruction().simplify() |
|
|
|
|
.equals(instr))) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("constr "+i+" differs: " |
|
|
|
|
+ib); |
|
|
|
|
break this_loop; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!(clazzAnalyzer |
|
|
|
|
.getField(pfo.getFieldName(), pfo.getFieldType()) |
|
|
|
|
.setSpecial(expr))) { |
|
|
|
|
big_loop: |
|
|
|
|
for (;;) { |
|
|
|
|
for (int i=0; i< constrCount; i++) { |
|
|
|
|
if (sb[i] == null) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("setField failed"); |
|
|
|
|
break this_loop; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i< constrCount; i++) { |
|
|
|
|
if (sb[i] instanceof SequentialBlock) |
|
|
|
|
sb[i] = sb[i].getSubBlocks()[1]; |
|
|
|
|
else |
|
|
|
|
sb[i] = null; |
|
|
|
|
} |
|
|
|
|
for (int i=0; i< constrCount; i++) { |
|
|
|
|
if (sb[i] == null) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("constr "+i+" is over"); |
|
|
|
|
break this_loop; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
GlobalOptions.err.println("constr "+i+" is over"); |
|
|
|
|
break big_loop; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
big_loop: |
|
|
|
|
for (;;) { |
|
|
|
|
StructuredBlock ib = |
|
|
|
|
(sb[0] instanceof SequentialBlock) |
|
|
|
|
? sb[0].getSubBlocks()[0] |
|
|
|
@ -297,24 +460,21 @@ public class TransformConstructors { |
|
|
|
|
else |
|
|
|
|
sb[i] = null; |
|
|
|
|
} |
|
|
|
|
for (int i=0; i< constrCount; i++) |
|
|
|
|
if (sb[i] == null) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_CONSTRS) != 0) |
|
|
|
|
GlobalOptions.err.println("constr "+i+" is over"); |
|
|
|
|
break big_loop; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int i=0; i< constrCount; i++) { |
|
|
|
|
if (start[i] == null) |
|
|
|
|
continue; |
|
|
|
|
if (sb[i] == null) |
|
|
|
|
start[i].removeBlock(); |
|
|
|
|
else { |
|
|
|
|
sb[i].replace(start[i]); |
|
|
|
|
sb[i].simplify(); |
|
|
|
|
for (int i=0; i< constrCount; i++) { |
|
|
|
|
if (start[i] != null) { |
|
|
|
|
if (sb[i] == null) |
|
|
|
|
start[i].removeBlock(); |
|
|
|
|
else { |
|
|
|
|
sb[i].replace(start[i]); |
|
|
|
|
sb[i].simplify(); |
|
|
|
|
} |
|
|
|
|
// Check for jikes continuation
|
|
|
|
|
checkJikesContinuation(clazzAnalyzer, cons[i]); |
|
|
|
|
} |
|
|
|
|
checkImplicitAnonymousConstructor(clazzAnalyzer, cons[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|