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

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

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

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

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

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

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

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

@ -26,104 +26,106 @@ import jode.ConstantArrayOperator;
import jode.ConstOperator; import jode.ConstOperator;
import jode.Type; import jode.Type;
public class CreateConstantArray implements Transformation { public class CreateConstantArray {
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;
int lastindex = -1; public static boolean transform(InstructionContainer ic,
while (ib.getInstruction() instanceof ArrayStoreOperator) { StructuredBlock last) {
ArrayStoreOperator store = /* Situation:
(ArrayStoreOperator) ib.getInstruction(); * PUSH new Array[]
* DUP
* PUSH index
* PUSH value
* stack_2[stack_1] = stack_0
* ...
*/
if (last.outer instanceof SequentialBlock) {
sequBlock = (SequentialBlock) sequBlock.outer; SequentialBlock sequBlock = (SequentialBlock) last.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
Expression lastconst = ib.getInstruction();
sequBlock = (SequentialBlock) sequBlock.outer; if (!(ic.getInstruction() instanceof ArrayStoreOperator)
ib = (InstructionBlock) sequBlock.subBlocks[0]; || !(sequBlock.subBlocks[0] instanceof InstructionBlock)
Expression indexexpr = ib.getInstruction(); || !(sequBlock.outer instanceof SequentialBlock))
ConstOperator indexop =
(ConstOperator) indexexpr.getOperator();
if (!indexop.getType().isOfType(Type.tUInt))
return false; return false;
int index = Integer.parseInt(indexop.getValue()); ArrayStoreOperator store
if (index >= 0 && consts == null) { = (ArrayStoreOperator) ic.getInstruction();
lastindex = index; InstructionBlock ib = (InstructionBlock)sequBlock.subBlocks[0];
consts = new Expression[lastindex+1]; sequBlock = (SequentialBlock) sequBlock.outer;
} else if (index < 0 || index > lastindex)
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)
|| !(sequBlock.outer instanceof SequentialBlock))
return false; return false;
else {
while (index < lastindex) { Expression expr = ib.getInstruction();
consts[lastindex--] = ib = (InstructionBlock)sequBlock.subBlocks[0];
new ConstOperator(Type.tUnknown, "0");
}
}
consts[lastindex--] = lastconst;
sequBlock = (SequentialBlock) sequBlock.outer; 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]; 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.depth != 0
|| dup.count != store.getLValueType().stackSize()) || dup.count != store.getLValueType().stackSize()
|| !(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false; return false;
count++;
sequBlock = (SequentialBlock) sequBlock.outer; int index = Integer.parseInt(indexOp.getValue());
ib = (InstructionBlock)sequBlock.subBlocks[0]; ib = (InstructionBlock)sequBlock.subBlocks[0];
}
if (count == 0) if (ib.getInstruction() instanceof ComplexExpression
return false; && (ib.getInstruction().getOperator()
while (lastindex >= 0) instanceof NewArrayOperator)) {
consts[lastindex--] = new ConstOperator(Type.tUnknown, "0"); /* This is the first element */
ComplexExpression newArrayExpr = ComplexExpression newArrayExpr =
(ComplexExpression) ib.getInstruction(); (ComplexExpression) ib.getInstruction();
NewArrayOperator newArrayOp = NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator(); (NewArrayOperator) newArrayExpr.getOperator();
type = newArrayOp.getType(); if (newArrayOp.getOperandCount() != 1
if (newArrayOp.getOperandCount() != 1) || !(newArrayExpr.getSubExpressions()[0]
instanceof ConstOperator))
return false; return false;
Expression countexpr = newArrayExpr.getSubExpressions()[0];
ConstOperator countop = ConstOperator countop =
(ConstOperator) countexpr.getOperator(); (ConstOperator) newArrayExpr.getSubExpressions()[0];
if (!countop.getType().isOfType(Type.tUInt)) if (!countop.getType().isOfType(Type.tUInt))
return false; return false;
int arraylength = Integer.parseInt(countop.getValue()); int arraylength = Integer.parseInt(countop.getValue());
if (arraylength != consts.length) { if (arraylength <= index)
if (arraylength < consts.length)
return false; 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) if (jode.Decompiler.isVerbose)
System.err.print("a"); System.err.print('a');
lastBlock.setInstruction ConstantArrayOperator cao
(new ComplexExpression = new ConstantArrayOperator(newArrayOp.getType(),
(new ConstantArrayOperator(type, consts.length), arraylength);
consts)); cao.setValue(index, expr);
lastBlock.moveDefinitions(sequBlock.subBlocks[0], lastBlock); ic.setInstruction(cao);
lastBlock.replace(sequBlock.subBlocks[0]); ic.moveDefinitions(sequBlock, last);
flow.lastModified.moveDefinitions(sequBlock.subBlocks[1], last.replace(sequBlock);
flow.lastModified);
flow.lastModified.replace(sequBlock.subBlocks[1]);
return true; 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; package jode.flow;
import jode.Operator; import jode.Operator;
import jode.NopOperator;
import jode.Expression; import jode.Expression;
import jode.ComplexExpression; import jode.ComplexExpression;
@ -32,47 +33,53 @@ import jode.ComplexExpression;
* expr(op, [ expr_1, ..., expr_n ]) * expr(op, [ expr_1, ..., expr_n ])
* </pre> * </pre>
*/ */
public class CreateExpression implements Transformation { public class CreateExpression {
/** /**
* This does the transformation. * This does the transformation.
* @param FlowBlock the flow block to transform. * @param FlowBlock the flow block to transform.
* @return true if flow block was simplified. * @return true if flow block was simplified.
*/ */
public boolean transform(FlowBlock flow) { public static boolean transform(InstructionContainer ic,
if (!(flow.lastModified instanceof InstructionContainer) StructuredBlock last) {
|| !(flow.lastModified.outer instanceof SequentialBlock))
int params = ic.getInstruction().getOperandCount();
if (params == 0)
return false; return false;
InstructionContainer ic = (InstructionContainer) flow.lastModified; ComplexExpression parent = null;
if (ic.getInstruction() instanceof Operator) { Expression inner = ic.getInstruction();
while (inner instanceof ComplexExpression) {
parent = (ComplexExpression)inner;
inner = parent.getSubExpressions()[0];
}
Operator op = (Operator) ic.getInstruction(); if (!(inner instanceof Operator))
int params = op.getOperandCount();
if (params == 0)
return false; 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. /* First check if Expression can be created, but do nothing yet.
*/ */
Expression lastExpression = null;
for (int i = params;;) { for (int i = params;;) {
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)) if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false; return false;
InstructionBlock block = Expression expr =
(InstructionBlock) sequBlock.subBlocks[0]; ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
Expression expr = block.getInstruction();
if (!expr.isVoid()) { if (!expr.isVoid()) {
if (--i == 0) if (--i == 0)
break; break;
} else if (lastExpression != null } else if (lastExpression == null
&& lastExpression.canCombine(expr) <= 0) || lastExpression.canCombine(expr) <= 0)
return false; return false;
if (expr.getOperandCount() > 0) if (expr.getOperandCount() > 0)
@ -81,6 +88,7 @@ public class CreateExpression implements Transformation {
return false; return false;
lastExpression = expr; lastExpression = expr;
if (!(sequBlock.outer instanceof SequentialBlock)) if (!(sequBlock.outer instanceof SequentialBlock))
return false; return false;
sequBlock = (SequentialBlock) sequBlock.outer; sequBlock = (SequentialBlock) sequBlock.outer;
@ -88,13 +96,12 @@ public class CreateExpression implements Transformation {
/* Now, do the combination. Everything must succeed now. /* 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; ;) { for (int i=params; ;) {
InstructionBlock block = Expression expr =
(InstructionBlock) sequBlock.subBlocks[0]; ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
Expression expr = block.getInstruction();
if (!expr.isVoid()) { if (!expr.isVoid()) {
exprs[--i] = expr; exprs[--i] = expr;
@ -109,11 +116,20 @@ public class CreateExpression implements Transformation {
if(jode.Decompiler.isVerbose) if(jode.Decompiler.isVerbose)
System.err.print('x'); System.err.print('x');
ic.setInstruction(new ComplexExpression(op, exprs)); Expression newExpr;
ic.moveDefinitions(sequBlock, ic); if (params == 1 && op instanceof NopOperator) {
ic.replace(sequBlock); 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 true;
} }
return false;
}
} }

@ -21,23 +21,19 @@ package jode.flow;
import jode.Expression; import jode.Expression;
import jode.StoreInstruction; import jode.StoreInstruction;
public class CreateForInitializer implements Transformation { public class CreateForInitializer {
/** /**
* This combines an variable initializer into a for statement * 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) if (!(last.outer instanceof SequentialBlock))
|| !(flow.lastModified.outer instanceof SequentialBlock))
return false; return false;
LoopBlock forBlock = (LoopBlock) flow.lastModified; SequentialBlock sequBlock = (SequentialBlock) last.outer;
if (forBlock.type != forBlock.FOR || forBlock.init != null)
return false;
SequentialBlock sequBlock = (SequentialBlock) forBlock.outer;
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)) if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false; return false;
@ -53,8 +49,8 @@ public class CreateForInitializer implements Transformation {
System.err.print('f'); System.err.print('f');
forBlock.init = initializer; forBlock.init = initializer;
forBlock.moveDefinitions(forBlock.outer, forBlock); forBlock.moveDefinitions(last.outer, null);
forBlock.replace(forBlock.outer); last.replace(last.outer);
return true; return true;
} }
} }

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

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

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

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

@ -253,4 +253,10 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
public boolean jumpMayBeChanged() { public boolean jumpMayBeChanged() {
return mayChangeJump; 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.Expression;
import jode.NopOperator; import jode.NopOperator;
public class RemoveEmpty implements Transformation { public class RemoveEmpty {
public boolean transform (FlowBlock fb) { public static boolean removeSwap(SpecialBlock swapBlock,
return (removeNop(fb) || removeSwap(fb) || removeEmpty(fb)); StructuredBlock last) {
}
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) {
/* Remove non needed swaps; convert: /* Remove non needed swaps; convert:
* *
* PUSH expr1 * PUSH expr1
@ -67,37 +36,43 @@ public class RemoveEmpty implements Transformation {
* PUSH expr2 * PUSH expr2
* PUSH expr1 * PUSH expr1
*/ */
StructuredBlock block = flow.lastModified; if (last.outer instanceof SequentialBlock
if (block instanceof SpecialBlock && last.outer.outer instanceof SequentialBlock
&& ((SpecialBlock)block).type == SpecialBlock.SWAP && last.outer.getSubBlocks()[0] instanceof InstructionBlock
&& block.outer instanceof SequentialBlock && last.outer.outer.getSubBlocks()[0]
&& block.outer.outer instanceof SequentialBlock
&& block.outer.getSubBlocks()[0] instanceof InstructionBlock
&& block.outer.outer.getSubBlocks()[0]
instanceof InstructionBlock) { instanceof InstructionBlock) {
InstructionBlock block1 InstructionBlock block1
= (InstructionBlock) block.outer.outer.getSubBlocks()[0]; = (InstructionBlock) last.outer.outer.getSubBlocks()[0];
InstructionBlock block2 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() if (block1.getInstruction().isVoid()
|| block2.getInstruction().isVoid()) || block2.getInstruction().isVoid())
return false; return false;
/* PUSH expr1 == block1 /* PUSH expr1 == block1
* PUSH expr2 * PUSH expr2
* SWAP * SWAP
* ...
*/ */
block.outer.replace(block1.outer); last.outer.replace(block1.outer);
/* PUSH expr2 /* PUSH expr2
* SWAP * SWAP
* ...
*/ */
block1.replace(block); block1.replace(swapBlock);
block1.moveJump(block.jump); block1.moveJump(swapBlock.jump);
/* PUSH expr2 /* PUSH expr2
* PUSH expr1 * PUSH expr1
*/ */
flow.lastModified = block1; block1.flowBlock.lastModified = block1.outer;
return true; return true;
} }
return false; return false;

@ -56,4 +56,9 @@ public class SpecialBlock extends StructuredBlock {
+ ((count == 1) ? "" : "2") + ((count == 1) ? "" : "2")
+ ((depth == 0) ? "" : "_X"+depth)); + ((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 * Removes the jump. This does not update the successors vector
* of the flow block, you have to do it yourself. */ * of the flow block, you have to do it yourself. */
public void removeJump() { public final void removeJump() {
if (jump != null) { if (jump != null) {
jump.prev = null; jump.prev = null;
jump = null; jump = null;
@ -208,21 +208,15 @@ public abstract class StructuredBlock {
* will be moved to this block (may be this). * will be moved to this block (may be this).
*/ */
void moveDefinitions(StructuredBlock from, StructuredBlock sub) { void moveDefinitions(StructuredBlock from, StructuredBlock sub) {
if (from != sub && from != this) { while (from != sub && from != this) {
/* define(...) will not move from blocks, that are not sub blocks, used.unionExact(from.used);
* 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);
}
from.used.removeAllElements(); from.used.removeAllElements();
StructuredBlock[] subs = from.getSubBlocks(); 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); moveDefinitions(subs[i], sub);
from = subs[subs.length-1];
} }
} }
@ -282,12 +276,17 @@ public abstract class StructuredBlock {
* @return the new combined block. * @return the new combined block.
*/ */
public StructuredBlock appendBlock(StructuredBlock block) { public StructuredBlock appendBlock(StructuredBlock block) {
if (block instanceof EmptyBlock) {
moveJump(block.jump);
return this;
} else {
SequentialBlock sequBlock = new SequentialBlock(); SequentialBlock sequBlock = new SequentialBlock();
sequBlock.replace(this); sequBlock.replace(this);
sequBlock.setFirst(this); sequBlock.setFirst(this);
sequBlock.setSecond(block); sequBlock.setSecond(block);
return sequBlock; return sequBlock;
} }
}
/** /**
* Removes this block, or replaces it with an EmptyBlock. * Removes this block, or replaces it with an EmptyBlock.
@ -318,14 +317,6 @@ public abstract class StructuredBlock {
return false; 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() { public VariableSet propagateUsage() {
StructuredBlock[] subs = getSubBlocks(); StructuredBlock[] subs = getSubBlocks();
VariableSet allUse = (VariableSet) used.clone(); VariableSet allUse = (VariableSet) used.clone();
@ -371,7 +362,7 @@ public abstract class StructuredBlock {
} }
subs[i].checkConsistent(); subs[i].checkConsistent();
} }
if (jump != null) { if (jump != null && jump.destination != null) {
Jump jumps = (Jump) flowBlock.successors.get(jump.destination); Jump jumps = (Jump) flowBlock.successors.get(jump.destination);
for (; jumps != jump; jumps = jumps.next) { for (; jumps != jump; jumps = jumps.next) {
if (jumps == null) if (jumps == null)
@ -484,5 +475,12 @@ public abstract class StructuredBlock {
return super.toString(); 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.untab();
writer.println("}"); writer.println("}");
} }
public boolean doTransformations() {
return CompleteSynchronized.transform(this, flowBlock.lastModified);
}
} }

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

Loading…
Cancel
Save