if,while,try-catch works

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@9 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent e776825477
commit 6951265a2d
  1. 37
      jode/CombineCatchLocal.java
  2. 86
      jode/CreateConstantArray.java
  3. 58
      jode/CreateIfStatements.java
  4. 42
      jode/CreateNewConstructor.java
  5. 67
      jode/CreateTryCatchStatements.java
  6. 26
      jode/CreateWhileStatements.java
  7. 19
      jode/RemoveNop.java
  8. 5
      jode/Transformation.java
  9. 7
      jode/jode/Decompiler.java
  10. 123
      jode/jode/bytecode/Opcodes.java
  11. 682
      jode/jode/decompiler/CodeAnalyzer.java
  12. 4
      jode/jode/decompiler/ImportHandler.java
  13. 11
      jode/jode/decompiler/LocalInfo.java
  14. 66
      jode/jode/decompiler/LocalVariableAnalyzer.java
  15. 6
      jode/jode/decompiler/MethodAnalyzer.java
  16. 1
      jode/jode/decompiler/TabbedPrintWriter.java
  17. 4
      jode/jode/expr/AssignOperator.java
  18. 75
      jode/jode/expr/CatchInstructionHeader.java
  19. 51
      jode/jode/expr/CombineIfGotoExpressions.java
  20. 7
      jode/jode/expr/CompareBinaryOperator.java
  21. 7
      jode/jode/expr/CompareUnaryOperator.java
  22. 12
      jode/jode/expr/ConstOperator.java
  23. 2
      jode/jode/expr/ConstantArrayOperator.java
  24. 2
      jode/jode/expr/ConstructorOperator.java
  25. 67
      jode/jode/expr/CreateAssignExpression.java
  26. 36
      jode/jode/expr/CreateExpression.java
  27. 108
      jode/jode/expr/CreateIfThenElseOperator.java
  28. 99
      jode/jode/expr/CreatePostIncExpression.java
  29. 45
      jode/jode/expr/Expression.java
  30. 173
      jode/jode/expr/IfInstructionHeader.java
  31. 418
      jode/jode/expr/InstructionHeader.java
  32. 17
      jode/jode/expr/JsrInstructionHeader.java
  33. 86
      jode/jode/expr/MethodInstructionHeader.java
  34. 5
      jode/jode/expr/Operator.java
  35. 14
      jode/jode/expr/PostFixOperator.java
  36. 4
      jode/jode/expr/RetInstructionHeader.java
  37. 2
      jode/jode/expr/SimpleOperator.java
  38. 61
      jode/jode/expr/SimpleSwitchInstructionHeader.java
  39. 9
      jode/jode/expr/SimplifyExpression.java
  40. 171
      jode/jode/expr/TryCatchInstructionHeader.java
  41. 54
      jode/jode/expr/TryInstructionHeader.java
  42. 133
      jode/jode/expr/WhileInstructionHeader.java
  43. 8
      jode/jode/type/ClassRangeType.java
  44. 7
      jode/jode/type/MyType.java

@ -0,0 +1,37 @@
package jode;
import java.util.Vector;
import sun.tools.java.Identifier;
public class CombineCatchLocal implements Transformation{
static Identifier idException = Identifier.lookup("exception");
public InstructionHeader transform(InstructionHeader ih) {
CatchInstructionHeader catchIH;
LocalInfo local;
try {
catchIH = (CatchInstructionHeader)ih;
ih = ih.nextInstruction;
if (ih.getPredecessors().size() != 1)
return null;
Instruction instr = ih.getInstruction();
if (instr instanceof PopOperator) {
local = new LocalInfo(99);
local.setName(idException);
} else if (instr instanceof LocalStoreOperator) {
local = ((LocalStoreOperator) instr).getLocalInfo();
local.setName(idException);
} else
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
if (!catchIH.combineWithLocal(local))
return null;
if(Decompiler.isVerbose)
System.err.print("c");
return catchIH;
}
}

@ -0,0 +1,86 @@
package jode;
import sun.tools.java.Type;
public class CreateConstantArray implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
Expression[] consts;
int count;
Type type;
try {
if (ih.getInstruction() instanceof DupOperator)
/* this is not the end of the array assign */
return null;
ih = ih.getSimpleUniquePredecessor();
ArrayStoreOperator store =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression lastconst = (Expression) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression lastindexexpr = (Expression) ih.getInstruction();
ConstOperator lastindexop =
(ConstOperator) lastindexexpr.getOperator();
if (!MyType.isOfType(lastindexop.getType(), MyType.tInt))
return null;
int lastindex = Integer.parseInt(lastindexop.getValue());
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
consts = new Expression[lastindex+1];
consts[lastindex] = lastconst;
count = 1;
while (lastindex-- > 0) {
ih = ih.getSimpleUniquePredecessor();
ArrayStoreOperator store2 =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
lastconst = (Expression) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression indexexpr = (Expression) ih.getInstruction();
ConstOperator indexop =
(ConstOperator) indexexpr.getOperator();
if (!MyType.isOfType(indexop.getType(), MyType.tUInt))
return null;
int index = Integer.parseInt(indexop.getValue());
if (index > lastindex)
return null;
while (index < lastindex) {
consts[lastindex] = new Expression
(new ConstOperator(MyType.tUnknown, ""),
new Expression[0]);
lastindex--;
}
consts[lastindex] = lastconst;
ih = ih.getSimpleUniquePredecessor();
dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
count++;
}
ih = ih.getSimpleUniquePredecessor();
Expression newArrayExpr = (Expression) ih.getInstruction();
NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator();
type = newArrayOp.getType();
if (newArrayOp.getOperandCount() != 1)
return null;
Expression countexpr =
(Expression) newArrayExpr.getSubExpressions()[0];
ConstOperator countop =
(ConstOperator) countexpr.getOperator();
if (!MyType.isOfType(countop.getType(), MyType.tUInt))
return null;
if (Integer.parseInt(countop.getValue()) != consts.length)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator op = new ConstantArrayOperator(type, consts.length);
return ih.combine(4*count+1, new Expression(op, consts));
}
}

@ -0,0 +1,58 @@
package jode;
public class CreateIfStatements implements Transformation {
public InstructionHeader transform(InstructionHeader ifgoto) {
if (ifgoto.getFlowType() != ifgoto.IFGOTO ||
ifgoto.nextInstruction == null ||
ifgoto.getSuccessors()[1].getAddress() <=
ifgoto.getSuccessors()[0].getAddress())
return null;
InstructionHeader next = ifgoto.getSuccessors()[1];
InstructionHeader endBlock = next;
if (ifgoto.outer != next.outer) {
if (ifgoto.outer.endBlock != next)
return null;
next = null;
}
InstructionHeader thenStart = ifgoto.nextInstruction;
InstructionHeader thenEnd;
for (thenEnd = thenStart;
thenEnd != null && thenEnd.nextInstruction != next;
thenEnd = thenEnd.nextInstruction) {
}
if (thenEnd == null)
return null;
InstructionHeader elseStart = null;
InstructionHeader elseEnd = null;
if (next != null &&
thenEnd.getFlowType() == thenEnd.GOTO &&
thenEnd.successors[0].getAddress() > next.getAddress()) {
elseStart = next;
endBlock = next = thenEnd.successors[0];
if (ifgoto.outer != next.outer) {
if (ifgoto.outer.endBlock != next)
return null;
next = null;
}
for (elseEnd = elseStart;
elseEnd != null && elseEnd.nextInstruction != next;
elseEnd = elseEnd.nextInstruction) {
}
/* XXX return error or create if-then?
*/
if (elseEnd == null)
return null;
}
if(Decompiler.isVerbose)
System.err.print("i");
return new IfInstructionHeader
(ifgoto, elseStart != null, thenEnd, elseEnd, endBlock);
}
}

@ -0,0 +1,42 @@
package jode;
public class CreateNewConstructor implements Transformation{
public InstructionHeader transform(InstructionHeader ih) {
InvokeOperator constrCall;
Expression exprs[];
try {
constrCall = (InvokeOperator) ih.getInstruction();
if (!constrCall.isConstructor())
return null;
int params = constrCall.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>0; i--) {
ih = ih.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid())
return null; /* XXX */
}
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != 1 && dup.getDepth() != 0)
return null;
ih = ih.getSimpleUniquePredecessor();
exprs[0] = (Expression) ih.getInstruction();
if (exprs[0].isVoid())
return null;
NewOperator op = (NewOperator) exprs[0].getOperator();
if (constrCall.getClassType() != op.getType())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ConstructorOperator conOp =
new ConstructorOperator(constrCall.getClassType(),
constrCall.getField());
return ih.combine(exprs.length+2, new Expression(conOp, exprs));
}
}

@ -0,0 +1,67 @@
package jode;
public class CreateTryCatchStatements implements Transformation {
public InstructionHeader transform(InstructionHeader tryIH) {
if (tryIH.getFlowType() != tryIH.TRY ||
tryIH.successors.length == 1 ||
tryIH.nextInstruction == null)
return null;
/* find handler with largest end address
* and count the catches.
*/
InstructionHeader endIH = tryIH;
int index = 0, count = 0;
for (int i=1; i < tryIH.successors.length; i+=2) {
if (tryIH.successors[i] == endIH)
count++;
else if (tryIH.successors[i].addr > endIH.addr) {
endIH = tryIH.successors[i];
count = 1;
}
}
if (count == 0 || endIH.outer != tryIH.outer)
return null;
/* now find all corresponding catches */
InstructionHeader[] catchIH = new InstructionHeader[count+1];
InstructionHeader[] remaining =
new InstructionHeader[tryIH.successors.length-2*count];
int index1 = 0, index2=0;
remaining[index2++] = tryIH.successors[0];
catchIH[index1++] = tryIH;
for (int i=1; i < tryIH.successors.length; i+=2) {
if (tryIH.successors[i] == endIH) {
/* assume that the catches are already sorted */
if (tryIH.successors[i+1].outer != tryIH.outer ||
tryIH.successors[i+1].flowType != InstructionHeader.CATCH)
return null;
catchIH[index1] = tryIH.successors[i+1];
index1++;
} else {
remaining[index2++] = tryIH.successors[i];
remaining[index2++] = tryIH.successors[i+1];
}
}
InstructionHeader endBlock = tryIH.outer.endBlock;
if (endIH != catchIH[1]) {
if ((endIH.flowType != endIH.RETURN ||
endIH.getInstruction().getType() != MyType.tVoid) &&
endIH.flowType != endIH.GOTO)
return null;
if (endIH.successors[0].outer == tryIH.outer)
endBlock = endIH.successors[0];
else if (endIH.successors[0] != endBlock)
return null;
}
if (Decompiler.isVerbose)
System.err.print("t");
return new TryCatchInstructionHeader
(catchIH, endIH, remaining, endBlock);
}
}

@ -0,0 +1,26 @@
package jode;
public class CreateWhileStatements implements Transformation {
public InstructionHeader transform(InstructionHeader gotoIH) {
if (gotoIH.flowType != gotoIH.GOTO || gotoIH.nextInstruction == null ||
gotoIH.successors[0].addr < gotoIH.nextInstruction.addr)
return null;
InstructionHeader block = gotoIH.nextInstruction;
if (block == null)
block = gotoIH.outer.endBlock;
InstructionHeader ifgoto = gotoIH.successors[0];
if (ifgoto.getFlowType() != ifgoto.IFGOTO ||
ifgoto.successors[1] != block ||
ifgoto.outer != block.outer)
return null;
if(Decompiler.isVerbose)
System.err.print("w");
return new WhileInstructionHeader(gotoIH, ifgoto, block);
}
}

