*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@38 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent d5131c70be
commit d2f597be45
  1. 6
      jode/jode/Decompiler.java
  2. 193
      jode/jode/bytecode/Opcodes.java
  3. 3
      jode/jode/decompiler/CodeAnalyzer.java
  4. 5
      jode/jode/decompiler/LocalVariableTable.java
  5. 43
      jode/jode/expr/Expression.java
  6. 4
      jode/jode/flow/BreakBlock.java
  7. 46
      jode/jode/flow/BreakableBlock.java
  8. 159
      jode/jode/flow/FlowBlock.java
  9. 46
      jode/jode/flow/LoopBlock.java
  10. 16
      jode/jode/flow/SequentialBlock.java
  11. 22
      jode/jode/flow/StructuredBlock.java
  12. 152
      jode/jode/flow/SwitchBlock.java
  13. 22
      jode/jode/type/ClassRangeType.java
  14. 2
      jode/jode/type/MyType.java

@ -24,6 +24,8 @@ import java.lang.reflect.Modifier;
public class Decompiler { public class Decompiler {
public static boolean isVerbose = false; public static boolean isVerbose = false;
public static boolean isDebugging = false; public static boolean isDebugging = false;
public static boolean isTypeDebugging = false;
public static boolean showLVT = false;
public static void main(String[] params) { public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment(); JodeEnvironment env = new JodeEnvironment();
@ -32,6 +34,10 @@ public class Decompiler {
isVerbose = true; isVerbose = true;
else if (params[i].equals("-debug")) else if (params[i].equals("-debug"))
isDebugging = true; isDebugging = true;
else if (params[i].equals("-type"))
isTypeDebugging = true;
else if (params[i].equals("-lvt"))
showLVT = true;
else else
env.doClass(params[i]); env.doClass(params[i]);
} }

@ -48,40 +48,65 @@ public abstract class Opcodes implements RuntimeConstants {
}; };
public static FlowBlock createNormal(int addr, int length, public static FlowBlock createNormal(CodeAnalyzer ca,
int addr, int length,
Instruction instr) Instruction instr)
{ {
return new FlowBlock(addr, length, return new FlowBlock(ca, addr, length,
new InstructionBlock(instr, new InstructionBlock(instr,
new Jump(addr+length))); new Jump(addr+length)));
} }
public static FlowBlock createGoto(int addr, int length, public static FlowBlock createGoto(CodeAnalyzer ca,
int addr, int length,
int destAddr) int destAddr)
{ {
return new FlowBlock(addr, length, new EmptyBlock(new Jump(destAddr))); return new FlowBlock(ca, addr, length,
new EmptyBlock(new Jump(destAddr)));
} }
public static FlowBlock createIfGoto(int addr, int length, public static FlowBlock createJsr(CodeAnalyzer ca,
int addr, int length,
int destAddr)
{
return new FlowBlock(ca, addr, length,
new JsrBlock(new Jump(addr+length),
new Jump(destAddr)));
}
public static FlowBlock createIfGoto(CodeAnalyzer ca,
int addr, int length,
int destAddr, Instruction instr) int destAddr, Instruction instr)
{ {
ConditionalBlock ifBlock = ConditionalBlock ifBlock =
new ConditionalBlock(instr, new ConditionalBlock(instr,
new Jump(destAddr), new Jump(destAddr),
new Jump(addr+length)); new Jump(addr+length));
return new FlowBlock(addr, length, ifBlock); return new FlowBlock(ca, addr, length, ifBlock);
} }
public static FlowBlock createSwitch(int addr, int length, public static FlowBlock createSwitch(CodeAnalyzer ca,
int addr, int length,
int[] cases, int[] dests) int[] cases, int[] dests)
{ {
return new FlowBlock(addr, length, new SwitchBlock(cases, dests)); return new FlowBlock(ca, addr, length,
new SwitchBlock(new NopOperator(MyType.tInt),
cases, dests));
} }
public static FlowBlock createBlock(int addr, int length, public static FlowBlock createBlock(CodeAnalyzer ca,
int addr, int length,
StructuredBlock block) StructuredBlock block)
{ {
return new FlowBlock(addr, length, block); return new FlowBlock(ca, addr, length, block);
}
public static FlowBlock createRet(CodeAnalyzer ca,
int addr, int length,
LocalInfo local)
{
return new FlowBlock(ca, addr, length,
new RetBlock(local));
} }
/** /**
@ -103,43 +128,43 @@ public abstract class Opcodes implements RuntimeConstants {
int opcode = stream.readUnsignedByte(); int opcode = stream.readUnsignedByte();
switch (opcode) { switch (opcode) {
case opc_nop: case opc_nop:
return createNormal(addr, 1, new NopOperator()); return createNormal(ca, addr, 1, new NopOperator());
case opc_aconst_null: case opc_aconst_null:
return createNormal return createNormal
(addr, 1, new ConstOperator(OBJECT_TYPE, "null")); (ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
case opc_iconst_m1: case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return createNormal return createNormal
(addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); (ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
case opc_lconst_0: case opc_lconst_1: case opc_lconst_0: case opc_lconst_1:
return createNormal return createNormal
(addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(LONG_TYPE, (LONG_TYPE,
Integer.toString(opcode - opc_lconst_0) + "L")); Integer.toString(opcode - opc_lconst_0) + "L"));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return createNormal return createNormal
(addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(FLOAT_TYPE, (FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0F")); Integer.toString(opcode - opc_fconst_0) + ".0F"));
case opc_dconst_0: case opc_dconst_1: case opc_dconst_0: case opc_dconst_1:
return createNormal return createNormal
(addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(DOUBLE_TYPE, (DOUBLE_TYPE,
Integer.toString(opcode - opc_dconst_0) + ".0")); Integer.toString(opcode - opc_dconst_0) + ".0"));
case opc_bipush: case opc_bipush:
return createNormal return createNormal
(addr, 2, new ConstOperator (ca, addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte()))); (ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush: case opc_sipush:
return createNormal return createNormal
(addr, 3, new ConstOperator (ca, addr, 3, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readShort()))); (ALL_INT_TYPE, Integer.toString(stream.readShort())));
case opc_ldc: { case opc_ldc: {
int index = stream.readUnsignedByte(); int index = stream.readUnsignedByte();
return createNormal return createNormal
(addr, 2, new ConstOperator (ca, addr, 2, new ConstOperator
(ca.env.getConstantType(index), (ca.env.getConstantType(index),
ca.env.getConstant(index).toString())); ca.env.getConstant(index).toString()));
} }
@ -147,14 +172,14 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_ldc2_w: { case opc_ldc2_w: {
int index = stream.readUnsignedShort(); int index = stream.readUnsignedShort();
return createNormal return createNormal
(addr, 3, new ConstOperator (ca, addr, 3, new ConstOperator
(ca.env.getConstantType(index), (ca.env.getConstantType(index),
ca.env.getConstant(index).toString())); ca.env.getConstant(index).toString()));
} }
case opc_iload: case opc_lload: case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload: case opc_fload: case opc_dload: case opc_aload:
return createNormal return createNormal
(addr, 2, new LocalLoadOperator (ca, addr, 2, new LocalLoadOperator
(types[0][opcode-opc_iload], (types[0][opcode-opc_iload],
ca.getLocalInfo(addr, stream.readUnsignedByte()))); ca.getLocalInfo(addr, stream.readUnsignedByte())));
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3:
@ -163,19 +188,19 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_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: case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3:
return createNormal return createNormal
(addr, 1, new LocalLoadOperator (ca, addr, 1, new LocalLoadOperator
(types[0][(opcode-opc_iload_0)/4], (types[0][(opcode-opc_iload_0)/4],
ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3))); ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3)));
case opc_iaload: case opc_laload: case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload: case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload: case opc_baload: case opc_caload: case opc_saload:
return createNormal return createNormal
(addr, 1, new ArrayLoadOperator (ca, addr, 1, new ArrayLoadOperator
(types[1][opcode - opc_iaload])); (types[1][opcode - opc_iaload]));
case opc_istore: case opc_lstore: case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore: case opc_fstore: case opc_dstore: case opc_astore:
return createNormal return createNormal
(addr, 2, new LocalStoreOperator (ca, addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore], (types[0][opcode-opc_istore],
ca.getLocalInfo(addr, stream.readUnsignedByte()), ca.getLocalInfo(addr, stream.readUnsignedByte()),
Operator.ASSIGN_OP)); Operator.ASSIGN_OP));
@ -190,7 +215,7 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_astore_0: case opc_astore_1: case opc_astore_0: case opc_astore_1:
case opc_astore_2: case opc_astore_3: case opc_astore_2: case opc_astore_3:
return createNormal return createNormal
(addr, 1, new LocalStoreOperator (ca, addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4], (types[0][(opcode-opc_istore_0)/4],
ca.getLocalInfo(addr, (opcode-opc_istore_0) & 3), ca.getLocalInfo(addr, (opcode-opc_istore_0) & 3),
Operator.ASSIGN_OP)); Operator.ASSIGN_OP));
@ -198,43 +223,43 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_fastore: case opc_dastore: case opc_aastore: case opc_fastore: case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore: case opc_bastore: case opc_castore: case opc_sastore:
return createNormal return createNormal
(addr, 1, new ArrayStoreOperator (ca, addr, 1, new ArrayStoreOperator
(types[1][opcode - opc_iastore])); (types[1][opcode - opc_iastore]));
case opc_pop: case opc_pop2: case opc_pop: case opc_pop2:
return createNormal return createNormal
(addr, 1, new PopOperator(opcode - opc_pop + 1)); (ca, addr, 1, new PopOperator(opcode - opc_pop + 1));
case opc_dup: case opc_dup_x1: case opc_dup_x2: case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
return createNormal return createNormal
(addr, 1, new DupOperator (ca, addr, 1, new DupOperator
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1)); ((opcode - opc_dup)%3, (opcode - opc_dup)/3+1));
case opc_swap: case opc_swap:
return createNormal(addr, 1, new SwapOperator()); return createNormal(ca, addr, 1, new SwapOperator());
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: 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_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: 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_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem: case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
return createNormal return createNormal
(addr, 1, new BinaryOperator (ca, addr, 1, new BinaryOperator
(types[0][(opcode - opc_iadd)%4], (types[0][(opcode - opc_iadd)%4],
(opcode - opc_iadd)/4+Operator.ADD_OP)); (opcode - opc_iadd)/4+Operator.ADD_OP));
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
return createNormal return createNormal
(addr, 1, new UnaryOperator (ca, addr, 1, new UnaryOperator
(types[0][opcode - opc_ineg], Operator.NEG_OP)); (types[0][opcode - opc_ineg], Operator.NEG_OP));
case opc_ishl: case opc_lshl: case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr: case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr: case opc_iushr: case opc_lushr:
return createNormal return createNormal
(addr, 1, new ShiftOperator (ca, addr, 1, new ShiftOperator
(types[0][(opcode - opc_ishl)%2], (types[0][(opcode - opc_ishl)%2],
(opcode - opc_ishl)/2 + Operator.SHIFT_OP)); (opcode - opc_ishl)/2 + Operator.SHIFT_OP));
case opc_iand: case opc_land: case opc_iand: case opc_land:
case opc_ior : case opc_lor : case opc_ior : case opc_lor :
case opc_ixor: case opc_lxor: case opc_ixor: case opc_lxor:
return createNormal return createNormal
(addr, 1, new BinaryOperator (ca, addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2], (types[0][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP)); (opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: { case opc_iinc: {
@ -247,7 +272,7 @@ public abstract class Opcodes implements RuntimeConstants {
} }
LocalInfo li = ca.getLocalInfo(addr, local); LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal return createNormal
(addr, 3, new IIncOperator (ca, addr, 3, new IIncOperator
(li, Integer.toString(value), (li, Integer.toString(value),
operation + Operator.OPASSIGN_OP)); operation + Operator.OPASSIGN_OP));
} }
@ -260,48 +285,46 @@ public abstract class Opcodes implements RuntimeConstants {
if (to >= from) if (to >= from)
to++; to++;
return createNormal return createNormal
(addr, 1, new ConvertOperator(types[0][from], (ca, addr, 1, new ConvertOperator(types[0][from],
types[0][to])); types[0][to]));
} }
case opc_i2b: case opc_i2c: case opc_i2s: case opc_i2b: case opc_i2c: case opc_i2s:
return createNormal return createNormal
(addr, 1, new ConvertOperator (ca, addr, 1, new ConvertOperator
(ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5])); (ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5]));
case opc_lcmp: case opc_lcmp:
case opc_fcmpl: case opc_fcmpg: case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg: case opc_dcmpl: case opc_dcmpg:
return createNormal return createNormal
(addr, 1, new CompareToIntOperator (ca, addr, 1, new CompareToIntOperator
(types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2)); (types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2));
case opc_ifeq: case opc_ifne: case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return createIfGoto return createIfGoto
(addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator new CompareUnaryOperator
(ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP)); (ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP));
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt:
case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple:
return createIfGoto return createIfGoto
(addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator new CompareBinaryOperator
(ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP)); (ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP));
case opc_if_acmpeq: case opc_if_acmpne: case opc_if_acmpeq: case opc_if_acmpne:
return createIfGoto return createIfGoto
(addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator new CompareBinaryOperator
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); (OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP));
case opc_goto: case opc_goto:
return createGoto return createGoto
(addr, 3, addr+stream.readShort()); (ca, addr, 3, addr+stream.readShort());
// case opc_jsr: case opc_jsr:
// return createGoto //XXX return createJsr
// (addr, 3, addr+stream.readShort()); (ca, addr, 3, addr+stream.readShort());
// case opc_ret: case opc_ret:
// return createReturn //XXX return createRet
// (addr, 2, (ca, addr, 2,
// new LocalLoadOperator ca.getLocalInfo(addr, stream.readUnsignedByte()));
// (OBJECT_TYPE,
// ca.getLocalInfo(addr, stream.readUnsignedByte())));
case opc_tableswitch: { case opc_tableswitch: {
int length = 3-(addr % 4); int length = 3-(addr % 4);
stream.skip(length); stream.skip(length);
@ -317,7 +340,7 @@ public abstract class Opcodes implements RuntimeConstants {
dests[cases.length] = def; dests[cases.length] = def;
length += 13 + 4 * cases.length; length += 13 + 4 * cases.length;
return createSwitch return createSwitch
(addr, length, cases, dests); (ca, addr, length, cases, dests);
} }
case opc_lookupswitch: { case opc_lookupswitch: {
int length = 3-(addr % 4); int length = 3-(addr % 4);
@ -333,7 +356,7 @@ public abstract class Opcodes implements RuntimeConstants {
dests[npairs] = def; dests[npairs] = def;
length += 9 + 8 * npairs; length += 9 + 8 * npairs;
return createSwitch return createSwitch
(addr, length, cases, dests); (ca, addr, length, cases, dests);
} }
case opc_ireturn: case opc_lreturn: case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: { case opc_freturn: case opc_dreturn: case opc_areturn: {
@ -341,23 +364,23 @@ public abstract class Opcodes implements RuntimeConstants {
(ca.getMethod().mdef.getType().getReturnType(), (ca.getMethod().mdef.getType().getReturnType(),
types[0][opcode-opc_ireturn]); types[0][opcode-opc_ireturn]);
return createBlock return createBlock
(addr, 1, new ReturnBlock(new NopOperator(retType))); (ca, addr, 1, new ReturnBlock(new NopOperator(retType)));
} }
case opc_return: case opc_return:
/* Address -1 is interpreted as end of method */ /* Address -1 is interpreted as end of method */
return createBlock return createBlock
(addr, 1, new EmptyBlock(new Jump(-1))); (ca, addr, 1, new EmptyBlock(new Jump(-1)));
case opc_getstatic: case opc_getstatic:
case opc_getfield: case opc_getfield:
return createNormal return createNormal
(addr, 3, new GetFieldOperator (ca, addr, 3, new GetFieldOperator
(ca, opcode == opc_getstatic, (ca, opcode == opc_getstatic,
(FieldDefinition)ca.env.getConstant (FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
case opc_putstatic: case opc_putstatic:
case opc_putfield: case opc_putfield:
return createNormal return createNormal
(addr, 3, new PutFieldOperator (ca, addr, 3, new PutFieldOperator
(ca, opcode == opc_putstatic, (ca, opcode == opc_putstatic,
(FieldDefinition)ca.env.getConstant (FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
@ -365,14 +388,14 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_invokespecial: case opc_invokespecial:
case opc_invokestatic : case opc_invokestatic :
return createNormal return createNormal
(addr, 3, new InvokeOperator (ca, addr, 3, new InvokeOperator
(ca, (ca,
opcode == opc_invokestatic, opcode == opc_invokespecial, opcode == opc_invokestatic, opcode == opc_invokespecial,
(FieldDefinition)ca.env.getConstant (FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
case opc_invokeinterface: { case opc_invokeinterface: {
FlowBlock fb = createNormal FlowBlock fb = createNormal
(addr, 5, new InvokeOperator (ca, addr, 5, new InvokeOperator
(ca, false, false, (ca, false, false,
(FieldDefinition)ca.env.getConstant (FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
@ -384,7 +407,7 @@ public abstract class Opcodes implements RuntimeConstants {
ca.env.getConstant(stream.readUnsignedShort()); ca.env.getConstant(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName()); Type type = MyType.tClassOrArray(cldec.getName());
return createNormal return createNormal
(addr, 3, new NewOperator(type, ca.env.getTypeString(type))); (ca, addr, 3, new NewOperator(type, ca.env.getTypeString(type)));
} }
case opc_newarray: { case opc_newarray: {
Type type; Type type;
@ -401,7 +424,7 @@ public abstract class Opcodes implements RuntimeConstants {
throw new ClassFormatError("Invalid newarray operand"); throw new ClassFormatError("Invalid newarray operand");
} }
return createNormal return createNormal
(addr, 2, (ca, addr, 2,
new NewArrayOperator(MyType.tArray(type), new NewArrayOperator(MyType.tArray(type),
type.toString(), 1)); type.toString(), 1));
} }
@ -411,22 +434,22 @@ public abstract class Opcodes implements RuntimeConstants {
Identifier ident = cldec.getName(); Identifier ident = cldec.getName();
Type type = MyType.tClassOrArray(cldec.getName()); Type type = MyType.tClassOrArray(cldec.getName());
return createNormal return createNormal
(addr, 3, new NewArrayOperator (ca, addr, 3, new NewArrayOperator
(MyType.tArray(type), ca.env.getTypeString(type),1)); (MyType.tArray(type), ca.env.getTypeString(type),1));
} }
case opc_arraylength: case opc_arraylength:
return createNormal return createNormal
(addr, 1, new ArrayLengthOperator()); (ca, addr, 1, new ArrayLengthOperator());
case opc_athrow: case opc_athrow:
return createBlock return createBlock
(addr, 1, (ca, addr, 1,
new ThrowBlock(new NopOperator(MyType.tUObject))); new ThrowBlock(new NopOperator(MyType.tUObject)));
case opc_checkcast: { case opc_checkcast: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
(stream.readUnsignedShort()); (stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName()); Type type = MyType.tClassOrArray(cldec.getName());
return createNormal return createNormal
(addr, 3, new CheckCastOperator (ca, addr, 3, new CheckCastOperator
(type, ca.env.getTypeString(type))); (type, ca.env.getTypeString(type)));
} }
case opc_instanceof: { case opc_instanceof: {
@ -434,28 +457,28 @@ public abstract class Opcodes implements RuntimeConstants {
(stream.readUnsignedShort()); (stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName()); Type type = MyType.tClassOrArray(cldec.getName());
return createNormal return createNormal
(addr, 3, (ca, addr, 3,
new InstanceOfOperator(type, ca.env.getTypeString(type))); new InstanceOfOperator(type, ca.env.getTypeString(type)));
} }
case opc_monitorenter: case opc_monitorenter:
return createNormal(addr, 1, return createNormal(ca, addr, 1,
new MonitorEnterOperator()); new MonitorEnterOperator());
case opc_monitorexit: case opc_monitorexit:
return createNormal(addr, 1, return createNormal(ca, addr, 1,
new MonitorExitOperator()); new MonitorExitOperator());
case opc_wide: { case opc_wide: {
switch (opcode=stream.readUnsignedByte()) { switch (opcode=stream.readUnsignedByte()) {
case opc_iload: case opc_lload: case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload: case opc_fload: case opc_dload: case opc_aload:
return createNormal return createNormal
(addr, 4, (ca, addr, 4,
new LocalLoadOperator(types[0][opcode-opc_iload], new LocalLoadOperator
new LocalInfo (types[0][opcode-opc_iload],
(stream.readUnsignedShort()))); ca.getLocalInfo(addr, stream.readUnsignedShort())));
case opc_istore: case opc_lstore: case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore: case opc_fstore: case opc_dstore: case opc_astore:
return createNormal return createNormal
(addr, 4, (ca, addr, 4,
new LocalStoreOperator new LocalStoreOperator
(types[0][opcode-opc_istore], (types[0][opcode-opc_istore],
ca.getLocalInfo(addr, stream.readUnsignedShort()), ca.getLocalInfo(addr, stream.readUnsignedShort()),
@ -470,16 +493,14 @@ public abstract class Opcodes implements RuntimeConstants {
} }
LocalInfo li = ca.getLocalInfo(addr, local); LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal return createNormal
(addr, 6, new IIncOperator (ca, addr, 6, new IIncOperator
(li, Integer.toString(value), (li, Integer.toString(value),
operation + Operator.OPASSIGN_OP)); operation + Operator.OPASSIGN_OP));
} }
// case opc_ret: case opc_ret:
// return new RetInstructionHeader return createRet
// (addr, 4, (ca, addr, 4,
// new LocalLoadOperator ca.getLocalInfo(addr, stream.readUnsignedShort()));
// (INT_TYPE,
// ca.getLocalInfo(addr, stream.readUnsignedShort())));
default: default:
throw new ClassFormatError("Invalid wide opcode "+opcode); throw new ClassFormatError("Invalid wide opcode "+opcode);
} }
@ -493,23 +514,23 @@ public abstract class Opcodes implements RuntimeConstants {
for (int i=0; i<dimension; i++) for (int i=0; i<dimension; i++)
baseType = baseType.getElementType(); baseType = baseType.getElementType();
return createNormal return createNormal
(addr, 4, (ca, addr, 4,
new NewArrayOperator new NewArrayOperator
(type, ca.env.getTypeString(baseType), dimension)); (type, ca.env.getTypeString(baseType), dimension));
} }
case opc_ifnull: case opc_ifnonnull: case opc_ifnull: case opc_ifnonnull:
return createIfGoto return createIfGoto
(addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator new CompareUnaryOperator
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP)); (OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP));
case opc_goto_w: case opc_goto_w:
return createGoto return createGoto
(addr, 5, addr + stream.readInt()); (ca, addr, 5, addr + stream.readInt());
// case opc_jsr_w: case opc_jsr_w:
// return createGoto return createJsr
// (addr, 5, addr+stream.readInt()); // XXX (ca, addr, 5, addr+stream.readInt());
default: default:
throw new ClassFormatError("Invalid opcode "+opcode); throw new ClassFormatError("Invalid opcode "+opcode);
} }
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
ex.printStackTrace(); ex.printStackTrace();

@ -139,14 +139,13 @@ public class CodeAnalyzer implements Analyzer, Constants {
static jode.flow.Transformation[] exprTrafos = { static jode.flow.Transformation[] exprTrafos = {
new jode.flow.RemoveEmpty(), new jode.flow.RemoveEmpty(),
// new CombineCatchLocal(),
new jode.flow.CreateExpression(), new jode.flow.CreateExpression(),
new jode.flow.CreatePostIncExpression(), new jode.flow.CreatePostIncExpression(),
new jode.flow.CreateAssignExpression(), new jode.flow.CreateAssignExpression(),
new jode.flow.CreateNewConstructor(), new jode.flow.CreateNewConstructor(),
new jode.flow.CombineIfGotoExpressions(), new jode.flow.CombineIfGotoExpressions(),
new jode.flow.CreateIfThenElseOperator(), new jode.flow.CreateIfThenElseOperator(),
// new CreateConstantArray(), new jode.flow.CreateConstantArray(),
new jode.flow.SimplifyExpression() new jode.flow.SimplifyExpression()
}; };

@ -58,6 +58,11 @@ public class LocalVariableTable {
env.getConstantPool(). env.getConstantPool().
getValue(name_i)), getValue(name_i)),
env.getConstantPool().getType(desc_i)); env.getConstantPool().getType(desc_i));
if (Decompiler.showLVT)
System.err.println(""+env.getConstantPool().getValue(name_i)
+": "+env.getConstantPool().getType(desc_i)
+" range "+start+" - "+(start+length)
+" slot "+slot);
} }
readfromclass = true; readfromclass = true;
} }

@ -73,31 +73,26 @@ public class Expression extends Instruction {
public Expression tryToCombine(Expression e) { public Expression tryToCombine(Expression e) {
if (e.operator instanceof StoreInstruction) { if (e.operator instanceof StoreInstruction) {
StoreInstruction store = (StoreInstruction) e.operator; StoreInstruction store = (StoreInstruction) e.operator;
Expression search = this; if (store.matches(operator)) {
while (true) { int i;
if (store.matches(search.operator)) { for (i=0; i < e.subExpressions.length-1; i++) {
int i; if (!e.subExpressions[i].equals
for (i=0; i < e.subExpressions.length-1; i++) { (subExpressions[i]))
if (!e.subExpressions[i].equals break;
(search.subExpressions[i])) }
break; if (i == e.subExpressions.length-1) {
} operator =
if (i == e.subExpressions.length-1) { new AssignOperator(store.getOperator(), store);
search.operator = subExpressions = e.subExpressions;
new AssignOperator(store.getOperator(), store); return this;
search.subExpressions = e.subExpressions; }
return this; }
} for (int i=0; i < subExpressions.length; i++) {
Expression combined = subExpressions[i].tryToCombine(e);
if (combined != null) {
subExpressions[i] = combined;
return this;
} }
if (search.subExpressions.length == 0)
break;
if (search.getOperator() instanceof AssignOperator)
search = search.subExpressions[subExpressions.length-1];
else if (search.getOperator() instanceof StringAddOperator &&
search.subExpressions[1] == emptyString)
search = search.subExpressions[1];
else
search = search.subExpressions[0];
} }
} }
return null; return null;

@ -26,8 +26,8 @@ public class BreakBlock extends StructuredBlock {
String label; String label;
public BreakBlock(BreakableBlock breaksBlock, boolean needsLabel) { public BreakBlock(BreakableBlock breaksBlock, boolean needsLabel) {
this.breaksBlock = breaksBlock; this.breaksBlock = (StructuredBlock) breaksBlock;
breaksBlock.mayChangeJump = false; breaksBlock.setBreaked();
if (needsLabel) if (needsLabel)
label = breaksBlock.getLabel(); label = breaksBlock.getLabel();
else else

@ -21,54 +21,16 @@ import jode.TabbedPrintWriter;
/** /**
* This is a structured block, that supports break. * This is a structured block, that supports break.
*/ */
public abstract class BreakableBlock extends StructuredBlock { public interface BreakableBlock {
boolean mayChangeJump = true;
/**
* Print the source code for this structured block. This handles
* everything that is unique for all structured blocks and calls
* dumpInstruction afterwards.
* @param writer The tabbed print writer, where we print to.
*/
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (label != null) {
writer.untab();
writer.println(label+":");
writer.tab();
}
super.dumpSource(writer);
}
/**
* The serial number for labels.
*/
static int serialno = 0;
/**
* The label of this instruction, or null if it needs no label.
*/
String label = null;
/** /**
* Returns the label of this block and creates a new label, if * Returns the label of this block and creates a new label, if
* there wasn't a label previously. * there wasn't a label previously.
*/ */
public String getLabel() { public String getLabel();
if (label == null)
label = "label_"+(serialno++)+"_";
return label;
}
/** /**
* Determines if there is a sub block, that flows through to the end * Is called by BreakBlock, to tell us that this block is breaked.
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/ */
public boolean jumpMayBeChanged() { public void setBreaked();
return mayChangeJump;
}
} }

@ -21,6 +21,7 @@ package jode.flow;
import java.util.*; import java.util.*;
import jode.TabbedPrintWriter; import jode.TabbedPrintWriter;
import jode.Expression; import jode.Expression;
import jode.CodeAnalyzer;
/** /**
* A flow block is the structure of which the flow graph consists. A * A flow block is the structure of which the flow graph consists. A
@ -34,12 +35,18 @@ import jode.Expression;
public class FlowBlock { public class FlowBlock {
static FlowBlock END_OF_METHOD = static FlowBlock END_OF_METHOD =
new FlowBlock(Integer.MAX_VALUE, 0, new EmptyBlock()); new FlowBlock(null, Integer.MAX_VALUE, 0, new EmptyBlock());
static { static {
END_OF_METHOD.label = "END_OF_METHOD"; END_OF_METHOD.label = "END_OF_METHOD";
} }
/**
* The code analyzer. This is used to pretty printing the
* Types and to get information about all locals in this code.
*/
CodeAnalyzer code;
/** /**
* The in locals. This are the locals, which are used in this * The in locals. This are the locals, which are used in this
* flow block and whose values may be the result of a assignment * flow block and whose values may be the result of a assignment
@ -89,7 +96,9 @@ public class FlowBlock {
* The default constructor. Creates a new flowblock containing * The default constructor. Creates a new flowblock containing
* only the given structured block. * only the given structured block.
*/ */
public FlowBlock(int addr, int length, StructuredBlock block) { public FlowBlock(CodeAnalyzer code, int addr, int length,
StructuredBlock block) {
this.code = code;
this.addr = addr; this.addr = addr;
this.length = length; this.length = length;
this.block = block; this.block = block;
@ -657,15 +666,32 @@ public class FlowBlock {
*/ */
StructuredBlock precedingcase = null; StructuredBlock precedingcase = null;
StructuredBlock nextcase = null; StructuredBlock nextcase = null;
/*XXX*/ if (appendBlock instanceof SwitchBlock) {
nextcase = ((SwitchBlock) appendBlock).findCase(succ);
precedingcase =
((SwitchBlock) appendBlock).prevCase(precedingcase);
enum = successors.elements();
while (nextcase != null && enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null
|| jump.destination != succ
|| jump.prev == nextcase
|| (precedingcase != null
&& precedingcase.contains(jump.prev)))
continue;
nextcase = null;
}
}
if (succ == END_OF_METHOD) { if (succ == END_OF_METHOD) {
} else if (nextcase != null) { } else if (nextcase != null) {
SwitchBlock switchBlock = (SwitchBlock) appendBlock; SwitchBlock switchBlock = (SwitchBlock) appendBlock;
/* Now put the succ.block into the next case. /* Now put the succ.block into the next case.
*/ */
switchBlock.replaceSubBlock(nextcase,succ.block); nextcase.removeJump();
succ.block.outer = switchBlock; succ.block.replace(nextcase, succ.block);
/* nextcase is not referenced any more */ /* nextcase is not referenced any more */
/* Do the following modifications on the struct block. */ /* Do the following modifications on the struct block. */
@ -750,56 +776,63 @@ public class FlowBlock {
} }
} }
/* Now remove the jump of the appendBlock if it points to successor. /* appendBlock may be zero, if this is the switchcase with
*/ * precedingcase = null. But in this case, there can't be
if (appendBlock.jump != null && * any jumps.
appendBlock.jump.destination == succ) */
appendBlock.removeJump(); if (appendBlock != null) {
/* Now remove the jump of the appendBlock if it points to
/* If there are further jumps, put a do/while(0) block around * successor.
* appendBlock and replace every remaining jump with a break */
* to the do/while block. if (appendBlock.jump != null
*/ && appendBlock.jump.destination == succ)
LoopBlock doWhileFalse = null; appendBlock.removeJump();
enum = successors.elements();
while (enum.hasMoreElements()) { /* If there are further jumps, put a do/while(0) block around
Jump jump = (Jump) enum.nextElement(); * appendBlock and replace every remaining jump with a break
* to the do/while block.
if (jump == null || jump.destination != succ) */
continue; LoopBlock doWhileFalse = null;
enum = successors.elements();
if (doWhileFalse == null) while (enum.hasMoreElements()) {
doWhileFalse = new LoopBlock(LoopBlock.DOWHILE, Jump jump = (Jump) enum.nextElement();
LoopBlock.FALSE);
if (jump == null || jump.destination != succ)
int breaklevel = 1; continue;
for (StructuredBlock surrounder = jump.prev.outer;
surrounder != appendBlock.outer; if (doWhileFalse == null)
surrounder = surrounder.outer) { doWhileFalse = new LoopBlock(LoopBlock.DOWHILE,
if (surrounder instanceof BreakableBlock) { LoopBlock.FALSE);
breaklevel++;
} int breaklevel = 1;
} for (StructuredBlock surrounder = jump.prev.outer;
surrounder != appendBlock.outer;
SequentialBlock sequBlock = new SequentialBlock(); surrounder = surrounder.outer) {
StructuredBlock prevBlock = jump.prev; if (surrounder instanceof BreakableBlock) {
prevBlock.removeJump(); breaklevel++;
}
sequBlock.replace(prevBlock, prevBlock); }
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1)); SequentialBlock sequBlock = new SequentialBlock();
} StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
if (doWhileFalse != null) {
doWhileFalse.replace(appendBlock, appendBlock); sequBlock.replace(prevBlock, prevBlock);
doWhileFalse.setBody(appendBlock); sequBlock.setFirst(prevBlock);
} sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1));
}
/* Believe it or not: Now the rule, that the first part of a
* SequentialBlock shouldn't be another SequentialBlock is if (doWhileFalse != null) {
* fulfilled. <p> doWhileFalse.replace(appendBlock, appendBlock);
* doWhileFalse.setBody(appendBlock);
* This isn't easy to prove, it has a lot to do with the }
}
/* Believe it or not: Now the rule, that the first part of a
* SequentialBlock shouldn't be another SequentialBlock is
* fulfilled. <p>
*
* This isn't easy to prove, it has a lot to do with the
* transformation in optimizeJump and the fact that * transformation in optimizeJump and the fact that
* appendBlock was the innermost Block containing all jumps * appendBlock was the innermost Block containing all jumps
* and lastModified. * and lastModified.
@ -868,6 +901,21 @@ public class FlowBlock {
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
VariableSet defineHere = updateInOut(this, false); VariableSet defineHere = updateInOut(this, false);
while (lastModified != block) {
lastModified = lastModified.outer;
if (lastModified instanceof SequentialBlock
&& lastModified.getSubBlocks()[0]
instanceof RawTryCatchBlock) {
/* We leave the catch block of a raw-try-catch-block.
* We shall now create the Catch- resp. FinallyBlock.
*/
lastModified =
createCatchBlock((SequentialBlock)lastModified);
}
}
/* If there is only one jump to the beginning and it is the /* If there is only one jump to the beginning and it is the
* last jump and (there is a do/while(0) block surrounding * last jump and (there is a do/while(0) block surrounding
* everything but the last instruction, or the last * everything but the last instruction, or the last
@ -1000,6 +1048,7 @@ public class FlowBlock {
public void makeDeclaration(VariableSet param) { public void makeDeclaration(VariableSet param) {
in.merge(param); in.merge(param);
in.subtract(param); in.subtract(param);
block.propagateUsage();
block.makeDeclaration(param); block.makeDeclaration(param);
} }

@ -23,7 +23,7 @@ import jode.*;
/** /**
* This is the structured block for an Loop block. * This is the structured block for an Loop block.
*/ */
public class LoopBlock extends BreakableBlock { public class LoopBlock extends StructuredBlock implements BreakableBlock {
public static final int WHILE = 0; public static final int WHILE = 0;
public static final int DOWHILE = 1; public static final int DOWHILE = 1;
@ -130,6 +130,11 @@ public class LoopBlock extends BreakableBlock {
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
if (label != null) {
writer.untab();
writer.println(label+":");
writer.tab();
}
boolean needBrace = ! (bodyBlock instanceof InstructionBlock); boolean needBrace = ! (bodyBlock instanceof InstructionBlock);
switch (type) { switch (type) {
case WHILE: case WHILE:
@ -153,4 +158,43 @@ public class LoopBlock extends BreakableBlock {
else if (needBrace) else if (needBrace)
writer.println("}"); writer.println("}");
} }
boolean mayChangeJump = true;
/**
* The serial number for labels.
*/
static int serialno = 0;
/**
* The label of this instruction, or null if it needs no label.
*/
String label = null;
/**
* Returns the label of this block and creates a new label, if
* there wasn't a label previously.
*/
public String getLabel() {
if (label == null)
label = "while_"+(serialno++)+"_";
return label;
}
/**
* Is called by BreakBlock, to tell us that this block is breaked.
*/
public void setBreaked() {
mayChangeJump = false;
}
/**
* Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/
public boolean jumpMayBeChanged() {
return mayChangeJump;
}
} }

@ -63,6 +63,22 @@ public class SequentialBlock extends StructuredBlock {
return getNextFlowBlock(); return getNextFlowBlock();
} }
/**
* Make the declarations, i.e. initialize the declare variable
* to correct values. This will declare every variable that
* is marked as used, but not done.
* @param done The set of the already declare variables.
*/
public void makeDeclaration(VariableSet done) {
/* A sequential block is special, since it doesn't declare
* any local Variable, but let the first sub block do this.
*/
declare = new VariableSet();
subBlocks[0].makeDeclaration(done);
done.addExact(used);
subBlocks[1].makeDeclaration(done);
}
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {

@ -70,7 +70,7 @@ public abstract class StructuredBlock {
* The variable set containing all variables we must declare. * The variable set containing all variables we must declare.
* The analyzation is done in makeDeclaration * The analyzation is done in makeDeclaration
*/ */
VariableSet declare = new VariableSet(); VariableSet declare;
/** /**
* The surrounding structured block. If this is the outermost * The surrounding structured block. If this is the outermost
@ -285,15 +285,10 @@ public abstract class StructuredBlock {
} }
if (subs.length == 2) { if (subs.length == 2) {
/* All variables used in both sub blocks, are used in /* All variables used in both sub blocks, are used in
* this block, too. But a sequential block is a notable * this block, too.
* exception, since it is enough if the first sub block */
* declares the Variable
*/
VariableSet newUse = childUse[0].intersectExact(childUse[1]); VariableSet newUse = childUse[0].intersectExact(childUse[1]);
if (this instanceof SequentialBlock) used.addExact(newUse);
subs[0].used.addExact(newUse);
else
used.addExact(newUse);
} }
return allUse; return allUse;
} }
@ -305,8 +300,13 @@ public abstract class StructuredBlock {
* @param done The set of the already declare variables. * @param done The set of the already declare variables.
*/ */
public void makeDeclaration(VariableSet done) { public void makeDeclaration(VariableSet done) {
propagateUsage(); declare = new VariableSet();
declare.addExact(used); java.util.Enumeration enum = used.elements();
while (enum.hasMoreElements()) {
LocalInfo local = ((LocalInfo) enum.nextElement()).getLocalInfo();
if (!declare.contains(local))
declare.addElement(local);
}
declare.subtractExact(done); declare.subtractExact(done);
done.addExact(declare); done.addExact(declare);

@ -23,27 +23,82 @@ import jode.TabbedPrintWriter;
/** /**
* This is the structured block for an empty block. * This is the structured block for an empty block.
*/ */
public class SwitchBlock extends BreakableBlock { public class SwitchBlock extends InstructionContainer
int[] cases; implements BreakableBlock {
StructuredBlock[] caseBlocks; CaseBlock[] caseBlocks;
public SwitchBlock(int[] cases, int[] dests) { public SwitchBlock(jode.Instruction instr,
this.cases = cases; int[] cases, int[] dests) {
this.caseBlocks = new StructuredBlock[dests.length]; super(instr);
for (int i=0; i<dests.length; i++) { this.caseBlocks = new CaseBlock[dests.length];
/* XXX sort the destinations, multi-cases? */ int lastDest = -1;
caseBlocks[i] = new EmptyBlock(new Jump(dests[i])); boolean lastBlock = true;
for (int i=dests.length-1; i>=0; i--) {
/**
* Sort the destinations by finding the greatest destAddr
*/
int index = 0;
for (int j=1; j<dests.length; j++) {
if (dests[j] >= dests[index])
index = j;
}
int value;
if (index == cases.length)
value = -1;
else
value = cases[index];
if (dests[index] == lastDest)
this.caseBlocks[i] = new CaseBlock(value);
else
this.caseBlocks[i] = new CaseBlock(value,
new Jump(dests[index]));
this.caseBlocks[i].outer = this;
this.caseBlocks[i].isLastBlock = lastBlock;
lastBlock = false;
lastDest = dests[index];
dests[index] = -1;
if (index == cases.length)
this.caseBlocks[i].isDefault = true;
} }
this.jump = null; this.jump = null;
mayChangeJump = true; mayChangeJump = true;
} }
public void dumpInstruction(TabbedPrintWriter writer) /**
throws java.io.IOException * Find the case that jumps directly to destination.
{ * @return The sub block of the case block, which jumps to destination.
writer.println("switch (/* XXX implement */)"); */
public StructuredBlock findCase(FlowBlock destination) {
for (int i=0; i < caseBlocks.length; i++) {
if (caseBlocks[i].subBlock != null
&& caseBlocks[i].subBlock instanceof EmptyBlock
&& caseBlocks[i].subBlock.jump != null
&& caseBlocks[i].subBlock.jump.destination == destination)
return caseBlocks[i].subBlock;
}
return null;
} }
/**
* Find the case that precedes the given case.
* @param block The sub block of the case, whose predecessor should
* be returned.
* @return The sub block of the case precedes the given case.
*/
public StructuredBlock prevCase(StructuredBlock block) {
for (int i=caseBlocks.length-1; i>=0; i--) {
if (caseBlocks[i].subBlock == block) {
for (i--; i>=0; i--) {
if (caseBlocks[i].subBlock != null)
return caseBlocks[i].subBlock;
}
}
}
return null;
}
/** /**
* Returns the block where the control will normally flow to, when * Returns the block where the control will normally flow to, when
@ -53,20 +108,83 @@ public class SwitchBlock extends BreakableBlock {
* the behaviour is undefined, so take care. * the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */ * @return null, if the control flows to another FlowBlock. */
public StructuredBlock getNextBlock(StructuredBlock subBlock) { public StructuredBlock getNextBlock(StructuredBlock subBlock) {
/*XXX*/ for (int i=0; i< caseBlocks.length-1; i++) {
if (subBlock == caseBlocks[i]) {
return caseBlocks[i+1];
}
}
return getNextBlock(); return getNextBlock();
} }
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
/*XXX*/ for (int i=0; i< caseBlocks.length-1; i++) {
if (subBlock == caseBlocks[i]) {
return null;
}
}
return getNextFlowBlock(); return getNextFlowBlock();
} }
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("switch ("+instr+") {");
for (int i=0; i < caseBlocks.length; i++)
caseBlocks[i].dumpSource(writer);
writer.println("}");
}
public void setInstruction(jode.Instruction instr) {
super.setInstruction(instr);
sun.tools.java.Type type = instr.getType();
if (type != caseBlocks[0].type) {
for (int i=0; i < caseBlocks.length; i++)
caseBlocks[i].type = type;
}
}
/** /**
* Returns all sub block of this structured block. * Returns all sub block of this structured block.
*/ */
public StructuredBlock[] getSubBlocks() { public StructuredBlock[] getSubBlocks() {
return caseBlocks; return caseBlocks;
} }
}
boolean mayChangeJump = true;
/**
* The serial number for labels.
*/
static int serialno = 0;
/**
* The label of this instruction, or null if it needs no label.
*/
String label = null;
/**
* Returns the label of this block and creates a new label, if
* there wasn't a label previously.
*/
public String getLabel() {
if (label == null)
label = "switch_"+(serialno++)+"_";
return label;
}
/**
* Is called by BreakBlock, to tell us that this block is breaked.
*/
public void setBreaked() {
mayChangeJump = false;
}
/**
* Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/
public boolean jumpMayBeChanged() {
return mayChangeJump;
}
}

@ -238,6 +238,8 @@ public class ClassRangeType extends MyType {
/** /**
* Returns the generalized type of t1 and t2, e.g * Returns the generalized type of t1 and t2, e.g
* tObject, tString -> tObject * tObject, tString -> tObject
* object , interface -> object
* since a sub class of object may implement interface
* int , short -> int * int , short -> int
* tArray(tObject), tArray(tUnknown) -> tArray(tUnknown) * tArray(tObject), tArray(tUnknown) -> tArray(tUnknown)
* tArray(tUnknown), tObject -> tObject * tArray(tUnknown), tObject -> tObject
@ -308,14 +310,14 @@ public class ClassRangeType extends MyType {
ClassDeclaration c2 = new ClassDeclaration(t2.getClassName()); ClassDeclaration c2 = new ClassDeclaration(t2.getClassName());
try { try {
/* if one of the two types is an interface which /* if one of the two types is an interface, return
* is implemented by the other type the interface * the other type, since at least a subtype of the
* is the result. * other type may implement the interface.
*/ */
if (c1.getClassDefinition(env).implementedBy(env, c2)) if (c1.getClassDefinition(env).isInterface())
return t1;
if (c2.getClassDefinition(env).implementedBy(env, c1))
return t2; return t2;
if (c2.getClassDefinition(env).isInterface())
return t1;
ClassDefinition c = c1.getClassDefinition(env); ClassDefinition c = c1.getClassDefinition(env);
while(c != null && !c.superClassOf(env, c2)) { while(c != null && !c.superClassOf(env, c2)) {
@ -339,7 +341,11 @@ public class ClassRangeType extends MyType {
" to <" + bottom + "-" + top + " to <" + bottom + "-" + top +
"> to <error>"); "> to <error>");
Thread.dumpStack(); Thread.dumpStack();
} } else if (Decompiler.isTypeDebugging) {
System.err.println("intersecting "+ this +" and "+ type +
" to <" + bottom + "-" + top +
"> to " + newType);
}
return newType; return newType;
} }
@ -350,7 +356,7 @@ public class ClassRangeType extends MyType {
public String typeString(String string, boolean flag1, boolean flag2) public String typeString(String string, boolean flag1, boolean flag2)
{ {
if (Decompiler.isDebugging) if (Decompiler.isTypeDebugging)
return "<"+bottomType+"-"+topType+">" + string; return "<"+bottomType+"-"+topType+">" + string;
else if (bottomType != null) else if (bottomType != null)
return bottomType.typeString(string, flag1, flag2); return bottomType.typeString(string, flag1, flag2);

@ -63,7 +63,7 @@ public class MyType extends Type {
return new ClassRangeType(tObject, type); return new ClassRangeType(tObject, type);
else if (typeCode == 103) else if (typeCode == 103)
return (((ClassRangeType)type).topType == null return (((ClassRangeType)type).topType == null
? tUnknown : new ClassRangeType(tObject, null)); ? tUnknown : new ClassRangeType(tObject, type));
else else
return type; return type;
} }

Loading…
Cancel
Save