diff --git a/jode/jode/flow/TransformConstructors.java b/jode/jode/flow/TransformConstructors.java index ff168ea..c2c3aad 100644 --- a/jode/jode/flow/TransformConstructors.java +++ b/jode/jode/flow/TransformConstructors.java @@ -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) @@ -118,103 +366,18 @@ public class TransformConstructors { StructuredBlock[] start = new StructuredBlock[constrCount]; 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))) { - 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; - } - } - } - } - big_loop: for (;;) { + 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; + } + } + 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]); } } } +