@ -0,0 +1,19 @@
package jode;
public class RemoveNop implements Transformation {
public InstructionHeader transform (InstructionHeader ih) {
Instruction pred;
try {
NopOperator op = (NopOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
pred = ih.getInstruction();
if (pred == null)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
return ih.combine(2, pred);
}
}

@ -0,0 +1,5 @@
package jode;
public interface Transformation {
public InstructionHeader transform(InstructionHeader ih);
}

@ -3,13 +3,16 @@ import sun.tools.java.*;
import java.lang.reflect.Modifier;
public class Decompiler {
public static boolean isVerbose = false;
public static boolean isDebugging = false;
public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment();
for (int i=0; i<params.length; i++) {
if (params[i].equals("-v"))
env.isVerbose = true;
isVerbose = true;
else if (params[i].equals("-debug"))
env.isDebugging = true;
isDebugging = true;
else
env.doClass(params[i]);
}

@ -48,42 +48,42 @@ public abstract class Opcodes implements RuntimeConstants{
int opcode = stream.readUnsignedByte();
switch (opcode) {
case opc_nop:
return new InstructionHeader(addr, 1, new NopOperator());
return InstructionHeader.createNormal(addr, 1, new NopOperator());
case opc_aconst_null:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConstOperator
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
case opc_lconst_0: case opc_lconst_1:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConstOperator
(LONG_TYPE,
Integer.toString(opcode - opc_lconst_0) + "L"));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConstOperator
(FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0F"));
case opc_dconst_0: case opc_dconst_1:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConstOperator
(DOUBLE_TYPE,
Integer.toString(opcode - opc_dconst_0) + ".0"));
case opc_bipush:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readShort())));
case opc_ldc: {
int index = stream.readUnsignedByte();
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 2, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
@ -91,14 +91,14 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_ldc_w:
case opc_ldc2_w: {
int index = stream.readUnsignedShort();
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
}
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 2, new LocalLoadOperator
(types[0][opcode-opc_iload],
stream.readUnsignedByte()));
@ -107,19 +107,19 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3:
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3:
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new LocalLoadOperator
(types[0][(opcode-opc_iload_0)/4],
(opcode-opc_iload_0) & 3));
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ArrayLoadOperator
(types[1][opcode - opc_iaload]));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore],
stream.readUnsignedByte(),
@ -134,7 +134,7 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_dstore_2: case opc_dstore_3:
case opc_astore_0: case opc_astore_1:
case opc_astore_2: case opc_astore_3:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4],
(opcode-opc_istore_0) & 3,
@ -142,43 +142,43 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ArrayStoreOperator
(types[1][opcode - opc_iastore]));
case opc_pop: case opc_pop2:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new PopOperator(opcode - opc_pop + 1));
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new DupOperator
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1));
case opc_swap:
return new InstructionHeader(addr, 1, new SwapOperator());
return InstructionHeader.createNormal(addr, 1, new SwapOperator());
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new BinaryOperator
(types[0][(opcode - opc_iadd)%4],
(opcode - opc_iadd)/4+Operator.ADD_OP));
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new UnaryOperator
(types[0][opcode - opc_ineg], Operator.NEG_OP));
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ShiftOperator
(types[0][(opcode - opc_ishl)%2],
(opcode - opc_ishl)/2 + Operator.SHIFT_OP));
case opc_iand: case opc_land:
case opc_ior : case opc_lor :
case opc_ixor: case opc_lxor:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
@ -190,7 +190,7 @@ public abstract class Opcodes implements RuntimeConstants{
value = -value;
operation = Operator.NEG_OP;
}
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new IIncOperator
(local, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
@ -203,50 +203,49 @@ public abstract class Opcodes implements RuntimeConstants{
int to = (opcode-opc_i2l)%3;
if (to >= from)
to++;
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConvertOperator(types[0][from],
types[0][to]));
}
case opc_i2b: case opc_i2c: case opc_i2s:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ConvertOperator
(ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5]));
case opc_lcmp:
case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new CompareToIntOperator
(types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2));
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return InstructionHeader.conditional
return InstructionHeader.createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP));
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt:
case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple:
return InstructionHeader.conditional
return InstructionHeader.createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP));
case opc_if_acmpeq: case opc_if_acmpne:
return InstructionHeader.conditional
return InstructionHeader.createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP));
case opc_goto:
return InstructionHeader.jump
return InstructionHeader.createGoto
(addr, 3, addr+stream.readShort(), new NopOperator());
case opc_jsr:
return InstructionHeader.jump
return InstructionHeader.createGoto //XXX
(addr, 3, addr+stream.readShort(),
new JsrOperator());
case opc_ret:
return InstructionHeader.ret
return InstructionHeader.createReturn //XXX
(addr, 2,
new LocalLoadOperator
(INT_TYPE,
stream.readUnsignedByte()));
(OBJECT_TYPE, stream.readUnsignedByte()));
case opc_tableswitch: {
int length = 3-(addr % 4);
stream.skip(length);
@ -261,9 +260,8 @@ public abstract class Opcodes implements RuntimeConstants{
}
dests[cases.length] = def;
length += 13 + 4 * cases.length;
return new InstructionHeader
(addr, length, new NopOperator(),
ALL_INT_TYPE, cases, dests);
return InstructionHeader.createSwitch
(addr, length, new NopOperator(), cases, dests);
}
case opc_lookupswitch: {
int length = 3-(addr % 4);
@ -278,35 +276,34 @@ public abstract class Opcodes implements RuntimeConstants{
}
dests[npairs] = def;
length += 9 + 8 * npairs;
return new InstructionHeader
(addr, length, new NopOperator(),
ALL_INT_TYPE, cases, dests);
return InstructionHeader.createSwitch
(addr, length, new NopOperator(), cases, dests);
}
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: {
Type retType = MyType.intersection
(ca.getMethod().mdef.getType().getReturnType(),
types[0][opcode-opc_ireturn]);
return InstructionHeader.ret
return InstructionHeader.createReturn
(addr, 1, new ReturnOperator(retType));
}
case opc_return: {
Type retType = MyType.intersection
(ca.getMethod().mdef.getType().getReturnType(),
VOID_TYPE);
return InstructionHeader.ret
return InstructionHeader.createReturn
(addr, 1, new ReturnOperator(retType));
}
case opc_getstatic:
case opc_getfield:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new GetFieldOperator
(ca, opcode == opc_getstatic,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
case opc_putstatic:
case opc_putfield:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new PutFieldOperator
(ca, opcode == opc_putstatic,
(FieldDefinition)ca.env.getConstant
@ -314,14 +311,14 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic :
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new InvokeOperator
(ca,
opcode == opc_invokestatic, opcode == opc_invokespecial,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
case opc_invokeinterface: {
InstructionHeader ih = new InstructionHeader
InstructionHeader ih = InstructionHeader.createNormal
(addr, 5, new InvokeOperator
(ca, false, false,
(FieldDefinition)ca.env.getConstant
@ -333,7 +330,7 @@ public abstract class Opcodes implements RuntimeConstants{
ClassDeclaration cldec = (ClassDeclaration)
ca.env.getConstant(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new NewOperator(type, ca.env.getTypeString(type)));
}
case opc_newarray: {
@ -350,7 +347,7 @@ public abstract class Opcodes implements RuntimeConstants{
default:
throw new ClassFormatError("Invalid newarray operand");
}
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 2,
new NewArrayOperator(MyType.tArray(type),
type.toString(), 1));
@ -360,21 +357,21 @@ public abstract class Opcodes implements RuntimeConstants{
(stream.readUnsignedShort());
Identifier ident = cldec.getName();
Type type = MyType.tClassOrArray(cldec.getName());
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new NewArrayOperator
(MyType.tArray(type), ca.env.getTypeString(type),1));
}
case opc_arraylength:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 1, new ArrayLengthOperator());
case opc_athrow:
return InstructionHeader.ret
return InstructionHeader.createReturn
(addr, 1, new ThrowOperator());
case opc_checkcast: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3, new CheckCastOperator
(type, ca.env.getTypeString(type)));
}
@ -382,27 +379,27 @@ public abstract class Opcodes implements RuntimeConstants{
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 3,
new InstanceOfOperator(type, ca.env.getTypeString(type)));
}
case opc_monitorenter:
return new InstructionHeader(addr, 1,
return InstructionHeader.createNormal(addr, 1,
new MonitorEnterOperator());
case opc_monitorexit:
return new InstructionHeader(addr, 1,
return InstructionHeader.createNormal(addr, 1,
new MonitorExitOperator());
case opc_wide: {
switch (opcode=stream.readUnsignedByte()) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 4,
new LocalLoadOperator(types[0][opcode-opc_iload],
stream.readUnsignedShort()));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 4,
new LocalStoreOperator(types[0][opcode-opc_istore],
stream.readUnsignedShort(),
@ -415,7 +412,7 @@ public abstract class Opcodes implements RuntimeConstants{
value = -value;
operation = Operator.NEG_OP;
}
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 6, new IIncOperator
(local, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
@ -437,21 +434,21 @@ public abstract class Opcodes implements RuntimeConstants{
Type baseType = type;
for (int i=0; i<dimension; i++)
baseType = baseType.getElementType();
return new InstructionHeader
return InstructionHeader.createNormal
(addr, 4,
new NewArrayOperator
(type, ca.env.getTypeString(baseType), dimension));
}
case opc_ifnull: case opc_ifnonnull:
return InstructionHeader.conditional
return InstructionHeader.createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP));
case opc_goto_w:
return InstructionHeader.jump
return InstructionHeader.createGoto
(addr, 5, addr + stream.readInt(), new NopOperator());
case opc_jsr_w:
return InstructionHeader.jump
return InstructionHeader.createGoto
(addr, 5, addr+stream.readInt(), new JsrOperator());
default:
throw new ClassFormatError("Invalid opcode "+opcode);

@ -1,7 +1,5 @@
package jode;
import sun.tools.java.*;
import java.lang.reflect.Modifier;
import java.util.*;
import java.io.*;
public class CodeAnalyzer implements Analyzer, Constants {
@ -9,10 +7,6 @@ public class CodeAnalyzer implements Analyzer, Constants {
BinaryCode bincode;
MethodInstructionHeader methodHeader;
int[] references;
Hashtable tryAddrs = new Hashtable();
Hashtable catchAddrs = new Hashtable();
Hashtable labels = new Hashtable();
MethodAnalyzer method;
public JodeEnvironment env;
@ -22,9 +16,10 @@ public class CodeAnalyzer implements Analyzer, Constants {
*/
public MethodAnalyzer getMethod() {return method;}
void readCode(byte[] code)
void readCode()
throws ClassFormatError
{
byte[] code = bincode.getCode();
InstructionHeader[] instr = new InstructionHeader[code.length];
int returnCount;
try {
@ -37,82 +32,21 @@ public class CodeAnalyzer implements Analyzer, Constants {
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
methodHeader = new MethodInstructionHeader(instr);
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
methodHeader = new MethodInstructionHeader(env, instr, handlers);
}
void setExceptionHandler(BinaryExceptionHandler handler) {
/*
tryAddrs.put(new Integer(handler.startPC), handler);
references[handler.startPC]++;
catchAddrs.put(new Integer(handler.handlerPC), handler);
references[handler.handlerPC]++;
*/
}
/*
Instruction getInstruction(int addr) {
return instr[addr];
}
void setInstruction(int addr, Instruction i) {
instr[addr] = i;
}
void removeInstruction(int addr) {
instr[addr] = null;
}
*/
static int WRONG = -3;
static int SPECIAL = -2;
static int FIRST = -1;
int getPreviousAddr(int addr) {
/*
int i;
for (i = addr-1; i >= 0 && instr[i] == null; i--) {}
return i;
*/
return addr;
}
int getNextAddr(int addr) {
/*
return addr + instr[addr].getLength();
*/
return addr;
}
int getPredecessor(int addr) {
/*
if (references[addr] != 1)
return WRONG;
if (addr == 0)
return FIRST;
if (catchAddrs.get(new Integer(addr)) != null)
return SPECIAL;
int i = getPreviousAddr(addr);
if (instr[i].getLength() != addr-i)
throw new RuntimeException("length mismatch");
int[] successors = instr[i].getSuccessors();
for (int j=0; j< successors.length; j++) {
if (successors[j] == addr)
return i;
}
*/
return WRONG;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
InstructionHeader ih;
for (ih = methodHeader.getNextInstruction(); ih != null;
ih = ih.getNextInstruction()) {
ih.dumpSource(writer);
}
methodHeader.dumpSource(writer);
}
public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e)
@ -121,593 +55,37 @@ public class CodeAnalyzer implements Analyzer, Constants {
method = ma;
env = e;
bincode = bc;
readCode(bincode.getCode());
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
for (int i=0; i<handlers.length; i++) {
setExceptionHandler(handlers[i]);
}
}
// public InstructionHeader convertIInc(InstructionHeader ih) {
// Expression[] expr = {
// new Expression
// (new ConstOperator(ALL_INT_TYPE,
// Integer.toString(value)),
// new Expression[0])
// };
// return new InstructionHeader
// (addr, 6, new Expression
// (new LocalStoreOperator
// (ALL_INT_TYPE, local,
// Operator.OPASSIGN_OP+operation),
// expr));
// }
public InstructionHeader removeNop(InstructionHeader ih) {
Instruction pred;
try {
NopOperator op = (NopOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
pred = ih.getInstruction();
if (pred == null)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
ih.combine(2, pred);
return ih;
}
public InstructionHeader createConstantArray(InstructionHeader ih) {
Expression[] consts;
int count;
Type type;
try {
if (ih.getInstruction() instanceof DupOperator)
/* this is not the end of the array assign */
return null;
ih = ih.getSimpleUniquePredecessor();
ArrayStoreOperator store =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression lastconst = (Expression) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression lastindexexpr = (Expression) ih.getInstruction();
ConstOperator lastindexop =
(ConstOperator) lastindexexpr.getOperator();
if (!MyType.isOfType(lastindexop.getType(), MyType.tInt))
return null;
int lastindex = Integer.parseInt(lastindexop.getValue());
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
consts = new Expression[lastindex+1];
consts[lastindex] = lastconst;
count = 1;
while (lastindex-- > 0) {
ih = ih.getSimpleUniquePredecessor();
ArrayStoreOperator store2 =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
lastconst = (Expression) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression indexexpr = (Expression) ih.getInstruction();
ConstOperator indexop =
(ConstOperator) indexexpr.getOperator();
if (!MyType.isOfType(indexop.getType(), MyType.tUInt))
return null;
int index = Integer.parseInt(indexop.getValue());
if (index > lastindex)
return null;
while (index < lastindex) {
consts[lastindex] = new Expression
(new ConstOperator(MyType.tUnknown, ""),
new Expression[0]);
lastindex--;
}
consts[lastindex] = lastconst;
ih = ih.getSimpleUniquePredecessor();
dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
count++;
}
ih = ih.getSimpleUniquePredecessor();
Expression newArrayExpr = (Expression) ih.getInstruction();
NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator();
type = newArrayOp.getType();
if (newArrayOp.getOperandCount() != 1)
return null;
Expression countexpr =
(Expression) newArrayExpr.getSubExpressions()[0];
ConstOperator countop =
(ConstOperator) countexpr.getOperator();
if (!MyType.isOfType(countop.getType(), MyType.tUInt))
return null;
if (Integer.parseInt(countop.getValue()) != consts.length)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator op = new ConstantArrayOperator(type, consts.length);
ih.combine(4*count+1, new Expression(op, consts));
return ih;
}
public InstructionHeader createExpression(InstructionHeader ih) {
Operator op;
Expression exprs[];
int params;
try {
op = (Operator) ih.getInstruction();
params = op.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>=0; i--) {
ih = ih.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid()) {
if (i == params-1)
return null;
Expression e = exprs[i+1].tryToCombine(exprs[i]);
if (e == null)
return null;
i++;
exprs[i] = e;
ih.combine(2, e);
}
}
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
ih.combine(params+1, new Expression(op, exprs));
return ih;
}
// public int combineExpressions(int addr) {
// int count = 0;
// int start = addr;
// if (!(instr[addr] instanceof Expression) ||
// !((Expression)instr[addr]).isVoid())
// return -1;
// do {
// addr = getNextAddr(addr);
// count++;
// } while (addr < instr.length &&
// references[addr] == 1 &&
// instr[addr] instanceof Expression &&
// ((Expression)instr[addr]).isVoid());
// Expression[] expr = new Expression[count];
// addr = start;
// for (int i=0; i < count; i++) {
// expr[i] = (Expression)instr[addr];
// int next = getNextAddr(addr);
// instr[addr] = null;
// addr = next;
// }
// instr[start] = new Block(start, addr-start, expr);
// return start;
// }
public InstructionHeader createAssignExpression(InstructionHeader ih) {
StoreInstruction store;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != store.getLValueOperandCount() &&
dup.getCount() != store.getLValueType().stackSize())
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store));
return ih;
}
public InstructionHeader createLocalPostIncExpression(InstructionHeader ih)
{
IIncOperator iinc;
int op;
Type type;
try {
Expression iincExpr = (Expression) ih.getInstruction();
iinc = (IIncOperator) iincExpr.getOperator();
if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP)
op = Operator.INC_OP;
else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP)
op = Operator.DEC_OP;
else
return null;
if (!iinc.getValue().equals("1") &&
!iinc.getValue().equals("-1"))
return null;
if (iinc.getValue().equals("-1"))
op ^= 1;
ih = ih.getSimpleUniquePredecessor();
Expression loadExpr = (Expression) ih.getInstruction();
LocalLoadOperator load =
(LocalLoadOperator)loadExpr.getOperator();
if (!iinc.matches(load))
return null;
type = MyType.intersection(load.getType(), MyType.tUInt);
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new LocalPostFixOperator(type, op, iinc);
ih.combine(2, postop);
return ih;
}
public InstructionHeader createPostIncExpression(InstructionHeader ih) {
StoreInstruction store;
int op;
Type type;
try {
store = (StoreInstruction) ih.getInstruction();
if (store.getLValueOperandCount() == 0)
return null;
ih = ih.getSimpleUniquePredecessor();
BinaryOperator binOp = (BinaryOperator) ih.getInstruction();
if (binOp.getOperator() == store.ADD_OP)
op = Operator.INC_OP;
else if (store.getOperator() == store.NEG_OP)
op = Operator.DEC_OP;
else
return null;
ih = ih.getSimpleUniquePredecessor();
Expression expr = (Expression) ih.getInstruction();
ConstOperator constOp = (ConstOperator) expr.getOperator();
if (!constOp.getValue().equals("1") &&
!constOp.getValue().equals("-1"))
return null;
if (constOp.getValue().equals("-1"))
op ^= 1;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != store.getLValueType().stackSize() ||
dup.getDepth() != store.getLValueOperandCount())
return null;
ih = ih.getSimpleUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup2 = (DupOperator) ih.getInstruction();
if (dup2.getCount() != store.getLValueOperandCount() ||
dup2.getDepth() != 0)
return null;
type = MyType.intersection(load.getType(), store.getLValueType());
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new PostFixOperator(type, op, store);
ih.combine(6, postop);
return ih;
}
public InstructionHeader createAssignOp(InstructionHeader ih) {
Expression rightHandSide;
StoreInstruction store;
BinaryOperator binop;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
binop = (BinaryOperator) ih.getInstruction();
if (binop.getOperator() < binop.ADD_OP ||
binop.getOperator() >= binop.ASSIGN_OP)
return null;
ih = ih.getSimpleUniquePredecessor();
rightHandSide = (Expression) ih.getInstruction();
if (rightHandSide.isVoid())
return null; /* XXX */
ih = ih.getSimpleUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 &&
dup.getCount() != store.getLValueOperandCount())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ih.combine(3, rightHandSide);
InstructionHeader storeIH = ih.getNextInstruction();
store.setOperator(store.OPASSIGN_OP+binop.getOperator());
store.setLValueType(MyType.intersection(binop.getType(),
store.getLValueType()));
storeIH.combine(2, store);
return ih;
}
public InstructionHeader combineNewConstructor(InstructionHeader ih) {
InvokeOperator constrCall;
Expression exprs[];
try {
constrCall = (InvokeOperator) ih.getInstruction();
if (!constrCall.isConstructor())
return null;
int params = constrCall.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>0; i--) {
ih = ih.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid())
return null; /* XXX */
}
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != 1 && dup.getDepth() != 0)
return null;
ih = ih.getSimpleUniquePredecessor();
exprs[0] = (Expression) ih.getInstruction();
if (exprs[0].isVoid())
return null;
NewOperator op = (NewOperator) exprs[0].getOperator();
if (constrCall.getClassType() != op.getType())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ConstructorOperator conOp =
new ConstructorOperator(constrCall.getClassType(),
constrCall.getField());
ih.combine(exprs.length+2, new Expression(conOp, exprs));
return ih;
}
public InstructionHeader combineIfGotoExpressions(InstructionHeader ih2) {
InstructionHeader ih1;
Expression[] e;
int operator;
try {
if (ih2.switchType != MyType.tBoolean)
return null;
InstructionHeader[] dests2 = ih2.getSuccessors();
/* if ih2.getSimpleUniquePredecessor.getOperator().isVoid() XXX */
Vector predec = ih2.getPredecessors();
if (predec.size() != 1)
return null;
ih1 = (InstructionHeader) predec.elementAt(0);
if (ih1.switchType != MyType.tBoolean)
return null;
InstructionHeader[] dests1 = ih1.getSuccessors();
if (dests1[0] != ih2)
return null;
if (dests1[1] == dests2[0]) {
e = new Expression[2];
operator = Operator.LOG_AND_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = ((Expression)ih1.getInstruction()).negate();
} else if (dests1[1] == dests2[1]) {
e = new Expression[2];
operator = Operator.LOG_OR_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = (Expression)ih1.getInstruction();
} else
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
Expression cond =
new Expression(new BinaryOperator(Type.tBoolean, operator), e);
ih1.combineConditional(cond);
return ih1;
}
public InstructionHeader createFunnyIfThenElseOp(InstructionHeader ih) {
Expression cond = null;
try {
InstructionHeader ifHeader= ih;
if (ifHeader.switchType != MyType.tBoolean)
return null;
CompareUnaryOperator compare =
(CompareUnaryOperator) ifHeader.getInstruction();
if ((compare.getOperator() & ~1) != compare.EQUALS_OP)
return null;
Enumeration enum = ih.getPredecessors().elements();
while (enum.hasMoreElements()) {
try {
ih = (InstructionHeader) enum.nextElement();
Expression zeroExpr = (Expression) ih.getInstruction();
ConstOperator zero =
(ConstOperator) zeroExpr.getOperator();
if (!zero.getValue().equals("0"))
continue;
ih = ih.getUniquePredecessor();
if (ih.switchType != MyType.tBoolean)
continue;
if (compare.getOperator() == compare.EQUALS_OP &&
ih.getSuccessors()[1] != ifHeader.getSuccessors()[0]
|| compare.getOperator() == compare.NOTEQUALS_OP &&
ih.getSuccessors()[1] != ifHeader.getSuccessors()[1])
continue;
cond = (Expression) ih.getInstruction();
break;
} catch (ClassCastException ex) {
} catch (NullPointerException ex) {
}
}
if (cond == null)
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
InstructionHeader next = ih.nextInstruction;
ih.nextInstruction = next.nextInstruction;
ih.successors[1].predecessors.removeElement(ih);
ih.switchType = MyType.tVoid;
ih.successors = next.successors;
ih.successors[0].predecessors.removeElement(next);
ih.successors[0].predecessors.addElement(ih);
ih.succs = next.succs;
ih.length += next.length;
return ih;
}
public InstructionHeader createIfThenElseOperator(InstructionHeader ih) {
InstructionHeader ifHeader;
Expression e[] = new Expression[3];
InstructionHeader[] succs;
try {
Vector predec = ih.getPredecessors();
if (predec.size() != 1)
return null;
ifHeader = (InstructionHeader) predec.elementAt(0);
if (ifHeader.switchType != Type.tBoolean)
return null;
succs = ifHeader.getSuccessors();
if (succs[1] != ih ||
succs[0].getNextInstruction() != succs[1] ||
succs[0].getSuccessors().length != 1 ||
succs[1].getSuccessors().length != 1 ||
succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0])
return null;
e[0] = ((Expression) ifHeader.getInstruction()).negate();
e[1] = (Expression) succs[0].getInstruction();
e[2] = (Expression) succs[1].getInstruction();
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
IfThenElseOperator iteo = new IfThenElseOperator
(MyType.intersection(e[1].getType(),e[2].getType()));
ifHeader.instr = new Expression(iteo, e);
ifHeader.nextInstruction = ih.nextInstruction;
ifHeader.length = ih.addr + ih.length - ifHeader.addr;
ifHeader.succs = ih.succs;
ifHeader.successors = ih.successors;
ifHeader.switchType = Type.tVoid;
ifHeader.successors[0].predecessors.removeElement(succs[0]);
ifHeader.successors[0].predecessors.removeElement(succs[1]);
ifHeader.successors[0].predecessors.addElement(ifHeader);
return ifHeader;
}
readCode();
}
static Transformation[] exprTrafos = {
new RemoveNop(),
new CombineCatchLocal(),
new CreateExpression(),
new CreatePostIncExpression(),
new CreateAssignExpression(),
new CreateNewConstructor(),
new CombineIfGotoExpressions(),
new CreateIfThenElseOperator(),
new CreateConstantArray()
};
static Transformation[] simplifyTrafos = { new SimplifyExpression() };
static Transformation[] blockTrafos = {
new CreateTryCatchStatements(),
new CreateIfStatements(),
new CreateWhileStatements()
};
public void analyze()
{
InstructionHeader ih, next;
for (ih = methodHeader.getNextInstruction(); ih != null;
ih = next) {
if (env.isVerbose)
System.err.print(".");
// System.err.println(""+ih.getAddress());
if ((next = removeNop(ih)) != null) continue;
if ((next = createExpression(ih)) != null) continue;
if ((next = createPostIncExpression(ih)) != null) continue;
if ((next = createLocalPostIncExpression(ih)) != null) continue;
if ((next = createAssignOp(ih)) != null) continue;
if ((next = combineNewConstructor(ih)) != null) continue;
if ((next = combineIfGotoExpressions(ih)) != null) continue;
if ((next = createFunnyIfThenElseOp(ih)) != null) continue;
if ((next = createIfThenElseOperator(ih)) != null) continue;
if ((next = createAssignExpression(ih)) != null) continue;
if ((next = createConstantArray(ih)) != null) continue;
next = ih.getNextInstruction();
}
for (ih = methodHeader.getNextInstruction(); ih != null;
ih = ih.getNextInstruction()) {
ih.instr = ih.getInstruction().simplify();
}
// for (int addr = 0; addr < instr.length; ) {
// int nextAddr;
// nextAddr = createExpression(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = createAssignExpression(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = createArrayOpAssign(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = createPostIncExpression(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// // nextAddr = createIfGotoStatement(addr);
// // if (nextAddr >= 0) {
// // addr = nextAddr;
// // continue;
// // }
// nextAddr = combineIfGotoExpressions(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = combineConditionalExpr(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// addr += instr[addr].getLength();
// }
// for (int addr = 0; addr < instr.length; ) {
// int nextAddr;
// nextAddr = combineExpressions(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// addr += instr[addr].getLength();
// }
methodHeader.doTransformations(exprTrafos);
methodHeader.doTransformations(simplifyTrafos);
methodHeader.doTransformations(blockTrafos);
}
public String getTypeString(Type type) {
return type.toString();
return env.getTypeString(type);
}
public ClassDefinition getClassDefinition() {

@ -8,9 +8,6 @@ public class JodeEnvironment extends LoadEnvironment {
BinaryClass main;
Identifier pkg;
public boolean isVerbose = false;
public boolean isDebugging = false;
JodeEnvironment() {
super(null);
MyType.setEnvironment(this);
@ -91,7 +88,6 @@ public class JodeEnvironment extends LoadEnvironment {
a.analyze();
TabbedPrintWriter writer =
new TabbedPrintWriter(System.out, " ");
writer.verbosity = isDebugging?10:0;
a.dumpSource(writer);
} catch (ClassNotFound e) {
error(e.toString());

@ -14,6 +14,7 @@ import sun.tools.java.*;
*/
public class LocalInfo {
private static int serialnr = 0;
private int slot;
private Identifier name;
private Type type;
private LocalInfo shadow;
@ -25,9 +26,9 @@ public class LocalInfo {
* @param slot The slot of this variable.
*/
public LocalInfo(int slot) {
name = Identifier.lookup("local_"+slot+"__"+serialnr);
name = null;
type = MyType.tUnknown;
serialnr++;
this.slot = slot;
}
/**
@ -39,10 +40,10 @@ public class LocalInfo {
* @param li the local info that we want to shadow.
*/
public void combineWith(LocalInfo li) {
if (this == li)
return;
if (shadow != null)
shadow.combineWith(li);
li = li.getLocalInfo();
if (this != li)
shadow = li;
}
@ -62,6 +63,8 @@ public class LocalInfo {
public Identifier getName() {
if (shadow != null)
return shadow.getName();
if (name == null)
name = Identifier.lookup("local_"+slot+"__"+serialnr++);
return name;
}

@ -61,14 +61,28 @@ public class LocalVariableAnalyzer {
}
public void analyze(MethodInstructionHeader mih) {
{
Type[] paramTypes = mdef.getType().getArgumentTypes();
int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length;
argLocals = new LocalInfo[length];
int offset = 0;
if (!mdef.isStatic()) {
argLocals[0] = new LocalInfo(0);
argLocals[0].setType(mdef.getClassDefinition().getType());
offset++;
}
for (int i=0; i< paramTypes.length; i++) {
argLocals[offset+i] = new LocalInfo(i+offset);
argLocals[offset+i].setType(paramTypes[i]);
}
}
Hashtable done = new Hashtable();
Stack instrStack = new Stack();
Stack readsStack = new Stack();
LocalInfo[] reads = new LocalInfo[maxlocals];
Enumeration predec = mih.getPredecessors().elements();
Enumeration predec = mih.getReturns().elements();
while (predec.hasMoreElements()) {
instrStack.push(predec.nextElement());
readsStack.push(reads);
@ -81,8 +95,6 @@ public class LocalVariableAnalyzer {
(LocalInfo[]) done.get(instr);
reads = (LocalInfo[]) readsStack.pop();
if (env.isVerbose)
System.err.print(".");
// System.err.println("");
// System.err.print("Addr: "+instr.getAddress()+ " [");
// for (int i=0; i< maxlocals; i++) {
@ -108,8 +120,11 @@ public class LocalVariableAnalyzer {
continue;
}
if (!(instr instanceof MethodInstructionHeader)) {
if (instr.getInstruction() instanceof LocalVarOperator) {
if (Decompiler.isVerbose)
System.err.print(".");
LocalVarOperator op =
(LocalVarOperator)instr.getInstruction();
int slot = op.getSlot();
@ -127,41 +142,27 @@ public class LocalVariableAnalyzer {
newReads[slot] = null;
reads = newReads;
done.put(instr, reads);
}
predec = instr.getPredecessors().elements();
if (predec.hasMoreElements()) {
while (predec.hasMoreElements()) {
instrStack.push(predec.nextElement());
readsStack.push(reads);
}
} else {
/* This is the first instruction
*/
for (int i=0; i < argLocals.length; i++) {
if (reads[i] != null)
argLocals[i].combineWith(reads[i]);
}
done.put(instr, reads);
}
// System.err.println("");
reads = (LocalInfo[]) done.get(mih);
Type[] paramTypes = mdef.getType().getArgumentTypes();
int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length;
argLocals = new LocalInfo[length];
int offset = 0;
if (!mdef.isStatic()) {
LocalInfo li = reads[0];
if (li == null)
li = new LocalInfo(0);
li.setName(Constants.idThis);
li.setType(mdef.getClassDefinition().getType());
argLocals[0] = li.getLocalInfo();
offset++;
}
for (int i=0; i< paramTypes.length; i++) {
LocalInfo li = reads[i+offset];
if (li == null)
li = new LocalInfo(i+offset);
li.setType(paramTypes[i]);
argLocals[offset+i] = li.getLocalInfo();
}
if (!mdef.isStatic())
argLocals[0].setName(Constants.idThis);
// System.err.println("done!");
}
public void createLocalInfo(CodeAnalyzer code) {
@ -175,13 +176,14 @@ public class LocalVariableAnalyzer {
argLocals = new LocalInfo[length];
for (int i=0; i < length; i++)
argLocals[i] = lvt.getLocal(i).getInfo(-1);
for (InstructionHeader ih = mih.getNextInstruction();
for (InstructionHeader ih = mih.getFirst();
ih != null; ih = ih.getNextInstruction()) {
if (ih.getInstruction() instanceof LocalVarOperator) {
LocalVarOperator op =
(LocalVarOperator)ih.getInstruction();
int slot = op.getSlot();
LocalInfo li = lvt.getLocal(slot).getInfo(ih.getAddress());
LocalInfo li =
lvt.getLocal(slot).getInfo(ih.getAddress());
op.setLocalInfo(li);
}
}

@ -35,15 +35,15 @@ public class MethodAnalyzer implements Analyzer, Constants {
{
if (code == null)
return;
if (env.isVerbose)
if (Decompiler.isVerbose)
System.err.print(mdef.getName().toString()+": locals ");
lva.createLocalInfo(code);
if (env.isVerbose) {
if (Decompiler.isVerbose) {
System.err.println("");
System.err.print("code ");
}
code.analyze();
if (env.isVerbose)
if (Decompiler.isVerbose)
System.err.println("");
}

@ -6,7 +6,6 @@ public class TabbedPrintWriter {
String tabstr;
StringBuffer indent;
PrintWriter pw;
int verbosity=0;
public TabbedPrintWriter (OutputStream os, String tabstr) {
pw = new PrintWriter(os);

@ -9,6 +9,10 @@ public class AssignOperator extends Operator {
this.store = store;
}
public StoreInstruction getStore() {
return store;
}
public int getPriority() {
return store.getPriority();
}

@ -0,0 +1,75 @@
package jode;
import sun.tools.java.Type;
import java.util.Vector;
public class CatchInstructionHeader extends InstructionHeader {
Type type;
String typeString;
LocalInfo local;
CatchInstructionHeader(Type type, String typeString,
InstructionHeader firstInstr,
InstructionHeader outer) {
super(CATCH, firstInstr.addr, firstInstr.addr,
new InstructionHeader[1], outer);
movePredecessors(firstInstr);
successors[0] = firstInstr;
firstInstr.predecessors = new Vector();
firstInstr.predecessors.addElement(this);
prevInstruction = firstInstr.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
nextInstruction = firstInstr;
firstInstr.prevInstruction = this;
this.type = type;
this.typeString = typeString;
}
public LocalInfo getLocal() {
return local;
}
/**
* Combines this catch instruction header with the next instruction
* header which should containt only a LocalStoreOperator or a pop
* according to the parameter. (This is where the exception gets
* stored.
* @param local The local where the exception is stored.
* @return true if the operation succeeded.
*/
public boolean combineWithLocal(LocalInfo local) {
InstructionHeader next = nextInstruction;
if (this.local != null || successors[0] != next)
return false;
this.local = local;
successors = next.successors;
nextInstruction = next.nextInstruction;
if (nextInstruction != null)
nextInstruction.prevInstruction = this;
for (int i=0; i< successors.length; i++) {
successors[i].predecessors.removeElement(next);
successors[i].predecessors.addElement(this);
}
return true;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging)
dumpDebugging(writer);
writer.println("} catch ("+typeString+" "+
(local != null ? local.getName()
: (Object) "stack_0") + ") {");
}
}

@ -0,0 +1,51 @@
package jode;
import java.util.Vector;
public class CombineIfGotoExpressions implements Transformation{
public InstructionHeader transform(InstructionHeader ih2) {
InstructionHeader ih1;
Expression[] e;
int operator;
try {
if (ih2.getFlowType() != ih2.IFGOTO)
return null;
InstructionHeader[] dests2 = ih2.getSuccessors();
/* if ih2.getSimpleUniquePredecessor.getOperator().isVoid() XXX */
Vector predec = ih2.getPredecessors();
if (predec.size() != 1)
return null;
ih1 = (InstructionHeader) predec.elementAt(0);
if (ih1.getFlowType() != ih1.IFGOTO)
return null;
InstructionHeader[] dests1 = ih1.getSuccessors();
if (dests1[0] != ih2)
return null;
if (dests1[1] == dests2[0]) {
e = new Expression[2];
operator = Operator.LOG_AND_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = ((Expression)ih1.getInstruction()).negate();
} else if (dests1[1] == dests2[1]) {
e = new Expression[2];
operator = Operator.LOG_OR_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = (Expression)ih1.getInstruction();
} else
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
Expression cond =
new Expression(new BinaryOperator(MyType.tBoolean, operator), e);
return ih1.combineConditional(cond);
}
}

@ -25,13 +25,6 @@ public class CompareBinaryOperator extends SimpleOperator {
return getPriority()+i;
}
public void setOperandType(Type[] inputTypes) {
super.setOperandType(inputTypes);
Type operandType =
MyType.intersection(operandTypes[0],operandTypes[1]);
operandTypes[0] = operandTypes[1] = operandType;
}
public boolean equals(Object o) {
return (o instanceof CompareBinaryOperator) &&
((CompareBinaryOperator)o).operator == operator;

@ -2,9 +2,12 @@ package jode;
import sun.tools.java.Type;
public class CompareUnaryOperator extends SimpleOperator {
boolean objectType;
public CompareUnaryOperator(Type type, int op) {
super(Type.tBoolean, op, 1);
operandTypes[0] = type;
objectType = (type == MyType.tUObject);
}
public int getPriority() {
@ -31,8 +34,6 @@ public class CompareUnaryOperator extends SimpleOperator {
}
public String toString(String[] operands) {
return operands[0] + getOperatorString() +
(MyType.isOfType(operandTypes[0],
MyType.tObject)?"null":"0");
return operands[0] + getOperatorString() + (objectType?"null":"0");
}
}

@ -6,6 +6,8 @@ public class ConstOperator extends NoArgOperator {
public ConstOperator(Type type, String value) {
super(type);
if (type == MyType.tString)
value = quoted(value);
this.value = value;
}
@ -17,10 +19,10 @@ public class ConstOperator extends NoArgOperator {
return 1000;
}
public String quoted(String str) {
public static String quoted(String str) {
StringBuffer result = new StringBuffer("\"");
for (int i=0; i< value.length(); i++) {
switch (value.charAt(i)) {
for (int i=0; i< str.length(); i++) {
switch (str.charAt(i)) {
case '\t':
result.append("\\t");
break;
@ -34,7 +36,7 @@ public class ConstOperator extends NoArgOperator {
result.append("\\\"");
break;
default:
result.append(value.charAt(i));
result.append(str.charAt(i));
}
}
return result.append("\"").toString();
@ -46,8 +48,6 @@ public class ConstOperator extends NoArgOperator {
}
public String toString(String[] operands) {
if (MyType.isOfType(type, Type.tString))
return quoted(value);
if (type == Type.tBoolean) {
if (value.equals("0"))
return "false";

@ -6,7 +6,7 @@ public class ConstantArrayOperator extends SimpleOperator {
public ConstantArrayOperator(Type type, int size) {
super(type, 0, size);
for (int i=0; i< size; i++)
operandTypes[i] = type.getElementType();
operandTypes[i] = MyType.tSubType(type.getElementType());
}
public int getPriority() {

@ -25,7 +25,7 @@ public class ConstructorOperator extends Operator {
public Type getOperandType(int i) {
if (i == 0)
return MyType.tSubType(type);
return field.getClassDeclaration().getType(); // or subtype? XXX
return MyType.tSubType(field.getType().getArgumentTypes()[i-1]);
}

@ -0,0 +1,67 @@
package jode;
public class CreateAssignExpression implements Transformation{
public InstructionHeader transform(InstructionHeader ih) {
InstructionHeader next = createAssignOp(ih);
if (next != null)
return next;
return createAssignExpression(ih);
}
public InstructionHeader createAssignOp(InstructionHeader ih) {
Expression rightHandSide;
StoreInstruction store;
BinaryOperator binop;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
binop = (BinaryOperator) ih.getInstruction();
if (binop.getOperator() < binop.ADD_OP ||
binop.getOperator() >= binop.ASSIGN_OP)
return null;
ih = ih.getSimpleUniquePredecessor();
rightHandSide = (Expression) ih.getInstruction();
if (rightHandSide.isVoid())
return null; /* XXX */
ih = ih.getSimpleUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 &&
dup.getCount() != store.getLValueOperandCount())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ih = ih.combine(3, rightHandSide);
InstructionHeader storeIH = ih.getNextInstruction();
store.setOperator(store.OPASSIGN_OP+binop.getOperator());
store.setLValueType(MyType.intersection(binop.getType(),
store.getLValueType()));
storeIH.combine(2, store);
return ih;
}
public InstructionHeader createAssignExpression(InstructionHeader ih) {
StoreInstruction store;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != store.getLValueOperandCount() &&
dup.getCount() != store.getLValueType().stackSize())
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
return ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store));
}
}

@ -0,0 +1,36 @@
package jode;
public class CreateExpression implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
Operator op;
Expression exprs[];
int params;
try {
op = (Operator) ih.getInstruction();
params = op.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>=0; i--) {
ih = ih.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid()) {
if (i == params-1)
return null;
Expression e = exprs[i+1].tryToCombine(exprs[i]);
if (e == null)
return null;
i++;
exprs[i] = e;
ih = ih.combine(2, e);
}
}
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
if(Decompiler.isVerbose && params > 0)
System.err.print("x");
return ih.combine(params+1, new Expression(op, exprs));
}
}

@ -0,0 +1,108 @@
package jode;
import java.util.Enumeration;
import java.util.Vector;
public class CreateIfThenElseOperator implements Transformation{
public InstructionHeader createFunny(InstructionHeader ih) {
Expression cond = null;
try {
InstructionHeader ifHeader= ih;
if (ifHeader.getFlowType() != ifHeader.IFGOTO)
return null;
CompareUnaryOperator compare =
(CompareUnaryOperator) ifHeader.getInstruction();
if ((compare.getOperator() & ~1) != compare.EQUALS_OP)
return null;
Enumeration enum = ih.getPredecessors().elements();
while (enum.hasMoreElements()) {
try {
ih = (InstructionHeader) enum.nextElement();
Expression zeroExpr = (Expression) ih.getInstruction();
ConstOperator zero =
(ConstOperator) zeroExpr.getOperator();
if (!zero.getValue().equals("0"))
continue;
ih = ih.getUniquePredecessor();
if (ih.getFlowType() != ih.IFGOTO)
continue;
if (compare.getOperator() == compare.EQUALS_OP &&
ih.getSuccessors()[1] != ifHeader.getSuccessors()[0]
|| compare.getOperator() == compare.NOTEQUALS_OP &&
ih.getSuccessors()[1] != ifHeader.getSuccessors()[1])
continue;
cond = (Expression) ih.getInstruction();
break;
} catch (ClassCastException ex) {
} catch (NullPointerException ex) {
}
}
if (cond == null)
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
InstructionHeader next = ih.nextInstruction;
ih.successors[1].predecessors.removeElement(ih);
next.instr = ih.instr;
next.movePredecessors(ih);
return next;
}
public InstructionHeader create(InstructionHeader ih) {
InstructionHeader ifHeader;
Expression e[] = new Expression[3];
InstructionHeader[] succs;
try {
Vector predec = ih.getPredecessors();
if (predec.size() != 1)
return null;
ifHeader = (InstructionHeader) predec.elementAt(0);
if (ifHeader.getFlowType() != ifHeader.IFGOTO)
return null;
succs = ifHeader.getSuccessors();
if (succs[1] != ih ||
succs[0].getNextInstruction() != succs[1] ||
succs[0].getSuccessors().length != 1 ||
succs[1].getSuccessors().length != 1 ||
succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0])
return null;
e[0] = ((Expression) ifHeader.getInstruction()).negate();
e[1] = (Expression) succs[0].getInstruction();
if (e[1].isVoid())
return null;
e[2] = (Expression) succs[1].getInstruction();
if (e[2].isVoid())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
IfThenElseOperator iteo = new IfThenElseOperator
(MyType.intersection(e[1].getType(),e[2].getType()));
ih.instr = new Expression(iteo, e);
ih.movePredecessors(ifHeader);
ih.nextInstruction.predecessors.removeElement(ifHeader.successors[0]);
return ih;
}
public InstructionHeader transform(InstructionHeader ih) {
InstructionHeader next = createFunny(ih);
if (next != null)
return next;
return create(ih);
}
}

@ -0,0 +1,99 @@
package jode;
import sun.tools.java.Type;
public class CreatePostIncExpression implements Transformation {
public InstructionHeader transform(InstructionHeader ih)
{
InstructionHeader next = createLocalPostInc(ih);
if (next != null)
return next;
return createPostInc(ih);
}
public InstructionHeader createLocalPostInc(InstructionHeader ih) {
IIncOperator iinc;
int op;
Type type;
try {
Expression iincExpr = (Expression) ih.getInstruction();
iinc = (IIncOperator) iincExpr.getOperator();
if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP)
op = Operator.INC_OP;
else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP)
op = Operator.DEC_OP;
else
return null;
if (!iinc.getValue().equals("1") &&
!iinc.getValue().equals("-1"))
return null;
if (iinc.getValue().equals("-1"))
op ^= 1;
ih = ih.getSimpleUniquePredecessor();
Expression loadExpr = (Expression) ih.getInstruction();
LocalLoadOperator load =
(LocalLoadOperator)loadExpr.getOperator();
if (!iinc.matches(load))
return null;
type = MyType.intersection(load.getType(), MyType.tUInt);
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new LocalPostFixOperator(type, op, iinc);
return ih.combine(2, postop);
}
public InstructionHeader createPostInc(InstructionHeader ih) {
StoreInstruction store;
int op;
Type type;
try {
store = (StoreInstruction) ih.getInstruction();
if (store.getLValueOperandCount() == 0)
return null;
ih = ih.getSimpleUniquePredecessor();
BinaryOperator binOp = (BinaryOperator) ih.getInstruction();
if (binOp.getOperator() == store.ADD_OP)
op = Operator.INC_OP;
else if (store.getOperator() == store.NEG_OP)
op = Operator.DEC_OP;
else
return null;
ih = ih.getSimpleUniquePredecessor();
Expression expr = (Expression) ih.getInstruction();
ConstOperator constOp = (ConstOperator) expr.getOperator();
if (!constOp.getValue().equals("1") &&
!constOp.getValue().equals("-1"))
return null;
if (constOp.getValue().equals("-1"))
op ^= 1;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != store.getLValueType().stackSize() ||
dup.getDepth() != store.getLValueOperandCount())
return null;
ih = ih.getSimpleUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup2 = (DupOperator) ih.getInstruction();
if (dup2.getCount() != store.getLValueOperandCount() ||
dup2.getDepth() != 0)
return null;
type = MyType.intersection(load.getType(), store.getLValueType());
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new PostFixOperator(type, op, store);
return ih.combine(6, postop);
}
}

@ -6,11 +6,13 @@ import sun.tools.java.FieldDefinition;
public class Expression extends Instruction {
Operator operator;
Expression[] subExpressions;
Expression parent = null;
public Expression(Operator op, Expression[] sub) {
super(MyType.tUnknown);
operator = op;
subExpressions = sub;
operator.setExpression(this);
if (subExpressions.length != op.getOperandCount())
throw new AssertError ("Operand count mismatch: "+
subExpressions.length + " != " +
@ -18,6 +20,7 @@ public class Expression extends Instruction {
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);
@ -95,10 +98,12 @@ public class Expression extends Instruction {
}
}
public void setType(Type type) {
if (operator.setType(type))
updateSubTypes();
this.type = operator.getType();
public void setType(Type newType) {
newType = MyType.intersection(type, newType);
if (newType != type) {
type = newType;
operator.setType(type);
}
}
public boolean isVoid() {
@ -193,6 +198,38 @@ public class Expression extends Instruction {
return subExpressions[0].negate().simplify();
}
}
// if ((operator instanceof AssignOperator ||
// operator instanceof StoreInstruction) &&
// subExpressions[subExpressions.length-1]
// .operator instanceof ConstOperator) {
// StoreInstruction store;
// if (operator instanceof AssignOperator)
// store = ((AssignOperator)operator).getStore();
// else
// store = (StoreInstruction)operator;
// ConstOperator one = (ConstOperator)
// subExpressions[subExpressions.length-1].operator;
// if ((operator.getOperator() ==
// operator.OPASSIGN_OP+operator.ADD_OP ||
// operator.getOperator() ==
// operator.OPASSIGN_OP+operator.NEG_OP) &&
// (one.getValue().equals("1") ||
// one.getValue().equals("-1"))) {
// int op = ((operator.getOperator() ==
// operator.OPASSIGN_OP+operator.ADD_OP) ==
// one.getValue().equals("1"))?
// operator.INC_OP : operator.DEC_OP;
// return new Expression
// (new PostFixOperator
// (store.getType(), op, store,
// operator instanceof StoreInstruction),
// new Expression[0]).simplify();
// }
// }
if (operator instanceof CompareUnaryOperator &&
subExpressions[0].operator instanceof CompareToIntOperator) {
CompareBinaryOperator newOp = new CompareBinaryOperator

@ -0,0 +1,173 @@
package jode;
import java.util.Enumeration;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H, pred = normal, succ = {C,E}
* B: if ( instr ) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: then-instr 1
* <p>
* prev = C, next = H!, pred = normal succ = normal
* D: instructions of then part
* <p>
* } else {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* E: else-instr 1
* <p>
* prev = E, next = null, pred = normal, succ = normal
* F: instructions of then part
* <p>
* }
* prev = B, ..., pred = normal, succ = normal
* H: ...
* </pre>
*/
public class IfInstructionHeader extends InstructionHeader {
boolean hasElsePart;
/**
* Creates a new if statement. There are several conditions that
* must be met:
* <ul>
* <li><code> ifHeader.successors[0] == thenStart
* </code></li>
* <li><code> ifHeader.successors[1] == thenEnd.nextInstruction
* </code></li>
* <li><code> elseStart == null || (thenEnd.flowType = GOTO &&
* elseEnd.nextInstruction == thenEnd.successors[0])
* </code></li>
* <li><code> elseStart == null || elseStart = thenEnd.nextInstruction
* </code></li>
* <li><code> thenStart.nextInstruction....nextInstruction = thenEnd
* </code></li>
* <li><code> elseStart.nextInstruction....nextInstruction = elseEnd
* </code></li>
* </ul>
* @param ifHeader the instruction header whichs contains the
* if goto statement.
* @param thenStart the start of the then part.
* @param thenEnd the end of the then part.
* @param elseStart the start of the else part.
* @param elseEnd the end of the then part.
* @param next the next instruction after the if statement.
*/
public IfInstructionHeader(InstructionHeader ifHeader,
boolean hasElsePart,
InstructionHeader thenEnd,
InstructionHeader elseEnd,
InstructionHeader endBlock) {
super(IFSTATEMENT, ifHeader.addr, endBlock.addr,
ifHeader.successors, ifHeader.outer);
this.instr = ((Expression)ifHeader.getInstruction()).negate();
this.movePredecessors(ifHeader);
this.outer = ifHeader.outer;
this.endBlock = endBlock;
successors[0].predecessors.removeElement(ifHeader);
successors[1].predecessors.removeElement(ifHeader);
successors[0].predecessors.addElement(this);
successors[1].predecessors.addElement(this);
successors[0].prevInstruction = null;
InstructionHeader next = thenEnd.nextInstruction;
thenEnd.nextInstruction = null;
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
if (ih.outer == outer)
ih.outer = this;
this.hasElsePart = hasElsePart;
if (hasElsePart) {
thenEnd.flowType = thenEnd.NORMAL;
successors[1].prevInstruction = null;
next = elseEnd.nextInstruction;
elseEnd.nextInstruction = null;
for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction)
if (ih.outer == outer)
ih.outer = this;
}
this.nextInstruction = next;
if (next != null)
next.prevInstruction = this;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
boolean braces = successors[0].flowType != NORMAL ||
successors[0].nextInstruction != null;
writer.println("if (" + instr.toString() + ")" + (braces ? " {": ""));
writer.tab();
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
if (hasElsePart) {
if (braces)
writer.print("} ");
braces = successors[1].flowType != NORMAL ||
successors[1].nextInstruction != null;
if (!braces && successors[1].flowType == IFSTATEMENT) {
writer.print("else ");
successors[1].dumpSource(writer);
} else {
writer.println("else" + (braces ? " {": ""));
writer.tab();
for (InstructionHeader ih = successors[1];
ih != null; ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
}
}
if (braces)
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
if (hasElsePart) {
for (InstructionHeader ih = successors[1]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
}
return super.doTransformations(trafo);
}
}

@ -11,50 +11,131 @@ import sun.tools.java.Type;
* @author Jochen Hoenicke
*/
public class InstructionHeader {
int addr, length;
public final static int METHOD =-1;
public final static int NORMAL = 0;
public final static int GOTO = 1;
public final static int IFGOTO = 2;
public final static int SWITCH = 3;
public final static int JSR = 4;
public final static int RET = 5;
public final static int RETURN = 6;
public final static int TRY = 7;
public final static int CATCH = 8;
public final static int IFSTATEMENT = 10;
public final static int WHILESTATEMENT = 11;
public final static int DOWHILESTATEMENT = 12;
public final static int FORSTATEMENT = 13;
public final static int TRYCATCHBLOCK = 14;
public final static int EMPTY = 99;
/**
* The flow type of the instruction header, this is one of the
* above constants.
*/
int flowType;
/**
* The address of this and the following instruction header.
*/
int addr, nextAddr;
/**
* The underlying instruction. This is null for some special
* instructions (depends on flowType).
*/
Instruction instr;
InstructionHeader nextInstruction;
/**
* The instruction header representing the surrounding block.
*/
InstructionHeader outer = null;
/**
* A simple doubly linked list of instructions in code order
* (without caring about jump instructions).
*/
InstructionHeader nextInstruction, prevInstruction;
/**
* The first instruction after this block. This should be only
* set for blocks, that is headers which are outer of other headers.
* This gives the instruction where the control flows after this
* block.
*/
InstructionHeader endBlock;
Type switchType;
int[] cases;
int[] succs;
/**
* A more complex doubly linked list of instructions. The
* successors are the possible destinations of jump and switch
* instructions. The predecessors are the reverse things.
* The predeccors sits in a vector to make it easier to add
* or remove one, when creating or manipulating other instruction
* headers.
*/
InstructionHeader[] successors;
Vector predecessors = new Vector();
/**
* Create a new InstructionHeader.
* @param addr The address of this Instruction.
* @param length The length of this Instruction.
* The addresses of the successors of this header. This are
* resolved by resolveSuccessors and then deleted.
*/
int[] succs = null;
/**
* Create a new InstructionHeader, that must be resolved later.
* @param flowType The type of this instruction header.
* @param addr The address of this instruction header.
* @param nextAddr The address of the next instruction header.
* @param instr The underlying Instruction.
* @param succs The successors of this instruction header
* (the addresses, are resolved later).
*/
public InstructionHeader(int addr, int length, Instruction instr) {
int[] succs = { addr + length };
protected InstructionHeader(int flowType, int addr, int nextAddr,
Instruction instr, int[] succs) {
this.flowType = flowType;
this.addr = addr;
this.length = length;
this.nextAddr = nextAddr;
this.instr = instr;
switchType = MyType.tVoid;
this.cases = new int[0];
this.succs = succs;
}
/**
* Create a new InstructionHeader.
* @param addr The address of this Instruction.
* @param length The length of this Instruction.
* @param instr The underlying Instruction.
* @param type The type of the switch
* @param cases The possible cases
* @param succs The destinations (one longer for default)
* @param flowType The type of this instruction header.
* @param addr The address of this instruction header.
* @param nextAddr The address of the next instruction header.
* @param successors The successors of this instruction header.
* @param outer The instruction header of the surrounding block.
*/
public InstructionHeader(int addr, int length, Instruction instr,
Type type, int[] cases, int[] succs) {
protected InstructionHeader(int flowType, int addr, int nextAddr,
InstructionHeader[] successors,
InstructionHeader outer) {
this.flowType = flowType;
this.addr = addr;
this.length = length;
this.nextAddr = nextAddr;
this.instr = instr;
switchType = type;
this.cases = cases;
this.succs = succs;
this.successors = successors;
this.outer = outer;
}
/**
* Create a new InstructionHeader of zero length.
* @param flowType The type of this instruction header.
* @param addr The address of this Instruction.
* @param outer The instruction header of the surrounding block.
*/
protected InstructionHeader(int flowType, int addr,
InstructionHeader outer) {
this(flowType, addr, addr, new InstructionHeader[0], outer);
}
/**
* Create an InstructionHeader for a normal instruction.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param instr The underlying Instruction.
*/
public static InstructionHeader createNormal(int addr, int length,
Instruction instr) {
int[] succs = { addr + length };
return new InstructionHeader(NORMAL, addr, addr + length,
instr, succs);
}
/**
@ -63,10 +144,10 @@ public class InstructionHeader {
* @param length The length of this instruction.
* @param instr The underlying Instruction.
*/
public static InstructionHeader ret(int addr, int length,
public static InstructionHeader createReturn(int addr, int length,
Instruction instr) {
return new InstructionHeader (addr, length, instr,
MyType.tVoid, new int[0], new int[0]);
return new InstructionHeader(RETURN, addr, addr + length,
instr, new int[0]);
}
/**
@ -76,11 +157,11 @@ public class InstructionHeader {
* @param instr The underlying Instruction.
* @param dest The destination address of the jump.
*/
public static InstructionHeader jump(int addr, int length, int dest,
public static InstructionHeader createGoto(int addr, int length, int dest,
Instruction instr) {
int [] succs = { dest };
return new InstructionHeader (addr, length, instr,
MyType.tVoid, new int[0], succs);
return new InstructionHeader (GOTO, addr, addr + length,
instr, succs);
}
/**
@ -90,21 +171,80 @@ public class InstructionHeader {
* @param instr The underlying Instruction.
* @param dest The destination address of the jump.
*/
public static InstructionHeader conditional(int addr, int length, int dest,
Instruction instr) {
int[] cases = { 0 };
public static InstructionHeader createIfGoto(int addr, int length,
int dest, Instruction instr) {
int[] succs = { addr+length , dest };
return new InstructionHeader (addr, length, instr,
MyType.tBoolean, cases, succs);
return new InstructionHeader (IFGOTO, addr, addr + length,
instr, succs);
}
/**
* Create an InstructionHeader for a switch.
* @param addr The address of this Instruction.
* @param length The length of this Instruction.
* @param instr The underlying Instruction.
* @param cases The possible cases
* @param succs The destinations (one longer for default)
*/
public static InstructionHeader createSwitch(int addr, int length,
Instruction instr,
int[] cases, int[] succs) {
InstructionHeader ih =
new SimpleSwitchInstructionHeader(addr, addr+length, instr,
cases, succs);
return ih;
}
static int ids =0;
int id = -1;
public String toString() {
return instr.toString();
if (id == -1) id = ids++;
return addr+"__"+id;
}
/**
* Get the address of this instruction.
* @return The address.
* Returns the InstructionHeader where a break of this instruction
* would jump to. Does only make sense for do/while/for-loops and
* switch instructions.
*/
public InstructionHeader getBreak() {
return null;
}
/**
* Returns the InstructionHeader where a continue of this instruction
* would jump to. Does only make sense for do/while/for-loops.
*/
public InstructionHeader getContinue() {
return null;
}
/**
* Get the flow type of this instruction.
* @return the flow type.
*/
public int getFlowType() {
return flowType;
}
static int serialnr = 0;
String label = null;
/**
* Get the label of this instruction. It is created on the fly
* if it didn't exists before.
* @return the label.
*/
public String getLabel() {
if (label == null)
label = "label_" + serialnr++;
return label;
}
/**
* Get the address of this instruction. This is probably only useful
* for debugging purposes.
* @return the address.
*/
public int getAddress() {
return addr;
@ -112,25 +252,33 @@ public class InstructionHeader {
/**
* Get the next address in code order.
* @return The next instruction
* @return the next instruction
*/
public int getNextAddr() {
return addr+length;
return nextAddr;
}
/**
* Get the underlying instruction.
* @return The underlying instruction.
* @return the underlying instruction.
*/
public Instruction getInstruction() {
return instr;
}
/**
* Set the underlying instruction.
* @param instr the underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.instr = instr;
}
/**
* Get the next instruction in code order. This function mustn't
* be called before resolveSuccessors is executed for this
* InstructionHeaders.
* @return The next instruction
* @return the next instruction
*/
public InstructionHeader getNextInstruction() {
return nextInstruction;
@ -146,10 +294,22 @@ public class InstructionHeader {
return successors;
}
public boolean hasDirectPredecessor() {
return predecessors.size() == 1 &&
((InstructionHeader)predecessors.elementAt(0)).
getNextInstruction() == this;
/**
* Returns true if this instruction header needs a label.
*/
protected boolean needsLabel() {
/* An instruction my have only one prevInstruction, but
* may have more then one predecessor that has its
* nextInstruction pointing to us.
*/
for (int i=0; i<predecessors.size(); i++) {
InstructionHeader ih =
(InstructionHeader)predecessors.elementAt(i);
if (ih.flowType == GOTO ||
(ih.flowType == IFGOTO && ih.successors[1] == this))
return true;
}
return false;
}
/**
@ -157,14 +317,13 @@ public class InstructionHeader {
* unique predecessor.
*/
public InstructionHeader getUniquePredecessor() {
if (predecessors.size() != 1)
return null;
InstructionHeader pre = (InstructionHeader)predecessors.elementAt(0);
return (pre.getNextInstruction() == this) ? pre : null;
return (predecessors.size() == 1 &&
predecessors.elementAt(0) == prevInstruction) ?
prevInstruction : null;
}
/**
* Get the unique predecessor which mustn't be a (un)conditional jump
* Get the unique predecessor which mustn't be a conditional jump
* @return the predecessor or null if there isn't a such a thing
*/
public InstructionHeader getSimpleUniquePredecessor() {
@ -172,7 +331,6 @@ public class InstructionHeader {
return (pre.getSuccessors().length != 1) ? null : pre;
}
/**
* Get the predecessors of this instruction. This function mustn't
* be called before resolveSuccessors is executed for all
@ -190,82 +348,126 @@ public class InstructionHeader {
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
if (addr+length < instHeaders.length)
nextInstruction = instHeaders[addr+length];
else
if (nextAddr < instHeaders.length) {
nextInstruction = instHeaders[nextAddr];
instHeaders[nextAddr].prevInstruction = this;
} else
nextInstruction = null;
successors = new InstructionHeader[succs.length];
for (int i=0; i< succs.length; i++) {
successors[i] = instHeaders[succs[i]];
successors[i].predecessors.addElement(this);
}
succs = null;
}
public void dumpDebugging(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.print(""+toString()+
": <"+addr + " - "+(nextAddr-1)+"> preds: ");
for (int i=0; i<predecessors.size(); i++) {
if (i>0) writer.print(", ");
writer.print(""+predecessors.elementAt(i));
}
writer.println("");
writer.print("outend: "+outer.endBlock+
" prev: "+prevInstruction+", next: "+ nextInstruction +
" succs: ");
for (int i=0; i<successors.length; i++) {
if (i>0) writer.print(", ");
writer.print(""+successors[i]);
}
writer.println("");
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (writer.verbosity > 5) {
writer.println("<"+addr + " - "+(addr+length-1)+">");
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
// writer.print("predecs: ");
// for (int i=0; i<predecessors.size(); i++) {
// if (i>0) writer.print(", ");
// writer.print(""+((InstructionHeader)predecessors.elementAt(i)).
// getAddress());
// }
// writer.println("");
if (!hasDirectPredecessor() && addr != 0)
writer.print("addr_"+addr+": ");
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
if (switchType == MyType.tBoolean) {
if (flowType == IFGOTO) {
writer.println("if ("+instr.toString()+") goto addr_"+succs[1]);
if (succs[0] != addr + length)
writer.println("goto addr_"+succs[0]);
writer.println("if ("+instr.toString()+") goto "+
successors[1].getLabel());
} else if (switchType == MyType.tVoid) {
} else {
if (flowType != EMPTY) {
if (!(instr instanceof NopOperator)) {
if (instr.getType() != MyType.tVoid)
writer.print("push ");
writer.println(instr.toString()+";");
if (succs.length > 0 && succs[0] != addr + length)
writer.println("goto addr_"+succs[0]);
}
if (flowType == GOTO)
writer.println("goto "+successors[0].getLabel());
}
} else {
writer.println("switch ("+instr.toString()+") {");
writer.tab();
writer.untab();
}
if (writer.verbosity > 5)
if (Decompiler.isDebugging)
writer.untab();
}
/**
* Moves the predecessors from the InstructionHeader <em>from</em> to
* the current instruction. The current predecessors are overwritten
* and you must make sure that no live InstructionHeader points to
* the current. <p>
* The predecessors of <em>from</em> are informed about this change.
* @param from The instruction header which predecessors are moved.
*/
public void movePredecessors(InstructionHeader from) {
addr = from.addr;
prevInstruction = from.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
predecessors = from.predecessors;
for (int i=0; i < predecessors.size(); i++) {
InstructionHeader pre =
(InstructionHeader)predecessors.elementAt(i);
for (int j=0; j<pre.successors.length; j++)
if (pre.successors[j] == from)
pre.successors[j] = this;
}
}
/**
* This method replaces multiple InstructionHeaders by a single one.
* The next count Instructions must be unique.
* @param count the number of InstructionHeaders that should be replaced.
* @param instr the new instruction; this should be equivalent to the
* old <em>count</em instructions.
* @return the InstructionHeader representing the combined instructions.
*/
public void combine(int count, Instruction newInstr) {
InstructionHeader last = this;
this.instr = newInstr;
public InstructionHeader combine(int count, Instruction newInstr) {
InstructionHeader ih = this;
for (int i=1; i < count; i++) {
last = last.getSuccessors()[0];
length += last.length;
}
switchType = last.switchType;
cases = last.cases;
succs = last.succs;
successors = last.successors;
nextInstruction = last.nextInstruction;
for (int i=0; i< successors.length; i++) {
successors[i].predecessors.removeElement(last);
successors[i].predecessors.addElement(this);
ih = ih.nextInstruction;
}
ih.instr = newInstr;
ih.movePredecessors(this);
return ih;
}
public InstructionHeader doTransformations(Transformation[] trafo) {
for (int i=0; i<trafo.length; i++) {
InstructionHeader newInstr = trafo[i].transform(this);
if (newInstr != null)
return newInstr;
}
return null;
}
/**
@ -276,25 +478,11 @@ public class InstructionHeader {
* @param newCondition the new instruction; this should be equivalent
* to the old two conditions.
*/
public void combineConditional(Instruction newCondition) {
nextInstruction.successors[0].predecessors.
removeElement(nextInstruction);
nextInstruction.successors[1].predecessors.
removeElement(nextInstruction);
instr = newCondition;
succs[0] = nextInstruction.succs[0]; // aid debugging
successors[0] = nextInstruction.successors[0];
if (successors[1] != nextInstruction.successors[1]) {
succs[1] = nextInstruction.succs[1]; // aid debugging
successors[1] = nextInstruction.successors[1];
successors[1].predecessors.addElement(this);
} else {
successors[0].predecessors.addElement(this);
}
length += nextInstruction.length; // aid debugging
nextInstruction = nextInstruction.nextInstruction;
public InstructionHeader combineConditional(Instruction newCondition) {
successors[1].predecessors.removeElement(this);
InstructionHeader next = nextInstruction;
next.instr = newCondition;
next.movePredecessors(this);
return next;
}
}

@ -20,22 +20,11 @@ public class JsrInstructionHeader extends InstructionHeader {
* <li> void for an unconditional Jsr. </li></ul>
*/
public JsrInstructionHeader(int addr, int length, int dest,
Instruction instr) {
super(addr,length, instr);
Instruction instr, int[] succs) {
super(JSR, addr, addr+length, instr, succs);
this.dest = dest;
}
/**
* Get the successors of this instructions. This function mustn't
* be called before resolveSuccessors is executed for this
* InstructionHeaders.
* @return Array of successors.
*/
public InstructionHeader[] getSuccessors() {
InstructionHeader[] result = { destination };
return result;
}
/**
* Resolve the successors and predecessors and build a doubly
* linked list.
@ -43,7 +32,7 @@ public class JsrInstructionHeader extends InstructionHeader {
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
nextInstruction = instHeaders[addr+length];
nextInstruction = instHeaders[nextAddr];
destination = instHeaders[dest];
destination.predecessors.addElement(this);
/* Ret.successors.addElement(nextInstruction); XXX */

@ -1,35 +1,91 @@
package jode;
import java.util.Vector;
import sun.tools.java.BinaryExceptionHandler;
import sun.tools.java.Type;
/**
* This class is the end point of the InstructionHeader list.
* @author Jochen Hoenicke
*/
public class MethodInstructionHeader extends InstructionHeader {
InstructionHeader first, last;
/**
* Create a new InstructionHeader.
* @param addr The address of this Instruction.
* @param length The length of this Instruction.
* @param instr The underlying Instruction.
*/
public MethodInstructionHeader(InstructionHeader[] instr) {
super(-1,1,null);
nextInstruction = instr[0];
nextInstruction.predecessors.addElement(this);
for (int addr = 0; addr < instr.length; ) {
public MethodInstructionHeader(JodeEnvironment env,
InstructionHeader[] instr,
BinaryExceptionHandler[] handlers) {
super(METHOD, 0, instr.length, new InstructionHeader[0], null);
first = new InstructionHeader(EMPTY, 0, this);
last = new InstructionHeader(EMPTY, instr.length, this);
first.nextInstruction = instr[0];
instr[0].prevInstruction = first;
for (int addr = 0; ; addr = instr[addr].nextAddr) {
instr[addr].outer = this;
instr[addr].resolveSuccessors(instr);
if (instr[addr].succs.length == 0)
predecessors.addElement(instr[addr]);
addr = instr[addr].getNextAddr();
if (instr[addr].flowType == RETURN) {
InstructionHeader[] lastArr = { last };
instr[addr].successors = lastArr;
last.predecessors.addElement(instr[addr]);
}
if (instr[addr].nextAddr == instr.length) {
instr[addr].nextInstruction = last;
last.prevInstruction = instr[addr];
break;
}
/**
* Resolve the successors and predecessors and build a doubly
* linked list.
* @param instHeaders an array of the InstructionHeaders, indexed
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
}
for (int i=0; i<handlers.length; i++) {
InstructionHeader tryIH = instr[handlers[i].startPC];
if (tryIH.flowType != TRY)
instr[handlers[i].startPC] = tryIH =
new TryInstructionHeader(tryIH, this);
Type type = handlers[i].exceptionClass.getType();
instr[handlers[i].handlerPC] =
new CatchInstructionHeader
(type, env.getTypeString(type),
instr[handlers[i].handlerPC], this);
InstructionHeader endIH = instr[handlers[i].endPC];
InstructionHeader catchIH = instr[handlers[i].handlerPC];
((TryInstructionHeader)tryIH).addHandler(endIH, catchIH);
}
endBlock = last;
}
public InstructionHeader getFirst() {
return first.nextInstruction;
}
public Vector getReturns() {
return last.predecessors;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
for (InstructionHeader ih = first.nextInstruction;
ih != last; ih = ih.nextInstruction)
ih.dumpSource(writer);
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (InstructionHeader ih = first.nextInstruction;
ih != last; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
return null;
}
}

@ -27,6 +27,7 @@ public abstract class Operator extends Instruction {
};
protected int operator;
protected Expression expression = null;
Operator (Type type, int op) {
super(type);
@ -35,6 +36,10 @@ public abstract class Operator extends Instruction {
throw new AssertError("type == null");
}
public void setExpression(Expression expr) {
expression = expr;
}
public int getOperator() {
return operator;
}

@ -3,14 +3,21 @@ import sun.tools.java.Type;
public class PostFixOperator extends Operator {
StoreInstruction store;
boolean postfix;
public PostFixOperator(Type type, int op, StoreInstruction store) {
public PostFixOperator(Type type, int op, StoreInstruction store,
boolean postfix) {
super(type, op);
this.store = store;
this.postfix = postfix;
}
public PostFixOperator(Type type, int op, StoreInstruction store) {
this (type, op, store, true);
}
public int getPriority() {
return 800;
return postfix ? 800 : 700;
}
public int getOperandPriority(int i) {
@ -40,6 +47,9 @@ public class PostFixOperator extends Operator {
}
public String toString(String[] operands) {
if (postfix)
return store.getLValueString(operands) + getOperatorString();
else
return getOperatorString() + store.getLValueString(operands);
}
}

@ -19,7 +19,7 @@ public class RetInstructionHeader extends InstructionHeader {
* @param instr The underlying Instruction of int type (ret addr).
*/
public RetInstructionHeader(int addr, int length, Instruction instr) {
super(addr, length, instr);
super(RET, addr, addr+length, instr, new int[0]);
}
/**
@ -40,6 +40,6 @@ public class RetInstructionHeader extends InstructionHeader {
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
nextInstruction = instHeaders[addr+length];
nextInstruction = instHeaders[nextAddr];
}
}

@ -23,8 +23,6 @@ public abstract class SimpleOperator extends Operator {
public void setOperandType(Type[] t) {
for (int i=0; i< operandTypes.length; i++) {
if (MyType.intersection(operandTypes[i], t[i]) == Type.tError)
System.err.println("Error: "+operandTypes[i]+","+t[i]);
operandTypes[i] = MyType.intersection(operandTypes[i], t[i]);
}
}

@ -0,0 +1,61 @@
package jode;
/**
* This is an InstructionHeader for simple switch statements. Simple
* means that this is without blocks.
* @author Jochen Hoenicke
*/
public class SimpleSwitchInstructionHeader extends InstructionHeader {
/**
* The case labels of a switch instruction header.
*/
int[] cases;
/**
* Create an InstructionHeader for a conditional or unconditional
* Switch.
* @param addr The address of this instruction.
* @param nextAddr The address of the next instruction header.
* @param instr The underlying Instruction, the type of must be
* an integer type.
* @param cases The value of the cases.
* @param dests The destination addresses belonging to the cases
* plus the default destination address.
*/
public SimpleSwitchInstructionHeader(int addr, int nextAddr,
Instruction instr,
int[] cases, int[] dests) {
super(SWITCH, addr, nextAddr, instr, dests);
this.cases = cases;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
writer.println("switch ("+instr.toString()+") {");
writer.tab();
for (int i=0; i<cases.length; i++)
writer.println("case "+cases[i]+": goto "+
successors[i].getLabel());
writer.println("default: "+
successors[successors.length-1].getLabel());
writer.println("}");
writer.untab();
if (Decompiler.isDebugging)
writer.untab();
}
}

@ -0,0 +1,9 @@
package jode;
public class SimplifyExpression implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
if (ih.getInstruction() != null)
ih.setInstruction(ih.getInstruction().simplify());
return null;
}
}

@ -0,0 +1,171 @@
package jode;
import java.util.Vector;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H, pred = normal, succ = {C,E}
* B: try {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: then-instr 1
* <p>
* prev = C, next = H!, pred = normal succ = normal
* D: instructions of then part
* <p>
* } catch (...) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* E: else-instr 1
* <p>
* prev = E, next = null, pred = normal, succ = normal
* F: instructions of then part
* <p>
* }
* prev = B, ..., pred = normal, succ = normal
* H: ...
* </pre>
*
* TODO: Implement finally.
*/
public class TryCatchInstructionHeader extends InstructionHeader {
/**
* Creates a try catch statement. There are several conditions that
* must be met:
* <ul>
* <li><code>
* </code></li>
* </ul>
* @param successors the successors of this try, that is
* the try header and the catch headers.
* @param endHeader the end hader of the first try block.
* This must be successors[1] or a single goto or return
* statement jumping to endBlock.
* @param remaining the remaining successors of the old try header.
* @param endBlock the endBlock of this try statement
*/
public TryCatchInstructionHeader(InstructionHeader[] successors,
InstructionHeader endHeader,
InstructionHeader[] remaining,
InstructionHeader endBlock) {
super(TRYCATCHBLOCK, successors[0].addr, endBlock.addr,
successors, successors[0].outer);
InstructionHeader tryHeader = successors[0];
this.movePredecessors(tryHeader);
if (remaining.length > 1) {
tryHeader.predecessors = new Vector();
tryHeader.predecessors.addElement(this);
tryHeader.prevInstruction = null;
tryHeader.successors = remaining;
} else {
successors[0] = tryHeader.nextInstruction;
if (successors[0] != null) {
successors[0].prevInstruction = null;
successors[0].predecessors.addElement(this);
}
}
this.endBlock = endBlock;
this.nextInstruction = (endBlock.outer == outer) ? endBlock : null;
if (nextInstruction != null)
endBlock.prevInstruction = this;
if (endHeader != successors[1])
endHeader.successors[0].predecessors.removeElement(endHeader);
for (int i=1; i< successors.length; i++) {
endHeader.predecessors.removeElement(tryHeader);
successors[i].predecessors.removeElement(tryHeader);
successors[i].predecessors.addElement(this);
}
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction) {
if (ih.outer == outer)
ih.outer = this;
if (ih.nextInstruction == endHeader)
ih.nextInstruction = null;
}
for (int i=1; i< successors.length; i++) {
for (InstructionHeader ih = successors[i]; ih != null;
ih = ih.nextInstruction) {
if (ih.outer == outer)
ih.outer = this;
if ((i < successors.length-1 &&
ih.nextInstruction == successors[i+1])
|| ih.nextInstruction == endBlock)
ih.nextInstruction = null;
if (ih.nextInstruction == null &&
(ih.flowType == GOTO ||
(ih.flowType == RETURN &&
ih.getInstruction().getType() == MyType.tVoid)) &&
ih.successors[0] == endBlock)
ih.flowType = NORMAL;
}
}
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
writer.println("try {");
writer.tab();
if (successors[0] == null)
writer.print("/* empty */");
else {
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
}
writer.untab();
for (int i=1; i< successors.length; i++) {
InstructionHeader catchIH = successors[i];
catchIH.dumpSource(writer);
writer.tab();
if (catchIH.nextInstruction == null)
writer.println("/* empty */");
else {
for (InstructionHeader ih = catchIH.nextInstruction;
ih != null; ih = ih.nextInstruction)
ih.dumpSource(writer);
}
writer.untab();
}
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (int i=0; i < successors.length; i++) {
for (InstructionHeader ih = successors[i]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
}
return null;
}
}

@ -0,0 +1,54 @@
package jode;
import java.util.Vector;
public class TryInstructionHeader extends InstructionHeader {
TryInstructionHeader(InstructionHeader firstInstr,
InstructionHeader outer) {
super(TRY, firstInstr.addr, firstInstr.addr,
new InstructionHeader[1], outer);
movePredecessors(firstInstr);
successors[0] = firstInstr;
firstInstr.predecessors = new Vector();
firstInstr.predecessors.addElement(this);
prevInstruction = firstInstr.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
nextInstruction = firstInstr;
firstInstr.prevInstruction = this;
}
public void addHandler(InstructionHeader endInstr,
InstructionHeader catchInstr) {
InstructionHeader[] newSuccessors =
new InstructionHeader[successors.length+2];
System.arraycopy(successors, 0, newSuccessors, 0, successors.length);
successors = newSuccessors;
successors[successors.length-2] = endInstr;
successors[successors.length-1] = catchInstr;
endInstr.predecessors.addElement(this);
catchInstr.predecessors.addElement(this);
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging)
dumpDebugging(writer);
if (successors.length > 1) {
writer.print ("try: ");
for (int i=1; i<successors.length; i+=2)
writer.print("to "+successors[i].getLabel()+
" catch "+successors[i+1].getLabel()+"; ");
writer.println("");
}
}
}

@ -0,0 +1,133 @@
package jode;
import java.util.Enumeration;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H or null, pred = normal, succ = {H,C}
* B: while ( instr ) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: first block-instr
* <p>
* prev = C, next = E, pred = normal succ = normal
* D: ...
* <p>
* prev = D, next = null, pred = normal succ = {B}
* E: last block-instr
* }
* <p>
* prev = B, ..., pred = (normal+{G}) \ {C..F}, succ = normal
* H: ...
* </pre>
*/
public class WhileInstructionHeader extends InstructionHeader {
/**
* Creates a new while statement.
* @param prev the goto instruction in front of this while loop.
* @param ifHeader the instruction header which contains the
* if-goto statement.
* @param blockStart the start of the inner block.
* @param blockEnd the end of the inner block.
* @param next the instruction header after this if block.
*/
public WhileInstructionHeader(InstructionHeader prev,
InstructionHeader ifHeader,
InstructionHeader block) {
super(WHILESTATEMENT,
ifHeader.successors[1].addr, ifHeader.successors[0].addr,
ifHeader.successors, ifHeader.outer);
this.instr = ifHeader.instr;
this.outer = ifHeader.outer;
this.endBlock = this;
this.movePredecessors(ifHeader);
this.addr = successors[1].addr;
prev.flowType = NORMAL;
this.prevInstruction = successors[1].prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
this.nextInstruction = ifHeader.nextInstruction;
if (nextInstruction != null)
nextInstruction.prevInstruction = this;
successors[1].prevInstruction = null;
ifHeader.prevInstruction.nextInstruction = null;
successors[0].predecessors.removeElement(ifHeader);
successors[1].predecessors.removeElement(ifHeader);
successors[0].predecessors.addElement(this);
successors[1].predecessors.addElement(this);
for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction)
if (ih.outer == outer)
ih.outer = this;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
boolean braces = successors[1].nextInstruction != null;
writer.println("while (" + instr.toString() + ")" +
(braces ? " {": ""));
writer.tab();
for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
if (braces)
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
/**
* Returns the InstructionHeader where a break of this instruction
* would jump to. Does only make sense for do/while/for-loops and
* switch instructions.
*/
public InstructionHeader getBreak() {
return successors[0];
}
/**
* Returns the InstructionHeader where a continue of this instruction
* would jump to. Does only make sense for do/while/for-loops.
*/
public InstructionHeader getContinue() {
return this;
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (InstructionHeader ih = successors[1]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
return super.doTransformations(trafo);
}
}

@ -239,9 +239,9 @@ public class ClassRangeType extends MyType {
if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) {
if (t1.getTypeCode() < t2.getTypeCode())
return t2;
else
return t1;
else
return t2;
}
if ((t1.getTypeCode() != 9 && t1.getTypeCode() != 10) ||
(t1.getTypeCode() != 9 && t1.getTypeCode() != 10))
@ -315,10 +315,12 @@ public class ClassRangeType extends MyType {
Type top = getGeneralizedType(topType, type.topType);
Type newType = createRangeType(bottom,top);
if (newType == tError)
if (newType == tError) {
System.err.println("intersecting "+ this +" and "+ type +
" to <" + bottom + "-" + top +
"> to <error>");
Thread.dumpStack();
}
return newType;
}

@ -97,6 +97,12 @@ public class MyType extends Type {
// System.err.println("intersecting "+ t1 +" and "+ t2);
/* Trivial cases first.
*/
if (t1 == tError || t2 == tError) {
System.err.println("intersecting "+ t1 +" and "+ t2 +
" to <error>");
Thread.dumpStack();
return tError;
}
if (t1 == t2 || t2 == tUnknown)
return t1;
if (t1 == tUnknown)
@ -126,6 +132,7 @@ public class MyType extends Type {
if (t1.getTypeCode() != 103 || t2.getTypeCode() != 103) {
System.err.println("intersecting "+ t1 +" and "+ t2 +
" to <error>");
Thread.dumpStack();
return tError;
}

Loading…
Cancel
Save