*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@107 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent a421adad08
commit ba05fcd077
  1. 611
      jode/jode/bytecode/Opcodes.java
  2. 131
      jode/jode/decompiler/CodeAnalyzer.java
  3. 14
      jode/jode/expr/ComplexExpression.java
  4. 48
      jode/jode/expr/ConstantArrayOperator.java
  5. 5
      jode/jode/expr/ConstructorOperator.java
  6. 3
      jode/jode/expr/Expression.java
  7. 20
      jode/jode/flow/CombineIfGotoExpressions.java
  8. 20
      jode/jode/flow/CompleteSynchronized.java
  9. 7
      jode/jode/flow/ConditionalBlock.java
  10. 61
      jode/jode/flow/CreateAssignExpression.java
  11. 154
      jode/jode/flow/CreateConstantArray.java
  12. 70
      jode/jode/flow/CreateExpression.java
  13. 20
      jode/jode/flow/CreateForInitializer.java
  14. 238
      jode/jode/flow/CreateIfThenElseOperator.java
  15. 51
      jode/jode/flow/CreateNewConstructor.java
  16. 177
      jode/jode/flow/CreatePrePostIncExpression.java
  17. 270
      jode/jode/flow/FlowBlock.java
  18. 10
      jode/jode/flow/InstructionContainer.java
  19. 6
      jode/jode/flow/LoopBlock.java
  20. 69
      jode/jode/flow/RemoveEmpty.java
  21. 5
      jode/jode/flow/SpecialBlock.java
  22. 42
      jode/jode/flow/StructuredBlock.java
  23. 4
      jode/jode/flow/SynchronizedBlock.java
  24. 2
      jode/jode/type/ClassInterfacesType.java

