diff --git a/jode/jode/flow/CreateAssignExpression.java b/jode/jode/flow/CreateAssignExpression.java
index 15bf379..a38975f 100644
--- a/jode/jode/flow/CreateAssignExpression.java
+++ b/jode/jode/flow/CreateAssignExpression.java
@@ -58,14 +58,15 @@ public class CreateAssignExpression {
StoreInstruction store = (StoreInstruction) ic.getInstruction();
if (!store.isFreeOperator())
return false;
- int lvalueCount = store.getLValue().getFreeOperandCount();
+ Expression lvalue = store.getSubExpressions()[0];
+ int lvalueCount = lvalue.getFreeOperandCount();
boolean isAssignOp = false;
if (opBlock.subBlocks[0] instanceof SpecialBlock) {
SpecialBlock dup = (SpecialBlock) opBlock.subBlocks[0];
if (dup.type != SpecialBlock.DUP
|| dup.depth != lvalueCount
- || dup.count != store.getLValue().getType().stackSize()
+ || dup.count != lvalue.getType().stackSize()
|| !(opBlock.outer instanceof SequentialBlock))
return false;
opBlock = (SequentialBlock) opBlock.outer;
@@ -102,7 +103,7 @@ public class CreateAssignExpression {
if (expr instanceof ConvertOperator
&& expr.getSubExpressions()[0] instanceof Operator
- && expr.getType().isOfType(store.getLValue().getType())) {
+ && expr.getType().isOfType(lvalue.getType())) {
/* This gets tricky. We need to allow something like
* s = (short) (int) ((double) s / 0.1);
@@ -129,9 +130,9 @@ public class CreateAssignExpression {
|| !(loadExpr.isFreeOperator(lvalueCount)))
return false;
- if (store.getLValue() instanceof LocalStoreOperator)
+ if (lvalue instanceof LocalStoreOperator)
((LocalLoadOperator)loadExpr).getLocalInfo().combineWith
- (((LocalStoreOperator)store.getLValue()).getLocalInfo());
+ (((LocalStoreOperator)lvalue).getLocalInfo());
rightHandSide = expr.getSubExpressions()[1];
} else {
@@ -159,9 +160,9 @@ public class CreateAssignExpression {
|| !(((Operator) simple).isFreeOperator(lvalueCount)))
return false;
- if (store.getLValue() instanceof LocalStoreOperator)
+ if (lvalue instanceof LocalStoreOperator)
((LocalLoadOperator)simple).getLocalInfo().combineWith
- (((LocalStoreOperator)store.getLValue()).getLocalInfo());
+ (((LocalStoreOperator)lvalue).getLocalInfo());
/* ... and remove it. */
if (parent != null) {
@@ -177,7 +178,7 @@ public class CreateAssignExpression {
dup.removeBlock();
ib.setInstruction(rightHandSide);
- store.getLValue().setType(rvalueType);
+ lvalue.setType(rvalueType);
store.makeOpAssign(store.OPASSIGN_OP + opIndex);
if (isAssignOp)
@@ -199,10 +200,11 @@ public class CreateAssignExpression {
if (sequBlock.subBlocks[0] instanceof SpecialBlock
&& store.isFreeOperator()) {
+ Expression lvalue = store.getSubExpressions()[0];
SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
if (dup.type != SpecialBlock.DUP
- || dup.depth != store.getLValue().getFreeOperandCount()
- || dup.count != store.getLValue().getType().stackSize())
+ || dup.depth != lvalue.getFreeOperandCount()
+ || dup.count != lvalue.getType().stackSize())
return false;
dup.removeBlock();
diff --git a/jode/jode/flow/CreatePrePostIncExpression.java b/jode/jode/flow/CreatePrePostIncExpression.java
index 7faf8b6..c42d029 100644
--- a/jode/jode/flow/CreatePrePostIncExpression.java
+++ b/jode/jode/flow/CreatePrePostIncExpression.java
@@ -113,8 +113,9 @@ public class CreatePrePostIncExpression {
* not yet resolved (and note that the rvalue part
* should also have 1 remaining operand)
*/
- int lvalueCount = store.getLValue().getFreeOperandCount();
- if (!store.getLValue().isFreeOperator()
+ Expression lvalue = store.getSubExpressions()[0];
+ int lvalueCount = lvalue.getFreeOperandCount();
+ if (!((Operator)lvalue).isFreeOperator()
|| !store.isVoid()
|| !(store.getSubExpressions()[1] instanceof BinaryOperator))
return false;
@@ -148,7 +149,7 @@ public class CreatePrePostIncExpression {
SpecialBlock dup = (SpecialBlock) sb.subBlocks[0];
if (dup.type != SpecialBlock.DUP
- || dup.count != store.getLValue().getType().stackSize()
+ || dup.count != lvalue.getType().stackSize()
|| dup.depth != lvalueCount)
return false;
@@ -176,7 +177,7 @@ public class CreatePrePostIncExpression {
return false;
}
ic.setInstruction
- (new PrePostFixOperator(store.getLValue().getType(), op,
+ (new PrePostFixOperator(lvalue.getType(), op,
store.getLValue(), true));
ic.moveDefinitions(sb, last);
last.replace(sb);
diff --git a/jode/jode/flow/FlowBlock.java.in b/jode/jode/flow/FlowBlock.java.in
index e473163..b60b777 100644
--- a/jode/jode/flow/FlowBlock.java.in
+++ b/jode/jode/flow/FlowBlock.java.in
@@ -1743,4 +1743,3 @@ public class FlowBlock {
}
}
}
-
diff --git a/jode/jode/flow/TransformConstructors.java b/jode/jode/flow/TransformConstructors.java
index 5ce594b..90c563b 100644
--- a/jode/jode/flow/TransformConstructors.java
+++ b/jode/jode/flow/TransformConstructors.java
@@ -26,6 +26,7 @@ import jode.decompiler.ClassAnalyzer;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.FieldAnalyzer;
import jode.decompiler.MethodAnalyzer;
+import jode.decompiler.OuterValues;
import jode.decompiler.OuterValueListener;
import jode.expr.*;
import jode.type.MethodType;
@@ -37,16 +38,32 @@ import java.util.Vector;
import java.util.Enumeration;
/**
- * This class will transform the constructors. This involves several
- * steps:
+ * This class will transform the constructors. We differ three types of
+ * constructors:
+ *
- type0
+ * - are constructors, that call no constructors or whose default super
+ * call was already removed.
java.lang.Object.<init>
+ * and static constructors are examples for the first kind.
+ * - type1
+ * - are constructors, that call the constructor of super class
+ * - type2
+ * - are constructors, that call another constructor of the same class
+ *
*
- * - remove implicit super() call
- * - move constant field initializations that occur in all constructors
- * (except those that start with a this() call) to the fields.
- * - For inner classes check if the this$0 field(s) is/are
+ * The transformation involves several steps:
+ *
+ * The first step is done by removeSynthInitializers, which does the following:
+ *
- For inner classes check if the this$0 field(s) is/are
* initialized corectly, remove the initializer and mark that
* field.
* - For method scope classes also check the val$xx fields.
+ *
+ *
+ * In the last analyze phase (makeDeclaration) the rest is done:
+ *
+ * - remove implicit super() call
+ * - move constant field initializations that occur in all constructors
+ * (except those that start with a this() call) to the fields.
* - For jikes class check for a constructor$xx call, and mark that
* as the real constructor, moving the super call of the original
* constructor
@@ -62,9 +79,8 @@ import java.util.Enumeration;
*
* @author Jochen Hoenicke
* @see jode.decompiler.FieldAnalyzer#setInitializer
- * @see jode.decompiler.ClassAnalyzer#getOuterValues
- */
-public class TransformConstructors implements OuterValueListener {
+ * @see jode.decompiler.ClassAnalyzer#getOuterValues */
+public class TransformConstructors {
/* What is sometimes confusing is the distinction between slot and
* parameter. Most times parameter nr = slot nr, but double and
* long parameters take two slots, so the remaining parameters
@@ -73,20 +89,15 @@ public class TransformConstructors implements OuterValueListener {
ClassAnalyzer clazzAnalyzer;
boolean isStatic;
- MethodAnalyzer[] cons;
- /**
- * @see jode.decompiler.ClassAnalyzer#outerValues
- */
- Expression[] outerValues;
- /**
- * The minimal first slot number after the outerValues. This is because
- * the outerValues array may shrink to the desired size. */
- int ovMinSlots;
- /**
- * The maximal first slot number after the outerValues.
+ /* The method analyzers of the constructors: type0 constructors
+ * come first, then type1, then type2.
*/
- int ovMaxSlots;
+ MethodAnalyzer[] cons;
+ int type0Count;
+ int type01Count;
+
+ OuterValues outerValues;
boolean jikesAnonInner = false;
@@ -95,61 +106,91 @@ public class TransformConstructors implements OuterValueListener {
this.clazzAnalyzer = clazzAnalyzer;
this.isStatic = isStatic;
this.cons = cons;
- this.ovMinSlots = 1;
this.outerValues = clazzAnalyzer.getOuterValues();
- if (outerValues != null) {
- clazzAnalyzer.addOuterValueListener(this);
- ovMaxSlots = Integer.MAX_VALUE;
- updateOuterValues(outerValues.length);
- } else
- ovMaxSlots = 1;
- }
-
- public String dumpOuterValues() {
- if (outerValues == null)
- return "null";
- StringBuffer sb = new StringBuffer();
- int slot = 1;
- for (int i=0; i < outerValues.length; i++) {
- if (i>0)
- sb.append(", ");
- if (slot == ovMinSlots)
- sb.append("[");
- sb.append(outerValues[i]);
- if (slot == ovMaxSlots)
- sb.append("]");
- slot += outerValues[i].getType().stackSize();
- }
- sb.append(" ["+ovMinSlots+","+ovMaxSlots+"]");
- return sb.toString();
+ lookForConstructorCall();
}
+
+ /**
+ * Returns the type of the constructor. We differ three types of
+ * constructors:
+ * - type1
+ * - are constructors, that call the constructor of super class
+ * - type2
+ * - are constructors, that call another constructor of the same
+ * class
+ * - type0
+ * - are constructors, that call no constructors.
+ *
java.lang.Object.<init>
and static constructors
+ * are examples for this
+ *
+ * @param body the content of the constructor.
+ * @return the type of the constructor.
+ */
+ private int getConstructorType(StructuredBlock body) {
+ /* A non static constructor must begin with a call to
+ * another constructor. Either to a constructor of the
+ * same class or to the super class */
+ InstructionBlock ib;
+ if (body instanceof InstructionBlock)
+ ib = (InstructionBlock)body;
+ else if (body instanceof SequentialBlock
+ && (body.getSubBlocks()[0]
+ instanceof InstructionBlock))
+ ib = (InstructionBlock) body.getSubBlocks()[0];
+ else
+ return 0;
+
+ Expression superExpr = ib.getInstruction().simplify();
+ if (!(superExpr instanceof InvokeOperator)
+ || superExpr.getFreeOperandCount() != 0)
+ return 0;
+ InvokeOperator superInvoke = (InvokeOperator) superExpr;
+ if (!superInvoke.isConstructor()
+ || !superInvoke.isSuperOrThis())
+ return 0;
+ Expression thisExpr = superInvoke.getSubExpressions()[0];
+ if (!isThis(thisExpr, clazzAnalyzer.getClazz()))
+ return 0;
+
+ if (superInvoke.isThis())
+ return 2;
+ else
+ return 1;
+ }
+
+ public void lookForConstructorCall() {
+ type01Count = cons.length;
+ for (int i=0; i< type01Count; ) {
+ MethodAnalyzer current = cons[i];
+ FlowBlock header = cons[i].getMethodHeader();
+ /* Check that code block is fully analyzed */
+ if (header == null || !header.hasNoJumps())
+ return;
- public void updateOuterValues(int count) {
- int outerSlots = 1;
- outerValues = clazzAnalyzer.getOuterValues();
- for (int i=0; i< count; i++)
- outerSlots += outerValues[i].getType().stackSize();
- if (outerSlots < ovMaxSlots)
- ovMaxSlots = outerSlots;
-
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("OuterValues: " + dumpOuterValues());
-
- if (ovMaxSlots < ovMinSlots) {
- GlobalOptions.err.println
- ("WARNING: something got wrong with scoped class "
- +clazzAnalyzer.getClazz()+": "+ovMinSlots+","+ovMaxSlots);
- GlobalOptions.err.println
- ("CAN'T REPAIR. PRODUCED CODE IS PROBABLY WRONG.");
- new Throwable().printStackTrace(GlobalOptions.err);
- ovMinSlots = outerSlots;
+ StructuredBlock body = cons[i].getMethodHeader().block;
+ int type = isStatic ? 0 : getConstructorType(body);
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("constr "+i+": type"+type+" "+body);
+
+ switch(type) {
+ case 0:
+ // type0 are moved to the beginning.
+ cons[i] = cons[type0Count];
+ cons[type0Count++] = current;
+ /* fall through */
+ case 1:
+ // type1 are not moved at all.
+ i++;
+ break;
+ case 2:
+ // type2 are moved to the end.
+ cons[i] = cons[--type01Count];
+ cons[type01Count] = current;
+ break;
+ }
}
}
-
- public void shrinkingOuterValues(ClassAnalyzer ca, int newCount) {
- updateOuterValues(newCount);
- }
public static boolean isThis(Expression thisExpr, ClassInfo clazz) {
return ((thisExpr instanceof ThisOperator)
@@ -157,337 +198,366 @@ public class TransformConstructors implements OuterValueListener {
}
/**
- * Translate a slot into an index into the outerValues array.
- * @return index into outerValues array or -1, if not matched.
+ * Check if this is a single anonymous constructor and mark it as
+ * such. We only check if the super() call is correctly formed and
+ * ignore the rest of the body.
+ *
+ * This method also marks the jikesAnonymousInner.
*/
- public int getOuterValueIndex(int slot) {
- int ovSlot = 1; // slot of first outerValue
- for (int i=0; i < outerValues.length; i++) {
- if (ovSlot == slot)
- return i;
- ovSlot += outerValues[i].getType().stackSize();
- }
- return -1;
- }
+ private void checkAnonymousConstructor() {
+ if (isStatic || cons.length != 1
+ || type01Count - type0Count != 1
+ || clazzAnalyzer.getName() != null)
+ return;
- /**
- * This will be
- */
- private boolean checkAnonymousConstructor(MethodAnalyzer constr,
- InstructionBlock superBlock) {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("checkAnonymousConstructor of "
+ +clazzAnalyzer.getClazz());
- if (clazzAnalyzer.getName() != null)
- return false;
+ StructuredBlock sb = cons[0].getMethodHeader().block;
+ if (sb instanceof SequentialBlock)
+ sb = sb.getSubBlocks()[0];
+ InstructionBlock superBlock = (InstructionBlock) sb;
/**
* Situation:
* constructor(outerValues, params) {
- * super(params);
+ * super(someOuters, params);
* }
*
- * Mark constructor as anonymous constructor.
- */
+ * For jikes anonymous classes that extends class or method
+ * scoped classes the situation is more unusal for type1. We
+ * check if this is the case and mark the class as
+ * jikesAnonymousInner:
+ *
+ * constructor(outerValues, params, outerClass) {
+ * outerClass.super(someOuters, params);
+ * constructor$?(outerValues[0], params);
+ * }
+ *
+ * Mark constructor as anonymous constructor. */
Expression expr = superBlock.getInstruction().simplify();
-
- if (!(expr instanceof InvokeOperator))
- return false;
-
- InvokeOperator superCall = (InvokeOperator) expr;
- superBlock.setInstruction(superCall);
-
- if (superCall.getFreeOperandCount() != 0
- || !superCall.isConstructor() || !superCall.isSuperOrThis())
- return false;
-
+ InvokeOperator superCall = (InvokeOperator) expr;
Expression[] subExpr = superCall.getSubExpressions();
- Expression thisExpr = subExpr[0];
- if (!isThis(thisExpr, clazzAnalyzer.getClazz()))
- return false;
- Type[] constrParams = constr.getType().getParameterTypes();
+ /* An anonymous constructor may also give locals
+ * to its super constructor.
+ */
+ for (int i = 1; i < subExpr.length; i++) {
+ if (!(subExpr[i] instanceof LocalLoadOperator))
+ return;
+ }
+
+ Type[] params = cons[0].getType().getParameterTypes();
+ boolean jikesAnon = false;
+
+ int minOuter = params.length;
+
+ int slot = 1;
+ for (int i = 0; i < params.length - 1; i++)
+ slot += params[i].stackSize();
+
+ /* slot counts from last slot down. */
+
+ int start = 1;
+ if (subExpr.length > 1 && slot > 1) {
+ LocalLoadOperator llop = (LocalLoadOperator) subExpr[1];
- int ovLength = constrParams.length - (subExpr.length - 1);
- int ovSlots = 1;
- for (int i=0; i< ovLength; i++) {
- ovSlots += outerValues[i].getType().stackSize();
+ if (llop.getLocalInfo().getSlot() == slot) {
+ jikesAnon = true;
+ start++;
+ // This is not an outer value.
+ minOuter--;
+ slot -= params[minOuter - 1].stackSize();
+ }
}
+ int sub = subExpr.length - 1;
+ /* Check how many parameters are passed correctly. */
+ while (sub >= start) {
+ LocalLoadOperator llop = (LocalLoadOperator) subExpr[sub];
+
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println(" pos "+sub+": "+slot+","
+ + llop.getLocalInfo().getSlot()+
+ "; "+minOuter);
+
+ if (llop.getLocalInfo().getSlot() != slot) {
+ // restore the slot.
+ slot += params[minOuter - 1].stackSize();
+ break;
+ }
+ sub--;
+ /* This parameter is not forced to be an outer value */
+ minOuter--;
+ if (minOuter == 0)
+ break;
+ slot -= params[minOuter - 1].stackSize();
+ }
+ ClassAnalyzer superAna = superCall.getClassAnalyzer();
+ OuterValues superOV = null;
+ if (superAna != null
+ && superAna.getParent() instanceof MethodAnalyzer) {
+ // super is a method scope class.
+ superOV = superAna.getOuterValues();
+ }
+ int minSuperOuter = sub - start + 1;
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("anonymousConstructor: slots expected: "
- +ovSlots+" possible: ["
- +ovMinSlots+","+ovMaxSlots+"]");
- if (ovSlots < ovMinSlots || ovSlots > ovMaxSlots)
- return false;
- int slot = ovSlots;
- int start = jikesAnonInner ? 2 : 1;
- for (int i = start; i < subExpr.length; i++) {
- if (!(subExpr[i] instanceof LocalLoadOperator))
- return false;
- LocalLoadOperator llop = (LocalLoadOperator) subExpr[i];
-
- if (llop.getLocalInfo().getSlot() != slot)
- return false;
- slot += subExpr[i].getType().stackSize();
+ GlobalOptions.err.println(" super outer: " + superOV);
+
+ /* The remaining sub expressions must be outerValues. */
+ for (; sub >= start; sub--) {
+ LocalLoadOperator llop = (LocalLoadOperator) subExpr[sub];
+ if (llop.getLocalInfo().getSlot() >= slot) {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println(" Illegal slot at "+sub+":"
+ + llop.getLocalInfo().getSlot());
+ return;
+ }
}
- if (jikesAnonInner) {
- if (!(subExpr[1] instanceof LocalLoadOperator))
- return false;
- LocalLoadOperator llop = (LocalLoadOperator) subExpr[1];
-
- if (llop.getLocalInfo().getSlot() != slot)
- return false;
+
+ if (minSuperOuter > 0) {
+ if (superOV == null || superOV.getCount() < minSuperOuter) {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println(" super outer doesn't match: "
+ + minSuperOuter);
+ return;
+ }
+ superOV.setMinCount(minSuperOuter);
}
+
+ outerValues.setMinCount(minOuter);
+ if (superOV != null) {
+ final int ovdiff = minOuter - minSuperOuter;
+ outerValues.setCount(superOV.getCount() + ovdiff);
+ superOV.addOuterValueListener(new OuterValueListener() {
+ public void shrinkingOuterValues
+ (OuterValues other, int newCount) {
+ outerValues.setCount(newCount + ovdiff);
+ }
+ });
+ } else
+ outerValues.setCount(minOuter);
+
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("anonymousConstructors succeeded");
- ovMinSlots = ovMaxSlots = ovSlots;
- constr.setAnonymousConstructor(true);
- return true;
+ GlobalOptions.err.println(" succeeded: "+outerValues);
+ if (jikesAnon)
+ outerValues.setJikesAnonymousInner(true);
+ cons[0].setAnonymousConstructor(true);
+ superBlock.removeBlock();
+ type0Count++;
}
- public boolean checkJikesSuperAndFillLoads(Expression expr,
- Vector localLoads) {
+ private boolean checkJikesSuper(Expression expr) {
if (expr instanceof LocalStoreOperator
|| expr instanceof IIncOperator)
return false;
+ if (expr instanceof Operator) {
+ Expression subExpr[] = ((Operator)expr).getSubExpressions();
+ for (int i=0; i< subExpr.length; i++) {
+ if (!checkJikesSuper(subExpr[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+ private Expression renameJikesSuper(Expression expr,
+ MethodAnalyzer methodAna,
+ int firstOuterSlot,
+ int firstParamSlot,
+ int slotDist) {
if (expr instanceof LocalLoadOperator) {
LocalLoadOperator llop = (LocalLoadOperator) expr;
int slot = llop.getLocalInfo().getSlot();
- if (slot != 1) {
- /* slot 1 is outerValues[0], which is okay */
- if (slot < ovMinSlots)
- return false;
- if (slot < ovMaxSlots)
- ovMaxSlots = slot;
+ if (slot < firstOuterSlot)
+ return llop;
+ if (slot >= firstParamSlot) {
+ Type[] paramTypes = methodAna.getType().getParameterTypes();
+ int param;
+ slot -= slotDist + 1;
+ for (param = 0; slot > 0 && param < paramTypes.length; param++)
+ slot -= paramTypes[param].stackSize();
+ llop.setLocalInfo(methodAna.getParamInfo(1+param));
+ llop.setMethodAnalyzer(methodAna);
+ return llop;
}
- localLoads.addElement(llop);
+ return outerValues.getValueBySlot(slot);
}
if (expr instanceof Operator) {
Expression subExpr[] = ((Operator)expr).getSubExpressions();
for (int i=0; i< subExpr.length; i++) {
- if (!checkJikesSuperAndFillLoads(subExpr[i], localLoads))
- return false;
+ Expression newSubExpr =
+ renameJikesSuper(subExpr[i], methodAna,
+ firstOuterSlot, firstParamSlot, slotDist);
+ if (newSubExpr != subExpr[i])
+ ((Operator)expr).setSubExpressions(i, newSubExpr);
}
}
- return true;
+ return expr;
}
- public boolean checkJikesContinuation(MethodAnalyzer constr) {
- MethodType constrType = constr.getType();
-
- /*
- * Situation:
- * constructor(outerValues, params) {
- * [optional: super(expressions builded of (outerValues[0], params))]
- * constructor$?(outerValues[0], params);
- * }
- *
- * For anonymous classes that extends class/method scope classes
- * the situation is more unusal:
- * constructor(outerValues, params, outerClass) {
- * outerClass.super(params);
- * constructor$?(outerValues[0], params);
- * }
- *
- * The outerValues[0] parameter is the normal this of the
- * surrounding method (but what is the surrounding method?
- * That can't be determined in some cases). If the
-s * surrounding method is static, the outerValues[0] parameter
- * disappears!
- *
- * Move optional super to method constructor$?
- * (renaming local variables) and mark constructor and
- * constructor$? as Jikes constructor. */
+ public void checkJikesContinuation() {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ System.err.println("checkJikesContinuation: "+outerValues);
+ constr_loop:
+ for (int i=0; i < cons.length; i++) {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("constr "+i+" type"
+ + (i < type0Count ? 0 :
+ i < type01Count ? 1 : 2) + " : "
+ + cons[i].getMethodHeader());
- StructuredBlock sb = constr.getMethodHeader().block;
-
- Vector localLoads = null;
- InstructionBlock superBlock = null;
- boolean mayBeAnonInner = false;
- int anonInnerSlot = 1;
- 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];
-
- Expression superExpr = superBlock.getInstruction().simplify();
- if (!(superExpr instanceof InvokeOperator))
- return false;
-
- InvokeOperator superInvoke = (InvokeOperator) superExpr;
- superBlock.setInstruction(superInvoke);
+ MethodAnalyzer constr = cons[i];
+ MethodType constrType = constr.getType();
- if (superInvoke.getFreeOperandCount() != 0
- || !superInvoke.isConstructor()
- || !superInvoke.isSuperOrThis())
- return false;
+ /*
+ * constructor(outerValues, params, opt. jikesAnonInner param) {
+ * optional super/this(expressions);
+ * constructor$?(optional outerValues[0], params);
+ * }
+ *
+ * The outerValues[0] parameter is the normal this of the
+ * surrounding method (but what is the surrounding method?
+ * That can't be determined in some cases). If the
+ * surrounding method is static, the outerValues[0] parameter
+ * disappears!
+ *
+ * Move optional super to method constructor$?
+ * (renaming local variables) and mark constructor and
+ * constructor$? as Jikes constructor.
+ */
+ StructuredBlock sb = constr.getMethodHeader().block;
- Expression[] subExpr = superInvoke.getSubExpressions();
- Expression thisExpr = subExpr[0];
- if (!isThis(thisExpr, clazzAnalyzer.getClazz()))
- return false;
-
- ClassInfo superClazz = superInvoke.getClassInfo();
- if ((Decompiler.options &
- (Decompiler.OPTION_ANON | Decompiler.OPTION_INNER)) != 0
- && clazzAnalyzer.getName() == null
- && superClazz.getOuterClasses() != null
- && subExpr[1] instanceof LocalLoadOperator) {
- Type[] paramTypes = constrType.getParameterTypes();
- anonInnerSlot = 1;
- for (int i=0; i< paramTypes.length-1; i++) {
- anonInnerSlot += paramTypes[i].stackSize();
+ Vector localLoads = null;
+ InstructionBlock superBlock = null;
+ if (i >= type0Count) {
+ if (!(sb instanceof SequentialBlock)
+ || !(sb.getSubBlocks()[1] instanceof InstructionBlock))
+ continue constr_loop;
+
+ superBlock = (InstructionBlock) sb.getSubBlocks()[0];
+ sb = sb.getSubBlocks()[1];
+
+ Expression superExpr = superBlock.getInstruction().simplify();
+ InvokeOperator superInvoke = (InvokeOperator) superExpr;
+ superBlock.setInstruction(superInvoke);
+
+ Expression[] subExpr = superInvoke.getSubExpressions();
+ for (int j=1; j< subExpr.length; j++) {
+ if (!checkJikesSuper(subExpr[j]))
+ continue constr_loop;
}
- if (((LocalLoadOperator)
- subExpr[1]).getLocalInfo().getSlot() == anonInnerSlot)
- mayBeAnonInner = true;
}
- localLoads = new Vector();
- for (int i=2; i< subExpr.length; i++) {
- if (!checkJikesSuperAndFillLoads(subExpr[i], localLoads))
- return false;
+ if (!(sb instanceof InstructionBlock))
+ continue constr_loop;
+
+ /* Now check the constructor$? invocation */
+ Expression lastExpr
+ = ((InstructionBlock)sb).getInstruction().simplify();
+ if (!(lastExpr instanceof InvokeOperator))
+ continue constr_loop;
+
+ InvokeOperator invoke = (InvokeOperator) lastExpr;
+ if (!invoke.isThis()
+ || invoke.getFreeOperandCount() != 0)
+ continue constr_loop;
+ MethodAnalyzer methodAna = invoke.getMethodAnalyzer();
+ if (methodAna == null)
+ continue constr_loop;
+ MethodType methodType = methodAna.getType();
+ Expression[] methodParams = invoke.getSubExpressions();
+
+ if (!methodAna.getName().startsWith("constructor$")
+ || methodType.getReturnType() != Type.tVoid)
+ continue constr_loop;
+
+ if (!isThis(methodParams[0], clazzAnalyzer.getClazz()))
+ continue constr_loop;
+ for (int j=1; j < methodParams.length; j++) {
+ if (!(methodParams[j] instanceof LocalLoadOperator))
+ continue constr_loop;
}
-
- } else if (!(sb instanceof InstructionBlock))
- return false;
-
- /* Now check the constructor$? invocation */
- Expression lastExpr
- = ((InstructionBlock)sb).getInstruction().simplify();
- 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;
- MethodType methodType = methodAna.getType();
- Expression[] constrParams = invoke.getSubExpressions();
-
- if (!methodAna.getName().startsWith("constructor$")
- || methodType.getReturnType() != Type.tVoid)
- return false;
-
- if (!isThis(invoke.getSubExpressions()[0],
- clazzAnalyzer.getClazz()))
- return false;
- /* Now check if this must be of the anonymous extends inner
- * class form */
- if (mayBeAnonInner
- && constrParams.length > 0
- && !(constrParams[constrParams.length-1]
- instanceof LocalLoadOperator
- && (((LocalLoadOperator)
- constrParams[constrParams.length-1]).getLocalInfo()
- .getSlot() == anonInnerSlot)))
- jikesAnonInner = true;
-
-
- int ovLength = constrType.getParameterTypes().length
- - methodType.getParameterTypes().length;
-
- if (jikesAnonInner)
- ovLength--;
-
- int firstArg = 1;
- boolean unsureOuter = false;
- boolean canHaveOuter = false;
- if (outerValues != null && outerValues.length > 0
- && outerValues[0] instanceof ThisOperator
- && firstArg < constrParams.length
- && constrParams[firstArg] instanceof LocalLoadOperator
- && ((LocalLoadOperator)
- constrParams[firstArg]).getLocalInfo().getSlot() == 1) {
- if (ovLength == 0 && ovMinSlots == 1)
- /* It is not sure, if outerValues[0] is present or not.
+ Type[] paramTypes = constr.getType().getParameterTypes();
+ int paramCount = paramTypes.length;
+ if (outerValues.isJikesAnonymousInner())
+ paramCount--;
+
+ int minOuterCount = 0;
+ int maxOuterCount = paramCount - methodParams.length + 2;
+ int slot = 1;
+ int firstParam = 1;
+ Expression outer0 = null;
+
+ if (maxOuterCount > 0 && outerValues.getCount() > 0) {
+ /* check if the outerValues[0] param is present.
+ * we can't be sure if maxOuterCount equals 1, but
+ * we assume so.
+ * Also calculate the correct minOuterSlots.
*/
- unsureOuter = true;
-
- /* Assume outerValues[0] is there */
- ovLength++;
- firstArg++;
- canHaveOuter = true;
- }
-
- if (ovLength > outerValues.length)
- return false;
- int ovSlots = 1;
- for (int i=0; i< ovLength; i++) {
- ovSlots += outerValues[i].getType().stackSize();
- }
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("jikesConstrCont: slots expected: "
- +ovSlots+" possible: ["
- +ovMinSlots+","+ovMaxSlots+"]");
+ if (((LocalLoadOperator)methodParams[firstParam]
+ ).getLocalInfo().getSlot() == 1) {
+ outer0 = outerValues.getValue(0);
+ firstParam++;
+ } else
+ maxOuterCount--;
+ minOuterCount = maxOuterCount;
+ for (int j=0; j < maxOuterCount; j++)
+ slot += paramTypes[j].stackSize();
+ }
- if (ovSlots < ovMinSlots || ovSlots > ovMaxSlots)
- return false;
+ if (minOuterCount > outerValues.getCount())
+ continue constr_loop;
- {
- int slot = ovSlots;
- for (int j = firstArg; j < constrParams.length; j++) {
- if (!(constrParams[j] instanceof LocalLoadOperator))
- return false;
- LocalLoadOperator llop
- = (LocalLoadOperator) constrParams[j];
- if (llop.getLocalInfo().getSlot() != slot)
- return false;
- slot += constrParams[j].getType().stackSize();
+ int firstParamSlot = slot;
+ int firstOuterSlot = firstParam;
+ int slotDist = firstParamSlot - firstOuterSlot;
+ /* check the remaining parameters.
+ */
+ for (int j=firstParam; j < methodParams.length; j++) {
+ if (((LocalLoadOperator) methodParams[j]
+ ).getLocalInfo().getSlot() != slot)
+ continue constr_loop;
+ slot += methodParams[j].getType().stackSize();
}
- }
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("jikesConstrCont succeded.");
- if (unsureOuter) {
- ovMaxSlots = 2;
- } else {
- ovMinSlots = ovMaxSlots = ovSlots;
- }
- if (superBlock != null
- && checkAnonymousConstructor(constr, superBlock)) {
- superBlock = null;
- }
-
- constr.getMethodHeader().block.removeBlock();
+ outerValues.setMinCount(minOuterCount);
+ outerValues.setCount(maxOuterCount);
- /* 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 slot = llop.getLocalInfo().getSlot();
-
- int newSlot = (slot == 1
- ? 1 /* outerValues[0] */
- : slot - ovSlots + 2);
- llop.setMethodAnalyzer(methodAna);
- llop.setLocalInfo(methodAna.getLocalInfo(0, newSlot));
+ /* Now move the constructor call.
+ */
+ if (superBlock != null) {
+ Expression newExpr =
+ renameJikesSuper(superBlock.getInstruction(), methodAna,
+ firstOuterSlot, firstParamSlot, slotDist);
+ superBlock.removeBlock();
+ methodAna.insertStructuredBlock(superBlock);
+ }
+ if (outer0 != null) {
+ constr.getParamInfo(1).setExpression(outer0);
+ cons[i].getMethodHeader().simplify();
}
- methodAna.insertStructuredBlock(superBlock);
+
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println(" succeeded");
+
+ constr.setJikesConstructor(constr);
+ methodAna.setJikesConstructor(constr);
+ methodAna.setHasOuterValue(firstOuterSlot == 2);
+ if (constr.isAnonymousConstructor())
+ methodAna.setAnonymousConstructor(true);
}
- clazzAnalyzer.setJikesAnonymousInner(jikesAnonInner);
- constr.setJikesConstructor(true);
- methodAna.setJikesConstructor(true);
- methodAna.setHasOuterValue(canHaveOuter);
- if (constr.isAnonymousConstructor()
- && methodAna.getMethodHeader().block instanceof EmptyBlock)
- methodAna.setAnonymousConstructor(true);
- return true;
}
/**
@@ -507,19 +577,14 @@ s * surrounding method is static, the outerValues[0] parameter
if (outerValues != null
&& (Decompiler.options & Decompiler.OPTION_CONTRAFO) != 0) {
int slot = ((LocalLoadOperator)expr).getLocalInfo().getSlot();
- int pos = getOuterValueIndex(slot);
- if (pos >= 0 && slot < ovMaxSlots) {
- expr = outerValues[pos];
- if (slot >= ovMinSlots)
- ovMinSlots = slot + expr.getType().stackSize();
- return expr;
- }
+ Expression outExpr = outerValues.getValueBySlot(slot);
+ if (outExpr != null)
+ return outExpr;
}
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
GlobalOptions.err.println("not outerValue: "+expr
- +" ["+ovMinSlots
- +","+ovMaxSlots+"]");
+ +" "+outerValues);
return null;
}
if (expr instanceof Operator) {
@@ -536,107 +601,38 @@ s * surrounding method is static, the outerValues[0] parameter
return expr;
}
- public void initSyntheticFields() {
- if ((Decompiler.options & Decompiler.OPTION_CONTRAFO) == 0)
- return;
- if (isStatic)
+ public void removeSynthInitializers() {
+ if ((Decompiler.options & Decompiler.OPTION_CONTRAFO) == 0
+ || isStatic || type01Count == 0)
return;
- if (cons.length == 0)
- return;
+ checkAnonymousConstructor();
- int constrCount = cons.length;
- StructuredBlock[] sb = new StructuredBlock[constrCount];
- for (int i=0; i< constrCount; ) {
- FlowBlock header = cons[i].getMethodHeader();
- /* Check that code block is fully analyzed */
- if (header == null || !header.hasNoJumps())
- return;
-
- /* sb[i] will iterate the instructions of the constructor. */
- sb[i] = cons[i].getMethodHeader().block;
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("constr "+i+": "+sb[i]);
-
- /* A non static constructor must begin with a call to
- * another constructor. Either to a constructor of the
- * same class or to the super class
- */
- InstructionBlock ib;
- if (sb[i] instanceof InstructionBlock)
- ib = (InstructionBlock)sb[i];
- else if (sb[i] instanceof SequentialBlock
- && (sb[i].getSubBlocks()[0]
- instanceof InstructionBlock))
- ib = (InstructionBlock) sb[i].getSubBlocks()[0];
- else
- return;
-
- Expression superExpr = ib.getInstruction().simplify();
- if (!(superExpr instanceof InvokeOperator)
- || superExpr.getFreeOperandCount() != 0)
- return;
- InvokeOperator superInvoke = (InvokeOperator) superExpr;
- if (!superInvoke.isConstructor()
- || !superInvoke.isSuperOrThis())
- return;
- Expression thisExpr = superInvoke.getSubExpressions()[0];
- if (!isThis(thisExpr, clazzAnalyzer.getClazz()))
- return;
-
- if (superInvoke.isThis()) {
- /* This constructor calls another constructor of this
- * class, which will do the initialization. We can skip
- * this constructor.
- */
- /* Move constructor to the end of cons array, and
- * decrease constrCount. It will not be transformed
- * any further.
- */
- MethodAnalyzer temp = cons[i];
- cons[i] = cons[--constrCount];
- cons[constrCount] = temp;
- continue;
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("removeSynthInitializers of "
+ +clazzAnalyzer.getClazz());
+
+ /* sb will iterate the instructions of the constructor. */
+ StructuredBlock[] sb = new StructuredBlock[type01Count];
+ for (int i=0; i < type01Count; i++) {
+ sb[i] = cons[i].getMethodHeader().block;
+ if (i >= type0Count) {
+ if (sb[i] instanceof SequentialBlock)
+ sb[i] = sb[i].getSubBlocks()[1];
+ else
+ /* One constructor is done. There is no field */
+ return;
}
-
- /* This constructor begins with a super call, as
- * expected.
- */
-
- if (sb[i] instanceof SequentialBlock)
- sb[i] = sb[i].getSubBlocks()[1];
- else
- sb[i] = null;
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("normal constructor");
- i++;
}
- StructuredBlock[] start = new StructuredBlock[constrCount];
- for (int i=0; i< constrCount; i++)
- start[i] = sb[i];
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]
: sb[0];
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("fieldInit: "+ib);
-
if (!(ib instanceof InstructionBlock))
break big_loop;
@@ -652,19 +648,21 @@ s * surrounding method is static, the outerValues[0] parameter
break big_loop;
PutFieldOperator pfo = (PutFieldOperator) store.getLValue();
- if (pfo.isStatic() != isStatic || !pfo.isThis())
+ if (pfo.isStatic() != isStatic
+ || pfo.getClassInfo() != clazzAnalyzer.getClazz())
break big_loop;
if (!isThis(pfo.getSubExpressions()[0],
clazzAnalyzer.getClazz()))
break big_loop;
- FieldAnalyzer field = clazzAnalyzer.getField(pfo.getFieldName(),
- pfo.getFieldType());
+ int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
+ pfo.getFieldType());
+ FieldAnalyzer fieldAna = clazzAnalyzer.getField(field);
/* Don't check for final. Jikes sometimes omits this attribute.
*/
- if (!field.isSynthetic())
+ if (!fieldAna.isSynthetic())
break big_loop;
Expression expr = store.getSubExpressions()[1];
@@ -672,12 +670,7 @@ s * surrounding method is static, the outerValues[0] parameter
if (expr == null)
break big_loop;
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("field " + pfo.getFieldName()
- + " = " + expr);
-
- for (int i=1; i< constrCount; i++) {
+ for (int i=1; i< type01Count; i++) {
ib = (sb[i] instanceof SequentialBlock)
? sb[i].getSubBlocks()[0]
: sb[i];
@@ -686,131 +679,122 @@ s * surrounding method is static, the outerValues[0] parameter
.equals(instr))) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("constr "+i+" differs: "+ib);
+ GlobalOptions.err.println(" constr 0 and "+i
+ +" differ: "
+ +instr+"<-/->"+ib);
break big_loop;
}
}
- if (!(field.setInitializer(expr))) {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println(" field " + pfo.getFieldName()
+ + " = " + expr);
+
+ if (!(fieldAna.setInitializer(expr))) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("setField failed");
+ GlobalOptions.err.println(" setField failed");
break big_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 (start[i] != null) {
- if (sb[i] == null)
- start[i].removeBlock();
- else {
- sb[i].replace(start[i]);
- sb[i].simplify();
+ boolean done = false;
+ for (int i=0; i< type01Count; i++) {
+ if (sb[i] instanceof SequentialBlock) {
+ StructuredBlock next = sb[i].getSubBlocks()[1];
+ next.replace(sb[i]);
+ sb[i] = next;
+ } else {
+ sb[i].removeBlock();
+ sb[i] = null;
+ done = true;
}
+ }
+
+ if (done) {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("one constr is over");
+ break;
}
- }
+ }
}
- public void transformBlockInitializer(StructuredBlock block) {
- StructuredBlock start = block;
- while (block != null) {
- init_loop:
- do {
- StructuredBlock ib =
- (block instanceof SequentialBlock)
- ? block.getSubBlocks()[0]
- : block;
-
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("fieldInit: "+ib);
-
- if (!(ib instanceof InstructionBlock))
- break init_loop;
-
- Expression instr
- = ((InstructionBlock) ib).getInstruction().simplify();
-
- if (!(instr instanceof StoreInstruction)
- || instr.getFreeOperandCount() != 0)
- break init_loop;
-
- StoreInstruction store = (StoreInstruction) instr;
- if (!(store.getLValue() instanceof PutFieldOperator))
- break init_loop;
-
- PutFieldOperator pfo = (PutFieldOperator) store.getLValue();
- if (pfo.isStatic() != isStatic || !pfo.isThis())
- break init_loop;
-
- if (!isStatic) {
- if (!isThis(pfo.getSubExpressions()[0],
- clazzAnalyzer.getClazz())) {
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("not this: "+instr);
- break init_loop;
- }
- }
-
- Expression expr = store.getSubExpressions()[1];
- expr = transformFieldInitializer(expr);
- if (expr == null)
- break init_loop;
-
+ public int transformOneField(int lastField, StructuredBlock ib) {
+
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("fieldInit: "+ib);
+
+ if (!(ib instanceof InstructionBlock))
+ return -1;
+
+ Expression instr = ((InstructionBlock) ib).getInstruction().simplify();
+
+ if (!(instr instanceof StoreInstruction)
+ || instr.getFreeOperandCount() != 0)
+ return -1;
+
+ StoreInstruction store = (StoreInstruction) instr;
+ if (!(store.getLValue() instanceof PutFieldOperator))
+ return -1;
+
+ PutFieldOperator pfo = (PutFieldOperator) store.getLValue();
+ if (pfo.isStatic() != isStatic
+ || pfo.getClassInfo() != clazzAnalyzer.getClazz())
+ return -1;
+
+ if (!isStatic) {
+ if (!isThis(pfo.getSubExpressions()[0],
+ clazzAnalyzer.getClazz())) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("field " + pfo.getFieldName()
- + " = " + expr);
-
- FieldAnalyzer field = clazzAnalyzer
- .getField(pfo.getFieldName(), pfo.getFieldType());
-
- if (!(field.setInitializer(expr))) {
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("setField failed");
- break init_loop;
- }
-
- block.removeBlock();
- if (start != block) {
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("adding block initializer");
-
- clazzAnalyzer.addBlockInitializer(field, start);
- }
-
- if (block instanceof SequentialBlock)
- start = block.getSubBlocks()[1];
- else
- start = null;
- } while (false);
-
- if (block instanceof SequentialBlock)
- block = block.getSubBlocks()[1];
- else
- block = null;
+ GlobalOptions.err.println("not this: "+instr);
+ return -1;
+ }
}
+
+ Expression expr = store.getSubExpressions()[1];
+ expr = transformFieldInitializer(expr);
+ if (expr == null)
+ return -1;
+
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("field " + pfo.getFieldName()
+ + " = " + expr);
+
+ int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
+ pfo.getFieldType());
- if (start != null) {
+ if (field < lastField
+ || !(clazzAnalyzer.getField(field).setInitializer(expr))) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("adding block initializer");
-
- clazzAnalyzer.addBlockInitializer(null, start);
+ GlobalOptions.err.println("set field failed");
+ return -1;
+ }
+ return field;
+ }
+
+ public void transformBlockInitializer(StructuredBlock block) {
+ StructuredBlock start = null;
+ StructuredBlock tail = null;
+ int lastField = -1;
+ while (block instanceof SequentialBlock) {
+ StructuredBlock ib = block.getSubBlocks()[0];
+ int field = transformOneField(lastField, ib);
+ if (field < 0)
+ clazzAnalyzer.addBlockInitializer(lastField + 1, ib);
+ else
+ lastField = field;
+ block = block.getSubBlocks()[1];
}
+ if (transformOneField(lastField, block) < 0)
+ clazzAnalyzer.addBlockInitializer(lastField + 1, block);
}
public boolean checkBlockInitializer(InvokeOperator invoke) {
@@ -831,169 +815,100 @@ s * surrounding method is static, the outerValues[0] parameter
if (!isThis(invoke.getSubExpressions()[0],
clazzAnalyzer.getClazz()))
- return false;
-
+ return false;
+
methodAna.setJikesBlockInitializer(true);
transformBlockInitializer(flow.block);
return true;
}
- /**
- * This does the normal constructor transformations.
- *
- * javac copies the field initializers to each constructor. This
- * will undo the transformation: it will tell the fields about the
- * initial value and removes the initialization from all constructors.
- *
- * There are of course many checks necessary: All field
- * initializers must be equal in all constructors, and there
- * mustn't be locals that used in field initialization (except
- * outerValue - locals).
- */
- public void transform() {
- if (cons.length == 0)
- return;
-
- int constrCount = cons.length;
- StructuredBlock[] sb = new StructuredBlock[constrCount];
- for (int i=0; i< constrCount; ) {
+ private void removeDefaultSuper() {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("removeDefaultSuper of "
+ + clazzAnalyzer.getClazz());
+ /* Check if we can remove the super() call of type1 constructors.
+ * This transforms a type1 constructor in a type0 constructor.
+ */
+ for (int i=type0Count; i< type01Count; i++) {
+ MethodAnalyzer current = cons[i];
FlowBlock header = cons[i].getMethodHeader();
- /* Check that code block is fully analyzed */
- if (header == null || !header.hasNoJumps())
- return;
-
- /* sb[i] will iterate the instructions of the constructor. */
- sb[i] = cons[i].getMethodHeader().block;
+ StructuredBlock body = header.block;
+
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("constr "+i+": "+sb[i]);
-
- if (!isStatic) {
- /* A non static constructor must begin with a call to
- * another constructor. Either to a constructor of the
- * same class or to the super class
- */
- InstructionBlock ib;
- if (sb[i] instanceof InstructionBlock)
- ib = (InstructionBlock)sb[i];
- else if (sb[i] instanceof SequentialBlock
- && (sb[i].getSubBlocks()[0]
- instanceof InstructionBlock))
- ib = (InstructionBlock) sb[i].getSubBlocks()[0];
- else
- return;
-
- Expression superExpr = ib.getInstruction().simplify();
- if (!(superExpr instanceof InvokeOperator)
- || superExpr.getFreeOperandCount() != 0)
- return;
- InvokeOperator superInvoke = (InvokeOperator) superExpr;
- if (!superInvoke.isConstructor()
- || !superInvoke.isSuperOrThis())
- return;
- Expression thisExpr = superInvoke.getSubExpressions()[0];
- if (!isThis(thisExpr, clazzAnalyzer.getClazz()))
- return;
-
- if (superInvoke.isThis()) {
- /* This constructor calls another constructor of this
- * class, which will do the initialization. We can skip
- * this constructor.
- */
- /* But first check that outerValues are correctly promoted
- * XXX: Note that I couldn't check this code, yet,
- * since I couldn't find a compiler that can handle
- * this() calls in method scoped classes :-(
- */
- for (int slot = 1, j=0; slot < ovMaxSlots; j++) {
- Expression param
- = superInvoke.getSubExpressions()[j+1];
- if (!(param instanceof LocalLoadOperator)
- || ((LocalLoadOperator)
- param).getLocalInfo().getSlot() != slot) {
- ovMaxSlots = slot;
- break;
- }
- slot += param.getType().stackSize();
- }
+ GlobalOptions.err.println("constr "+i+": "+body);
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("skipping this()");
- /* Move constructor to the end of cons array, and
- * decrease constrCount. It will not be transformed
- * any further.
- */
- MethodAnalyzer temp = cons[i];
- cons[i] = cons[--constrCount];
- cons[constrCount] = temp;
- continue;
- }
-
- /* This constructor begins with a super call, as
- * expected.
- */
- ClassInfo superClazz = superInvoke.getClassInfo();
- InnerClassInfo[] outers = superClazz.getOuterClasses();
+ InstructionBlock ib;
+ if (body instanceof InstructionBlock)
+ ib = (InstructionBlock) body;
+ else
+ ib = (InstructionBlock) body.getSubBlocks()[0];
+
+ InvokeOperator superInvoke = (InvokeOperator)
+ ib.getInstruction().simplify();
+ ClassInfo superClazz = superInvoke.getClassInfo();
+ InnerClassInfo[] outers = superClazz.getOuterClasses();
+ int superParamCount = superInvoke.getSubExpressions().length - 1;
+
+ if ((Decompiler.options & Decompiler.OPTION_INNER) != 0
+ && outers != null
+ && outers[0].outer != null
+ && outers[0].name != null
+ && !Modifier.isStatic(outers[0].modifiers)) {
+
+ if (superParamCount != 1
+ || !(superInvoke.getSubExpressions()[1]
+ instanceof ThisOperator))
+ continue;
+ } else {
/* If the super() has no parameters (or only default
* outerValue parameter for inner/anonymous classes), we
* can remove it
*/
- if ((Decompiler.options & Decompiler.OPTION_ANON) != 0
- && outers != null
- && (outers[0].outer == null || outers[0].name == null)) {
- ClassAnalyzer superAnalyzer = null;
- Object parent = clazzAnalyzer.getParent();
- while (parent != null) {
- if (parent instanceof MethodAnalyzer) {
- MethodAnalyzer methodAna = (MethodAnalyzer)parent;
- parent = methodAna.getClassAnalyzer().getParent();
- } else
- parent = ((ClassAnalyzer) parent).getParent();
- }
- if (superAnalyzer != null) {
- /* XXX check outer values.
- */
- }
- } else if ((Decompiler.options & Decompiler.OPTION_INNER) != 0
- && outers != null
- && outers[0].outer != null
- && outers[0].name != null) {
- if (!Modifier.isStatic(outers[0].modifiers)
- && (superInvoke.getMethodType().getParameterTypes()
- .length == 1)
- && (superInvoke.getSubExpressions()[1]
- instanceof ThisOperator))
- ib.removeBlock();
- } else if (superInvoke.getMethodType().getParameterTypes()
- .length == 0)
- ib.removeBlock();
+ ClassAnalyzer superClazzAna = superInvoke.getClassAnalyzer();
+ OuterValues superOV = null;
+ if (superClazzAna != null)
+ superOV = superClazzAna.getOuterValues();
+ if (superParamCount > 0
+ && (superOV == null
+ || superParamCount > superOV.getCount()))
+ continue;
+ }
+ ib.removeBlock();
+ if (i > type0Count) {
+ cons[i] = cons[type0Count];
+ cons[type0Count] = current;
+ }
+ type0Count++;
+ }
+ }
+
+ private void removeInitializers() {
+ if (type01Count == 0)
+ return;
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_CONSTRS) != 0)
+ GlobalOptions.err.println("removeInitializers");
+
+ StructuredBlock[] sb = new StructuredBlock[type01Count];
+ for (int i=0; i< type01Count; i++) {
+ FlowBlock header = cons[i].getMethodHeader();
+ /* sb[i] will iterate the instructions of the constructor. */
+ sb[i] = header.block;
+ if (i >= type0Count) {
if (sb[i] instanceof SequentialBlock)
sb[i] = sb[i].getSubBlocks()[1];
- else
+ else {
sb[i] = null;
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("normal constructor");
+ return;
+ }
}
- i++;
}
- StructuredBlock[] start = new StructuredBlock[constrCount];
- for (int i=0; i< constrCount; i++)
- start[i] = sb[i];
-
+ int lastField = -1;
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]
@@ -1001,7 +916,7 @@ s * surrounding method is static, the outerValues[0] parameter
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("fieldInit: "+ib);
+ GlobalOptions.err.println("Instruction: "+ib);
if (!(ib instanceof InstructionBlock))
break big_loop;
@@ -1009,8 +924,7 @@ s * surrounding method is static, the outerValues[0] parameter
Expression instr
= ((InstructionBlock) ib).getInstruction().simplify();
-
- for (int i=1; i< constrCount; i++) {
+ for (int i=1; i < type01Count; i++) {
ib = (sb[i] instanceof SequentialBlock)
? sb[i].getSubBlocks()[0]
: sb[i];
@@ -1026,109 +940,81 @@ s * surrounding method is static, the outerValues[0] parameter
if (instr instanceof InvokeOperator
&& checkBlockInitializer((InvokeOperator) instr)) {
- 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< type01Count; i++) {
+ if (sb[i] instanceof SequentialBlock) {
+ StructuredBlock next = sb[i].getSubBlocks()[1];
+ next.replace(sb[i]);
+ sb[i] = next;
+ } else {
+ sb[i].removeBlock();
+ sb[i] = null;
+ }
}
break big_loop;
}
- if (!(instr instanceof StoreInstruction)
- || instr.getFreeOperandCount() != 0)
- break big_loop;
-
- StoreInstruction store = (StoreInstruction) instr;
- if (!(store.getLValue() instanceof PutFieldOperator))
- break big_loop;
-
- PutFieldOperator pfo = (PutFieldOperator) store.getLValue();
- if (pfo.isStatic() != isStatic || !pfo.isThis())
+ int field = transformOneField(lastField, ib);
+ if (field < 0)
break big_loop;
- if (!isStatic) {
- if (!isThis(pfo.getSubExpressions()[0],
- clazzAnalyzer.getClazz())) {
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("not this: "+instr);
- break big_loop;
+ lastField = field;
+
+ boolean done = false;
+ for (int i=0; i< type01Count; i++) {
+ if (sb[i] instanceof SequentialBlock) {
+ StructuredBlock next = sb[i].getSubBlocks()[1];
+ next.replace(sb[i]);
+ sb[i] = next;
+ } else {
+ sb[i].removeBlock();
+ sb[i] = null;
+ done = true;
}
}
- Expression expr = store.getSubExpressions()[1];
- expr = transformFieldInitializer(expr);
- if (expr == null)
- break big_loop;
-
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("field " + pfo.getFieldName()
- + " = " + expr);
-
- if (!(clazzAnalyzer
- .getField(pfo.getFieldName(), pfo.getFieldType())
- .setInitializer(expr))) {
+ if (done) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("setField failed");
- break big_loop;
- }
-
-
- for (int i=0; i< constrCount; i++) {
- if (sb[i] instanceof SequentialBlock)
- sb[i] = sb[i].getSubBlocks()[1];
- else
- sb[i] = null;
- }
+ GlobalOptions.err.println("one constr is over");
+ break;
+ }
}
+ }
- 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();
- }
- if ((Decompiler.options & Decompiler.OPTION_CONTRAFO) != 0)
- // Check for jikes continuation
- checkJikesContinuation(cons[i]);
- }
- if ((Decompiler.options & Decompiler.OPTION_CONTRAFO) != 0
- && (cons[i].getMethodHeader().block
- instanceof InstructionBlock)) {
- checkAnonymousConstructor(cons[i],
- (InstructionBlock)
- cons[i].getMethodHeader().block);
- }
- }
- ovMinSlots = ovMaxSlots;
- int ovLength = 0;
- if (outerValues != null) {
- for (int slot=1; slot < ovMinSlots; ) {
- slot += outerValues[ovLength++].getType().stackSize();
- }
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_CONSTRS) != 0)
- GlobalOptions.err.println("shrinking outerValues from "
- + outerValues.length
- + " to " + ovLength);
+ /**
+ * This does the normal constructor transformations.
+ *
+ * javac copies the field initializers to each constructor. This
+ * will undo the transformation: it will tell the fields about the
+ * initial value and removes the initialization from all constructors.
+ *
+ * There are of course many checks necessary: All field
+ * initializers must be equal in all constructors, and there
+ * mustn't be locals that used in field initialization (except
+ * outerValue - locals).
+ */
+ public void transform() {
+ if ((Decompiler.options & Decompiler.OPTION_CONTRAFO) == 0
+ || cons.length == 0)
+ return;
+
+ removeDefaultSuper();
+ removeInitializers();
+ checkJikesContinuation();
- if (ovLength < outerValues.length) {
- clazzAnalyzer.shrinkOuterValues(ovLength);
+ if (outerValues != null) {
+ /* Now tell all constructors the value of outerValues parameters
+ * and simplify them again.
+ */
+ for (int i=0; i< cons.length; i++) {
+ for (int j = 0; j < outerValues.getCount(); j++)
+ cons[i].getParamInfo(j+1)
+ .setExpression(outerValues.getValue(j));
+ // if (outerValues.isJikesAnonymousConstructor()) {
+ // /*XXX???*/
+ // }
+ cons[i].getMethodHeader().simplify();
}
}
-
- /* Now tell _all_ constructors the value of outerValues-parameters
- * and simplify them again.
- */
- for (int i=0; i< cons.length; i++) {
- for (int j=0; j< ovLength; j++)
- cons[i].getParamInfo(j+1).setExpression(outerValues[j]);
- cons[i].getMethodHeader().simplify();
- }
}
}