@ -29,21 +29,21 @@ import gnu.bytecode.CpoolClass;
*/
public abstract class Opcodes {
public final static Type ALL_INT_TYPE = Type.tUInt;
public final static Type BOOL_INT_TYPE = Type.tBoolInt;
public final static Type INT_TYPE = Type.tInt;
public final static Type LONG_TYPE = Type.tLong;
public final static Type FLOAT_TYPE = Type.tFloat;
public final static Type DOUBLE_TYPE = Type.tDouble;
public final static Type OBJECT_TYPE = Type.tUObject;
public final static Type BOOLEAN_TYPE = Type.tBoolean;
public final static Type BYTEBOOL_TYPE = Type.tBoolByte;
public final static Type BYTE_TYPE = Type.tByte;
public final static Type CHAR_TYPE = Type.tChar;
public final static Type SHORT_TYPE = Type.tShort;
public final static Type VOID_TYPE = Type.tVoid;
private final static Type ALL_INT_TYPE = Type.tUInt;
private final static Type BOOL_INT_TYPE = Type.tBoolInt;
private final static Type INT_TYPE = Type.tInt;
private final static Type LONG_TYPE = Type.tLong;
private final static Type FLOAT_TYPE = Type.tFloat;
private final static Type DOUBLE_TYPE = Type.tDouble;
private final static Type OBJECT_TYPE = Type.tUObject;
private final static Type BOOLEAN_TYPE = Type.tBoolean;
private final static Type BYTEBOOL_TYPE = Type.tBoolByte;
private final static Type BYTE_TYPE = Type.tByte;
private final static Type CHAR_TYPE = Type.tChar;
private final static Type SHORT_TYPE = Type.tShort;
private final static Type VOID_TYPE = Type.tVoid;
public final static Type types[][] = {
private final static Type types[][] = {
{BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE },
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE,
BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE },
@ -51,277 +51,387 @@ public abstract class Opcodes {
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }
};
public static final int opc_nop = 0;
public static final int opc_aconst_null = 1;
public static final int opc_iconst_m1 = 2;
public static final int opc_iconst_0 = 3;
public static final int opc_iconst_1 = 4;
public static final int opc_iconst_2 = 5;
public static final int opc_iconst_3 = 6;
public static final int opc_iconst_4 = 7;
public static final int opc_iconst_5 = 8;
public static final int opc_lconst_0 = 9;
public static final int opc_lconst_1 = 10;
public static final int opc_fconst_0 = 11;
public static final int opc_fconst_1 = 12;
public static final int opc_fconst_2 = 13;
public static final int opc_dconst_0 = 14;
public static final int opc_dconst_1 = 15;
public static final int opc_bipush = 16;
public static final int opc_sipush = 17;
public static final int opc_ldc = 18;
public static final int opc_ldc_w = 19;
public static final int opc_ldc2_w = 20;
public static final int opc_iload = 21;
public static final int opc_lload = 22;
public static final int opc_fload = 23;
public static final int opc_dload = 24;
public static final int opc_aload = 25;
public static final int opc_iload_0 = 26;
public static final int opc_iload_1 = 27;
public static final int opc_iload_2 = 28;
public static final int opc_iload_3 = 29;
public static final int opc_lload_0 = 30;
public static final int opc_lload_1 = 31;
public static final int opc_lload_2 = 32;
public static final int opc_lload_3 = 33;
public static final int opc_fload_0 = 34;
public static final int opc_fload_1 = 35;
public static final int opc_fload_2 = 36;
public static final int opc_fload_3 = 37;
public static final int opc_dload_0 = 38;
public static final int opc_dload_1 = 39;
public static final int opc_dload_2 = 40;
public static final int opc_dload_3 = 41;
public static final int opc_aload_0 = 42;
public static final int opc_aload_1 = 43;
public static final int opc_aload_2 = 44;
public static final int opc_aload_3 = 45;
public static final int opc_iaload = 46;
public static final int opc_laload = 47;
public static final int opc_faload = 48;
public static final int opc_daload = 49;
public static final int opc_aaload = 50;
public static final int opc_baload = 51;
public static final int opc_caload = 52;
public static final int opc_saload = 53;
public static final int opc_istore = 54;
public static final int opc_lstore = 55;
public static final int opc_fstore = 56;
public static final int opc_dstore = 57;
public static final int opc_astore = 58;
public static final int opc_istore_0 = 59;
public static final int opc_istore_1 = 60;
public static final int opc_istore_2 = 61;
public static final int opc_istore_3 = 62;
public static final int opc_lstore_0 = 63;
public static final int opc_lstore_1 = 64;
public static final int opc_lstore_2 = 65;
public static final int opc_lstore_3 = 66;
public static final int opc_fstore_0 = 67;
public static final int opc_fstore_1 = 68;
public static final int opc_fstore_2 = 69;
public static final int opc_fstore_3 = 70;
public static final int opc_dstore_0 = 71;
public static final int opc_dstore_1 = 72;
public static final int opc_dstore_2 = 73;
public static final int opc_dstore_3 = 74;
public static final int opc_astore_0 = 75;
public static final int opc_astore_1 = 76;
public static final int opc_astore_2 = 77;
public static final int opc_astore_3 = 78;
public static final int opc_iastore = 79;
public static final int opc_lastore = 80;
public static final int opc_fastore = 81;
public static final int opc_dastore = 82;
public static final int opc_aastore = 83;
public static final int opc_bastore = 84;
public static final int opc_castore = 85;
public static final int opc_sastore = 86;
public static final int opc_pop = 87;
public static final int opc_pop2 = 88;
public static final int opc_dup = 89;
public static final int opc_dup_x1 = 90;
public static final int opc_dup_x2 = 91;
public static final int opc_dup2 = 92;
public static final int opc_dup2_x1 = 93;
public static final int opc_dup2_x2 = 94;
public static final int opc_swap = 95;
public static final int opc_iadd = 96;
public static final int opc_ladd = 97;
public static final int opc_fadd = 98;
public static final int opc_dadd = 99;
public static final int opc_isub = 100;
public static final int opc_lsub = 101;
public static final int opc_fsub = 102;
public static final int opc_dsub = 103;
public static final int opc_imul = 104;
public static final int opc_lmul = 105;
public static final int opc_fmul = 106;
public static final int opc_dmul = 107;
public static final int opc_idiv = 108;
public static final int opc_ldiv = 109;
public static final int opc_fdiv = 110;
public static final int opc_ddiv = 111;
public static final int opc_irem = 112;
public static final int opc_lrem = 113;
public static final int opc_frem = 114;
public static final int opc_drem = 115;
public static final int opc_ineg = 116;
public static final int opc_lneg = 117;
public static final int opc_fneg = 118;
public static final int opc_dneg = 119;
public static final int opc_ishl = 120;
public static final int opc_lshl = 121;
public static final int opc_ishr = 122;
public static final int opc_lshr = 123;
public static final int opc_iushr = 124;
public static final int opc_lushr = 125;
public static final int opc_iand = 126;
public static final int opc_land = 127;
public static final int opc_ior = 128;
public static final int opc_lor = 129;
public static final int opc_ixor = 130;
public static final int opc_lxor = 131;
public static final int opc_iinc = 132;
public static final int opc_i2l = 133;
public static final int opc_i2f = 134;
public static final int opc_i2d = 135;
public static final int opc_l2i = 136;
public static final int opc_l2f = 137;
public static final int opc_l2d = 138;
public static final int opc_f2i = 139;
public static final int opc_f2l = 140;
public static final int opc_f2d = 141;
public static final int opc_d2i = 142;
public static final int opc_d2l = 143;
public static final int opc_d2f = 144;
public static final int opc_i2b = 145;
public static final int opc_i2c = 146;
public static final int opc_i2s = 147;
public static final int opc_lcmp = 148;
public static final int opc_fcmpl = 149;
public static final int opc_fcmpg = 150;
public static final int opc_dcmpl = 151;
public static final int opc_dcmpg = 152;
public static final int opc_ifeq = 153;
public static final int opc_ifne = 154;
public static final int opc_iflt = 155;
public static final int opc_ifge = 156;
public static final int opc_ifgt = 157;
public static final int opc_ifle = 158;
public static final int opc_if_icmpeq = 159;
public static final int opc_if_icmpne = 160;
public static final int opc_if_icmplt = 161;
public static final int opc_if_icmpge = 162;
public static final int opc_if_icmpgt = 163;
public static final int opc_if_icmple = 164;
public static final int opc_if_acmpeq = 165;
public static final int opc_if_acmpne = 166;
public static final int opc_goto = 167;
public static final int opc_jsr = 168;
public static final int opc_ret = 169;
public static final int opc_tableswitch = 170;
public static final int opc_lookupswitch = 171;
public static final int opc_ireturn = 172;
public static final int opc_lreturn = 173;
public static final int opc_freturn = 174;
public static final int opc_dreturn = 175;
public static final int opc_areturn = 176;
public static final int opc_return = 177;
public static final int opc_getstatic = 178;
public static final int opc_putstatic = 179;
public static final int opc_getfield = 180;
public static final int opc_putfield = 181;
public static final int opc_invokevirtual = 182;
public static final int opc_invokespecial = 183;
public static final int opc_invokestatic = 184;
public static final int opc_invokeinterface = 185;
public static final int opc_xxxunusedxxx = 186;
public static final int opc_new = 187;
public static final int opc_newarray = 188;
public static final int opc_anewarray = 189;
public static final int opc_arraylength = 190;
public static final int opc_athrow = 191;
public static final int opc_checkcast = 192;
public static final int opc_instanceof = 193;
public static final int opc_monitorenter = 194;
public static final int opc_monitorexit = 195;
public static final int opc_wide = 196;
public static final int opc_multianewarray = 197;
public static final int opc_ifnull = 198;
public static final int opc_ifnonnull = 199;
public static final int opc_goto_w = 200;
public static final int opc_jsr_w = 201;
public static final int opc_breakpoint = 202;
private final static int opc_nop = 0;
private final static int opc_aconst_null = 1;
private final static int opc_iconst_m1 = 2;
private final static int opc_iconst_0 = 3;
private final static int opc_iconst_1 = 4;
private final static int opc_iconst_2 = 5;
private final static int opc_iconst_3 = 6;
private final static int opc_iconst_4 = 7;
private final static int opc_iconst_5 = 8;
private final static int opc_lconst_0 = 9;
private final static int opc_lconst_1 = 10;
private final static int opc_fconst_0 = 11;
private final static int opc_fconst_1 = 12;
private final static int opc_fconst_2 = 13;
private final static int opc_dconst_0 = 14;
private final static int opc_dconst_1 = 15;
private final static int opc_bipush = 16;
private final static int opc_sipush = 17;
private final static int opc_ldc = 18;
private final static int opc_ldc_w = 19;
private final static int opc_ldc2_w = 20;
private final static int opc_iload = 21;
private final static int opc_lload = 22;
private final static int opc_fload = 23;
private final static int opc_dload = 24;
private final static int opc_aload = 25;
private final static int opc_iload_0 = 26;
private final static int opc_iload_1 = 27;
private final static int opc_iload_2 = 28;
private final static int opc_iload_3 = 29;
private final static int opc_lload_0 = 30;
private final static int opc_lload_1 = 31;
private final static int opc_lload_2 = 32;
private final static int opc_lload_3 = 33;
private final static int opc_fload_0 = 34;
private final static int opc_fload_1 = 35;
private final static int opc_fload_2 = 36;
private final static int opc_fload_3 = 37;
private final static int opc_dload_0 = 38;
private final static int opc_dload_1 = 39;
private final static int opc_dload_2 = 40;
private final static int opc_dload_3 = 41;
private final static int opc_aload_0 = 42;
private final static int opc_aload_1 = 43;
private final static int opc_aload_2 = 44;
private final static int opc_aload_3 = 45;
private final static int opc_iaload = 46;
private final static int opc_laload = 47;
private final static int opc_faload = 48;
private final static int opc_daload = 49;
private final static int opc_aaload = 50;
private final static int opc_baload = 51;
private final static int opc_caload = 52;
private final static int opc_saload = 53;
private final static int opc_istore = 54;
private final static int opc_lstore = 55;
private final static int opc_fstore = 56;
private final static int opc_dstore = 57;
private final static int opc_astore = 58;
private final static int opc_istore_0 = 59;
private final static int opc_istore_1 = 60;
private final static int opc_istore_2 = 61;
private final static int opc_istore_3 = 62;
private final static int opc_lstore_0 = 63;
private final static int opc_lstore_1 = 64;
private final static int opc_lstore_2 = 65;
private final static int opc_lstore_3 = 66;
private final static int opc_fstore_0 = 67;
private final static int opc_fstore_1 = 68;
private final static int opc_fstore_2 = 69;
private final static int opc_fstore_3 = 70;
private final static int opc_dstore_0 = 71;
private final static int opc_dstore_1 = 72;
private final static int opc_dstore_2 = 73;
private final static int opc_dstore_3 = 74;
private final static int opc_astore_0 = 75;
private final static int opc_astore_1 = 76;
private final static int opc_astore_2 = 77;
private final static int opc_astore_3 = 78;
private final static int opc_iastore = 79;
private final static int opc_lastore = 80;
private final static int opc_fastore = 81;
private final static int opc_dastore = 82;
private final static int opc_aastore = 83;
private final static int opc_bastore = 84;
private final static int opc_castore = 85;
private final static int opc_sastore = 86;
private final static int opc_pop = 87;
private final static int opc_pop2 = 88;
private final static int opc_dup = 89;
private final static int opc_dup_x1 = 90;
private final static int opc_dup_x2 = 91;
private final static int opc_dup2 = 92;
private final static int opc_dup2_x1 = 93;
private final static int opc_dup2_x2 = 94;
private final static int opc_swap = 95;
private final static int opc_iadd = 96;
private final static int opc_ladd = 97;
private final static int opc_fadd = 98;
private final static int opc_dadd = 99;
private final static int opc_isub = 100;
private final static int opc_lsub = 101;
private final static int opc_fsub = 102;
private final static int opc_dsub = 103;
private final static int opc_imul = 104;
private final static int opc_lmul = 105;
private final static int opc_fmul = 106;
private final static int opc_dmul = 107;
private final static int opc_idiv = 108;
private final static int opc_ldiv = 109;
private final static int opc_fdiv = 110;
private final static int opc_ddiv = 111;
private final static int opc_irem = 112;
private final static int opc_lrem = 113;
private final static int opc_frem = 114;
private final static int opc_drem = 115;
private final static int opc_ineg = 116;
private final static int opc_lneg = 117;
private final static int opc_fneg = 118;
private final static int opc_dneg = 119;
private final static int opc_ishl = 120;
private final static int opc_lshl = 121;
private final static int opc_ishr = 122;
private final static int opc_lshr = 123;
private final static int opc_iushr = 124;
private final static int opc_lushr = 125;
private final static int opc_iand = 126;
private final static int opc_land = 127;
private final static int opc_ior = 128;
private final static int opc_lor = 129;
private final static int opc_ixor = 130;
private final static int opc_lxor = 131;
private final static int opc_iinc = 132;
private final static int opc_i2l = 133;
private final static int opc_i2f = 134;
private final static int opc_i2d = 135;
private final static int opc_l2i = 136;
private final static int opc_l2f = 137;
private final static int opc_l2d = 138;
private final static int opc_f2i = 139;
private final static int opc_f2l = 140;
private final static int opc_f2d = 141;
private final static int opc_d2i = 142;
private final static int opc_d2l = 143;
private final static int opc_d2f = 144;
private final static int opc_i2b = 145;
private final static int opc_i2c = 146;
private final static int opc_i2s = 147;
private final static int opc_lcmp = 148;
private final static int opc_fcmpl = 149;
private final static int opc_fcmpg = 150;
private final static int opc_dcmpl = 151;
private final static int opc_dcmpg = 152;
private final static int opc_ifeq = 153;
private final static int opc_ifne = 154;
private final static int opc_iflt = 155;
private final static int opc_ifge = 156;
private final static int opc_ifgt = 157;
private final static int opc_ifle = 158;
private final static int opc_if_icmpeq = 159;
private final static int opc_if_icmpne = 160;
private final static int opc_if_icmplt = 161;
private final static int opc_if_icmpge = 162;
private final static int opc_if_icmpgt = 163;
private final static int opc_if_icmple = 164;
private final static int opc_if_acmpeq = 165;
private final static int opc_if_acmpne = 166;
private final static int opc_goto = 167;
private final static int opc_jsr = 168;
private final static int opc_ret = 169;
private final static int opc_tableswitch = 170;
private final static int opc_lookupswitch = 171;
private final static int opc_ireturn = 172;
private final static int opc_lreturn = 173;
private final static int opc_freturn = 174;
private final static int opc_dreturn = 175;
private final static int opc_areturn = 176;
private final static int opc_return = 177;
private final static int opc_getstatic = 178;
private final static int opc_putstatic = 179;
private final static int opc_getfield = 180;
private final static int opc_putfield = 181;
private final static int opc_invokevirtual = 182;
private final static int opc_invokespecial = 183;
private final static int opc_invokestatic = 184;
private final static int opc_invokeinterface = 185;
private final static int opc_xxxunusedxxx = 186;
private final static int opc_new = 187;
private final static int opc_newarray = 188;
private final static int opc_anewarray = 189;
private final static int opc_arraylength = 190;
private final static int opc_athrow = 191;
private final static int opc_checkcast = 192;
private final static int opc_instanceof = 193;
private final static int opc_monitorenter = 194;
private final static int opc_monitorexit = 195;
private final static int opc_wide = 196;
private final static int opc_multianewarray = 197;
private final static int opc_ifnull = 198;
private final static int opc_ifnonnull = 199;
private final static int opc_goto_w = 200;
private final static int opc_jsr_w = 201;
private final static int opc_breakpoint = 202;
public static FlowBlock createNormal(CodeAnalyzer ca,
private static StructuredBlock createNormal(CodeAnalyzer ca,
int addr, int length,
Expression instr)
{
return new FlowBlock(ca, addr, length,
new InstructionBlock(instr,
new Jump(addr+length)));
return new InstructionBlock(instr, new Jump(addr+length));
}
public static FlowBlock createSpecial(CodeAnalyzer ca,
private static StructuredBlock createSpecial(CodeAnalyzer ca,
int addr, int length,
int type, int stackcount, int param)
{
return new FlowBlock(ca, addr, length,
new SpecialBlock(type, stackcount, param,
new Jump(addr+length)));
return new SpecialBlock(type, stackcount, param,
new Jump(addr+length));
}
public static FlowBlock createGoto(CodeAnalyzer ca,
private static StructuredBlock createGoto(CodeAnalyzer ca,
int addr, int length, int destAddr)
{
return new FlowBlock(ca, addr, length,
new EmptyBlock(new Jump(destAddr)));
return new EmptyBlock(new Jump(destAddr));
}
public static FlowBlock createJsr(CodeAnalyzer ca,
private static StructuredBlock createJsr(CodeAnalyzer ca,
int addr, int length,
int destAddr)
{
return new FlowBlock(ca, addr, length,
new JsrBlock(new Jump(addr+length),
new Jump(destAddr)));
return new JsrBlock(new Jump(addr+length),
new Jump(destAddr));
}
public static FlowBlock createIfGoto(CodeAnalyzer ca,
private static StructuredBlock createIfGoto(CodeAnalyzer ca,
int addr, int length,
int destAddr, Expression instr)
{
ConditionalBlock ifBlock =
new ConditionalBlock(instr,
return new ConditionalBlock(instr,
new Jump(destAddr),
new Jump(addr+length));
return new FlowBlock(ca, addr, length, ifBlock);
}
public static FlowBlock createSwitch(CodeAnalyzer ca,
private static StructuredBlock createSwitch(CodeAnalyzer ca,
int addr, int length,
int[] cases, int[] dests)
{
return new FlowBlock(ca, addr, length,
new SwitchBlock(new NopOperator(Type.tUInt),
cases, dests));
return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests);
}
public static FlowBlock createBlock(CodeAnalyzer ca,
private static StructuredBlock createBlock(CodeAnalyzer ca,
int addr, int length,
StructuredBlock block)
{
return new FlowBlock(ca, addr, length, block);
return block;
}
public static FlowBlock createRet(CodeAnalyzer ca,
private static StructuredBlock createRet(CodeAnalyzer ca,
int addr, int length,
LocalInfo local)
{
return new FlowBlock(ca, addr, length,
new RetBlock(local));
return new RetBlock(local);
}
/**
* Read an opcode out of a data input stream and determine its size
* and its successors.
* @param addr The current address.
* @param stream The stream containing the java byte code.
* @return An array of ints; the first entry is the size of the
* instruction, the remaining are the successors.
*/
public static int[] getSizeAndSuccs(int addr, DataInputStream stream)
throws IOException
{
int opcode = stream.readUnsignedByte();
switch (opcode) {
case opc_multianewarray:
stream.skip(3);
return new int[] { 4, addr+4 };
case opc_invokeinterface:
stream.skip(4);
return new int[] { 5, addr+5 };
case opc_wide: {
switch (opcode = stream.readUnsignedByte()) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
stream.skip(2);
return new int[] { 4, addr+4 };
case opc_iinc:
stream.skip(4);
return new int[] { 6, addr+6 };
case opc_ret:
stream.skip(2);
return new int[] { 4 };
default:
throw new ClassFormatError("Invalid wide opcode "+opcode);
}
}
case opc_ret:
return new int[] { 2 };
case opc_jsr_w:
return new int[] { 5, addr + 5, addr + stream.readInt() };
case opc_goto:
return new int[] { 3, addr + stream.readShort() };
case opc_goto_w:
return new int[] { 5, addr + stream.readInt() };
case opc_tableswitch: {
int length = 3-(addr % 4);
stream.skip(length);
int def = addr + stream.readInt();
int low = stream.readInt();
int high = stream.readInt();
int[] dests = new int[high-low+3];
for (int i=0; i+low <= high; i++) {
dests[i+1] = addr + stream.readInt();
}
dests[dests.length-1] = def;
dests[0] = length + 13 + 4 * (high-low+1);
return dests;
}
case opc_lookupswitch: {
int length = 3-(addr % 4);
stream.skip(length);
int def = stream.readInt();
int npairs = stream.readInt();
int[] dests = new int[npairs+2];
for (int i=0; i < npairs; i++) {
int value = stream.readInt();
dests[i+1] = addr + stream.readInt();
}
dests[npairs+1] = def;
dests[0] = length + 9 + 8 * npairs;
return dests;
}
case opc_ifnull: case opc_ifnonnull:
case opc_jsr:
return new int[] { 3, addr + 3, addr + stream.readShort() };
case opc_sipush:
case opc_ldc_w:
case opc_ldc2_w:
case opc_iinc:
case opc_getstatic:
case opc_getfield:
case opc_putstatic:
case opc_putfield:
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic :
case opc_new:
case opc_anewarray:
case opc_checkcast:
case opc_instanceof:
stream.skip(2);
return new int[] { 3, addr+3 };
}
if (opcode == opc_newarray
|| (opcode >= opc_bipush && opcode <= opc_aload)
|| (opcode >= opc_istore && opcode <= opc_astore)) {
stream.skip(1);
return new int[] { 2, addr+2 };
}
if (opcode >= opc_ireturn && opcode <= opc_return)
return new int[] { 1 };
if (opcode >= opc_ifeq && opcode <= opc_if_acmpne)
return new int[] { 3, addr + 3, addr + stream.readShort() };
if (opcode == opc_xxxunusedxxx || opcode > opc_breakpoint)
throw new ClassFormatError("Invalid opcode "+opcode);
return new int[] { 1, addr+1 };
}
/**
@ -335,11 +445,10 @@ public abstract class Opcodes {
* @exception IOException if an read error occured.
* @exception ClassFormatError if an invalid opcode is detected.
*/
public static FlowBlock readOpcode(int addr, DataInputStream stream,
public static StructuredBlock readOpcode(int addr, DataInputStream stream,
CodeAnalyzer ca)
throws IOException, ClassFormatError
{
try {
int opcode = stream.readUnsignedByte();
switch (opcode) {
case opc_nop:
@ -643,7 +752,7 @@ public abstract class Opcodes {
CpoolRef field = (CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort());
FlowBlock fb = createNormal
StructuredBlock block = createNormal
(ca, addr, 5, new InvokeOperator
(ca, false,
Type.tClass(field.getCpoolClass()
@ -652,7 +761,7 @@ public abstract class Opcodes {
.getType().getString()),
field.getNameAndType().getName().getString()));
int reserved = stream.readUnsignedShort();
return fb;
return block;
}
case opc_new: {
CpoolClass cpcls = (CpoolClass)
@ -785,9 +894,5 @@ public abstract class Opcodes {
default:
throw new ClassFormatError("Invalid opcode "+opcode);
}
} catch (ClassCastException ex) {
ex.printStackTrace();
throw new ClassFormatError("Constant has wrong type");
}
}
}

@ -36,7 +36,6 @@ import gnu.bytecode.Spy;
public class CodeAnalyzer implements Analyzer {
TransformExceptionHandlers handler;
FlowBlock methodHeader;
CodeAttr code;
MethodAnalyzer method;
@ -71,19 +70,78 @@ public class CodeAnalyzer implements Analyzer {
param.addElement(getLocalInfo(0, i));
}
void readCode(CodeAttr bincode)
private final static int SEQUENTIAL = 1;
private final static int PREDECESSORS = 2;
/**
* @param code The code array.
* @param handlers The exception handlers.
*/
void readCode(byte[] code, short[] handlers)
throws ClassFormatError
{
byte[] code = bincode.getCode();
byte[] flags = new byte[code.length];
int[] lengths = new int[code.length];
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
for (int addr = 0; addr < code.length; ) {
int[] succs = Opcodes.getSizeAndSuccs(addr, stream);
if (succs.length == 2
&& succs[1] == addr + succs[0])
flags[addr] |= SEQUENTIAL;
lengths[addr] = succs[0];
addr += succs[0];
for (int i=1; i<succs.length; i++)
if (succs[i] != addr)
flags[succs[i]] |= PREDECESSORS;
}
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
for (int i=0; i<handlers.length; i += 4) {
int start = handlers[i + 0];
int handler = handlers[i + 2];
if (start < 0) start += 65536;
if (handler < 0) handler += 65536;
flags[start] |= PREDECESSORS;
flags[handler] |= PREDECESSORS;
}
FlowBlock[] instr = new FlowBlock[code.length];
int returnCount;
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
/* While we read the opcodes into FlowBlocks
* we try to combine sequential blocks, as soon as we
* find two sequential instructions in a row, where the
* second has no predecessors.
*/
int mark = 1000;
FlowBlock lastBlock = null;
for (int addr = 0; addr < code.length; ) {
instr[addr] = Opcodes.readOpcode(addr, stream, this);
jode.flow.StructuredBlock block
= Opcodes.readOpcode(addr, stream, this);
addr = instr[addr].getNextAddr();
if (jode.Decompiler.isVerbose && addr > mark) {
System.err.print('.');
mark += 1000;
}
if (lastBlock != null && flags[addr] == SEQUENTIAL) {
lastBlock.doSequentialT1(block, lengths[addr]);
} else {
instr[addr] = new FlowBlock(this, addr,
lengths[addr], block);
lastBlock = ((flags[addr] & SEQUENTIAL) == 0)
? null : instr[addr];
}
addr += lengths[addr];
}
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
@ -94,28 +152,74 @@ public class CodeAnalyzer implements Analyzer {
addr = instr[addr].getNextAddr();
}
handler = new TransformExceptionHandlers(instr);
short[] handlers = Spy.getExceptionHandlers(bincode);
TransformExceptionHandlers excHandlers
= new TransformExceptionHandlers(instr);
for (int i=0; i<handlers.length; i += 4) {
Type type = null;
int start = handlers[i + 0];
int end = handlers[i + 1];
int handler = handlers[i + 2];
if (start < 0) start += 65536;
if (end < 0) end += 65536;
if (handler < 0) handler += 65536;
if (handlers[i + 3 ] != 0) {
CpoolClass cpcls = (CpoolClass)
method.classAnalyzer.getConstant(handlers[i + 3]);
type = Type.tClass(cpcls.getName().getString());
}
handler.addHandler(handlers[i + 0], handlers[i + 1],
handlers[i + 2], type);
excHandlers.addHandler(start, end, handler, type);
}
if (Decompiler.isVerbose)
System.err.print('-');
excHandlers.analyze();
methodHeader = instr[0];
methodHeader.analyze();
}
// void readCode(byte[] code, short[] handlers)
// throws ClassFormatError
// {
// FlowBlock[] instr = new FlowBlock[code.length];
// int returnCount;
// try {
// DataInputStream stream =
// new DataInputStream(new ByteArrayInputStream(code));
// for (int addr = 0; addr < code.length; ) {
// instr[addr] = Opcodes.readOpcode(addr, stream, this);
// addr = instr[addr].getNextAddr();
// }
// } catch (IOException ex) {
// throw new ClassFormatError(ex.toString());
// }
// for (int addr=0; addr<instr.length; ) {
// instr[addr].resolveJumps(instr);
// addr = instr[addr].getNextAddr();
// }
// handler = new TransformExceptionHandlers(instr);
// for (int i=0; i<handlers.length; i += 4) {
// Type type = null;
// if (handlers[i + 3 ] != 0) {
// CpoolClass cpcls = (CpoolClass)
// method.classAnalyzer.getConstant(handlers[i + 3]);
// type = Type.tClass(cpcls.getName().getString());
// }
// handler.addHandler(handlers[i + 0], handlers[i + 1],
// handlers[i + 2], type);
// }
// methodHeader = instr[0];
// }
public void analyze()
{
readCode(code);
handler.analyze();
methodHeader.analyze();
byte[] codeArray = code.getCode();
short[] handlers = Spy.getExceptionHandlers(code);
readCode(codeArray, handlers);
Enumeration enum = allLocals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo)enum.nextElement();
@ -157,4 +261,3 @@ public class CodeAnalyzer implements Analyzer {
return method.classAnalyzer.clazz;
}
}

@ -132,6 +132,10 @@ public class ComplexExpression extends Expression {
return subExpressions;
}
public void setSubExpressions(int i, Expression expr) {
subExpressions[i] = expr;
updateSubTypes();
}
void updateSubTypes() {
for (int i=0; i < subExpressions.length; i++) {
if (i == 0 && operator instanceof ArrayStoreOperator) {
@ -255,7 +259,7 @@ public class ComplexExpression extends Expression {
return new ComplexExpression
(new StringAddOperator(), new Expression[]
{ e, subExpressions[1] });
{ e, subExpressions[1].simplifyString() });
}
if (operator instanceof ConstructorOperator
&& (((ConstructorOperator) operator).getClassType()
@ -263,7 +267,7 @@ public class ComplexExpression extends Expression {
if (subExpressions.length == 1 &&
subExpressions[0].getType().isOfType(Type.tString))
return subExpressions[0];
return subExpressions[0].simplifyString();
}
return null;
}
@ -278,6 +282,7 @@ public class ComplexExpression extends Expression {
Expression simple = subExpressions[0].simplifyStringBuffer();
if (simple != null)
return simple;
}
else if (invoke.getMethodName().equals("valueOf")
&& invoke.isStatic()
@ -309,7 +314,7 @@ public class ComplexExpression extends Expression {
{ left, right });
}
}
return null;
return this;
}
public Expression simplify() {
@ -382,7 +387,7 @@ public class ComplexExpression extends Expression {
}
else {
Expression stringExpr = simplifyString();
if (stringExpr != null)
if (stringExpr != this)
return stringExpr.simplify();
}
for (int i=0; i< subExpressions.length; i++) {
@ -392,3 +397,4 @@ public class ComplexExpression extends Expression {
return this;
}
}

@ -19,29 +19,55 @@
package jode;
public class ConstantArrayOperator extends SimpleOperator {
public class ConstantArrayOperator extends NoArgOperator {
ConstOperator empty;
Expression[] values;
Type argType;
public ConstantArrayOperator(Type type, int size) {
super(type, 0, size);
for (int i=0; i< size; i++)
operandTypes[i] = ((ArrayType)type).getElementType();
super(type);
values = new Expression[size];
argType = (type instanceof ArrayType)
? Type.tSubType(((ArrayType)type).getElementType()) : Type.tError;
empty = new ConstOperator(argType, "0");
}
public int getPriority() {
return 200;
public void setType(Type newtype) {
super.setType(newtype);
Type newArgType = (this.type instanceof ArrayType)
? Type.tSubType(((ArrayType)this.type).getElementType())
: Type.tError;
if (!newArgType.equals(argType)) {
argType = newArgType;
empty.setType(argType);
for (int i=0; i< values.length; i++)
if (values[i] != null)
values[i].setType(argType);
}
}
public int getOperandPriority(int i) {
return 0;
public boolean setValue(int index, Expression value) {
if (index < 0 || index > values.length || values[index] != null)
return false;
value.setType(argType);
setType(Type.tSuperType(Type.tArray(value.getType())));
values[index] = value;
value.parent = this;
return true;
}
public int getPriority() {
return 200;
}
public String toString(String[] operands) {
StringBuffer result
= new StringBuffer("new "+type+" {");
for (int i=0; i< getOperandCount(); i++) {
= new StringBuffer("new ").append(type).append(" { ");
for (int i=0; i< values.length; i++) {
if (i>0)
result.append(", ");
result.append(operands[i]);
result.append((values[i] != null) ? values[i] : empty);
}
return result.append(" }").toString();
}

@ -24,8 +24,9 @@ public class ConstructorOperator extends Operator {
MethodType methodType;
Type classType;
public ConstructorOperator(Type type, MethodType methodType) {
super(type, 0);
public ConstructorOperator(Type type, MethodType methodType,
boolean isVoid) {
super(isVoid ? Type.tVoid : type, 0);
this.classType = type;
this.methodType = methodType;
}

@ -107,6 +107,9 @@ public abstract class Expression {
public Expression simplify() {
return this;
}
public Expression simplifyString() {
return this;
}
static Expression EMPTYSTRING = new ConstOperator(Type.tString, "\"\"");

@ -24,14 +24,14 @@ import jode.ComplexExpression;
import jode.Type;
import jode.BinaryOperator;
public class CombineIfGotoExpressions implements Transformation{
public class CombineIfGotoExpressions {
public boolean transform(FlowBlock flow) {
if (!(flow.lastModified instanceof ConditionalBlock)
|| !(flow.lastModified.outer instanceof SequentialBlock))
public static boolean transform(ConditionalBlock cb,
StructuredBlock last) {
if (cb.jump == null
|| !(last.outer instanceof SequentialBlock))
return false;
ConditionalBlock cb = (ConditionalBlock) flow.lastModified;
SequentialBlock sequBlock = (SequentialBlock) cb.outer;
Expression[] e = new Expression[2];
@ -77,6 +77,10 @@ public class CombineIfGotoExpressions implements Transformation{
} else
return false;
/* We have changed some instructions above. We may never
* return with a failure now.
*/
sequBlock = (SequentialBlock) cb.outer;
while (sequBlock.subBlocks[0] instanceof InstructionBlock) {
/* Now combine the expression. Everything should
@ -90,14 +94,14 @@ public class CombineIfGotoExpressions implements Transformation{
sequBlock = (SequentialBlock) sequBlock.outer;
}
flow.removeSuccessor(prevJump);
cb.flowBlock.removeSuccessor(prevJump);
prevJump.prev.removeJump();
Expression cond =
new ComplexExpression
(new BinaryOperator(Type.tBoolean, operator), e);
cb.setInstruction(cond);
cb.moveDefinitions(sequBlock, cb);
cb.replace(sequBlock);
cb.moveDefinitions(sequBlock, last);
last.replace(sequBlock);
return true;
}
return false;

@ -24,22 +24,20 @@ import jode.LocalLoadOperator;
import jode.LocalStoreOperator;
import jode.Expression;
public class CompleteSynchronized implements Transformation {
public class CompleteSynchronized {
/**
* This combines the monitorenter and the initial expression
* into a synchronized statement
* @param flow The FlowBlock that is transformed
*/
public boolean transform(FlowBlock flow) {
public static boolean transform(SynchronizedBlock synBlock,
StructuredBlock last) {
if (!(flow.lastModified instanceof SynchronizedBlock)
|| flow.lastModified.outer == null)
if (!(last.outer instanceof SequentialBlock))
return false;
/* If the program is well formed, the following succeed */
SynchronizedBlock synBlock = (SynchronizedBlock) flow.lastModified;
try {
SequentialBlock sequBlock = (SequentialBlock) synBlock.outer;
@ -59,11 +57,11 @@ public class CompleteSynchronized implements Transformation {
System.err.print('s');
synBlock.isEntered = true;
synBlock.moveDefinitions(synBlock.outer,synBlock);
synBlock.replace(synBlock.outer);
synBlock.moveDefinitions(last.outer,last);
last.replace(last.outer);
/* Is there another expression? */
if (synBlock.outer == null)
if (!(last.outer instanceof SynchronizedBlock))
return false;
Expression object;
@ -85,8 +83,8 @@ public class CompleteSynchronized implements Transformation {
}
synBlock.object = object;
synBlock.moveDefinitions(synBlock.outer,synBlock);
synBlock.replace(synBlock.outer);
synBlock.moveDefinitions(last.outer,last);
last.replace(last.outer);
return true;
}
}

@ -76,4 +76,11 @@ public class ConditionalBlock extends InstructionContainer {
trueBlock.dumpSource(writer);
writer.untab();
}
public boolean doTransformations() {
StructuredBlock last = flowBlock.lastModified;
return super.doTransformations()
|| CombineIfGotoExpressions.transform(this, last)
|| CreateIfThenElseOperator.createFunny(this, last);
}
}

@ -20,21 +20,20 @@
package jode.flow;
import jode.*;
public class CreateAssignExpression implements Transformation{
public boolean transform(FlowBlock flow) {
if (!(flow.lastModified instanceof InstructionContainer)
|| !(flow.lastModified.outer instanceof SequentialBlock)
|| !(((InstructionContainer)flow.lastModified).getInstruction()
instanceof StoreInstruction)
|| !(((InstructionContainer)flow.lastModified).getInstruction()
.isVoid()))
public class CreateAssignExpression {
public static boolean transform(InstructionContainer ic,
StructuredBlock last) {
if (!(last.outer instanceof SequentialBlock)
|| !(ic.getInstruction() instanceof StoreInstruction)
|| !(ic.getInstruction().isVoid()))
return false;
return (createAssignOp(flow) || createAssignExpression(flow));
return (createAssignOp(ic, last) || createAssignExpression(ic, last));
}
public boolean createAssignOp(FlowBlock flow) {
public static boolean createAssignOp(InstructionContainer ic,
StructuredBlock last) {
/* Situation:
*
@ -53,11 +52,8 @@ public class CreateAssignExpression implements Transformation{
*
* If the optional dup is present the store*= becomes non void.
*/
InstructionContainer lastBlock
= (InstructionContainer) flow.lastModified;
SequentialBlock opBlock = (SequentialBlock) lastBlock.outer;
StoreInstruction store
= (StoreInstruction) lastBlock.getInstruction();
SequentialBlock opBlock = (SequentialBlock) last.outer;
StoreInstruction store = (StoreInstruction) ic.getInstruction();
boolean isAssignOp = false;
if (opBlock.subBlocks[0] instanceof SpecialBlock) {
@ -94,6 +90,12 @@ public class CreateAssignExpression implements Transformation{
int opIndex;
Expression rightHandSide;
if (expr.getOperator() instanceof ConvertOperator
&& expr.getSubExpressions()[0] instanceof ComplexExpression
&& expr.getOperator().getType().isOfType(store.getLValueType())) {
expr = (ComplexExpression) expr.getSubExpressions()[0];
}
if (expr.getOperator() instanceof BinaryOperator) {
BinaryOperator binop = (BinaryOperator) expr.getOperator();
@ -109,24 +111,24 @@ public class CreateAssignExpression implements Transformation{
Expression simple = expr.simplifyString();
rightHandSide = simple;
/* Now search for the leftmost operand ... */
ComplexExpression last = null;
ComplexExpression lastExpr = null;
while (simple instanceof ComplexExpression
&& simple.getOperator() instanceof StringAddOperator) {
last = (ComplexExpression) simple;
simple = last.getSubExpressions()[0];
lastExpr = (ComplexExpression) simple;
simple = lastExpr.getSubExpressions()[0];
}
/* ... check it ... */
if (last == null || !(simple instanceof Operator)
if (lastExpr == null || !(simple instanceof Operator)
|| !store.matches((Operator) simple))
return false;
/* ... and remove it. */
if (last.getParent() != null) {
((ComplexExpression)last.getParent()).getSubExpressions()[0]
= last.getSubExpressions()[1];
if (lastExpr.getParent() != null) {
((ComplexExpression)lastExpr.getParent())
.setSubExpressions(0,lastExpr.getSubExpressions()[1]);
} else
rightHandSide = last.getSubExpressions()[1];
rightHandSide = lastExpr.getSubExpressions()[1];
opIndex = Operator.ADD_OP;
}
@ -137,20 +139,19 @@ public class CreateAssignExpression implements Transformation{
if (isAssignOp)
store.makeNonVoid();
lastBlock.replace(opBlock.subBlocks[1]);
last.replace(opBlock.subBlocks[1]);
return true;
}
public boolean createAssignExpression(FlowBlock flow) {
public static boolean createAssignExpression(InstructionContainer ic,
StructuredBlock last) {
/* Situation:
* sequBlock:
* dup_X(lvalue_count)
* store instruction
*/
InstructionContainer lastBlock
= (InstructionContainer) flow.lastModified;
SequentialBlock sequBlock = (SequentialBlock) lastBlock.outer;
StoreInstruction store = (StoreInstruction) lastBlock.getInstruction();
SequentialBlock sequBlock = (SequentialBlock) last.outer;
StoreInstruction store = (StoreInstruction) ic.getInstruction();
if (sequBlock.subBlocks[0] instanceof SpecialBlock) {

@ -26,104 +26,106 @@ import jode.ConstantArrayOperator;
import jode.ConstOperator;
import jode.Type;
public class CreateConstantArray implements Transformation {
public boolean transform(FlowBlock flow) {
InstructionBlock lastBlock;
SequentialBlock sequBlock;
Expression[] consts = null;
int count = 0;
Type type;
try {
InstructionBlock ib = (InstructionBlock) flow.lastModified;
sequBlock = (SequentialBlock) ib.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
lastBlock = ib;
public class CreateConstantArray {
int lastindex = -1;
while (ib.getInstruction() instanceof ArrayStoreOperator) {
ArrayStoreOperator store =
(ArrayStoreOperator) ib.getInstruction();
public static boolean transform(InstructionContainer ic,
StructuredBlock last) {
/* Situation:
* PUSH new Array[]
* DUP
* PUSH index
* PUSH value
* stack_2[stack_1] = stack_0
* ...
*/
if (last.outer instanceof SequentialBlock) {
sequBlock = (SequentialBlock) sequBlock.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
Expression lastconst = ib.getInstruction();
SequentialBlock sequBlock = (SequentialBlock) last.outer;
sequBlock = (SequentialBlock) sequBlock.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
Expression indexexpr = ib.getInstruction();
ConstOperator indexop =
(ConstOperator) indexexpr.getOperator();
if (!indexop.getType().isOfType(Type.tUInt))
if (!(ic.getInstruction() instanceof ArrayStoreOperator)
|| !(sequBlock.subBlocks[0] instanceof InstructionBlock)
|| !(sequBlock.outer instanceof SequentialBlock))
return false;
int index = Integer.parseInt(indexop.getValue());
if (index >= 0 && consts == null) {
lastindex = index;
consts = new Expression[lastindex+1];
} else if (index < 0 || index > lastindex)
ArrayStoreOperator store
= (ArrayStoreOperator) ic.getInstruction();
InstructionBlock ib = (InstructionBlock)sequBlock.subBlocks[0];
sequBlock = (SequentialBlock) sequBlock.outer;
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)
|| !(sequBlock.outer instanceof SequentialBlock))
return false;
else {
while (index < lastindex) {
consts[lastindex--] =
new ConstOperator(Type.tUnknown, "0");
}
}
consts[lastindex--] = lastconst;
Expression expr = ib.getInstruction();
ib = (InstructionBlock)sequBlock.subBlocks[0];
sequBlock = (SequentialBlock) sequBlock.outer;
if (expr.getOperandCount() > 0
|| !(ib.getInstruction() instanceof ConstOperator)
|| !(sequBlock.subBlocks[0] instanceof SpecialBlock)
|| !(sequBlock.outer instanceof SequentialBlock))
return false;
ConstOperator indexOp = (ConstOperator) ib.getInstruction();
SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
if (dup.type != SpecialBlock.DUP
sequBlock = (SequentialBlock) sequBlock.outer;
if (!indexOp.getType().isOfType(Type.tUInt)
|| dup.type != SpecialBlock.DUP
|| dup.depth != 0
|| dup.count != store.getLValueType().stackSize())
|| dup.count != store.getLValueType().stackSize()
|| !(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false;
count++;
sequBlock = (SequentialBlock) sequBlock.outer;
int index = Integer.parseInt(indexOp.getValue());
ib = (InstructionBlock)sequBlock.subBlocks[0];
}
if (count == 0)
return false;
while (lastindex >= 0)
consts[lastindex--] = new ConstOperator(Type.tUnknown, "0");
if (ib.getInstruction() instanceof ComplexExpression
&& (ib.getInstruction().getOperator()
instanceof NewArrayOperator)) {
/* This is the first element */
ComplexExpression newArrayExpr =
(ComplexExpression) ib.getInstruction();
NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator();
type = newArrayOp.getType();
if (newArrayOp.getOperandCount() != 1)
if (newArrayOp.getOperandCount() != 1
|| !(newArrayExpr.getSubExpressions()[0]
instanceof ConstOperator))
return false;
Expression countexpr = newArrayExpr.getSubExpressions()[0];
ConstOperator countop =
(ConstOperator) countexpr.getOperator();
(ConstOperator) newArrayExpr.getSubExpressions()[0];
if (!countop.getType().isOfType(Type.tUInt))
return false;
int arraylength = Integer.parseInt(countop.getValue());
if (arraylength != consts.length) {
if (arraylength < consts.length)
if (arraylength <= index)
return false;
Expression[] newConsts = new Expression[arraylength];
System.arraycopy(consts, 0, newConsts, 0, consts.length);
for (int i=consts.length; i<arraylength; i++)
newConsts[i] = new ConstOperator(Type.tUnknown, "0");
consts = newConsts;
}
} catch (NullPointerException ex) {
return false;
} catch (ClassCastException ex) {
return false;
}
if (jode.Decompiler.isVerbose)
System.err.print("a");
lastBlock.setInstruction
(new ComplexExpression
(new ConstantArrayOperator(type, consts.length),
consts));
lastBlock.moveDefinitions(sequBlock.subBlocks[0], lastBlock);
lastBlock.replace(sequBlock.subBlocks[0]);
flow.lastModified.moveDefinitions(sequBlock.subBlocks[1],
flow.lastModified);
flow.lastModified.replace(sequBlock.subBlocks[1]);
System.err.print('a');
ConstantArrayOperator cao
= new ConstantArrayOperator(newArrayOp.getType(),
arraylength);
cao.setValue(index, expr);
ic.setInstruction(cao);
ic.moveDefinitions(sequBlock, last);
last.replace(sequBlock);
return true;
} else if (ib.getInstruction() instanceof ConstantArrayOperator) {
ConstantArrayOperator cao
= (ConstantArrayOperator) ib.getInstruction();
if (cao.setValue(index, expr)) {
/* adding Element succeeded */
ic.setInstruction(cao);
ic.moveDefinitions(sequBlock, last);
last.replace(sequBlock);
return true;
}
}
}
return false;
}
}

@ -19,6 +19,7 @@
package jode.flow;
import jode.Operator;
import jode.NopOperator;
import jode.Expression;
import jode.ComplexExpression;
@ -32,47 +33,53 @@ import jode.ComplexExpression;
* expr(op, [ expr_1, ..., expr_n ])
* </pre>
*/
public class CreateExpression implements Transformation {
public class CreateExpression {
/**
* This does the transformation.
* @param FlowBlock the flow block to transform.
* @return true if flow block was simplified.
*/
public boolean transform(FlowBlock flow) {
if (!(flow.lastModified instanceof InstructionContainer)
|| !(flow.lastModified.outer instanceof SequentialBlock))
public static boolean transform(InstructionContainer ic,
StructuredBlock last) {
int params = ic.getInstruction().getOperandCount();
if (params == 0)
return false;
InstructionContainer ic = (InstructionContainer) flow.lastModified;
if (ic.getInstruction() instanceof Operator) {
ComplexExpression parent = null;
Expression inner = ic.getInstruction();
while (inner instanceof ComplexExpression) {
parent = (ComplexExpression)inner;
inner = parent.getSubExpressions()[0];
}
Operator op = (Operator) ic.getInstruction();
int params = op.getOperandCount();
if (params == 0)
if (!(inner instanceof Operator))
return false;
Expression[] exprs = new Expression[params];
Operator op = (Operator)inner;
SequentialBlock sequBlock = (SequentialBlock) ic.outer;
if (!(last.outer instanceof SequentialBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock)last.outer;
Expression lastExpression = null;
/* First check if Expression can be created, but do nothing yet.
*/
Expression lastExpression = null;
for (int i = params;;) {
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false;
InstructionBlock block =
(InstructionBlock) sequBlock.subBlocks[0];
Expression expr =
((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
Expression expr = block.getInstruction();
if (!expr.isVoid()) {
if (--i == 0)
break;
} else if (lastExpression != null
&& lastExpression.canCombine(expr) <= 0)
} else if (lastExpression == null
|| lastExpression.canCombine(expr) <= 0)
return false;
if (expr.getOperandCount() > 0)
@ -81,6 +88,7 @@ public class CreateExpression implements Transformation {
return false;
lastExpression = expr;
if (!(sequBlock.outer instanceof SequentialBlock))
return false;
sequBlock = (SequentialBlock) sequBlock.outer;
@ -88,13 +96,12 @@ public class CreateExpression implements Transformation {
/* Now, do the combination. Everything must succeed now.
*/
sequBlock = (SequentialBlock) ic.outer;
Expression[] exprs = new Expression[params];
sequBlock = (SequentialBlock) last.outer;
for (int i=params; ;) {
InstructionBlock block =
(InstructionBlock) sequBlock.subBlocks[0];
Expression expr = block.getInstruction();
Expression expr =
((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
if (!expr.isVoid()) {
exprs[--i] = expr;
@ -109,11 +116,20 @@ public class CreateExpression implements Transformation {
if(jode.Decompiler.isVerbose)
System.err.print('x');
ic.setInstruction(new ComplexExpression(op, exprs));
ic.moveDefinitions(sequBlock, ic);
ic.replace(sequBlock);
Expression newExpr;
if (params == 1 && op instanceof NopOperator) {
exprs[0].setType(op.getType());
newExpr = exprs[0];
} else
newExpr = new ComplexExpression(op, exprs);
if (parent != null)
parent.setSubExpressions(0, newExpr);
else
ic.setInstruction(newExpr);
ic.moveDefinitions(sequBlock, last);
last.replace(sequBlock);
return true;
}
return false;
}
}

@ -21,23 +21,19 @@ package jode.flow;
import jode.Expression;
import jode.StoreInstruction;
public class CreateForInitializer implements Transformation {
public class CreateForInitializer {
/**
* This combines an variable initializer into a for statement
* @param flow The FlowBlock that is transformed
* @param forBlock the for block
* @param last the lastModified of the flow block.
*/
public boolean transform(FlowBlock flow) {
public static boolean transform(LoopBlock forBlock, StructuredBlock last) {
if (!(flow.lastModified instanceof LoopBlock)
|| !(flow.lastModified.outer instanceof SequentialBlock))
if (!(last.outer instanceof SequentialBlock))
return false;
LoopBlock forBlock = (LoopBlock) flow.lastModified;
if (forBlock.type != forBlock.FOR || forBlock.init != null)
return false;
SequentialBlock sequBlock = (SequentialBlock) forBlock.outer;
SequentialBlock sequBlock = (SequentialBlock) last.outer;
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false;
@ -53,8 +49,8 @@ public class CreateForInitializer implements Transformation {
System.err.print('f');
forBlock.init = initializer;
forBlock.moveDefinitions(forBlock.outer, forBlock);
forBlock.replace(forBlock.outer);
forBlock.moveDefinitions(last.outer, null);
last.replace(last.outer);
return true;
}
}

@ -20,24 +20,109 @@
package jode.flow;
import jode.Type;
import jode.Expression;
import jode.ConstOperator;
import jode.ComplexExpression;
import jode.IfThenElseOperator;
import jode.CompareUnaryOperator;
import java.util.Enumeration;
import java.util.Vector;
public class CreateIfThenElseOperator implements Transformation {
public class CreateIfThenElseOperator {
/**
* This handles the body of createFunny. There are three cases:
*
* <pre>
* --------
* IF (c2)
* GOTO trueDest -> PUSH c2
* PUSH false
* --------
* PUSH bool -> PUSH bool
* --------
* if (c2)
* (handled recursively) -> PUSH (c2 ? expr1 : expr2)
* else
* (handled recursively)
* --------
* </pre>
*/
private static boolean createFunnyHelper(FlowBlock trueDest,
FlowBlock falseDest,
StructuredBlock block) {
if (block instanceof InstructionBlock
&& !((InstructionBlock)block).getInstruction().isVoid())
return true;
if (block instanceof IfThenElseBlock) {
IfThenElseBlock ifBlock = (IfThenElseBlock) block;
Expression expr1, expr2;
if (ifBlock.elseBlock == null)
return false;
if (!createFunnyHelper(trueDest, falseDest, ifBlock.thenBlock)
| !createFunnyHelper(trueDest, falseDest, ifBlock.elseBlock))
return false;
if (jode.Decompiler.isVerbose)
System.err.print('?');
IfThenElseOperator iteo = new IfThenElseOperator(Type.tBoolean);
((InstructionBlock)ifBlock.thenBlock).setInstruction
(new ComplexExpression
(iteo, new Expression[] {
ifBlock.cond,
((InstructionBlock) ifBlock.thenBlock).getInstruction(),
((InstructionBlock) ifBlock.elseBlock).getInstruction()
}));
ifBlock.thenBlock.moveDefinitions(ifBlock, null);
ifBlock.thenBlock.replace(ifBlock);
return true;
}
if (block instanceof SequentialBlock
&& block.getSubBlocks()[0] instanceof ConditionalBlock
&& block.getSubBlocks()[1] instanceof InstructionBlock) {
ConditionalBlock condBlock =
(ConditionalBlock) block.getSubBlocks()[0];
InstructionBlock pushBlock =
(InstructionBlock) block.getSubBlocks()[1];
if (!(pushBlock.getInstruction() instanceof ConstOperator))
return false;
ConstOperator constOp =
(ConstOperator) pushBlock.getInstruction();
if (condBlock.trueBlock.jump.destination == trueDest
&& constOp.getValue().equals("0")) {
Expression cond = condBlock.getInstruction();
condBlock.flowBlock.removeSuccessor(condBlock.trueBlock.jump);
condBlock.trueBlock.removeJump();
pushBlock.setInstruction(cond);
pushBlock.moveDefinitions(block, null);
pushBlock.replace(block);
return true;
}
}
return false;
}
/**
* This handles the more complicated form of the ?-:-operator used
* in a conditional block. The simplest case is:
* <pre>
* if (cond)
* push e1
* PUSH e1
* else {
* IF (c2)
* GOTO flow_2_
* push 0
* PUSH false
* }
* -&gt;IF (stack_0 == 0)
* GOTO flow_1_
@ -60,104 +145,35 @@ public class CreateIfThenElseOperator implements Transformation {
* sometimes be better replaced with a correct jump.
* @param flow The FlowBlock that is transformed
*/
public boolean createFunny(FlowBlock flow) {
if (!(flow.lastModified instanceof ConditionalBlock))
return false;
ConditionalBlock conditional = (ConditionalBlock) flow.lastModified;
public static boolean createFunny(ConditionalBlock cb,
StructuredBlock last) {
if (!(conditional.trueBlock instanceof EmptyBlock)
|| conditional.trueBlock.jump == null
|| conditional.jump == null
|| !(conditional.getInstruction() instanceof CompareUnaryOperator))
if (cb.jump == null
|| !(cb.getInstruction() instanceof CompareUnaryOperator)
|| !(last.outer instanceof SequentialBlock)
|| !(last.outer.getSubBlocks()[0] instanceof IfThenElseBlock))
return false;
CompareUnaryOperator compare =
(CompareUnaryOperator) conditional.getInstruction();
(CompareUnaryOperator) cb.getInstruction();
FlowBlock trueDestination;
if (compare.getOperatorIndex() == compare.EQUALS_OP)
trueDestination = conditional.jump.destination;
else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP)
trueDestination = conditional.trueBlock.jump.destination;
else
FlowBlock falseDestination;
if (compare.getOperatorIndex() == compare.EQUALS_OP) {
trueDestination = cb.jump.destination;
falseDestination = cb.trueBlock.jump.destination;
} else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP) {
falseDestination = cb.jump.destination;
trueDestination = cb.trueBlock.jump.destination;
} else
return false;
Expression[] e = new Expression[3];
IfThenElseBlock ifBlock;
try {
SequentialBlock sequBlock =
(SequentialBlock) conditional.outer;
ifBlock = (IfThenElseBlock) sequBlock.subBlocks[0];
while (true) {
if (ifBlock.thenBlock instanceof IfThenElseBlock)
ifBlock = (IfThenElseBlock) ifBlock.thenBlock;
else if (ifBlock.elseBlock instanceof IfThenElseBlock)
ifBlock = (IfThenElseBlock) ifBlock.elseBlock;
else
break;
}
e[0] = ifBlock.cond;
StructuredBlock[] subBlocks = ifBlock.getSubBlocks();
if (subBlocks.length != 2)
return false;
for (int i=0; i< 2; i++) {
if (subBlocks[i] instanceof InstructionBlock) {
e[i+1] = ((InstructionBlock)subBlocks[i]).getInstruction();
continue;
}
sequBlock = (SequentialBlock) subBlocks[i];
ConditionalBlock condBlock =
(ConditionalBlock) sequBlock.subBlocks[0];
InstructionBlock pushBlock =
(InstructionBlock) sequBlock.subBlocks[1];
jode.ConstOperator zero =
(jode.ConstOperator) pushBlock.getInstruction();
if (!zero.getValue().equals("0"))
return false;
if (!(condBlock.trueBlock instanceof EmptyBlock)
|| condBlock.trueBlock.jump == null
|| condBlock.jump != null
|| condBlock.trueBlock.jump.destination
!= trueDestination)
return false;
Expression cond = condBlock.getInstruction();
flow.removeSuccessor(condBlock.trueBlock.jump);
condBlock.trueBlock.removeJump();
pushBlock.setInstruction(cond);
pushBlock.moveDefinitions(sequBlock, pushBlock);
pushBlock.replace(sequBlock);
e[i+1] = cond;
}
} catch (ClassCastException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
if (jode.Decompiler.isVerbose)
System.err.print('?');
IfThenElseOperator iteo = new IfThenElseOperator
(Type.tSuperType(e[1].getType())
.intersection(Type.tSuperType(e[2].getType())));
((InstructionBlock)ifBlock.thenBlock).
setInstruction(new ComplexExpression(iteo, e));
ifBlock.thenBlock.moveDefinitions(ifBlock, ifBlock.thenBlock);
ifBlock.thenBlock.replace(ifBlock);
return true;
SequentialBlock sequBlock = (SequentialBlock) last.outer;
return createFunnyHelper(trueDestination, falseDestination,
sequBlock.subBlocks[0]);
}
/**
@ -176,57 +192,47 @@ public class CreateIfThenElseOperator implements Transformation {
* The <code>-&gt;</code> points to the lastModified block.
* @param flow The FlowBlock that is transformed
*/
public boolean create(FlowBlock flow) {
public static boolean create(InstructionContainer ic,
StructuredBlock last) {
Expression e[] = new Expression[3];
InstructionBlock thenBlock;
try {
InstructionBlock elseBlock = (InstructionBlock) flow.lastModified;
SequentialBlock sequBlock = (SequentialBlock)elseBlock.outer;
if (sequBlock.subBlocks[1] != elseBlock)
if (ic.jump == null
|| !(last.outer instanceof SequentialBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock)last.outer;
if (!(sequBlock.subBlocks[0] instanceof IfThenElseBlock))
return false;
IfThenElseBlock ifBlock = (IfThenElseBlock)sequBlock.subBlocks[0];
if (ifBlock.elseBlock != null)
if (!(ifBlock.thenBlock instanceof InstructionBlock)
|| ifBlock.thenBlock.jump == null
|| ifBlock.thenBlock.jump.destination != ic.jump.destination
|| ifBlock.elseBlock != null)
return false;
thenBlock = (InstructionBlock) ifBlock.thenBlock;
if (thenBlock.jump.destination != elseBlock.jump.destination)
return false;
e[1] = thenBlock.getInstruction();
if (e[1].isVoid())
return false;
e[2] = elseBlock.getInstruction();
e[2] = ic.getInstruction();
if (e[2].isVoid())
return false;
e[0] = ifBlock.cond;
} catch (ClassCastException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
if (jode.Decompiler.isVerbose)
System.err.print('?');
flow.removeSuccessor(thenBlock.jump);
thenBlock.flowBlock.removeSuccessor(thenBlock.jump);
thenBlock.removeJump();
IfThenElseOperator iteo = new IfThenElseOperator
(Type.tSuperType(e[1].getType())
.intersection(Type.tSuperType(e[2].getType())));
((InstructionBlock)flow.lastModified).
setInstruction(new ComplexExpression(iteo, e));
flow.lastModified.moveDefinitions(flow.lastModified.outer, null);
flow.lastModified.replace(flow.lastModified.outer);
ic.setInstruction(new ComplexExpression(iteo, e));
ic.moveDefinitions(last.outer, last);
last.replace(last.outer);
return true;
}
public boolean transform(FlowBlock flow) {
return createFunny(flow) || create(flow);
}
}

@ -24,13 +24,14 @@ import jode.ComplexExpression;
import jode.ConstructorOperator;
import jode.NewOperator;
public class CreateNewConstructor implements Transformation{
public class CreateNewConstructor {
public boolean transform(FlowBlock flow) {
public static boolean transform(InstructionContainer ic,
StructuredBlock last) {
/* Situation:
*
* new <object>
* DUP
* (optional DUP)
* PUSH load_ops
* optionally: <= used for "string1 += string2"
* DUP_X2
@ -43,23 +44,21 @@ public class CreateNewConstructor implements Transformation{
* optionally:
* DUP_X1 <= remove the depth
* [ n non void + some void expressions ]
* PUSH new <object>(stack_n-1,...,stack_0)
* (optional PUSH) new <object>(stack_n-1,...,stack_0)
*/
if (!(flow.lastModified instanceof InstructionBlock)
|| !(flow.lastModified.outer instanceof SequentialBlock))
if (!(last.outer instanceof SequentialBlock))
return false;
InstructionBlock block = (InstructionBlock) flow.lastModified;
if (!(block.getInstruction() instanceof InvokeOperator))
if (!(ic.getInstruction() instanceof InvokeOperator))
return false;
InvokeOperator constrCall = (InvokeOperator) block.getInstruction();
InvokeOperator constrCall = (InvokeOperator) ic.getInstruction();
if (!constrCall.isConstructor())
return false;
/* The rest should probably succeed */
int params = constrCall.getOperandCount() - 1;
SpecialBlock optDup = null;
SequentialBlock sequBlock = (SequentialBlock) block.outer;
SpecialBlock optDupX2 = null;
SequentialBlock sequBlock = (SequentialBlock) last.outer;
while (params > 0) {
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false;
@ -74,11 +73,11 @@ public class CreateNewConstructor implements Transformation{
instanceof SpecialBlock) {
/* handle the optional dup */
sequBlock = (SequentialBlock) sequBlock.outer;
optDup = (SpecialBlock) sequBlock.subBlocks[0];
if (optDup.type != SpecialBlock.DUP
|| optDup.depth != 2)
optDupX2 = (SpecialBlock) sequBlock.subBlocks[0];
if (optDupX2.type != SpecialBlock.DUP
|| optDupX2.depth != 2)
return false;
params = optDup.count;
params = optDupX2.count;
} else
return false;
}
@ -93,17 +92,20 @@ public class CreateNewConstructor implements Transformation{
&& sequBlock.outer instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.outer;
SpecialBlock dup = null;
if (sequBlock.outer instanceof SequentialBlock
&& sequBlock.subBlocks[0] instanceof SpecialBlock) {
SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
dup = (SpecialBlock) sequBlock.subBlocks[0];
if (dup.type != SpecialBlock.DUP
|| dup.count != 1 || dup.depth != 0)
return false;
sequBlock = (SequentialBlock)sequBlock.outer;
}
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false;
block = (InstructionBlock) sequBlock.subBlocks[0];
InstructionBlock block = (InstructionBlock) sequBlock.subBlocks[0];
if (!(block.getInstruction() instanceof NewOperator))
return false;
@ -112,15 +114,14 @@ public class CreateNewConstructor implements Transformation{
return false;
block.removeBlock();
if (dup != null)
dup.removeBlock();
if (optDup != null)
optDup.depth = 0;
((InstructionContainer) flow.lastModified).setInstruction
(new ConstructorOperator(constrCall.getClassType(),
constrCall.getMethodType()));
if (optDupX2 != null)
optDupX2.depth = 0;
ic.setInstruction(new ConstructorOperator(constrCall.getClassType(),
constrCall.getMethodType(),
dup == null));
return true;
}
return false;
}
}

@ -20,30 +20,28 @@
package jode.flow;
import jode.*;
public class CreatePrePostIncExpression implements Transformation {
public class CreatePrePostIncExpression {
public boolean transform(FlowBlock flow)
public static boolean transform(InstructionContainer ic,
StructuredBlock last)
{
return (createLocalPrePostInc(flow) || createPostInc(flow));
return (createLocalPrePostInc(ic, last) || createPostInc(ic, last));
}
public boolean createLocalPrePostInc(FlowBlock flow) {
IIncOperator iinc;
boolean isPost;
int op;
InstructionContainer lastBlock;
Type type;
try {
lastBlock = (InstructionContainer) flow.lastModified;
public static boolean createLocalPrePostInc(InstructionContainer ic,
StructuredBlock last) {
Expression instr2 = lastBlock.getInstruction();
SequentialBlock sequBlock = (SequentialBlock)lastBlock.outer;
if (sequBlock.subBlocks[1] != lastBlock)
return false;
InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0];
Expression instr1 = ib.getInstruction();
if (last.outer instanceof SequentialBlock
&& last.outer.getSubBlocks()[0] instanceof InstructionBlock) {
Expression instr1 = ((InstructionBlock)
last.outer.getSubBlocks()[0])
.getInstruction();
Expression instr2 = ic.getInstruction();
IIncOperator iinc;
LocalLoadOperator load;
boolean isPost;
if (instr1 instanceof IIncOperator
&& instr2 instanceof LocalLoadOperator) {
iinc = (IIncOperator) instr1;
@ -57,6 +55,7 @@ public class CreatePrePostIncExpression implements Transformation {
} else
return false;
int op;
if (iinc.getOperatorIndex() == iinc.ADD_OP + iinc.OPASSIGN_OP)
op = Operator.INC_OP;
else if (iinc.getOperatorIndex() == iinc.NEG_OP + iinc.OPASSIGN_OP)
@ -72,94 +71,124 @@ public class CreatePrePostIncExpression implements Transformation {
if (!iinc.matches(load))
return false;
type = load.getType().intersection(Type.tUInt);
} catch (NullPointerException ex) {
return false;
} catch (ClassCastException ex) {
return false;
}
Operator ppop = new LocalPrePostFixOperator(type, op, iinc, isPost);
lastBlock.setInstruction(ppop);
lastBlock.moveDefinitions(lastBlock.outer, lastBlock);
lastBlock.replace(lastBlock.outer);
Type type = load.getType().intersection(Type.tUInt);
Operator ppop =
new LocalPrePostFixOperator(type, op, iinc, isPost);
ic.setInstruction(ppop);
ic.moveDefinitions(last.outer, last);
last.replace(last.outer);
return true;
}
return false;
}
public boolean createPostInc(FlowBlock flow) {
StoreInstruction store;
int op;
Type type;
InstructionBlock lastBlock;
SequentialBlock sequBlock;
try {
lastBlock = (InstructionBlock) flow.lastModified;
public static boolean createPostInc(InstructionContainer ic,
StructuredBlock last) {
Expression storeExpr = lastBlock.getInstruction();
store = (StoreInstruction) storeExpr.getOperator();
if (!store.isVoid())
/* Situation:
*
* PUSH load/storeOps PUSH load/storeOps
* DUP load/storeOps PUSH store++/--
* load (unresolved)
* DUP ->
* PUSH +/-1
* IADD/SUB
* store (unresolved)
*
* load (no params) -> PUSH store++/--
* DUP
* PUSH +/-1
* store IADD/SUB
*/
if (!(ic.getInstruction().getOperator() instanceof StoreInstruction)
|| !(ic.getInstruction().isVoid()))
return false;
sequBlock = (SequentialBlock) lastBlock.outer;
if (sequBlock.subBlocks[1] != lastBlock)
StoreInstruction store =
(StoreInstruction) ic.getInstruction().getOperator();
if (!(last.outer instanceof SequentialBlock))
return false;
SequentialBlock sb = (SequentialBlock)last.outer;
BinaryOperator binOp;
InstructionBlock ib;
if (store.getLValueOperandCount() > 0) {
ib = (InstructionBlock) sequBlock.subBlocks[0];
binOp = (BinaryOperator) ib.getInstruction();
sequBlock = (SequentialBlock) sequBlock.outer;
} else
binOp = (BinaryOperator)
((ComplexExpression) storeExpr).getSubExpressions()[0];
Expression binOp;
if (store.getLValueOperandCount() == 0) {
if (!(ic.getInstruction() instanceof ComplexExpression))
return false;
binOp = ((ComplexExpression) ic.getInstruction())
.getSubExpressions()[0];
} else {
if (!(sb.subBlocks[0] instanceof InstructionBlock)
|| !(sb.outer instanceof SequentialBlock))
return false;
binOp = ((InstructionBlock) sb.subBlocks[0])
.getInstruction();
sb = (SequentialBlock) sb.outer;
}
if (!(binOp instanceof BinaryOperator))
return false;
if (binOp.getOperatorIndex() == store.ADD_OP)
int op;
if (binOp.getOperator().getOperatorIndex() == store.ADD_OP)
op = Operator.INC_OP;
else if (store.getOperatorIndex() == store.NEG_OP)
else if (binOp.getOperator().getOperatorIndex() == store.NEG_OP)
op = Operator.DEC_OP;
else
return false;
ib = (InstructionBlock) sequBlock.subBlocks[0];
ConstOperator constOp = (ConstOperator) ib.getInstruction();
if (!constOp.getValue().equals("1") &&
!constOp.getValue().equals("-1"))
if (!(sb.subBlocks[0] instanceof InstructionBlock))
return false;
InstructionBlock ib = (InstructionBlock) sb.subBlocks[0];
if (!(ib.getInstruction() instanceof ConstOperator))
return false;
ConstOperator constOp = (ConstOperator) ib.getInstruction();
if (constOp.getValue().equals("-1"))
op ^= 1;
else if (!constOp.getValue().equals("1"))
return false;
sequBlock = (SequentialBlock) sequBlock.outer;
SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
if (!(sb.outer instanceof SequentialBlock))
return false;
sb = (SequentialBlock) sb.outer;
if (!(sb.subBlocks[0] instanceof SpecialBlock))
return false;
SpecialBlock dup = (SpecialBlock) sb.subBlocks[0];
if (dup.type != SpecialBlock.DUP
|| dup.count != store.getLValueType().stackSize()
|| dup.depth != store.getLValueOperandCount())
return false;
sequBlock = (SequentialBlock) sequBlock.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
Operator load = (Operator) ib.getInstruction();
if (!store.matches(load))
if (!(sb.outer instanceof SequentialBlock))
return false;
sb = (SequentialBlock) sb.outer;
if (!(sb.subBlocks[0] instanceof InstructionBlock))
return false;
ib = (InstructionBlock) sb.subBlocks[0];
if (!(ib.getInstruction() instanceof Operator)
|| !store.matches((Operator) ib.getInstruction()))
return false;
if (store.getLValueOperandCount() > 0) {
sequBlock = (SequentialBlock) sequBlock.outer;
SpecialBlock dup2 = (SpecialBlock) sequBlock.subBlocks[0];
if (!(sb.outer instanceof SequentialBlock))
return false;
sb = (SequentialBlock) sb.outer;
if (!(sb.subBlocks[0] instanceof SpecialBlock))
return false;
SpecialBlock dup2 = (SpecialBlock) sb.subBlocks[0];
if (dup2.type != SpecialBlock.DUP
|| dup2.count != store.getLValueOperandCount()
|| dup2.depth != 0)
return false;
}
type = load.getType().intersection(store.getLValueType());
} catch (NullPointerException ex) {
return false;
} catch (ClassCastException ex) {
return false;
}
Operator postop = new PrePostFixOperator(type, op, store, true);
lastBlock.setInstruction(postop);
lastBlock.moveDefinitions(sequBlock, lastBlock);
lastBlock.replace(sequBlock);
ic.setInstruction
(new PrePostFixOperator(store.getLValueType(), op, store, true));
ic.moveDefinitions(sb, last);
last.replace(sb);
return true;
}
}

@ -199,73 +199,69 @@ public class FlowBlock {
ConditionalBlock cb = (ConditionalBlock) jump.prev.outer;
Expression instr = cb.getInstruction();
/* If this is the first instruction of a while and the
* condition of the while is true, use the condition
* as while condition.
*/
if (cb.outer instanceof LoopBlock
|| (cb.outer instanceof SequentialBlock
&& cb.outer.getSubBlocks()[0] == cb
&& cb.outer.outer instanceof LoopBlock)) {
LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ?
(LoopBlock) cb.outer : (LoopBlock) cb.outer.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() != LoopBlock.DOWHILE &&
(loopBlock.jumpMayBeChanged()
|| loopBlock.getNextFlowBlock() == succ)) {
if (loopBlock.jump == null) {
/* consider this jump again */
loopBlock.moveJump(jump);
jumps = jump;
} else
jump.prev.removeJump();
loopBlock.setCondition(instr.negate());
loopBlock.moveDefinitions(cb, null);
cb.removeBlock();
continue;
}
} else if (cb.outer instanceof SequentialBlock
&& cb.outer.getSubBlocks()[1] == cb) {
/* And now for do/while loops, where the jump is
* at the end of the loop.
*/
/* First find the beginning of the loop */
StructuredBlock sb = cb.outer.outer;
while (sb instanceof SequentialBlock) {
sb = sb.outer;
}
/* sb is now the first and cb is the last
* instruction in the current block.
*/
if (sb instanceof LoopBlock) {
LoopBlock loopBlock = (LoopBlock) sb;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() == LoopBlock.WHILE &&
(loopBlock.jumpMayBeChanged()
|| loopBlock.getNextFlowBlock() == succ)) {
if (loopBlock.jump == null) {
/* consider this jump again */
loopBlock.moveJump(jump);
jumps = jump;
} else
jump.prev.removeJump();
loopBlock.setType(LoopBlock.DOWHILE);
loopBlock.setCondition(instr.negate());
loopBlock.moveDefinitions(cb, null);
cb.removeBlock();
continue;
}
}
}
// if (cb.outer instanceof LoopBlock
// || (cb.outer instanceof SequentialBlock
// && cb.outer.getSubBlocks()[0] == cb
// && cb.outer.outer instanceof LoopBlock)) {
// LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ?
// (LoopBlock) cb.outer : (LoopBlock) cb.outer.outer;
// if (loopBlock.getCondition() == LoopBlock.TRUE &&
// loopBlock.getType() != LoopBlock.DOWHILE &&
// (loopBlock.jumpMayBeChanged()
// || loopBlock.getNextFlowBlock() == succ)) {
// if (loopBlock.jump == null) {
// /* consider this jump again */
// loopBlock.moveJump(jump);
// jumps = jump;
// } else
// jump.prev.removeJump();
// loopBlock.setCondition(instr.negate());
// loopBlock.moveDefinitions(cb, null);
// cb.removeBlock();
// continue;
// }
// } else if (cb.outer instanceof SequentialBlock
// && cb.outer.getSubBlocks()[1] == cb) {
// /* And now for do/while loops, where the jump is
// * at the end of the loop.
// */
// /* First find the beginning of the loop */
// StructuredBlock sb = cb.outer.outer;
// while (sb instanceof SequentialBlock) {
// sb = sb.outer;
// }
// /* sb is now the first and cb is the last
// * instruction in the current block.
// */
// if (sb instanceof LoopBlock) {
// LoopBlock loopBlock = (LoopBlock) sb;
// if (loopBlock.getCondition() == LoopBlock.TRUE &&
// loopBlock.getType() == LoopBlock.WHILE &&
// (loopBlock.jumpMayBeChanged()
// || loopBlock.getNextFlowBlock() == succ)) {
// if (loopBlock.jump == null) {
// /* consider this jump again */
// loopBlock.moveJump(jump);
// jumps = jump;
// } else
// jump.prev.removeJump();
// loopBlock.setType(LoopBlock.DOWHILE);
// loopBlock.setCondition(instr.negate());
// loopBlock.moveDefinitions(cb, null);
// cb.removeBlock();
// continue;
// }
// }
// }
/* replace all conditional jumps to the successor, which
* are followed by a block which has the end of the block
@ -599,6 +595,30 @@ public class FlowBlock {
}
}
/**
* This is a special T1 transformation, that does also succeed, if
* the jumps in the flow block are not yet resolved. But it has
* a special precondition: The succ must be a simple instruction block,
* mustn't have another predecessor and all structured blocks in this
* flow block must be simple instruction blocks.
*/
public void doSequentialT1(StructuredBlock succ, int length) {
VariableSet succIn = new VariableSet();
succ.fillInGenSet(succIn, this.gen);
succIn.merge(lastModified.jump.gen);
succIn.subtract(lastModified.jump.kill);
succ.jump.gen.mergeGenKill(lastModified.jump.gen, succ.jump.kill);
succ.jump.kill.add(lastModified.jump.kill);
this.in.unionExact(succIn);
lastModified.removeJump();
lastModified = lastModified.appendBlock(succ);
this.length += length;
doTransformations();
}
/**
* Do a T1 transformation with succ if possible. It is possible,
* iff succ has exactly this block as predecessor.
@ -619,19 +639,25 @@ public class FlowBlock {
/* Update the in/out-Vectors now */
updateInOut(succ, jumps);
if (Decompiler.isFlowDebugging)
System.err.println("before Optimize: "+this);
/* Try to eliminate as many jumps as possible.
*/
jumps = optimizeJumps(jumps, succ);
if (Decompiler.isFlowDebugging)
System.err.println("before Remaining: "+this);
resolveRemaining(jumps);
if (Decompiler.isFlowDebugging)
System.err.println("after Optimize: "+this);
/* Now unify the blocks.
*/
lastModified.appendBlock(succ.block);
lastModified = lastModified.appendBlock(succ.block);
mergeSuccessors(succ);
/* Set last modified to the new correct value. */
lastModified = succ.lastModified;
/* This will also set last modified to the new correct value. */
doTransformations();
/* Set addr+length to correct value. */
if (succ.addr < addr)
@ -643,6 +669,44 @@ public class FlowBlock {
return true;
}
/**
* Find the exit condition of a for/while block. The loop block
* mustn't have an exit condition yet.
*/
public void mergeCondition() {
/* If the first instruction of a while is a conditional
* block, which jumps to the next address use the condition
* as while condition.
*/
LoopBlock loopBlock = (LoopBlock) lastModified;
int loopType = loopBlock.getType();
ConditionalBlock cb = null;
if (loopBlock.bodyBlock instanceof ConditionalBlock)
cb = (ConditionalBlock) loopBlock.bodyBlock;
else if (loopBlock.bodyBlock instanceof SequentialBlock
&& loopBlock.bodyBlock.getSubBlocks()[0]
instanceof ConditionalBlock)
cb = (ConditionalBlock) loopBlock.bodyBlock.getSubBlocks()[0];
else if (loopBlock.bodyBlock instanceof SequentialBlock
&& loopType == LoopBlock.WHILE) {
loopType = LoopBlock.DOWHILE;
SequentialBlock sequBlock = (SequentialBlock) loopBlock.bodyBlock;
while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
if (sequBlock.subBlocks[1] instanceof ConditionalBlock)
cb = (ConditionalBlock) sequBlock.subBlocks[1];
}
if (cb != null
&& cb.trueBlock.jump.destination.addr == addr + length) {
loopBlock.moveJump(cb.trueBlock.jump);
loopBlock.setCondition(cb.getInstruction().negate());
loopBlock.setType(loopType);
loopBlock.moveDefinitions(cb, null);
cb.removeBlock();
}
}
public boolean doT2(int start, int end) {
/* If there are no jumps to the beginning of this flow block
@ -800,6 +864,7 @@ public class FlowBlock {
*/
predecessors.removeElement(this);
lastModified = block;
mergeCondition();
/* T2 analysis succeeded */
checkConsistent();
@ -881,20 +946,20 @@ public class FlowBlock {
checkConsistent();
}
public void doTransformations() {
if (Decompiler.isFlowDebugging)
System.err.println("before Transformation: "+this);
static Transformation[] exprTrafos = {
new RemoveEmpty(),
new CreateExpression(),
new CreatePrePostIncExpression(),
new CreateAssignExpression(),
new CreateNewConstructor(),
new CombineIfGotoExpressions(),
new CreateIfThenElseOperator(),
new CreateConstantArray(),
new CreateForInitializer(),
new CompleteSynchronized(),
};
while (lastModified instanceof SequentialBlock) {
if (!lastModified.getSubBlocks()[0].doTransformations())
lastModified = lastModified.getSubBlocks()[1];
}
while (lastModified.doTransformations())
/* empty */;
if (Decompiler.isFlowDebugging)
System.err.println("after Transformation: "+this);
}
/**
* Search for an apropriate successor.
@ -944,21 +1009,12 @@ public class FlowBlock {
while (true) {
if (Decompiler.isFlowDebugging)
System.err.println("before Transformation: "+this);
/* First do some non flow transformations. */
int i=0;
while (i < exprTrafos.length) {
if (exprTrafos[i].transform(this))
i = 0;
else
i++;
checkConsistent();
if (lastModified instanceof SwitchBlock) {
/* analyze the switch first.
*/
analyzeSwitch(start, end);
}
if (Decompiler.isFlowDebugging)
System.err.println("after Transformation: "+this);
if (doT2(start, end)) {
@ -989,20 +1045,6 @@ public class FlowBlock {
+ addr + " - " + (addr+length));
return changed;
} else {
if (succ.block instanceof SwitchBlock) {
/* analyze succ, the new region is the
* continuous region of
* [start,end) \cap \compl [addr, addr+length)
* where succ.addr lies in.
*/
int newStart = (succ.addr > addr)
? addr+length : start;
int newEnd = (succ.addr > addr)
? end : addr;
if (succ.analyzeSwitch(newStart, newEnd))
break;
}
if ((succ.addr == addr+length
|| succ.addr+succ.length == addr)
/* Only do T1 transformation if the blocks are
@ -1058,14 +1100,14 @@ public class FlowBlock {
* regions. Only blocks whose address lies in the given address
* range are considered and it is taken care of, that the switch
* is never leaved. <p>
* The current flow block must contain the switch block as main
* block.
* The current flow block must contain the switch block as lastModified
* @param start the start of the address range.
* @param end the end of the address range.
*/
public boolean analyzeSwitch(int start, int end) {
SwitchBlock switchBlock = (SwitchBlock) block;
SwitchBlock switchBlock = (SwitchBlock) lastModified;
boolean changed = false;
int last = -1;
FlowBlock lastFlow = null;
for (int i=0; i < switchBlock.caseBlocks.length; i++) {
@ -1165,10 +1207,12 @@ public class FlowBlock {
jump.destination = END_OF_METHOD;
else
jump.destination = instr[jump.destAddr];
}
if (jump.destination == null)
throw new AssertError("Missing dest: "+jump.destAddr);
addSuccessor(jump);
}
}
}
/**
* Mark the flow block as first flow block in a method.

@ -56,6 +56,16 @@ public abstract class InstructionContainer extends StructuredBlock {
}
}
public boolean doTransformations() {
StructuredBlock last = flowBlock.lastModified;
return CreateNewConstructor.transform(this, last)
|| CreateExpression.transform(this, last)
|| CreatePrePostIncExpression.transform(this, last)
|| CreateAssignExpression.transform(this, last)
|| CreateIfThenElseOperator.create(this, last)
|| CreateConstantArray.transform(this, last);
}
/**
* Get the contained instruction.
* @return the contained instruction.

@ -253,4 +253,10 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
public boolean jumpMayBeChanged() {
return mayChangeJump;
}
public boolean doTransformations() {
return type == FOR && init == null
&& CreateForInitializer.transform(this, flowBlock.lastModified);
}
}

@ -21,41 +21,10 @@ package jode.flow;
import jode.Expression;
import jode.NopOperator;
public class RemoveEmpty implements Transformation {
public class RemoveEmpty {
public boolean transform (FlowBlock fb) {
return (removeNop(fb) || removeSwap(fb) || removeEmpty(fb));
}
public boolean removeNop(FlowBlock flow) {
StructuredBlock block = flow.lastModified;
if (block instanceof InstructionContainer
&& block.outer instanceof SequentialBlock
&& block.outer.getSubBlocks()[0] instanceof InstructionBlock) {
InstructionContainer ic = (InstructionContainer) block;
Expression nopInstr = ic.getInstruction();
if (!(nopInstr instanceof NopOperator)
|| nopInstr.getType() == jode.Type.tVoid)
return false;
InstructionBlock prev =
(InstructionBlock) ic.outer.getSubBlocks()[0];
Expression instr = prev.getInstruction();
if (instr.getType() == jode.Type.tVoid)
return false;
instr.setType(nopInstr.getType());
ic.setInstruction(instr);
ic.replace(ic.outer);
return true;
}
return false;
}
public boolean removeSwap(FlowBlock flow) {
public static boolean removeSwap(SpecialBlock swapBlock,
StructuredBlock last) {
/* Remove non needed swaps; convert:
*
* PUSH expr1
@ -67,37 +36,43 @@ public class RemoveEmpty implements Transformation {
* PUSH expr2
* PUSH expr1
*/
StructuredBlock block = flow.lastModified;
if (block instanceof SpecialBlock
&& ((SpecialBlock)block).type == SpecialBlock.SWAP
&& block.outer instanceof SequentialBlock
&& block.outer.outer instanceof SequentialBlock
&& block.outer.getSubBlocks()[0] instanceof InstructionBlock
&& block.outer.outer.getSubBlocks()[0]
if (last.outer instanceof SequentialBlock
&& last.outer.outer instanceof SequentialBlock
&& last.outer.getSubBlocks()[0] instanceof InstructionBlock
&& last.outer.outer.getSubBlocks()[0]
instanceof InstructionBlock) {
InstructionBlock block1
= (InstructionBlock) block.outer.outer.getSubBlocks()[0];
= (InstructionBlock) last.outer.outer.getSubBlocks()[0];
InstructionBlock block2
= (InstructionBlock) block.outer.getSubBlocks()[0];
= (InstructionBlock) last.outer.getSubBlocks()[0];
/* XXX check if blocks may be swapped
* (there mustn't be side effects in one of them).
*/
System.err.println("WARNING: this program contains a SWAP "
+"opcode and may not be translated correctly.");
if (block1.getInstruction().isVoid()
|| block2.getInstruction().isVoid())
return false;
/* PUSH expr1 == block1
* PUSH expr2
* SWAP
* ...
*/
block.outer.replace(block1.outer);
last.outer.replace(block1.outer);
/* PUSH expr2
* SWAP
* ...
*/
block1.replace(block);
block1.moveJump(block.jump);
block1.replace(swapBlock);
block1.moveJump(swapBlock.jump);
/* PUSH expr2
* PUSH expr1
*/
flow.lastModified = block1;
block1.flowBlock.lastModified = block1.outer;
return true;
}
return false;

@ -56,4 +56,9 @@ public class SpecialBlock extends StructuredBlock {
+ ((count == 1) ? "" : "2")
+ ((depth == 0) ? "" : "_X"+depth));
}
public boolean doTransformation() {
return type == SWAP
&& RemoveEmpty.removeSwap(this, flowBlock.lastModified);
}
}

@ -191,7 +191,7 @@ public abstract class StructuredBlock {
/**
* Removes the jump. This does not update the successors vector
* of the flow block, you have to do it yourself. */
public void removeJump() {
public final void removeJump() {
if (jump != null) {
jump.prev = null;
jump = null;
@ -208,21 +208,15 @@ public abstract class StructuredBlock {
* will be moved to this block (may be this).
*/
void moveDefinitions(StructuredBlock from, StructuredBlock sub) {
if (from != sub && from != this) {
/* define(...) will not move from blocks, that are not sub blocks,
* so we do it by hand.
*/
java.util.Enumeration enum = from.used.elements();
while (enum.hasMoreElements()) {
LocalInfo var =
((LocalInfo) enum.nextElement()).getLocalInfo();
if (!used.contains(var))
used.addElement(var);
}
while (from != sub && from != this) {
used.unionExact(from.used);
from.used.removeAllElements();
StructuredBlock[] subs = from.getSubBlocks();
for (int i=0; i<subs.length; i++)
if (subs.length == 0)
return;
for (int i=0; i<subs.length - 1; i++)
moveDefinitions(subs[i], sub);
from = subs[subs.length-1];
}
}
@ -282,12 +276,17 @@ public abstract class StructuredBlock {
* @return the new combined block.
*/
public StructuredBlock appendBlock(StructuredBlock block) {
if (block instanceof EmptyBlock) {
moveJump(block.jump);
return this;
} else {
SequentialBlock sequBlock = new SequentialBlock();
sequBlock.replace(this);
sequBlock.setFirst(this);
sequBlock.setSecond(block);
return sequBlock;
}
}
/**
* Removes this block, or replaces it with an EmptyBlock.
@ -318,14 +317,6 @@ public abstract class StructuredBlock {
return false;
}
public void define(VariableSet vars) {
java.util.Enumeration enum = vars.elements();
while (enum.hasMoreElements()) {
LocalInfo var = ((LocalInfo) enum.nextElement()).getLocalInfo();
used.addElement(var);
}
}
public VariableSet propagateUsage() {
StructuredBlock[] subs = getSubBlocks();
VariableSet allUse = (VariableSet) used.clone();
@ -371,7 +362,7 @@ public abstract class StructuredBlock {
}
subs[i].checkConsistent();
}
if (jump != null) {
if (jump != null && jump.destination != null) {
Jump jumps = (Jump) flowBlock.successors.get(jump.destination);
for (; jumps != jump; jumps = jumps.next) {
if (jumps == null)
@ -484,5 +475,12 @@ public abstract class StructuredBlock {
return super.toString();
}
}
/**
* Do simple transformation on the structuredBlock.
*/
public boolean doTransformations() {
return false;
}
}

@ -91,4 +91,8 @@ public class SynchronizedBlock extends StructuredBlock {
writer.untab();
writer.println("}");
}
public boolean doTransformations() {
return CompleteSynchronized.transform(this, flowBlock.lastModified);
}
}

@ -192,7 +192,7 @@ public class ClassInterfacesType extends Type {
return tError;
ClassInterfacesType other = (ClassInterfacesType) type;
Class clazz = null;
Class clazz;
Vector ifaces = new Vector();
/* First determine the clazz, one of the two classes must be a sub

Loading…
Cancel
Save