diff --git a/jode/jode/bytecode/Opcodes.java b/jode/jode/bytecode/Opcodes.java index a9202b7..cb3d7a7 100644 --- a/jode/jode/bytecode/Opcodes.java +++ b/jode/jode/bytecode/Opcodes.java @@ -29,21 +29,21 @@ import gnu.bytecode.CpoolClass; */ public abstract class Opcodes { - public final static Type ALL_INT_TYPE = Type.tUInt; - public final static Type BOOL_INT_TYPE = Type.tBoolInt; - public final static Type INT_TYPE = Type.tInt; - public final static Type LONG_TYPE = Type.tLong; - public final static Type FLOAT_TYPE = Type.tFloat; - public final static Type DOUBLE_TYPE = Type.tDouble; - public final static Type OBJECT_TYPE = Type.tUObject; - public final static Type BOOLEAN_TYPE = Type.tBoolean; - public final static Type BYTEBOOL_TYPE = Type.tBoolByte; - public final static Type BYTE_TYPE = Type.tByte; - public final static Type CHAR_TYPE = Type.tChar; - public final static Type SHORT_TYPE = Type.tShort; - public final static Type VOID_TYPE = Type.tVoid; + private final static Type ALL_INT_TYPE = Type.tUInt; + private final static Type BOOL_INT_TYPE = Type.tBoolInt; + private final static Type INT_TYPE = Type.tInt; + private final static Type LONG_TYPE = Type.tLong; + private final static Type FLOAT_TYPE = Type.tFloat; + private final static Type DOUBLE_TYPE = Type.tDouble; + private final static Type OBJECT_TYPE = Type.tUObject; + private final static Type BOOLEAN_TYPE = Type.tBoolean; + private final static Type BYTEBOOL_TYPE = Type.tBoolByte; + private final static Type BYTE_TYPE = Type.tByte; + private final static Type CHAR_TYPE = Type.tChar; + private final static Type SHORT_TYPE = Type.tShort; + private final static Type VOID_TYPE = Type.tVoid; - public final static Type types[][] = { + private final static Type types[][] = { {BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }, { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE, BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE }, @@ -51,277 +51,387 @@ public abstract class Opcodes { { ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE } }; - public static final int opc_nop = 0; - public static final int opc_aconst_null = 1; - public static final int opc_iconst_m1 = 2; - public static final int opc_iconst_0 = 3; - public static final int opc_iconst_1 = 4; - public static final int opc_iconst_2 = 5; - public static final int opc_iconst_3 = 6; - public static final int opc_iconst_4 = 7; - public static final int opc_iconst_5 = 8; - public static final int opc_lconst_0 = 9; - public static final int opc_lconst_1 = 10; - public static final int opc_fconst_0 = 11; - public static final int opc_fconst_1 = 12; - public static final int opc_fconst_2 = 13; - public static final int opc_dconst_0 = 14; - public static final int opc_dconst_1 = 15; - public static final int opc_bipush = 16; - public static final int opc_sipush = 17; - public static final int opc_ldc = 18; - public static final int opc_ldc_w = 19; - public static final int opc_ldc2_w = 20; - public static final int opc_iload = 21; - public static final int opc_lload = 22; - public static final int opc_fload = 23; - public static final int opc_dload = 24; - public static final int opc_aload = 25; - public static final int opc_iload_0 = 26; - public static final int opc_iload_1 = 27; - public static final int opc_iload_2 = 28; - public static final int opc_iload_3 = 29; - public static final int opc_lload_0 = 30; - public static final int opc_lload_1 = 31; - public static final int opc_lload_2 = 32; - public static final int opc_lload_3 = 33; - public static final int opc_fload_0 = 34; - public static final int opc_fload_1 = 35; - public static final int opc_fload_2 = 36; - public static final int opc_fload_3 = 37; - public static final int opc_dload_0 = 38; - public static final int opc_dload_1 = 39; - public static final int opc_dload_2 = 40; - public static final int opc_dload_3 = 41; - public static final int opc_aload_0 = 42; - public static final int opc_aload_1 = 43; - public static final int opc_aload_2 = 44; - public static final int opc_aload_3 = 45; - public static final int opc_iaload = 46; - public static final int opc_laload = 47; - public static final int opc_faload = 48; - public static final int opc_daload = 49; - public static final int opc_aaload = 50; - public static final int opc_baload = 51; - public static final int opc_caload = 52; - public static final int opc_saload = 53; - public static final int opc_istore = 54; - public static final int opc_lstore = 55; - public static final int opc_fstore = 56; - public static final int opc_dstore = 57; - public static final int opc_astore = 58; - public static final int opc_istore_0 = 59; - public static final int opc_istore_1 = 60; - public static final int opc_istore_2 = 61; - public static final int opc_istore_3 = 62; - public static final int opc_lstore_0 = 63; - public static final int opc_lstore_1 = 64; - public static final int opc_lstore_2 = 65; - public static final int opc_lstore_3 = 66; - public static final int opc_fstore_0 = 67; - public static final int opc_fstore_1 = 68; - public static final int opc_fstore_2 = 69; - public static final int opc_fstore_3 = 70; - public static final int opc_dstore_0 = 71; - public static final int opc_dstore_1 = 72; - public static final int opc_dstore_2 = 73; - public static final int opc_dstore_3 = 74; - public static final int opc_astore_0 = 75; - public static final int opc_astore_1 = 76; - public static final int opc_astore_2 = 77; - public static final int opc_astore_3 = 78; - public static final int opc_iastore = 79; - public static final int opc_lastore = 80; - public static final int opc_fastore = 81; - public static final int opc_dastore = 82; - public static final int opc_aastore = 83; - public static final int opc_bastore = 84; - public static final int opc_castore = 85; - public static final int opc_sastore = 86; - public static final int opc_pop = 87; - public static final int opc_pop2 = 88; - public static final int opc_dup = 89; - public static final int opc_dup_x1 = 90; - public static final int opc_dup_x2 = 91; - public static final int opc_dup2 = 92; - public static final int opc_dup2_x1 = 93; - public static final int opc_dup2_x2 = 94; - public static final int opc_swap = 95; - public static final int opc_iadd = 96; - public static final int opc_ladd = 97; - public static final int opc_fadd = 98; - public static final int opc_dadd = 99; - public static final int opc_isub = 100; - public static final int opc_lsub = 101; - public static final int opc_fsub = 102; - public static final int opc_dsub = 103; - public static final int opc_imul = 104; - public static final int opc_lmul = 105; - public static final int opc_fmul = 106; - public static final int opc_dmul = 107; - public static final int opc_idiv = 108; - public static final int opc_ldiv = 109; - public static final int opc_fdiv = 110; - public static final int opc_ddiv = 111; - public static final int opc_irem = 112; - public static final int opc_lrem = 113; - public static final int opc_frem = 114; - public static final int opc_drem = 115; - public static final int opc_ineg = 116; - public static final int opc_lneg = 117; - public static final int opc_fneg = 118; - public static final int opc_dneg = 119; - public static final int opc_ishl = 120; - public static final int opc_lshl = 121; - public static final int opc_ishr = 122; - public static final int opc_lshr = 123; - public static final int opc_iushr = 124; - public static final int opc_lushr = 125; - public static final int opc_iand = 126; - public static final int opc_land = 127; - public static final int opc_ior = 128; - public static final int opc_lor = 129; - public static final int opc_ixor = 130; - public static final int opc_lxor = 131; - public static final int opc_iinc = 132; - public static final int opc_i2l = 133; - public static final int opc_i2f = 134; - public static final int opc_i2d = 135; - public static final int opc_l2i = 136; - public static final int opc_l2f = 137; - public static final int opc_l2d = 138; - public static final int opc_f2i = 139; - public static final int opc_f2l = 140; - public static final int opc_f2d = 141; - public static final int opc_d2i = 142; - public static final int opc_d2l = 143; - public static final int opc_d2f = 144; - public static final int opc_i2b = 145; - public static final int opc_i2c = 146; - public static final int opc_i2s = 147; - public static final int opc_lcmp = 148; - public static final int opc_fcmpl = 149; - public static final int opc_fcmpg = 150; - public static final int opc_dcmpl = 151; - public static final int opc_dcmpg = 152; - public static final int opc_ifeq = 153; - public static final int opc_ifne = 154; - public static final int opc_iflt = 155; - public static final int opc_ifge = 156; - public static final int opc_ifgt = 157; - public static final int opc_ifle = 158; - public static final int opc_if_icmpeq = 159; - public static final int opc_if_icmpne = 160; - public static final int opc_if_icmplt = 161; - public static final int opc_if_icmpge = 162; - public static final int opc_if_icmpgt = 163; - public static final int opc_if_icmple = 164; - public static final int opc_if_acmpeq = 165; - public static final int opc_if_acmpne = 166; - public static final int opc_goto = 167; - public static final int opc_jsr = 168; - public static final int opc_ret = 169; - public static final int opc_tableswitch = 170; - public static final int opc_lookupswitch = 171; - public static final int opc_ireturn = 172; - public static final int opc_lreturn = 173; - public static final int opc_freturn = 174; - public static final int opc_dreturn = 175; - public static final int opc_areturn = 176; - public static final int opc_return = 177; - public static final int opc_getstatic = 178; - public static final int opc_putstatic = 179; - public static final int opc_getfield = 180; - public static final int opc_putfield = 181; - public static final int opc_invokevirtual = 182; - public static final int opc_invokespecial = 183; - public static final int opc_invokestatic = 184; - public static final int opc_invokeinterface = 185; - public static final int opc_xxxunusedxxx = 186; - public static final int opc_new = 187; - public static final int opc_newarray = 188; - public static final int opc_anewarray = 189; - public static final int opc_arraylength = 190; - public static final int opc_athrow = 191; - public static final int opc_checkcast = 192; - public static final int opc_instanceof = 193; - public static final int opc_monitorenter = 194; - public static final int opc_monitorexit = 195; - public static final int opc_wide = 196; - public static final int opc_multianewarray = 197; - public static final int opc_ifnull = 198; - public static final int opc_ifnonnull = 199; - public static final int opc_goto_w = 200; - public static final int opc_jsr_w = 201; - public static final int opc_breakpoint = 202; + private final static int opc_nop = 0; + private final static int opc_aconst_null = 1; + private final static int opc_iconst_m1 = 2; + private final static int opc_iconst_0 = 3; + private final static int opc_iconst_1 = 4; + private final static int opc_iconst_2 = 5; + private final static int opc_iconst_3 = 6; + private final static int opc_iconst_4 = 7; + private final static int opc_iconst_5 = 8; + private final static int opc_lconst_0 = 9; + private final static int opc_lconst_1 = 10; + private final static int opc_fconst_0 = 11; + private final static int opc_fconst_1 = 12; + private final static int opc_fconst_2 = 13; + private final static int opc_dconst_0 = 14; + private final static int opc_dconst_1 = 15; + private final static int opc_bipush = 16; + private final static int opc_sipush = 17; + private final static int opc_ldc = 18; + private final static int opc_ldc_w = 19; + private final static int opc_ldc2_w = 20; + private final static int opc_iload = 21; + private final static int opc_lload = 22; + private final static int opc_fload = 23; + private final static int opc_dload = 24; + private final static int opc_aload = 25; + private final static int opc_iload_0 = 26; + private final static int opc_iload_1 = 27; + private final static int opc_iload_2 = 28; + private final static int opc_iload_3 = 29; + private final static int opc_lload_0 = 30; + private final static int opc_lload_1 = 31; + private final static int opc_lload_2 = 32; + private final static int opc_lload_3 = 33; + private final static int opc_fload_0 = 34; + private final static int opc_fload_1 = 35; + private final static int opc_fload_2 = 36; + private final static int opc_fload_3 = 37; + private final static int opc_dload_0 = 38; + private final static int opc_dload_1 = 39; + private final static int opc_dload_2 = 40; + private final static int opc_dload_3 = 41; + private final static int opc_aload_0 = 42; + private final static int opc_aload_1 = 43; + private final static int opc_aload_2 = 44; + private final static int opc_aload_3 = 45; + private final static int opc_iaload = 46; + private final static int opc_laload = 47; + private final static int opc_faload = 48; + private final static int opc_daload = 49; + private final static int opc_aaload = 50; + private final static int opc_baload = 51; + private final static int opc_caload = 52; + private final static int opc_saload = 53; + private final static int opc_istore = 54; + private final static int opc_lstore = 55; + private final static int opc_fstore = 56; + private final static int opc_dstore = 57; + private final static int opc_astore = 58; + private final static int opc_istore_0 = 59; + private final static int opc_istore_1 = 60; + private final static int opc_istore_2 = 61; + private final static int opc_istore_3 = 62; + private final static int opc_lstore_0 = 63; + private final static int opc_lstore_1 = 64; + private final static int opc_lstore_2 = 65; + private final static int opc_lstore_3 = 66; + private final static int opc_fstore_0 = 67; + private final static int opc_fstore_1 = 68; + private final static int opc_fstore_2 = 69; + private final static int opc_fstore_3 = 70; + private final static int opc_dstore_0 = 71; + private final static int opc_dstore_1 = 72; + private final static int opc_dstore_2 = 73; + private final static int opc_dstore_3 = 74; + private final static int opc_astore_0 = 75; + private final static int opc_astore_1 = 76; + private final static int opc_astore_2 = 77; + private final static int opc_astore_3 = 78; + private final static int opc_iastore = 79; + private final static int opc_lastore = 80; + private final static int opc_fastore = 81; + private final static int opc_dastore = 82; + private final static int opc_aastore = 83; + private final static int opc_bastore = 84; + private final static int opc_castore = 85; + private final static int opc_sastore = 86; + private final static int opc_pop = 87; + private final static int opc_pop2 = 88; + private final static int opc_dup = 89; + private final static int opc_dup_x1 = 90; + private final static int opc_dup_x2 = 91; + private final static int opc_dup2 = 92; + private final static int opc_dup2_x1 = 93; + private final static int opc_dup2_x2 = 94; + private final static int opc_swap = 95; + private final static int opc_iadd = 96; + private final static int opc_ladd = 97; + private final static int opc_fadd = 98; + private final static int opc_dadd = 99; + private final static int opc_isub = 100; + private final static int opc_lsub = 101; + private final static int opc_fsub = 102; + private final static int opc_dsub = 103; + private final static int opc_imul = 104; + private final static int opc_lmul = 105; + private final static int opc_fmul = 106; + private final static int opc_dmul = 107; + private final static int opc_idiv = 108; + private final static int opc_ldiv = 109; + private final static int opc_fdiv = 110; + private final static int opc_ddiv = 111; + private final static int opc_irem = 112; + private final static int opc_lrem = 113; + private final static int opc_frem = 114; + private final static int opc_drem = 115; + private final static int opc_ineg = 116; + private final static int opc_lneg = 117; + private final static int opc_fneg = 118; + private final static int opc_dneg = 119; + private final static int opc_ishl = 120; + private final static int opc_lshl = 121; + private final static int opc_ishr = 122; + private final static int opc_lshr = 123; + private final static int opc_iushr = 124; + private final static int opc_lushr = 125; + private final static int opc_iand = 126; + private final static int opc_land = 127; + private final static int opc_ior = 128; + private final static int opc_lor = 129; + private final static int opc_ixor = 130; + private final static int opc_lxor = 131; + private final static int opc_iinc = 132; + private final static int opc_i2l = 133; + private final static int opc_i2f = 134; + private final static int opc_i2d = 135; + private final static int opc_l2i = 136; + private final static int opc_l2f = 137; + private final static int opc_l2d = 138; + private final static int opc_f2i = 139; + private final static int opc_f2l = 140; + private final static int opc_f2d = 141; + private final static int opc_d2i = 142; + private final static int opc_d2l = 143; + private final static int opc_d2f = 144; + private final static int opc_i2b = 145; + private final static int opc_i2c = 146; + private final static int opc_i2s = 147; + private final static int opc_lcmp = 148; + private final static int opc_fcmpl = 149; + private final static int opc_fcmpg = 150; + private final static int opc_dcmpl = 151; + private final static int opc_dcmpg = 152; + private final static int opc_ifeq = 153; + private final static int opc_ifne = 154; + private final static int opc_iflt = 155; + private final static int opc_ifge = 156; + private final static int opc_ifgt = 157; + private final static int opc_ifle = 158; + private final static int opc_if_icmpeq = 159; + private final static int opc_if_icmpne = 160; + private final static int opc_if_icmplt = 161; + private final static int opc_if_icmpge = 162; + private final static int opc_if_icmpgt = 163; + private final static int opc_if_icmple = 164; + private final static int opc_if_acmpeq = 165; + private final static int opc_if_acmpne = 166; + private final static int opc_goto = 167; + private final static int opc_jsr = 168; + private final static int opc_ret = 169; + private final static int opc_tableswitch = 170; + private final static int opc_lookupswitch = 171; + private final static int opc_ireturn = 172; + private final static int opc_lreturn = 173; + private final static int opc_freturn = 174; + private final static int opc_dreturn = 175; + private final static int opc_areturn = 176; + private final static int opc_return = 177; + private final static int opc_getstatic = 178; + private final static int opc_putstatic = 179; + private final static int opc_getfield = 180; + private final static int opc_putfield = 181; + private final static int opc_invokevirtual = 182; + private final static int opc_invokespecial = 183; + private final static int opc_invokestatic = 184; + private final static int opc_invokeinterface = 185; + private final static int opc_xxxunusedxxx = 186; + private final static int opc_new = 187; + private final static int opc_newarray = 188; + private final static int opc_anewarray = 189; + private final static int opc_arraylength = 190; + private final static int opc_athrow = 191; + private final static int opc_checkcast = 192; + private final static int opc_instanceof = 193; + private final static int opc_monitorenter = 194; + private final static int opc_monitorexit = 195; + private final static int opc_wide = 196; + private final static int opc_multianewarray = 197; + private final static int opc_ifnull = 198; + private final static int opc_ifnonnull = 199; + private final static int opc_goto_w = 200; + private final static int opc_jsr_w = 201; + private final static int opc_breakpoint = 202; - public static FlowBlock createNormal(CodeAnalyzer ca, - int addr, int length, - Expression instr) + private static StructuredBlock createNormal(CodeAnalyzer ca, + int addr, int length, + Expression instr) { - return new FlowBlock(ca, addr, length, - new InstructionBlock(instr, - new Jump(addr+length))); + return new InstructionBlock(instr, new Jump(addr+length)); } - public static FlowBlock createSpecial(CodeAnalyzer ca, + private static StructuredBlock createSpecial(CodeAnalyzer ca, int addr, int length, int type, int stackcount, int param) { - return new FlowBlock(ca, addr, length, - new SpecialBlock(type, stackcount, param, - new Jump(addr+length))); + return new SpecialBlock(type, stackcount, param, + new Jump(addr+length)); } - public static FlowBlock createGoto(CodeAnalyzer ca, - int addr, int length, int destAddr) + private static StructuredBlock createGoto(CodeAnalyzer ca, + int addr, int length, int destAddr) { - return new FlowBlock(ca, addr, length, - new EmptyBlock(new Jump(destAddr))); + return new EmptyBlock(new Jump(destAddr)); } - public static FlowBlock createJsr(CodeAnalyzer ca, - int addr, int length, - int destAddr) + private static StructuredBlock createJsr(CodeAnalyzer ca, + int addr, int length, + int destAddr) { - return new FlowBlock(ca, addr, length, - new JsrBlock(new Jump(addr+length), - new Jump(destAddr))); + return new JsrBlock(new Jump(addr+length), + new Jump(destAddr)); } - public static FlowBlock createIfGoto(CodeAnalyzer ca, - int addr, int length, - int destAddr, Expression instr) + private static StructuredBlock createIfGoto(CodeAnalyzer ca, + int addr, int length, + int destAddr, Expression instr) { - ConditionalBlock ifBlock = - new ConditionalBlock(instr, - new Jump(destAddr), - new Jump(addr+length)); - return new FlowBlock(ca, addr, length, ifBlock); + return new ConditionalBlock(instr, + new Jump(destAddr), + new Jump(addr+length)); } - public static FlowBlock createSwitch(CodeAnalyzer ca, - int addr, int length, - int[] cases, int[] dests) + private static StructuredBlock createSwitch(CodeAnalyzer ca, + int addr, int length, + int[] cases, int[] dests) { - return new FlowBlock(ca, addr, length, - new SwitchBlock(new NopOperator(Type.tUInt), - cases, dests)); + return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests); } - public static FlowBlock createBlock(CodeAnalyzer ca, - int addr, int length, - StructuredBlock block) + private static StructuredBlock createBlock(CodeAnalyzer ca, + int addr, int length, + StructuredBlock block) { - return new FlowBlock(ca, addr, length, block); + return block; } - public static FlowBlock createRet(CodeAnalyzer ca, - int addr, int length, - LocalInfo local) + private static StructuredBlock createRet(CodeAnalyzer ca, + int addr, int length, + LocalInfo local) { - return new FlowBlock(ca, addr, length, - new RetBlock(local)); + return new RetBlock(local); + } + + + /** + * Read an opcode out of a data input stream and determine its size + * and its successors. + * @param addr The current address. + * @param stream The stream containing the java byte code. + * @return An array of ints; the first entry is the size of the + * instruction, the remaining are the successors. + */ + public static int[] getSizeAndSuccs(int addr, DataInputStream stream) + throws IOException + { + int opcode = stream.readUnsignedByte(); + switch (opcode) { + case opc_multianewarray: + stream.skip(3); + return new int[] { 4, addr+4 }; + case opc_invokeinterface: + stream.skip(4); + return new int[] { 5, addr+5 }; + + case opc_wide: { + switch (opcode = stream.readUnsignedByte()) { + case opc_iload: case opc_lload: + case opc_fload: case opc_dload: case opc_aload: + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: + stream.skip(2); + return new int[] { 4, addr+4 }; + + case opc_iinc: + stream.skip(4); + return new int[] { 6, addr+6 }; + case opc_ret: + stream.skip(2); + return new int[] { 4 }; + default: + throw new ClassFormatError("Invalid wide opcode "+opcode); + } + } + case opc_ret: + return new int[] { 2 }; + + case opc_jsr_w: + return new int[] { 5, addr + 5, addr + stream.readInt() }; + + case opc_goto: + return new int[] { 3, addr + stream.readShort() }; + case opc_goto_w: + return new int[] { 5, addr + stream.readInt() }; + + case opc_tableswitch: { + int length = 3-(addr % 4); + stream.skip(length); + int def = addr + stream.readInt(); + int low = stream.readInt(); + int high = stream.readInt(); + int[] dests = new int[high-low+3]; + for (int i=0; i+low <= high; i++) { + dests[i+1] = addr + stream.readInt(); + } + dests[dests.length-1] = def; + dests[0] = length + 13 + 4 * (high-low+1); + return dests; + } + case opc_lookupswitch: { + int length = 3-(addr % 4); + stream.skip(length); + int def = stream.readInt(); + int npairs = stream.readInt(); + int[] dests = new int[npairs+2]; + for (int i=0; i < npairs; i++) { + int value = stream.readInt(); + dests[i+1] = addr + stream.readInt(); + } + dests[npairs+1] = def; + dests[0] = length + 9 + 8 * npairs; + return dests; + } + + case opc_ifnull: case opc_ifnonnull: + case opc_jsr: + return new int[] { 3, addr + 3, addr + stream.readShort() }; + + case opc_sipush: + case opc_ldc_w: + case opc_ldc2_w: + case opc_iinc: + case opc_getstatic: + case opc_getfield: + case opc_putstatic: + case opc_putfield: + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic : + case opc_new: + case opc_anewarray: + case opc_checkcast: + case opc_instanceof: + stream.skip(2); + return new int[] { 3, addr+3 }; + } + + if (opcode == opc_newarray + || (opcode >= opc_bipush && opcode <= opc_aload) + || (opcode >= opc_istore && opcode <= opc_astore)) { + stream.skip(1); + return new int[] { 2, addr+2 }; + } + + if (opcode >= opc_ireturn && opcode <= opc_return) + return new int[] { 1 }; + if (opcode >= opc_ifeq && opcode <= opc_if_acmpne) + return new int[] { 3, addr + 3, addr + stream.readShort() }; + if (opcode == opc_xxxunusedxxx || opcode > opc_breakpoint) + throw new ClassFormatError("Invalid opcode "+opcode); + + return new int[] { 1, addr+1 }; } /** @@ -335,155 +445,411 @@ public abstract class Opcodes { * @exception IOException if an read error occured. * @exception ClassFormatError if an invalid opcode is detected. */ - public static FlowBlock readOpcode(int addr, DataInputStream stream, - CodeAnalyzer ca) + public static StructuredBlock readOpcode(int addr, DataInputStream stream, + CodeAnalyzer ca) throws IOException, ClassFormatError { - try { - int opcode = stream.readUnsignedByte(); - switch (opcode) { - case opc_nop: - return createNormal(ca, addr, 1, new NopOperator()); - case opc_aconst_null: - return createNormal - (ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null")); - case opc_iconst_0: case opc_iconst_1: - return createNormal - (ca, addr, 1, new ConstOperator - (Type.tBoolInt, Integer.toString(opcode - opc_iconst_0))); - case opc_iconst_m1: case opc_iconst_2: - case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: - return createNormal - (ca, addr, 1, new ConstOperator - (ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); - case opc_lconst_0: case opc_lconst_1: - return createNormal - (ca, addr, 1, new ConstOperator - (LONG_TYPE, - Integer.toString(opcode - opc_lconst_0))); - case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: - return createNormal - (ca, addr, 1, new ConstOperator - (FLOAT_TYPE, - Integer.toString(opcode - opc_fconst_0) + ".0F")); - case opc_dconst_0: case opc_dconst_1: - return createNormal - (ca, addr, 1, new ConstOperator - (DOUBLE_TYPE, - Integer.toString(opcode - opc_dconst_0) + ".0")); - case opc_bipush: - return createNormal - (ca, addr, 2, new ConstOperator - (ALL_INT_TYPE, Integer.toString(stream.readByte()))); - case opc_sipush: - return createNormal - (ca, addr, 3, new ConstOperator - (Type.tRange(Type.tInt, Type.tChar), - Integer.toString(stream.readShort()))); - case opc_ldc: { - int index = stream.readUnsignedByte(); - return createNormal - (ca, addr, 2, new ConstOperator - (ca.method.classAnalyzer.getConstantType(index), - ca.method.classAnalyzer.getConstantString(index))); + int opcode = stream.readUnsignedByte(); + switch (opcode) { + case opc_nop: + return createNormal(ca, addr, 1, new NopOperator()); + case opc_aconst_null: + return createNormal + (ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null")); + case opc_iconst_0: case opc_iconst_1: + return createNormal + (ca, addr, 1, new ConstOperator + (Type.tBoolInt, Integer.toString(opcode - opc_iconst_0))); + case opc_iconst_m1: case opc_iconst_2: + case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: + return createNormal + (ca, addr, 1, new ConstOperator + (ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); + case opc_lconst_0: case opc_lconst_1: + return createNormal + (ca, addr, 1, new ConstOperator + (LONG_TYPE, + Integer.toString(opcode - opc_lconst_0))); + case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: + return createNormal + (ca, addr, 1, new ConstOperator + (FLOAT_TYPE, + Integer.toString(opcode - opc_fconst_0) + ".0F")); + case opc_dconst_0: case opc_dconst_1: + return createNormal + (ca, addr, 1, new ConstOperator + (DOUBLE_TYPE, + Integer.toString(opcode - opc_dconst_0) + ".0")); + case opc_bipush: + return createNormal + (ca, addr, 2, new ConstOperator + (ALL_INT_TYPE, Integer.toString(stream.readByte()))); + case opc_sipush: + return createNormal + (ca, addr, 3, new ConstOperator + (Type.tRange(Type.tInt, Type.tChar), + Integer.toString(stream.readShort()))); + case opc_ldc: { + int index = stream.readUnsignedByte(); + return createNormal + (ca, addr, 2, new ConstOperator + (ca.method.classAnalyzer.getConstantType(index), + ca.method.classAnalyzer.getConstantString(index))); + } + case opc_ldc_w: + case opc_ldc2_w: { + int index = stream.readUnsignedShort(); + return createNormal + (ca, addr, 3, new ConstOperator + (ca.method.classAnalyzer.getConstantType(index), + ca.method.classAnalyzer.getConstantString(index))); + } + case opc_iload: case opc_lload: + case opc_fload: case opc_dload: case opc_aload: + return createNormal + (ca, addr, 2, new LocalLoadOperator + (types[0][opcode-opc_iload], + ca.getLocalInfo(addr, stream.readUnsignedByte()))); + case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: + case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: + case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: + case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: + case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: + return createNormal + (ca, addr, 1, new LocalLoadOperator + (types[0][(opcode-opc_iload_0)/4], + ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3))); + case opc_iaload: case opc_laload: + case opc_faload: case opc_daload: case opc_aaload: + case opc_baload: case opc_caload: case opc_saload: + return createNormal + (ca, addr, 1, new ArrayLoadOperator + (types[1][opcode - opc_iaload])); + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: + return createNormal + (ca, addr, 2, new LocalStoreOperator + (types[0][opcode-opc_istore], + ca.getLocalInfo(addr+2, stream.readUnsignedByte()), + Operator.ASSIGN_OP)); + case opc_istore_0: case opc_istore_1: + case opc_istore_2: case opc_istore_3: + case opc_lstore_0: case opc_lstore_1: + case opc_lstore_2: case opc_lstore_3: + case opc_fstore_0: case opc_fstore_1: + case opc_fstore_2: case opc_fstore_3: + case opc_dstore_0: case opc_dstore_1: + case opc_dstore_2: case opc_dstore_3: + case opc_astore_0: case opc_astore_1: + case opc_astore_2: case opc_astore_3: + return createNormal + (ca, addr, 1, new LocalStoreOperator + (types[0][(opcode-opc_istore_0)/4], + ca.getLocalInfo(addr+1, (opcode-opc_istore_0) & 3), + Operator.ASSIGN_OP)); + case opc_iastore: case opc_lastore: + case opc_fastore: case opc_dastore: case opc_aastore: + case opc_bastore: case opc_castore: case opc_sastore: + return createNormal + (ca, addr, 1, new ArrayStoreOperator + (types[1][opcode - opc_iastore])); + case opc_pop: case opc_pop2: + return createNormal + (ca, addr, 1, new PopOperator(opcode - opc_pop + 1)); + case opc_dup: case opc_dup_x1: case opc_dup_x2: + case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: + return createSpecial + (ca, addr, 1, SpecialBlock.DUP, + (opcode - opc_dup)/3+1, (opcode - opc_dup)%3); + case opc_swap: + return createSpecial(ca, addr, 1, SpecialBlock.SWAP, 1, 0); + case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: + case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: + case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: + case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: + case opc_irem: case opc_lrem: case opc_frem: case opc_drem: + return createNormal + (ca, addr, 1, new BinaryOperator + (types[3][(opcode - opc_iadd)%4], + (opcode - opc_iadd)/4+Operator.ADD_OP)); + case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: + return createNormal + (ca, addr, 1, new UnaryOperator + (types[3][opcode - opc_ineg], Operator.NEG_OP)); + case opc_ishl: case opc_lshl: + case opc_ishr: case opc_lshr: + case opc_iushr: case opc_lushr: + return createNormal + (ca, addr, 1, new ShiftOperator + (types[3][(opcode - opc_ishl)%2], + (opcode - opc_ishl)/2 + Operator.SHIFT_OP)); + case opc_iand: case opc_land: + case opc_ior : case opc_lor : + case opc_ixor: case opc_lxor: + return createNormal + (ca, addr, 1, new BinaryOperator + (types[0][(opcode - opc_iand)%2], + (opcode - opc_iand)/2 + Operator.AND_OP)); + case opc_iinc: { + int local = stream.readUnsignedByte(); + int value = stream.readByte(); + int operation = Operator.ADD_OP; + if (value < 0) { + value = -value; + operation = Operator.NEG_OP; + } + LocalInfo li = ca.getLocalInfo(addr, local); + li.setType(ALL_INT_TYPE); + return createNormal + (ca, addr, 3, new IIncOperator + (li, Integer.toString(value), + operation + Operator.OPASSIGN_OP)); + } + case opc_i2l: case opc_i2f: case opc_i2d: + case opc_l2i: case opc_l2f: case opc_l2d: + case opc_f2i: case opc_f2l: case opc_f2d: + case opc_d2i: case opc_d2l: case opc_d2f: { + int from = (opcode-opc_i2l)/3; + int to = (opcode-opc_i2l)%3; + if (to >= from) + to++; + return createNormal + (ca, addr, 1, new ConvertOperator(types[3][from], + types[3][to])); + } + case opc_i2b: case opc_i2c: case opc_i2s: + return createNormal + (ca, addr, 1, new ConvertOperator + (ALL_INT_TYPE, types[2][opcode-opc_i2b])); + case opc_lcmp: + case opc_fcmpl: case opc_fcmpg: + case opc_dcmpl: case opc_dcmpg: + return createNormal + (ca, addr, 1, new CompareToIntOperator + (types[3][(opcode-(opc_lcmp-3))/2], + (opcode-(opc_lcmp-3))%2)); + case opc_ifeq: case opc_ifne: + return createIfGoto + (ca, addr, 3, addr+stream.readShort(), + new CompareUnaryOperator + (BOOL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP))); + case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: + return createIfGoto + (ca, addr, 3, addr+stream.readShort(), + new CompareUnaryOperator + (ALL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP))); + case opc_if_icmpeq: case opc_if_icmpne: + return createIfGoto + (ca, addr, 3, addr+stream.readShort(), + new CompareBinaryOperator + (Type.tBoolInt, + opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); + case opc_if_icmplt: case opc_if_icmpge: + case opc_if_icmpgt: case opc_if_icmple: + return createIfGoto + (ca, addr, 3, addr+stream.readShort(), + new CompareBinaryOperator + (ALL_INT_TYPE, + opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); + case opc_if_acmpeq: case opc_if_acmpne: + return createIfGoto + (ca, addr, 3, addr+stream.readShort(), + new CompareBinaryOperator + (OBJECT_TYPE, + opcode - (opc_if_acmpeq-Operator.COMPARE_OP))); + case opc_goto: + return createGoto + (ca, addr, 3, addr+stream.readShort()); + case opc_jsr: + return createJsr + (ca, addr, 3, addr+stream.readShort()); + case opc_ret: + return createRet + (ca, addr, 2, + ca.getLocalInfo(addr, stream.readUnsignedByte())); + 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[] cases = new int[high-low+1]; + int[] dests = new int[high-low+2]; + for (int i=0; i+low <= high; i++) { + cases[i] = i+low; + dests[i] = addr + stream.readInt(); + } + dests[cases.length] = def; + length += 13 + 4 * cases.length; + return createSwitch + (ca, addr, length, cases, dests); + } + case opc_lookupswitch: { + int length = 3-(addr % 4); + stream.skip(length); + int def = addr + stream.readInt(); + int npairs = stream.readInt(); + int[] cases = new int[npairs]; + int[] dests = new int[npairs+1]; + for (int i=0; i < npairs; i++) { + cases[i] = stream.readInt(); + dests[i] = addr + stream.readInt(); + } + dests[npairs] = def; + length += 9 + 8 * npairs; + return createSwitch + (ca, addr, length, cases, dests); + } + case opc_ireturn: case opc_lreturn: + case opc_freturn: case opc_dreturn: case opc_areturn: { + /* Address -1 is interpreted as end of method */ + Type retType = Type.tSubType(ca.getMethod().getReturnType()); + return createBlock + (ca, addr, 1, new ReturnBlock(new NopOperator(retType), + new Jump(-1))); + } + case opc_return: + return createBlock + (ca, addr, 1, new EmptyBlock(new Jump(-1))); + case opc_getstatic: + case opc_getfield: { + CpoolRef field = (CpoolRef)ca.method.classAnalyzer + .getConstant(stream.readUnsignedShort()); + return createNormal + (ca, addr, 3, new GetFieldOperator + (ca, opcode == opc_getstatic, + Type.tClass(field.getCpoolClass().getName().getString()), + Type.tType(field.getNameAndType().getType().getString()), + field.getNameAndType().getName().getString())); + } + case opc_putstatic: + case opc_putfield: { + CpoolRef field = (CpoolRef)ca.method.classAnalyzer + .getConstant(stream.readUnsignedShort()); + return createNormal + (ca, addr, 3, new PutFieldOperator + (ca, opcode == opc_putstatic, + Type.tClass(field.getCpoolClass().getName().getString()), + Type.tType(field.getNameAndType().getType().getString()), + field.getNameAndType().getName().getString())); + } + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic : { + CpoolRef field = (CpoolRef)ca.method.classAnalyzer + .getConstant(stream.readUnsignedShort()); + return createNormal + (ca, addr, 3, new InvokeOperator + (ca, opcode == opc_invokespecial, + Type.tClass(field.getCpoolClass() + .getName().getString()), + new MethodType(opcode == opc_invokestatic, + field.getNameAndType() + .getType().getString()), + field.getNameAndType().getName().getString())); + } + case opc_invokeinterface: { + CpoolRef field = (CpoolRef)ca.method.classAnalyzer.getConstant + (stream.readUnsignedShort()); + + StructuredBlock block = createNormal + (ca, addr, 5, new InvokeOperator + (ca, false, + Type.tClass(field.getCpoolClass() + .getName().getString()), + new MethodType(false, field.getNameAndType() + .getType().getString()), + field.getNameAndType().getName().getString())); + int reserved = stream.readUnsignedShort(); + return block; + } + case opc_new: { + CpoolClass cpcls = (CpoolClass) + ca.method.classAnalyzer.getConstant(stream.readUnsignedShort()); + Type type = Type.tClassOrArray(cpcls.getName().getString()); + type.useType(); + return createNormal + (ca, addr, 3, new NewOperator(type)); + } + case opc_newarray: { + Type type; + switch (stream.readUnsignedByte()) { + case 4: type = Type.tBoolean; break; + case 5: type = Type.tChar ; break; + case 6: type = Type.tFloat ; break; + case 7: type = Type.tDouble ; break; + case 8: type = Type.tByte ; break; + case 9: type = Type.tShort ; break; + case 10: type = Type.tInt ; break; + case 11: type = Type.tLong ; break; + default: + throw new ClassFormatError("Invalid newarray operand"); } - case opc_ldc_w: - case opc_ldc2_w: { - int index = stream.readUnsignedShort(); - return createNormal - (ca, addr, 3, new ConstOperator - (ca.method.classAnalyzer.getConstantType(index), - ca.method.classAnalyzer.getConstantString(index))); - } + type.useType(); + return createNormal + (ca, addr, 2, new NewArrayOperator(Type.tArray(type), 1)); + } + case opc_anewarray: { + CpoolClass cpcls = (CpoolClass) + ca.method.classAnalyzer.getConstant + (stream.readUnsignedShort()); + Type type = Type.tClassOrArray(cpcls.getName().getString()); + type.useType(); + return createNormal + (ca, addr, 3, new NewArrayOperator(Type.tArray(type), 1)); + } + case opc_arraylength: + return createNormal + (ca, addr, 1, new ArrayLengthOperator()); + case opc_athrow: + return createBlock + (ca, addr, 1, + new ThrowBlock(new NopOperator(Type.tUObject), + new Jump(-1))); + case opc_checkcast: { + CpoolClass cpcls = (CpoolClass) + ca.method.classAnalyzer.getConstant + (stream.readUnsignedShort()); + Type type = Type.tClassOrArray(cpcls.getName().getString()); + type.useType(); + return createNormal + (ca, addr, 3, new CheckCastOperator(type)); + } + case opc_instanceof: { + CpoolClass cpcls = (CpoolClass) + ca.method.classAnalyzer.getConstant + (stream.readUnsignedShort()); + Type type = Type.tClassOrArray(cpcls.getName().getString()); + type.useType(); + return createNormal + (ca, addr, 3, new InstanceOfOperator(type)); + } + case opc_monitorenter: + return createNormal(ca, addr, 1, + new MonitorEnterOperator()); + case opc_monitorexit: + return createNormal(ca, addr, 1, + new MonitorExitOperator()); + case opc_wide: { + switch (opcode=stream.readUnsignedByte()) { case opc_iload: case opc_lload: case opc_fload: case opc_dload: case opc_aload: - return createNormal - (ca, addr, 2, new LocalLoadOperator - (types[0][opcode-opc_iload], - ca.getLocalInfo(addr, stream.readUnsignedByte()))); - case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: - case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: - case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: - case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: - case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: - return createNormal - (ca, addr, 1, new LocalLoadOperator - (types[0][(opcode-opc_iload_0)/4], - ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3))); - case opc_iaload: case opc_laload: - case opc_faload: case opc_daload: case opc_aaload: - case opc_baload: case opc_caload: case opc_saload: - return createNormal - (ca, addr, 1, new ArrayLoadOperator - (types[1][opcode - opc_iaload])); + return createNormal + (ca, addr, 4, + new LocalLoadOperator + (types[0][opcode-opc_iload], + ca.getLocalInfo(addr, stream.readUnsignedShort()))); case opc_istore: case opc_lstore: case opc_fstore: case opc_dstore: case opc_astore: - return createNormal - (ca, addr, 2, new LocalStoreOperator - (types[0][opcode-opc_istore], - ca.getLocalInfo(addr+2, stream.readUnsignedByte()), - Operator.ASSIGN_OP)); - case opc_istore_0: case opc_istore_1: - case opc_istore_2: case opc_istore_3: - case opc_lstore_0: case opc_lstore_1: - case opc_lstore_2: case opc_lstore_3: - case opc_fstore_0: case opc_fstore_1: - case opc_fstore_2: case opc_fstore_3: - case opc_dstore_0: case opc_dstore_1: - case opc_dstore_2: case opc_dstore_3: - case opc_astore_0: case opc_astore_1: - case opc_astore_2: case opc_astore_3: - return createNormal - (ca, addr, 1, new LocalStoreOperator - (types[0][(opcode-opc_istore_0)/4], - ca.getLocalInfo(addr+1, (opcode-opc_istore_0) & 3), - Operator.ASSIGN_OP)); - case opc_iastore: case opc_lastore: - case opc_fastore: case opc_dastore: case opc_aastore: - case opc_bastore: case opc_castore: case opc_sastore: - return createNormal - (ca, addr, 1, new ArrayStoreOperator - (types[1][opcode - opc_iastore])); - case opc_pop: case opc_pop2: - return createNormal - (ca, addr, 1, new PopOperator(opcode - opc_pop + 1)); - case opc_dup: case opc_dup_x1: case opc_dup_x2: - case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: - return createSpecial - (ca, addr, 1, SpecialBlock.DUP, - (opcode - opc_dup)/3+1, (opcode - opc_dup)%3); - case opc_swap: - return createSpecial(ca, addr, 1, SpecialBlock.SWAP, 1, 0); - case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: - case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: - case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: - case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: - case opc_irem: case opc_lrem: case opc_frem: case opc_drem: - return createNormal - (ca, addr, 1, new BinaryOperator - (types[3][(opcode - opc_iadd)%4], - (opcode - opc_iadd)/4+Operator.ADD_OP)); - case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: - return createNormal - (ca, addr, 1, new UnaryOperator - (types[3][opcode - opc_ineg], Operator.NEG_OP)); - case opc_ishl: case opc_lshl: - case opc_ishr: case opc_lshr: - case opc_iushr: case opc_lushr: - return createNormal - (ca, addr, 1, new ShiftOperator - (types[3][(opcode - opc_ishl)%2], - (opcode - opc_ishl)/2 + Operator.SHIFT_OP)); - case opc_iand: case opc_land: - case opc_ior : case opc_lor : - case opc_ixor: case opc_lxor: return createNormal - (ca, addr, 1, new BinaryOperator - (types[0][(opcode - opc_iand)%2], - (opcode - opc_iand)/2 + Operator.AND_OP)); + (ca, addr, 4, + new LocalStoreOperator + (types[0][opcode-opc_istore], + ca.getLocalInfo(addr+4, stream.readUnsignedShort()), + Operator.ASSIGN_OP)); case opc_iinc: { - int local = stream.readUnsignedByte(); - int value = stream.readByte(); + int local = stream.readUnsignedShort(); + int value = stream.readShort(); int operation = Operator.ADD_OP; if (value < 0) { value = -value; @@ -492,302 +858,41 @@ public abstract class Opcodes { LocalInfo li = ca.getLocalInfo(addr, local); li.setType(ALL_INT_TYPE); return createNormal - (ca, addr, 3, new IIncOperator - (li, Integer.toString(value), - operation + Operator.OPASSIGN_OP)); - } - case opc_i2l: case opc_i2f: case opc_i2d: - case opc_l2i: case opc_l2f: case opc_l2d: - case opc_f2i: case opc_f2l: case opc_f2d: - case opc_d2i: case opc_d2l: case opc_d2f: { - int from = (opcode-opc_i2l)/3; - int to = (opcode-opc_i2l)%3; - if (to >= from) - to++; - return createNormal - (ca, addr, 1, new ConvertOperator(types[3][from], - types[3][to])); + (ca, addr, 6, new IIncOperator + (li, Integer.toString(value), + operation + Operator.OPASSIGN_OP)); } - case opc_i2b: case opc_i2c: case opc_i2s: - return createNormal - (ca, addr, 1, new ConvertOperator - (ALL_INT_TYPE, types[2][opcode-opc_i2b])); - case opc_lcmp: - case opc_fcmpl: case opc_fcmpg: - case opc_dcmpl: case opc_dcmpg: - return createNormal - (ca, addr, 1, new CompareToIntOperator - (types[3][(opcode-(opc_lcmp-3))/2], - (opcode-(opc_lcmp-3))%2)); - case opc_ifeq: case opc_ifne: - return createIfGoto - (ca, addr, 3, addr+stream.readShort(), - new CompareUnaryOperator - (BOOL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP))); - case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: - return createIfGoto - (ca, addr, 3, addr+stream.readShort(), - new CompareUnaryOperator - (ALL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP))); - case opc_if_icmpeq: case opc_if_icmpne: - return createIfGoto - (ca, addr, 3, addr+stream.readShort(), - new CompareBinaryOperator - (Type.tBoolInt, - opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); - case opc_if_icmplt: case opc_if_icmpge: - case opc_if_icmpgt: case opc_if_icmple: - return createIfGoto - (ca, addr, 3, addr+stream.readShort(), - new CompareBinaryOperator - (ALL_INT_TYPE, - opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); - case opc_if_acmpeq: case opc_if_acmpne: - return createIfGoto - (ca, addr, 3, addr+stream.readShort(), - new CompareBinaryOperator - (OBJECT_TYPE, - opcode - (opc_if_acmpeq-Operator.COMPARE_OP))); - case opc_goto: - return createGoto - (ca, addr, 3, addr+stream.readShort()); - case opc_jsr: - return createJsr - (ca, addr, 3, addr+stream.readShort()); case opc_ret: return createRet - (ca, addr, 2, - ca.getLocalInfo(addr, stream.readUnsignedByte())); - 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[] cases = new int[high-low+1]; - int[] dests = new int[high-low+2]; - for (int i=0; i+low <= high; i++) { - cases[i] = i+low; - dests[i] = addr + stream.readInt(); - } - dests[cases.length] = def; - length += 13 + 4 * cases.length; - return createSwitch - (ca, addr, length, cases, dests); - } - case opc_lookupswitch: { - int length = 3-(addr % 4); - stream.skip(length); - int def = addr + stream.readInt(); - int npairs = stream.readInt(); - int[] cases = new int[npairs]; - int[] dests = new int[npairs+1]; - for (int i=0; i < npairs; i++) { - cases[i] = stream.readInt(); - dests[i] = addr + stream.readInt(); - } - dests[npairs] = def; - length += 9 + 8 * npairs; - return createSwitch - (ca, addr, length, cases, dests); - } - case opc_ireturn: case opc_lreturn: - case opc_freturn: case opc_dreturn: case opc_areturn: { - /* Address -1 is interpreted as end of method */ - Type retType = Type.tSubType(ca.getMethod().getReturnType()); - return createBlock - (ca, addr, 1, new ReturnBlock(new NopOperator(retType), - new Jump(-1))); - } - case opc_return: - return createBlock - (ca, addr, 1, new EmptyBlock(new Jump(-1))); - case opc_getstatic: - case opc_getfield: { - CpoolRef field = (CpoolRef)ca.method.classAnalyzer - .getConstant(stream.readUnsignedShort()); - return createNormal - (ca, addr, 3, new GetFieldOperator - (ca, opcode == opc_getstatic, - Type.tClass(field.getCpoolClass().getName().getString()), - Type.tType(field.getNameAndType().getType().getString()), - field.getNameAndType().getName().getString())); - } - case opc_putstatic: - case opc_putfield: { - CpoolRef field = (CpoolRef)ca.method.classAnalyzer - .getConstant(stream.readUnsignedShort()); - return createNormal - (ca, addr, 3, new PutFieldOperator - (ca, opcode == opc_putstatic, - Type.tClass(field.getCpoolClass().getName().getString()), - Type.tType(field.getNameAndType().getType().getString()), - field.getNameAndType().getName().getString())); - } - case opc_invokevirtual: - case opc_invokespecial: - case opc_invokestatic : { - CpoolRef field = (CpoolRef)ca.method.classAnalyzer - .getConstant(stream.readUnsignedShort()); - return createNormal - (ca, addr, 3, new InvokeOperator - (ca, opcode == opc_invokespecial, - Type.tClass(field.getCpoolClass() - .getName().getString()), - new MethodType(opcode == opc_invokestatic, - field.getNameAndType() - .getType().getString()), - field.getNameAndType().getName().getString())); - } - case opc_invokeinterface: { - CpoolRef field = (CpoolRef)ca.method.classAnalyzer.getConstant - (stream.readUnsignedShort()); - - FlowBlock fb = createNormal - (ca, addr, 5, new InvokeOperator - (ca, false, - Type.tClass(field.getCpoolClass() - .getName().getString()), - new MethodType(false, field.getNameAndType() - .getType().getString()), - field.getNameAndType().getName().getString())); - int reserved = stream.readUnsignedShort(); - return fb; - } - case opc_new: { - CpoolClass cpcls = (CpoolClass) - ca.method.classAnalyzer.getConstant(stream.readUnsignedShort()); - Type type = Type.tClassOrArray(cpcls.getName().getString()); - type.useType(); - return createNormal - (ca, addr, 3, new NewOperator(type)); - } - case opc_newarray: { - Type type; - switch (stream.readUnsignedByte()) { - case 4: type = Type.tBoolean; break; - case 5: type = Type.tChar ; break; - case 6: type = Type.tFloat ; break; - case 7: type = Type.tDouble ; break; - case 8: type = Type.tByte ; break; - case 9: type = Type.tShort ; break; - case 10: type = Type.tInt ; break; - case 11: type = Type.tLong ; break; - default: - throw new ClassFormatError("Invalid newarray operand"); - } - type.useType(); - return createNormal - (ca, addr, 2, new NewArrayOperator(Type.tArray(type), 1)); - } - case opc_anewarray: { - CpoolClass cpcls = (CpoolClass) - ca.method.classAnalyzer.getConstant - (stream.readUnsignedShort()); - Type type = Type.tClassOrArray(cpcls.getName().getString()); - type.useType(); - return createNormal - (ca, addr, 3, new NewArrayOperator(Type.tArray(type), 1)); - } - case opc_arraylength: - return createNormal - (ca, addr, 1, new ArrayLengthOperator()); - case opc_athrow: - return createBlock - (ca, addr, 1, - new ThrowBlock(new NopOperator(Type.tUObject), - new Jump(-1))); - case opc_checkcast: { - CpoolClass cpcls = (CpoolClass) - ca.method.classAnalyzer.getConstant - (stream.readUnsignedShort()); - Type type = Type.tClassOrArray(cpcls.getName().getString()); - type.useType(); - return createNormal - (ca, addr, 3, new CheckCastOperator(type)); - } - case opc_instanceof: { - CpoolClass cpcls = (CpoolClass) - ca.method.classAnalyzer.getConstant - (stream.readUnsignedShort()); - Type type = Type.tClassOrArray(cpcls.getName().getString()); - type.useType(); - return createNormal - (ca, addr, 3, new InstanceOfOperator(type)); - } - case opc_monitorenter: - return createNormal(ca, addr, 1, - new MonitorEnterOperator()); - case opc_monitorexit: - return createNormal(ca, addr, 1, - new MonitorExitOperator()); - case opc_wide: { - switch (opcode=stream.readUnsignedByte()) { - case opc_iload: case opc_lload: - case opc_fload: case opc_dload: case opc_aload: - return createNormal - (ca, addr, 4, - new LocalLoadOperator - (types[0][opcode-opc_iload], - ca.getLocalInfo(addr, stream.readUnsignedShort()))); - case opc_istore: case opc_lstore: - case opc_fstore: case opc_dstore: case opc_astore: - return createNormal - (ca, addr, 4, - new LocalStoreOperator - (types[0][opcode-opc_istore], - ca.getLocalInfo(addr+4, stream.readUnsignedShort()), - Operator.ASSIGN_OP)); - case opc_iinc: { - int local = stream.readUnsignedShort(); - int value = stream.readShort(); - int operation = Operator.ADD_OP; - if (value < 0) { - value = -value; - operation = Operator.NEG_OP; - } - LocalInfo li = ca.getLocalInfo(addr, local); - li.setType(ALL_INT_TYPE); - return createNormal - (ca, addr, 6, new IIncOperator - (li, Integer.toString(value), - operation + Operator.OPASSIGN_OP)); - } - case opc_ret: - return createRet (ca, addr, 4, ca.getLocalInfo(addr, stream.readUnsignedShort())); - default: - throw new ClassFormatError("Invalid wide opcode "+opcode); - } - } - case opc_multianewarray: { - CpoolClass cpcls = (CpoolClass) - ca.method.classAnalyzer.getConstant - (stream.readUnsignedShort()); - Type type = Type.tClassOrArray(cpcls.getName().getString()); - int dimension = stream.readUnsignedByte(); - return createNormal - (ca, addr, 4, - new NewArrayOperator(type, dimension)); - } - case opc_ifnull: case opc_ifnonnull: - return createIfGoto - (ca, addr, 3, addr+stream.readShort(), - new CompareUnaryOperator - (OBJECT_TYPE, opcode - (opc_ifnull-Operator.COMPARE_OP))); - case opc_goto_w: - return createGoto - (ca, addr, 5, addr + stream.readInt()); - case opc_jsr_w: - return createJsr - (ca, addr, 5, addr+stream.readInt()); default: - throw new ClassFormatError("Invalid opcode "+opcode); + throw new ClassFormatError("Invalid wide opcode "+opcode); } - } catch (ClassCastException ex) { - ex.printStackTrace(); - throw new ClassFormatError("Constant has wrong type"); + } + case opc_multianewarray: { + CpoolClass cpcls = (CpoolClass) + ca.method.classAnalyzer.getConstant + (stream.readUnsignedShort()); + Type type = Type.tClassOrArray(cpcls.getName().getString()); + int dimension = stream.readUnsignedByte(); + return createNormal + (ca, addr, 4, + new NewArrayOperator(type, dimension)); + } + case opc_ifnull: case opc_ifnonnull: + return createIfGoto + (ca, addr, 3, addr+stream.readShort(), + new CompareUnaryOperator + (OBJECT_TYPE, opcode - (opc_ifnull-Operator.COMPARE_OP))); + case opc_goto_w: + return createGoto + (ca, addr, 5, addr + stream.readInt()); + case opc_jsr_w: + return createJsr + (ca, addr, 5, addr+stream.readInt()); + default: + throw new ClassFormatError("Invalid opcode "+opcode); } } } diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index cc66f6c..2bf55e2 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -36,7 +36,6 @@ import gnu.bytecode.Spy; public class CodeAnalyzer implements Analyzer { - TransformExceptionHandlers handler; FlowBlock methodHeader; CodeAttr code; MethodAnalyzer method; @@ -71,19 +70,78 @@ public class CodeAnalyzer implements Analyzer { param.addElement(getLocalInfo(0, i)); } - void readCode(CodeAttr bincode) + private final static int SEQUENTIAL = 1; + private final static int PREDECESSORS = 2; + /** + * @param code The code array. + * @param handlers The exception handlers. + */ + void readCode(byte[] code, short[] handlers) throws ClassFormatError { - byte[] code = bincode.getCode(); + byte[] flags = new byte[code.length]; + int[] lengths = new int[code.length]; + try { + DataInputStream stream = + new DataInputStream(new ByteArrayInputStream(code)); + for (int addr = 0; addr < code.length; ) { + int[] succs = Opcodes.getSizeAndSuccs(addr, stream); + if (succs.length == 2 + && succs[1] == addr + succs[0]) + flags[addr] |= SEQUENTIAL; + lengths[addr] = succs[0]; + addr += succs[0]; + for (int i=1; i mark) { + System.err.print('.'); + mark += 1000; + } - addr = instr[addr].getNextAddr(); + if (lastBlock != null && flags[addr] == SEQUENTIAL) { + + lastBlock.doSequentialT1(block, lengths[addr]); + + } else { + + instr[addr] = new FlowBlock(this, addr, + lengths[addr], block); + lastBlock = ((flags[addr] & SEQUENTIAL) == 0) + ? null : instr[addr]; + + } + addr += lengths[addr]; } } catch (IOException ex) { throw new ClassFormatError(ex.toString()); @@ -94,28 +152,74 @@ public class CodeAnalyzer implements Analyzer { addr = instr[addr].getNextAddr(); } - handler = new TransformExceptionHandlers(instr); - short[] handlers = Spy.getExceptionHandlers(bincode); - + TransformExceptionHandlers excHandlers + = new TransformExceptionHandlers(instr); for (int i=0; i values.length || values[index] != null) + return false; + value.setType(argType); + setType(Type.tSuperType(Type.tArray(value.getType()))); + values[index] = value; + value.parent = this; + return true; + } + + public int getPriority() { + return 200; } public String toString(String[] operands) { StringBuffer result - = new StringBuffer("new "+type+" {"); - for (int i=0; i< getOperandCount(); i++) { + = new StringBuffer("new ").append(type).append(" { "); + for (int i=0; i< values.length; i++) { if (i>0) result.append(", "); - result.append(operands[i]); + result.append((values[i] != null) ? values[i] : empty); } - return result.append("}").toString(); + return result.append(" }").toString(); } } diff --git a/jode/jode/expr/ConstructorOperator.java b/jode/jode/expr/ConstructorOperator.java index 2ad3717..8fbf78c 100644 --- a/jode/jode/expr/ConstructorOperator.java +++ b/jode/jode/expr/ConstructorOperator.java @@ -24,8 +24,9 @@ public class ConstructorOperator extends Operator { MethodType methodType; Type classType; - public ConstructorOperator(Type type, MethodType methodType) { - super(type, 0); + public ConstructorOperator(Type type, MethodType methodType, + boolean isVoid) { + super(isVoid ? Type.tVoid : type, 0); this.classType = type; this.methodType = methodType; } diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index 4e68c61..d152b12 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -107,6 +107,9 @@ public abstract class Expression { public Expression simplify() { return this; } + public Expression simplifyString() { + return this; + } static Expression EMPTYSTRING = new ConstOperator(Type.tString, "\"\""); diff --git a/jode/jode/flow/CombineIfGotoExpressions.java b/jode/jode/flow/CombineIfGotoExpressions.java index 7d4cfd0..2c9bdda 100644 --- a/jode/jode/flow/CombineIfGotoExpressions.java +++ b/jode/jode/flow/CombineIfGotoExpressions.java @@ -24,14 +24,14 @@ import jode.ComplexExpression; import jode.Type; import jode.BinaryOperator; -public class CombineIfGotoExpressions implements Transformation{ +public class CombineIfGotoExpressions { - public boolean transform(FlowBlock flow) { - if (!(flow.lastModified instanceof ConditionalBlock) - || !(flow.lastModified.outer instanceof SequentialBlock)) + public static boolean transform(ConditionalBlock cb, + StructuredBlock last) { + if (cb.jump == null + || !(last.outer instanceof SequentialBlock)) return false; - - ConditionalBlock cb = (ConditionalBlock) flow.lastModified; + SequentialBlock sequBlock = (SequentialBlock) cb.outer; Expression[] e = new Expression[2]; @@ -77,6 +77,10 @@ public class CombineIfGotoExpressions implements Transformation{ } else return false; + /* We have changed some instructions above. We may never + * return with a failure now. + */ + sequBlock = (SequentialBlock) cb.outer; while (sequBlock.subBlocks[0] instanceof InstructionBlock) { /* Now combine the expression. Everything should @@ -90,14 +94,14 @@ public class CombineIfGotoExpressions implements Transformation{ sequBlock = (SequentialBlock) sequBlock.outer; } - flow.removeSuccessor(prevJump); + cb.flowBlock.removeSuccessor(prevJump); prevJump.prev.removeJump(); Expression cond = new ComplexExpression (new BinaryOperator(Type.tBoolean, operator), e); cb.setInstruction(cond); - cb.moveDefinitions(sequBlock, cb); - cb.replace(sequBlock); + cb.moveDefinitions(sequBlock, last); + last.replace(sequBlock); return true; } return false; diff --git a/jode/jode/flow/CompleteSynchronized.java b/jode/jode/flow/CompleteSynchronized.java index 14a1e2a..99c3f9a 100644 --- a/jode/jode/flow/CompleteSynchronized.java +++ b/jode/jode/flow/CompleteSynchronized.java @@ -24,22 +24,20 @@ import jode.LocalLoadOperator; import jode.LocalStoreOperator; import jode.Expression; -public class CompleteSynchronized implements Transformation { +public class CompleteSynchronized { /** * This combines the monitorenter and the initial expression * into a synchronized statement * @param flow The FlowBlock that is transformed */ - public boolean transform(FlowBlock flow) { + public static boolean transform(SynchronizedBlock synBlock, + StructuredBlock last) { - if (!(flow.lastModified instanceof SynchronizedBlock) - || flow.lastModified.outer == null) + if (!(last.outer instanceof SequentialBlock)) return false; /* If the program is well formed, the following succeed */ - - SynchronizedBlock synBlock = (SynchronizedBlock) flow.lastModified; try { SequentialBlock sequBlock = (SequentialBlock) synBlock.outer; @@ -59,11 +57,11 @@ public class CompleteSynchronized implements Transformation { System.err.print('s'); synBlock.isEntered = true; - synBlock.moveDefinitions(synBlock.outer,synBlock); - synBlock.replace(synBlock.outer); + synBlock.moveDefinitions(last.outer,last); + last.replace(last.outer); /* Is there another expression? */ - if (synBlock.outer == null) + if (!(last.outer instanceof SynchronizedBlock)) return false; Expression object; @@ -85,8 +83,8 @@ public class CompleteSynchronized implements Transformation { } synBlock.object = object; - synBlock.moveDefinitions(synBlock.outer,synBlock); - synBlock.replace(synBlock.outer); + synBlock.moveDefinitions(last.outer,last); + last.replace(last.outer); return true; } } diff --git a/jode/jode/flow/ConditionalBlock.java b/jode/jode/flow/ConditionalBlock.java index 5cdb1e3..9bde6dc 100644 --- a/jode/jode/flow/ConditionalBlock.java +++ b/jode/jode/flow/ConditionalBlock.java @@ -76,4 +76,11 @@ public class ConditionalBlock extends InstructionContainer { trueBlock.dumpSource(writer); writer.untab(); } + + public boolean doTransformations() { + StructuredBlock last = flowBlock.lastModified; + return super.doTransformations() + || CombineIfGotoExpressions.transform(this, last) + || CreateIfThenElseOperator.createFunny(this, last); + } } diff --git a/jode/jode/flow/CreateAssignExpression.java b/jode/jode/flow/CreateAssignExpression.java index 1978bad..1445ed2 100644 --- a/jode/jode/flow/CreateAssignExpression.java +++ b/jode/jode/flow/CreateAssignExpression.java @@ -20,21 +20,20 @@ package jode.flow; import jode.*; -public class CreateAssignExpression implements Transformation{ - - public boolean transform(FlowBlock flow) { - if (!(flow.lastModified instanceof InstructionContainer) - || !(flow.lastModified.outer instanceof SequentialBlock) - || !(((InstructionContainer)flow.lastModified).getInstruction() - instanceof StoreInstruction) - || !(((InstructionContainer)flow.lastModified).getInstruction() - .isVoid())) +public class CreateAssignExpression { + + public static boolean transform(InstructionContainer ic, + StructuredBlock last) { + if (!(last.outer instanceof SequentialBlock) + || !(ic.getInstruction() instanceof StoreInstruction) + || !(ic.getInstruction().isVoid())) return false; - return (createAssignOp(flow) || createAssignExpression(flow)); + return (createAssignOp(ic, last) || createAssignExpression(ic, last)); } - public boolean createAssignOp(FlowBlock flow) { + public static boolean createAssignOp(InstructionContainer ic, + StructuredBlock last) { /* Situation: * @@ -53,11 +52,8 @@ public class CreateAssignExpression implements Transformation{ * * If the optional dup is present the store*= becomes non void. */ - InstructionContainer lastBlock - = (InstructionContainer) flow.lastModified; - SequentialBlock opBlock = (SequentialBlock) lastBlock.outer; - StoreInstruction store - = (StoreInstruction) lastBlock.getInstruction(); + SequentialBlock opBlock = (SequentialBlock) last.outer; + StoreInstruction store = (StoreInstruction) ic.getInstruction(); boolean isAssignOp = false; if (opBlock.subBlocks[0] instanceof SpecialBlock) { @@ -93,7 +89,13 @@ public class CreateAssignExpression implements Transformation{ int opIndex; Expression rightHandSide; + + if (expr.getOperator() instanceof ConvertOperator + && expr.getSubExpressions()[0] instanceof ComplexExpression + && expr.getOperator().getType().isOfType(store.getLValueType())) { + expr = (ComplexExpression) expr.getSubExpressions()[0]; + } if (expr.getOperator() instanceof BinaryOperator) { BinaryOperator binop = (BinaryOperator) expr.getOperator(); @@ -109,24 +111,24 @@ public class CreateAssignExpression implements Transformation{ Expression simple = expr.simplifyString(); rightHandSide = simple; /* Now search for the leftmost operand ... */ - ComplexExpression last = null; + ComplexExpression lastExpr = null; while (simple instanceof ComplexExpression && simple.getOperator() instanceof StringAddOperator) { - last = (ComplexExpression) simple; - simple = last.getSubExpressions()[0]; + lastExpr = (ComplexExpression) simple; + simple = lastExpr.getSubExpressions()[0]; } /* ... check it ... */ - if (last == null || !(simple instanceof Operator) + if (lastExpr == null || !(simple instanceof Operator) || !store.matches((Operator) simple)) return false; /* ... and remove it. */ - if (last.getParent() != null) { - ((ComplexExpression)last.getParent()).getSubExpressions()[0] - = last.getSubExpressions()[1]; + if (lastExpr.getParent() != null) { + ((ComplexExpression)lastExpr.getParent()) + .setSubExpressions(0,lastExpr.getSubExpressions()[1]); } else - rightHandSide = last.getSubExpressions()[1]; + rightHandSide = lastExpr.getSubExpressions()[1]; opIndex = Operator.ADD_OP; } @@ -137,20 +139,19 @@ public class CreateAssignExpression implements Transformation{ if (isAssignOp) store.makeNonVoid(); - lastBlock.replace(opBlock.subBlocks[1]); + last.replace(opBlock.subBlocks[1]); return true; } - public boolean createAssignExpression(FlowBlock flow) { + public static boolean createAssignExpression(InstructionContainer ic, + StructuredBlock last) { /* Situation: * sequBlock: * dup_X(lvalue_count) * store instruction */ - InstructionContainer lastBlock - = (InstructionContainer) flow.lastModified; - SequentialBlock sequBlock = (SequentialBlock) lastBlock.outer; - StoreInstruction store = (StoreInstruction) lastBlock.getInstruction(); + SequentialBlock sequBlock = (SequentialBlock) last.outer; + StoreInstruction store = (StoreInstruction) ic.getInstruction(); if (sequBlock.subBlocks[0] instanceof SpecialBlock) { diff --git a/jode/jode/flow/CreateConstantArray.java b/jode/jode/flow/CreateConstantArray.java index 23f137a..ceee767 100644 --- a/jode/jode/flow/CreateConstantArray.java +++ b/jode/jode/flow/CreateConstantArray.java @@ -26,104 +26,106 @@ import jode.ConstantArrayOperator; import jode.ConstOperator; 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; + public static boolean transform(InstructionContainer ic, + StructuredBlock last) { + /* Situation: + * PUSH new Array[] + * DUP + * PUSH index + * PUSH value + * stack_2[stack_1] = stack_0 + * ... + */ + if (last.outer instanceof SequentialBlock) { - int lastindex = -1; - while (ib.getInstruction() instanceof ArrayStoreOperator) { - ArrayStoreOperator store = - (ArrayStoreOperator) ib.getInstruction(); + SequentialBlock sequBlock = (SequentialBlock) last.outer; - sequBlock = (SequentialBlock) sequBlock.outer; - ib = (InstructionBlock) sequBlock.subBlocks[0]; - Expression lastconst = ib.getInstruction(); - - sequBlock = (SequentialBlock) sequBlock.outer; - ib = (InstructionBlock) sequBlock.subBlocks[0]; - Expression indexexpr = ib.getInstruction(); - ConstOperator indexop = - (ConstOperator) indexexpr.getOperator(); - if (!indexop.getType().isOfType(Type.tUInt)) - return false; - int index = Integer.parseInt(indexop.getValue()); - if (index >= 0 && consts == null) { - lastindex = index; - consts = new Expression[lastindex+1]; - } else if (index < 0 || index > lastindex) - return false; - else { - while (index < lastindex) { - consts[lastindex--] = - new ConstOperator(Type.tUnknown, "0"); - } - } - consts[lastindex--] = lastconst; - sequBlock = (SequentialBlock) sequBlock.outer; + if (!(ic.getInstruction() instanceof ArrayStoreOperator) + || !(sequBlock.subBlocks[0] instanceof InstructionBlock) + || !(sequBlock.outer instanceof SequentialBlock)) + return false; + ArrayStoreOperator store + = (ArrayStoreOperator) ic.getInstruction(); + InstructionBlock ib = (InstructionBlock)sequBlock.subBlocks[0]; + sequBlock = (SequentialBlock) sequBlock.outer; - SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0]; - if (dup.type != SpecialBlock.DUP - || dup.depth != 0 - || dup.count != store.getLValueType().stackSize()) - return false; - count++; - sequBlock = (SequentialBlock) sequBlock.outer; - ib = (InstructionBlock) sequBlock.subBlocks[0]; - } - if (count == 0) + if (!(sequBlock.subBlocks[0] instanceof InstructionBlock) + || !(sequBlock.outer instanceof SequentialBlock)) return false; - while (lastindex >= 0) - consts[lastindex--] = new ConstOperator(Type.tUnknown, "0"); - ComplexExpression newArrayExpr = - (ComplexExpression) ib.getInstruction(); - NewArrayOperator newArrayOp = - (NewArrayOperator) newArrayExpr.getOperator(); - type = newArrayOp.getType(); - if (newArrayOp.getOperandCount() != 1) + + Expression expr = ib.getInstruction(); + ib = (InstructionBlock)sequBlock.subBlocks[0]; + sequBlock = (SequentialBlock) sequBlock.outer; + + if (expr.getOperandCount() > 0 + || !(ib.getInstruction() instanceof ConstOperator) + || !(sequBlock.subBlocks[0] instanceof SpecialBlock) + || !(sequBlock.outer instanceof SequentialBlock)) return false; - Expression countexpr = newArrayExpr.getSubExpressions()[0]; - ConstOperator countop = - (ConstOperator) countexpr.getOperator(); - if (!countop.getType().isOfType(Type.tUInt)) + + ConstOperator indexOp = (ConstOperator) ib.getInstruction(); + SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0]; + sequBlock = (SequentialBlock) sequBlock.outer; + + if (!indexOp.getType().isOfType(Type.tUInt) + || dup.type != SpecialBlock.DUP + || dup.depth != 0 + || dup.count != store.getLValueType().stackSize() + || !(sequBlock.subBlocks[0] instanceof InstructionBlock)) return false; - int arraylength = Integer.parseInt(countop.getValue()); - if (arraylength != consts.length) { - if (arraylength < consts.length) + + int index = Integer.parseInt(indexOp.getValue()); + ib = (InstructionBlock)sequBlock.subBlocks[0]; + + if (ib.getInstruction() instanceof ComplexExpression + && (ib.getInstruction().getOperator() + instanceof NewArrayOperator)) { + /* This is the first element */ + ComplexExpression newArrayExpr = + (ComplexExpression) ib.getInstruction(); + NewArrayOperator newArrayOp = + (NewArrayOperator) newArrayExpr.getOperator(); + if (newArrayOp.getOperandCount() != 1 + || !(newArrayExpr.getSubExpressions()[0] + instanceof ConstOperator)) + return false; + + ConstOperator countop = + (ConstOperator) newArrayExpr.getSubExpressions()[0]; + if (!countop.getType().isOfType(Type.tUInt)) + return false; + + int arraylength = Integer.parseInt(countop.getValue()); + if (arraylength <= index) return false; - Expression[] newConsts = new Expression[arraylength]; - System.arraycopy(consts, 0, newConsts, 0, consts.length); - for (int i=consts.length; i */ -public class CreateExpression implements Transformation { +public class CreateExpression { /** * This does the transformation. * @param FlowBlock the flow block to transform. * @return true if flow block was simplified. */ - public boolean transform(FlowBlock flow) { - if (!(flow.lastModified instanceof InstructionContainer) - || !(flow.lastModified.outer instanceof SequentialBlock)) + public static boolean transform(InstructionContainer ic, + StructuredBlock last) { + + int params = ic.getInstruction().getOperandCount(); + if (params == 0) + return false; + + ComplexExpression parent = null; + Expression inner = ic.getInstruction(); + while (inner instanceof ComplexExpression) { + parent = (ComplexExpression)inner; + inner = parent.getSubExpressions()[0]; + } + + if (!(inner instanceof Operator)) + return false; + + Operator op = (Operator)inner; + + if (!(last.outer instanceof SequentialBlock)) return false; + SequentialBlock sequBlock = (SequentialBlock)last.outer; + + /* First check if Expression can be created, but do nothing yet. + */ + Expression lastExpression = null; + for (int i = params;;) { + + if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)) + return false; + + Expression expr = + ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); + + + if (!expr.isVoid()) { + if (--i == 0) + break; + } else if (lastExpression == null + || lastExpression.canCombine(expr) <= 0) + return false; - InstructionContainer ic = (InstructionContainer) flow.lastModified; - if (ic.getInstruction() instanceof Operator) { + if (expr.getOperandCount() > 0) + /* This is a not fully resolved expression in the + * middle, we must not touch it. */ + return false; - Operator op = (Operator) ic.getInstruction(); - int params = op.getOperandCount(); - if (params == 0) + lastExpression = expr; + + if (!(sequBlock.outer instanceof SequentialBlock)) return false; + sequBlock = (SequentialBlock) sequBlock.outer; + } - Expression[] exprs = new Expression[params]; - - SequentialBlock sequBlock = (SequentialBlock) ic.outer; - - Expression lastExpression = null; - /* First check if Expression can be created, but do nothing yet. - */ - for (int i=params; ;) { - if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)) - return false; - - InstructionBlock block = - (InstructionBlock) sequBlock.subBlocks[0]; - - Expression expr = block.getInstruction(); - - if (!expr.isVoid()) { - if (--i == 0) - break; - } else if (lastExpression != null - && lastExpression.canCombine(expr) <= 0) - return false; - - if (expr.getOperandCount() > 0) - /* This is a not fully resolved expression in the - * middle, we must not touch it. */ - return false; - - lastExpression = expr; - if (!(sequBlock.outer instanceof SequentialBlock)) - return false; - sequBlock = (SequentialBlock)sequBlock.outer; - } - - /* Now, do the combination. Everything must succeed now. - */ - sequBlock = (SequentialBlock) ic.outer; - for (int i=params; ;) { - - InstructionBlock block = - (InstructionBlock) sequBlock.subBlocks[0]; - - Expression expr = block.getInstruction(); - - if (!expr.isVoid()) { - exprs[--i] = expr; - if (i == 0) - break; - } else - exprs[i] = exprs[i].combine(expr); - - sequBlock = (SequentialBlock)sequBlock.outer; - } - - if(jode.Decompiler.isVerbose) - System.err.print('x'); + /* Now, do the combination. Everything must succeed now. + */ + Expression[] exprs = new Expression[params]; + sequBlock = (SequentialBlock) last.outer; + for (int i=params; ;) { + + Expression expr = + ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); + + if (!expr.isVoid()) { + exprs[--i] = expr; + if (i == 0) + break; + } else + exprs[i] = exprs[i].combine(expr); - ic.setInstruction(new ComplexExpression(op, exprs)); - ic.moveDefinitions(sequBlock, ic); - ic.replace(sequBlock); - return true; + sequBlock = (SequentialBlock)sequBlock.outer; } - return false; + + if(jode.Decompiler.isVerbose) + System.err.print('x'); + + Expression newExpr; + if (params == 1 && op instanceof NopOperator) { + exprs[0].setType(op.getType()); + newExpr = exprs[0]; + } else + newExpr = new ComplexExpression(op, exprs); + + if (parent != null) + parent.setSubExpressions(0, newExpr); + else + ic.setInstruction(newExpr); + + ic.moveDefinitions(sequBlock, last); + last.replace(sequBlock); + return true; } } diff --git a/jode/jode/flow/CreateForInitializer.java b/jode/jode/flow/CreateForInitializer.java index 23a4cf9..8628841 100644 --- a/jode/jode/flow/CreateForInitializer.java +++ b/jode/jode/flow/CreateForInitializer.java @@ -21,23 +21,19 @@ package jode.flow; import jode.Expression; import jode.StoreInstruction; -public class CreateForInitializer implements Transformation { +public class CreateForInitializer { /** * This combines an variable initializer into a for statement - * @param flow The FlowBlock that is transformed + * @param forBlock the for block + * @param last the lastModified of the flow block. */ - public boolean transform(FlowBlock flow) { + public static boolean transform(LoopBlock forBlock, StructuredBlock last) { - if (!(flow.lastModified instanceof LoopBlock) - || !(flow.lastModified.outer instanceof SequentialBlock)) + if (!(last.outer instanceof SequentialBlock)) return false; - LoopBlock forBlock = (LoopBlock) flow.lastModified; - if (forBlock.type != forBlock.FOR || forBlock.init != null) - return false; - - SequentialBlock sequBlock = (SequentialBlock) forBlock.outer; + SequentialBlock sequBlock = (SequentialBlock) last.outer; if (!(sequBlock.subBlocks[0] instanceof InstructionBlock)) return false; @@ -53,8 +49,8 @@ public class CreateForInitializer implements Transformation { System.err.print('f'); forBlock.init = initializer; - forBlock.moveDefinitions(forBlock.outer, forBlock); - forBlock.replace(forBlock.outer); + forBlock.moveDefinitions(last.outer, null); + last.replace(last.outer); return true; } } diff --git a/jode/jode/flow/CreateIfThenElseOperator.java b/jode/jode/flow/CreateIfThenElseOperator.java index de0d8e6..331719a 100644 --- a/jode/jode/flow/CreateIfThenElseOperator.java +++ b/jode/jode/flow/CreateIfThenElseOperator.java @@ -20,24 +20,109 @@ package jode.flow; import jode.Type; import jode.Expression; +import jode.ConstOperator; import jode.ComplexExpression; import jode.IfThenElseOperator; import jode.CompareUnaryOperator; import java.util.Enumeration; import java.util.Vector; -public class CreateIfThenElseOperator implements Transformation { +public class CreateIfThenElseOperator { + + /** + * This handles the body of createFunny. There are three cases: + * + *
+     * --------
+     *  IF (c2)
+     *    GOTO trueDest            ->   PUSH c2
+     *  PUSH false
+     * --------
+     *  PUSH bool                  ->   PUSH bool
+     * --------
+     *  if (c2)
+     *    (handled recursively)    ->   PUSH (c2 ? expr1 : expr2)
+     *  else
+     *    (handled recursively)
+     * --------
+     * 
+ */ + private static boolean createFunnyHelper(FlowBlock trueDest, + FlowBlock falseDest, + StructuredBlock block) { + + if (block instanceof InstructionBlock + && !((InstructionBlock)block).getInstruction().isVoid()) + return true; + + if (block instanceof IfThenElseBlock) { + IfThenElseBlock ifBlock = (IfThenElseBlock) block; + Expression expr1, expr2; + if (ifBlock.elseBlock == null) + return false; + + if (!createFunnyHelper(trueDest, falseDest, ifBlock.thenBlock) + | !createFunnyHelper(trueDest, falseDest, ifBlock.elseBlock)) + return false; + + if (jode.Decompiler.isVerbose) + System.err.print('?'); + + IfThenElseOperator iteo = new IfThenElseOperator(Type.tBoolean); + ((InstructionBlock)ifBlock.thenBlock).setInstruction + (new ComplexExpression + (iteo, new Expression[] { + ifBlock.cond, + ((InstructionBlock) ifBlock.thenBlock).getInstruction(), + ((InstructionBlock) ifBlock.elseBlock).getInstruction() + })); + + ifBlock.thenBlock.moveDefinitions(ifBlock, null); + ifBlock.thenBlock.replace(ifBlock); + return true; + } + + if (block instanceof SequentialBlock + && block.getSubBlocks()[0] instanceof ConditionalBlock + && block.getSubBlocks()[1] instanceof InstructionBlock) { + + ConditionalBlock condBlock = + (ConditionalBlock) block.getSubBlocks()[0]; + InstructionBlock pushBlock = + (InstructionBlock) block.getSubBlocks()[1]; + + if (!(pushBlock.getInstruction() instanceof ConstOperator)) + return false; + + ConstOperator constOp = + (ConstOperator) pushBlock.getInstruction(); + + if (condBlock.trueBlock.jump.destination == trueDest + && constOp.getValue().equals("0")) { + + Expression cond = condBlock.getInstruction(); + condBlock.flowBlock.removeSuccessor(condBlock.trueBlock.jump); + condBlock.trueBlock.removeJump(); + + pushBlock.setInstruction(cond); + pushBlock.moveDefinitions(block, null); + pushBlock.replace(block); + return true; + } + } + return false; + } /** * This handles the more complicated form of the ?-:-operator used * in a conditional block. The simplest case is: *
      *   if (cond)
-     *       push e1
+     *       PUSH e1
      *   else {
      *       IF (c2)
      *           GOTO flow_2_
-     *       push 0
+     *       PUSH false
      *   }
      * ->IF (stack_0 == 0)
      *     GOTO flow_1_
@@ -60,104 +145,35 @@ public class CreateIfThenElseOperator implements Transformation {
      * sometimes be better replaced with a correct jump.
      * @param flow The FlowBlock that is transformed 
      */
-    public boolean createFunny(FlowBlock flow) {
+    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)
-            || conditional.trueBlock.jump == null 
-            || conditional.jump == null
-            || !(conditional.getInstruction() instanceof CompareUnaryOperator))
+        if (cb.jump == null
+            || !(cb.getInstruction() instanceof CompareUnaryOperator)
+            || !(last.outer instanceof SequentialBlock)
+            || !(last.outer.getSubBlocks()[0] instanceof IfThenElseBlock))
             return false;
         
         CompareUnaryOperator compare = 
-            (CompareUnaryOperator) conditional.getInstruction();
+            (CompareUnaryOperator) cb.getInstruction();
 
         FlowBlock trueDestination;
-        if (compare.getOperatorIndex() == compare.EQUALS_OP)
-            trueDestination = conditional.jump.destination;
-        else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP)
-            trueDestination = conditional.trueBlock.jump.destination;
-        else
+        FlowBlock falseDestination;
+        if (compare.getOperatorIndex() == compare.EQUALS_OP) {
+            trueDestination = cb.jump.destination;
+            falseDestination = cb.trueBlock.jump.destination;
+        } else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP) {
+            falseDestination = cb.jump.destination;
+            trueDestination = cb.trueBlock.jump.destination;
+        } else
             return false;
 
         Expression[] e = new Expression[3];
         IfThenElseBlock ifBlock;
-        try {
-            SequentialBlock sequBlock = 
-                (SequentialBlock) conditional.outer;
-
-            ifBlock = (IfThenElseBlock) sequBlock.subBlocks[0];
-
-            while (true) {
-                if (ifBlock.thenBlock instanceof IfThenElseBlock)
-                    ifBlock = (IfThenElseBlock) ifBlock.thenBlock;
-                else if (ifBlock.elseBlock instanceof IfThenElseBlock)
-                    ifBlock = (IfThenElseBlock) ifBlock.elseBlock;
-                else
-                    break;
-            }
-
-            e[0] = ifBlock.cond;
-
-            StructuredBlock[] subBlocks = ifBlock.getSubBlocks();
-            if (subBlocks.length != 2)
-                return false;
-
-            for (int i=0; i< 2; i++) {
-                if (subBlocks[i] instanceof InstructionBlock) {
-                    e[i+1] = ((InstructionBlock)subBlocks[i]).getInstruction();
-                    continue;
-                }
-
-                sequBlock = (SequentialBlock) subBlocks[i];
-                ConditionalBlock condBlock = 
-                    (ConditionalBlock) sequBlock.subBlocks[0];
-                InstructionBlock pushBlock =
-                    (InstructionBlock) sequBlock.subBlocks[1];
-                
-                jode.ConstOperator zero = 
-                    (jode.ConstOperator) pushBlock.getInstruction();
-                if (!zero.getValue().equals("0"))
-                    return false;
-                
-                if (!(condBlock.trueBlock instanceof EmptyBlock)
-                    || condBlock.trueBlock.jump == null
-                    || condBlock.jump != null
-                    || condBlock.trueBlock.jump.destination 
-                    != trueDestination)
-                    return false;
-
-                Expression cond = condBlock.getInstruction();
-                flow.removeSuccessor(condBlock.trueBlock.jump);
-                condBlock.trueBlock.removeJump();
-                pushBlock.setInstruction(cond);
-                pushBlock.moveDefinitions(sequBlock, pushBlock);
-                pushBlock.replace(sequBlock);
-
-                e[i+1] = cond;
-            }
-        } catch (ClassCastException ex) {
-            return false;
-        } catch (NullPointerException ex) {
-            return false;
-        }
-
-        if (jode.Decompiler.isVerbose)
-            System.err.print('?');
 
-        IfThenElseOperator iteo = new IfThenElseOperator
-            (Type.tSuperType(e[1].getType())
-             .intersection(Type.tSuperType(e[2].getType())));
-
-        ((InstructionBlock)ifBlock.thenBlock).
-            setInstruction(new ComplexExpression(iteo, e));
-        ifBlock.thenBlock.moveDefinitions(ifBlock, ifBlock.thenBlock);
-        ifBlock.thenBlock.replace(ifBlock);
-        return true;
+        SequentialBlock sequBlock = (SequentialBlock) last.outer;
+        return createFunnyHelper(trueDestination, falseDestination,
+                                 sequBlock.subBlocks[0]);
     }
 
     /**
@@ -176,57 +192,47 @@ public class CreateIfThenElseOperator implements Transformation {
      * The -> points to the lastModified block.
      * @param flow The FlowBlock that is transformed
      */
-    public boolean create(FlowBlock flow) {
+    public static boolean create(InstructionContainer ic,
+                                 StructuredBlock last) {
         Expression e[] = new Expression[3];
         InstructionBlock thenBlock;
-        try {
-            InstructionBlock elseBlock = (InstructionBlock) flow.lastModified;
-
-            SequentialBlock sequBlock = (SequentialBlock)elseBlock.outer;
-            if (sequBlock.subBlocks[1] != elseBlock)
-                return false;
-
-            IfThenElseBlock ifBlock = (IfThenElseBlock)sequBlock.subBlocks[0];
-            if (ifBlock.elseBlock != null)
-                return false;
-
-            thenBlock = (InstructionBlock) ifBlock.thenBlock;
-
-            if (thenBlock.jump.destination != elseBlock.jump.destination)
-                return false;
-
-            e[1] = thenBlock.getInstruction();
-            if (e[1].isVoid())
-                return false;
-            e[2] = elseBlock.getInstruction();
-            if (e[2].isVoid())
-                return false;
-            e[0] = ifBlock.cond;
-
-        } catch (ClassCastException ex) {
+        if (ic.jump == null
+            || !(last.outer instanceof SequentialBlock))
             return false;
-        } catch (NullPointerException ex) {
+        SequentialBlock sequBlock = (SequentialBlock)last.outer;
+        if (!(sequBlock.subBlocks[0] instanceof IfThenElseBlock))
             return false;
-        }
 
+        IfThenElseBlock ifBlock = (IfThenElseBlock)sequBlock.subBlocks[0];
+        if (!(ifBlock.thenBlock instanceof InstructionBlock)
+            || ifBlock.thenBlock.jump == null
+            || ifBlock.thenBlock.jump.destination != ic.jump.destination
+            || ifBlock.elseBlock != null)
+            return false;
+        
+        thenBlock = (InstructionBlock) ifBlock.thenBlock;
+        
+        e[1] = thenBlock.getInstruction();
+        if (e[1].isVoid())
+            return false;
+        e[2] = ic.getInstruction();
+        if (e[2].isVoid())
+            return false;
+        e[0] = ifBlock.cond;
+        
         if (jode.Decompiler.isVerbose)
             System.err.print('?');
 
-        flow.removeSuccessor(thenBlock.jump);
+        thenBlock.flowBlock.removeSuccessor(thenBlock.jump);
         thenBlock.removeJump();
 
         IfThenElseOperator iteo = new IfThenElseOperator
             (Type.tSuperType(e[1].getType())
              .intersection(Type.tSuperType(e[2].getType())));
 
-        ((InstructionBlock)flow.lastModified).
-            setInstruction(new ComplexExpression(iteo, e));
-        flow.lastModified.moveDefinitions(flow.lastModified.outer, null);
-        flow.lastModified.replace(flow.lastModified.outer);
+        ic.setInstruction(new ComplexExpression(iteo, e));
+        ic.moveDefinitions(last.outer, last);
+        last.replace(last.outer);
         return true;
     }
-
-    public boolean transform(FlowBlock flow) {
-        return createFunny(flow) || create(flow);
-    }
 }
diff --git a/jode/jode/flow/CreateNewConstructor.java b/jode/jode/flow/CreateNewConstructor.java
index 2726407..f883814 100644
--- a/jode/jode/flow/CreateNewConstructor.java
+++ b/jode/jode/flow/CreateNewConstructor.java
@@ -24,13 +24,14 @@ import jode.ComplexExpression;
 import jode.ConstructorOperator;
 import jode.NewOperator;
 
-public class CreateNewConstructor implements Transformation{
+public class CreateNewConstructor {
 
-    public boolean transform(FlowBlock flow) {
+    public static boolean transform(InstructionContainer ic,
+                                    StructuredBlock last) {
         /* Situation:
          *
          *  new 
-         *  DUP
+         *  (optional DUP)
          *  PUSH load_ops
          *  optionally:  <= used for "string1 += string2"
          *      DUP_X2
@@ -43,23 +44,21 @@ public class CreateNewConstructor implements Transformation{
          *  optionally:
          *      DUP_X1      <= remove the depth
          *  [ n non void + some void expressions ]
-         *  PUSH new (stack_n-1,...,stack_0)
+         *  (optional PUSH) new (stack_n-1,...,stack_0)
          */
 
-        if (!(flow.lastModified instanceof InstructionBlock)
-            || !(flow.lastModified.outer instanceof SequentialBlock))
+        if (!(last.outer instanceof SequentialBlock))
             return false;
-        InstructionBlock block = (InstructionBlock) flow.lastModified;
-        if (!(block.getInstruction() instanceof InvokeOperator))
+        if (!(ic.getInstruction() instanceof InvokeOperator))
             return false;
-        InvokeOperator constrCall = (InvokeOperator) block.getInstruction();
+        InvokeOperator constrCall = (InvokeOperator) ic.getInstruction();
         if (!constrCall.isConstructor())
             return false;
 
         /* The rest should probably succeed */
         int params = constrCall.getOperandCount() - 1;
-        SpecialBlock optDup = null;
-        SequentialBlock sequBlock = (SequentialBlock) block.outer;
+        SpecialBlock optDupX2 = null;
+        SequentialBlock sequBlock = (SequentialBlock) last.outer;
         while (params > 0) {
             if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
                 return false;
@@ -74,11 +73,11 @@ public class CreateNewConstructor implements Transformation{
                     instanceof SpecialBlock) {
                     /* handle the optional dup */
                     sequBlock = (SequentialBlock) sequBlock.outer;
-                    optDup = (SpecialBlock) sequBlock.subBlocks[0];
-                    if (optDup.type != SpecialBlock.DUP
-                        || optDup.depth != 2)
+                    optDupX2 = (SpecialBlock) sequBlock.subBlocks[0];
+                    if (optDupX2.type != SpecialBlock.DUP
+                        || optDupX2.depth != 2)
                         return false;
-                    params = optDup.count;
+                    params = optDupX2.count;
                 } else
                     return false;
             }
@@ -93,34 +92,36 @@ public class CreateNewConstructor implements Transformation{
                && sequBlock.outer instanceof SequentialBlock)
             sequBlock = (SequentialBlock) sequBlock.outer;
                
+        SpecialBlock dup = null;
         if (sequBlock.outer instanceof SequentialBlock
             && sequBlock.subBlocks[0] instanceof SpecialBlock) {
-            SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
+
+            dup = (SpecialBlock) sequBlock.subBlocks[0];
             if (dup.type != SpecialBlock.DUP 
                 || dup.count != 1 || dup.depth != 0)
                 return false;
-
             sequBlock = (SequentialBlock)sequBlock.outer;
-            if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
-                return false;
-            block = (InstructionBlock) sequBlock.subBlocks[0];
-            if (!(block.getInstruction() instanceof NewOperator))
-                return false;
-
-            NewOperator op = (NewOperator) block.getInstruction();
-            if (constrCall.getClassType() != op.getType())
-                return false;
+        }
 
-            block.removeBlock();
+        if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
+            return false;
+        InstructionBlock block = (InstructionBlock) sequBlock.subBlocks[0];
+        if (!(block.getInstruction() instanceof NewOperator))
+            return false;
+        
+        NewOperator op = (NewOperator) block.getInstruction();
+        if (constrCall.getClassType() != op.getType())
+            return false;
+        
+        block.removeBlock();
+        if (dup != null)
             dup.removeBlock();
-            if (optDup != null)
-                optDup.depth = 0;
-            ((InstructionContainer) flow.lastModified).setInstruction
-                (new ConstructorOperator(constrCall.getClassType(), 
-                                         constrCall.getMethodType()));
-            return true;
-        }
-        return false;
+        if (optDupX2 != null)
+            optDupX2.depth = 0;
+        ic.setInstruction(new ConstructorOperator(constrCall.getClassType(), 
+                                                  constrCall.getMethodType(),
+                                                  dup == null));
+        return true;
     }
 }
 
diff --git a/jode/jode/flow/CreatePrePostIncExpression.java b/jode/jode/flow/CreatePrePostIncExpression.java
index 3838600..0e2f83f 100644
--- a/jode/jode/flow/CreatePrePostIncExpression.java
+++ b/jode/jode/flow/CreatePrePostIncExpression.java
@@ -20,30 +20,28 @@
 package jode.flow;
 import jode.*;
 
-public class CreatePrePostIncExpression implements Transformation {
+public class CreatePrePostIncExpression {
 
-    public boolean transform(FlowBlock flow)
+    public static boolean transform(InstructionContainer ic, 
+                                    StructuredBlock last)
     {
-        return (createLocalPrePostInc(flow) || createPostInc(flow));
+        return (createLocalPrePostInc(ic, last) || createPostInc(ic, last));
     }
     
-    public boolean createLocalPrePostInc(FlowBlock flow) {
-        IIncOperator iinc;
-        boolean isPost;
-        int op;
-        InstructionContainer lastBlock;
-        Type type;
-        try {
-            lastBlock = (InstructionContainer) flow.lastModified;
-
-            Expression instr2 = lastBlock.getInstruction();
-            SequentialBlock sequBlock = (SequentialBlock)lastBlock.outer;
-            if (sequBlock.subBlocks[1] != lastBlock)
-                return false;
-            InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0];
-            Expression instr1 = ib.getInstruction();
+    public static boolean createLocalPrePostInc(InstructionContainer ic, 
+                                                StructuredBlock last) {
+
+        if (last.outer instanceof SequentialBlock 
+            && last.outer.getSubBlocks()[0] instanceof InstructionBlock) {
 
+            Expression instr1 = ((InstructionBlock)
+                                 last.outer.getSubBlocks()[0])
+                .getInstruction();
+            Expression instr2 = ic.getInstruction();
+
+            IIncOperator iinc;
             LocalLoadOperator load;
+            boolean isPost;
             if (instr1 instanceof IIncOperator 
                 && instr2 instanceof LocalLoadOperator) {
                 iinc = (IIncOperator) instr1;
@@ -57,6 +55,7 @@ public class CreatePrePostIncExpression implements Transformation {
             } else
                 return false;
 
+            int op;
 	    if (iinc.getOperatorIndex() == iinc.ADD_OP + iinc.OPASSIGN_OP)
                 op = Operator.INC_OP;
             else if (iinc.getOperatorIndex() == iinc.NEG_OP + iinc.OPASSIGN_OP)
@@ -72,94 +71,124 @@ public class CreatePrePostIncExpression implements Transformation {
 	    if (!iinc.matches(load))
 		return false;
 
-	    type = load.getType().intersection(Type.tUInt);
-        } catch (NullPointerException ex) {
-            return false;
-        } catch (ClassCastException ex) {
-            return false;
+	    Type type = load.getType().intersection(Type.tUInt);
+            Operator ppop = 
+                new LocalPrePostFixOperator(type, op, iinc, isPost);
+
+            ic.setInstruction(ppop);
+            ic.moveDefinitions(last.outer, last);
+            last.replace(last.outer);
+            return true;
         }
-	Operator ppop = new LocalPrePostFixOperator(type, op, iinc, isPost);
-        lastBlock.setInstruction(ppop);
-        lastBlock.moveDefinitions(lastBlock.outer, lastBlock);
-        lastBlock.replace(lastBlock.outer);
-	return true;
+	return false;
     }
 
-    public boolean createPostInc(FlowBlock flow) {
-	StoreInstruction store;
-	int op;
-	Type type;
-        InstructionBlock lastBlock;
-        SequentialBlock sequBlock;
-        try {
-            lastBlock = (InstructionBlock) flow.lastModified;
-
-            Expression storeExpr = lastBlock.getInstruction();
-	    store = (StoreInstruction) storeExpr.getOperator();
-            if (!store.isVoid())
-                return false;
+    public static boolean createPostInc(InstructionContainer ic, 
+                                        StructuredBlock last) {
+
+        /* Situation:
+         *
+         *   PUSH load/storeOps              PUSH load/storeOps
+         *   DUP  load/storeOps              PUSH store++/--
+         *   load  (unresolved)
+         *   DUP                       ->
+         *   PUSH +/-1
+         *   IADD/SUB
+         *   store (unresolved)
+         *
+         *   load (no params)          ->    PUSH store++/--
+         *   DUP
+         *   PUSH +/-1
+         *   store IADD/SUB
+         */
+
+        if (!(ic.getInstruction().getOperator() instanceof StoreInstruction)
+            || !(ic.getInstruction().isVoid()))
+            return false;
+        
+        StoreInstruction store = 
+            (StoreInstruction) ic.getInstruction().getOperator();
 
-            sequBlock = (SequentialBlock) lastBlock.outer;
-            if (sequBlock.subBlocks[1] != lastBlock)
-                return false;
 
-            BinaryOperator binOp;
-            InstructionBlock ib;
-            if (store.getLValueOperandCount() > 0) {
-                ib = (InstructionBlock) sequBlock.subBlocks[0];
-                binOp = (BinaryOperator) ib.getInstruction();
-                sequBlock = (SequentialBlock) sequBlock.outer;
-            } else
-                binOp = (BinaryOperator) 
-                    ((ComplexExpression) storeExpr).getSubExpressions()[0];
+        if (!(last.outer instanceof SequentialBlock))
+            return false;
+        SequentialBlock sb = (SequentialBlock)last.outer;
 
-            if (binOp.getOperatorIndex() == store.ADD_OP)
-                op = Operator.INC_OP;
-            else if (store.getOperatorIndex() == store.NEG_OP)
-                op = Operator.DEC_OP;
-            else
+        Expression binOp;
+        if (store.getLValueOperandCount() == 0) {
+            if (!(ic.getInstruction() instanceof ComplexExpression))
                 return false;
-                
-            ib = (InstructionBlock) sequBlock.subBlocks[0];
-
-            ConstOperator constOp = (ConstOperator) ib.getInstruction();
-            if (!constOp.getValue().equals("1") &&
-		!constOp.getValue().equals("-1"))
-                return false;
-            if (constOp.getValue().equals("-1"))
-		op ^= 1;
-
-            sequBlock = (SequentialBlock) sequBlock.outer;
-            SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
-            if (dup.type != SpecialBlock.DUP
-                || dup.count != store.getLValueType().stackSize()
-                || dup.depth != store.getLValueOperandCount())
+            binOp = ((ComplexExpression) ic.getInstruction())
+                .getSubExpressions()[0];
+        } else {
+            if (!(sb.subBlocks[0] instanceof InstructionBlock)
+                || !(sb.outer instanceof SequentialBlock))
                 return false;
+            binOp = ((InstructionBlock) sb.subBlocks[0])
+                .getInstruction();
+            sb = (SequentialBlock) sb.outer;
+        }
+        if (!(binOp instanceof BinaryOperator))
+            return false;
+ 
+        int op;
+        if (binOp.getOperator().getOperatorIndex() == store.ADD_OP)
+            op = Operator.INC_OP;
+        else if (binOp.getOperator().getOperatorIndex() == store.NEG_OP)
+            op = Operator.DEC_OP;
+        else
+            return false;
+                
+        if (!(sb.subBlocks[0] instanceof InstructionBlock))
+            return false;
+        InstructionBlock ib = (InstructionBlock) sb.subBlocks[0];
+        if (!(ib.getInstruction() instanceof ConstOperator))
+            return false;
+        ConstOperator constOp = (ConstOperator) ib.getInstruction();
+        if (constOp.getValue().equals("-1"))
+            op ^= 1;
+        else if (!constOp.getValue().equals("1"))
+            return false;
 
-            sequBlock = (SequentialBlock) sequBlock.outer;
-            ib = (InstructionBlock) sequBlock.subBlocks[0];
-            Operator load = (Operator) ib.getInstruction();
-	    if (!store.matches(load))
-		return false;
+        if (!(sb.outer instanceof SequentialBlock))
+            return false;
+        sb = (SequentialBlock) sb.outer;
+        if (!(sb.subBlocks[0] instanceof SpecialBlock))
+            return false;
+            
+        SpecialBlock dup = (SpecialBlock) sb.subBlocks[0];
+        if (dup.type != SpecialBlock.DUP
+            || dup.count != store.getLValueType().stackSize()
+            || dup.depth != store.getLValueOperandCount())
+            return false;
 
-            if (store.getLValueOperandCount() > 0) {
-                sequBlock = (SequentialBlock) sequBlock.outer;
-                SpecialBlock dup2 = (SpecialBlock) sequBlock.subBlocks[0];
-                if (dup2.type != SpecialBlock.DUP
-                    || dup2.count != store.getLValueOperandCount() 
-                    || dup2.depth != 0)
-                    return false;
-            }
-	    type = load.getType().intersection(store.getLValueType());
-        } catch (NullPointerException ex) {
+        if (!(sb.outer instanceof SequentialBlock))
             return false;
-        } catch (ClassCastException ex) {
+        sb = (SequentialBlock) sb.outer;
+        if (!(sb.subBlocks[0] instanceof InstructionBlock))
+            return false;
+        ib = (InstructionBlock) sb.subBlocks[0];
+
+        if (!(ib.getInstruction() instanceof Operator)
+            || !store.matches((Operator) ib.getInstruction()))
             return false;
+
+        if (store.getLValueOperandCount() > 0) {
+            if (!(sb.outer instanceof SequentialBlock))
+                return false;
+            sb = (SequentialBlock) sb.outer;
+            if (!(sb.subBlocks[0] instanceof SpecialBlock))
+                return false;
+            SpecialBlock dup2 = (SpecialBlock) sb.subBlocks[0];
+            if (dup2.type != SpecialBlock.DUP
+                || dup2.count != store.getLValueOperandCount() 
+                || dup2.depth != 0)
+                return false;
         }
-	Operator postop = new PrePostFixOperator(type, op, store, true);
-        lastBlock.setInstruction(postop);
-        lastBlock.moveDefinitions(sequBlock, lastBlock);
-        lastBlock.replace(sequBlock);
+        ic.setInstruction
+            (new PrePostFixOperator(store.getLValueType(), op, store, true));
+        ic.moveDefinitions(sb, last);
+        last.replace(sb);
 	return true;
     }
 }
diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java
index ef70502..b5e65c0 100644
--- a/jode/jode/flow/FlowBlock.java
+++ b/jode/jode/flow/FlowBlock.java
@@ -199,73 +199,69 @@ public class FlowBlock {
                 ConditionalBlock cb = (ConditionalBlock) jump.prev.outer;
                 Expression instr = cb.getInstruction();
 
-		/* If this is the first instruction of a while and the
-		 * condition of the while is true, use the condition
-		 * as while condition.  
-		 */
-                if (cb.outer instanceof LoopBlock 
-                    || (cb.outer instanceof SequentialBlock 
-                        && cb.outer.getSubBlocks()[0] == cb 
-                        && cb.outer.outer instanceof LoopBlock)) {
-
-                    LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ?
-                        (LoopBlock) cb.outer : (LoopBlock) cb.outer.outer;
-
-                    if (loopBlock.getCondition() == LoopBlock.TRUE &&
-                        loopBlock.getType() != LoopBlock.DOWHILE &&
-                        (loopBlock.jumpMayBeChanged()
-                         || loopBlock.getNextFlowBlock() == succ)) {
-                        
-                        if (loopBlock.jump == null) {
-                            /* consider this jump again */
-                            loopBlock.moveJump(jump);
-                            jumps = jump;
-                        } else
-                            jump.prev.removeJump();
-
-                        loopBlock.setCondition(instr.negate());
-                        loopBlock.moveDefinitions(cb, null);
-                        cb.removeBlock();
-                        continue;
-                    }
-
-                } else if (cb.outer instanceof SequentialBlock 
-                           && cb.outer.getSubBlocks()[1] == cb) {
+//                 if (cb.outer instanceof LoopBlock 
+//                     || (cb.outer instanceof SequentialBlock 
+//                         && cb.outer.getSubBlocks()[0] == cb 
+//                         && cb.outer.outer instanceof LoopBlock)) {
+            
+//                     LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ?
+//                         (LoopBlock) cb.outer : (LoopBlock) cb.outer.outer;
 
-                    /* And now for do/while loops, where the jump is
-                     * at the end of the loop.
-                     */
+//                     if (loopBlock.getCondition() == LoopBlock.TRUE &&
+//                         loopBlock.getType() != LoopBlock.DOWHILE &&
+//                         (loopBlock.jumpMayBeChanged()
+//                          || loopBlock.getNextFlowBlock() == succ)) {
+                        
+//                         if (loopBlock.jump == null) {
+//                             /* consider this jump again */
+//                             loopBlock.moveJump(jump);
+//                             jumps = jump;
+//                         } else
+//                             jump.prev.removeJump();
+
+//                         loopBlock.setCondition(instr.negate());
+//                         loopBlock.moveDefinitions(cb, null);
+//                         cb.removeBlock();
+//                         continue;
+//                     }
+
+//                 } else if (cb.outer instanceof SequentialBlock 
+//                            && cb.outer.getSubBlocks()[1] == cb) {
+
+//                     /* And now for do/while loops, where the jump is
+//                      * at the end of the loop.
+//                      */
                     
-                    /* First find the beginning of the loop */
-                    StructuredBlock sb = cb.outer.outer;
-                    while (sb instanceof SequentialBlock) {
-                        sb = sb.outer;
-                    }
-                    /* sb is now the first and cb is the last
-                     * instruction in the current block.
-                     */
-                    if (sb instanceof LoopBlock) {
-                        LoopBlock loopBlock = (LoopBlock) sb;
-                        if (loopBlock.getCondition() == LoopBlock.TRUE &&
-                            loopBlock.getType() == LoopBlock.WHILE &&
-                            (loopBlock.jumpMayBeChanged()
-                             || loopBlock.getNextFlowBlock() == succ)) {
+//                     /* First find the beginning of the loop */
+//                     StructuredBlock sb = cb.outer.outer;
+//                     while (sb instanceof SequentialBlock) {
+//                         sb = sb.outer;
+//                     }
+//                     /* sb is now the first and cb is the last
+//                      * instruction in the current block.
+//                      */
+//                     if (sb instanceof LoopBlock) {
+//                         LoopBlock loopBlock = (LoopBlock) sb;
+//                         if (loopBlock.getCondition() == LoopBlock.TRUE &&
+//                             loopBlock.getType() == LoopBlock.WHILE &&
+//                             (loopBlock.jumpMayBeChanged()
+//                              || loopBlock.getNextFlowBlock() == succ)) {
                             
-                            if (loopBlock.jump == null) {
-                                /* consider this jump again */
-                                loopBlock.moveJump(jump);
-                                jumps = jump;
-                            } else
-                                jump.prev.removeJump();
-
-                            loopBlock.setType(LoopBlock.DOWHILE);
-                            loopBlock.setCondition(instr.negate());
-                            loopBlock.moveDefinitions(cb, null);
-                            cb.removeBlock();                            
-                            continue;
-                        }
-                    }
-                }
+//                             if (loopBlock.jump == null) {
+//                                 /* consider this jump again */
+//                                 loopBlock.moveJump(jump);
+//                                 jumps = jump;
+//                             } else
+//                                 jump.prev.removeJump();
+
+//                             loopBlock.setType(LoopBlock.DOWHILE);
+//                             loopBlock.setCondition(instr.negate());
+//                             loopBlock.moveDefinitions(cb, null);
+//                             cb.removeBlock();                            
+//                             continue;
+//                         }
+//                     }
+//                 }
 
 		/* replace all conditional jumps to the successor, which
 		 * are followed by a block which has the end of the block
@@ -599,6 +595,30 @@ public class FlowBlock {
         }
     }
 
+
+    /**
+     * This is a special T1 transformation, that does also succeed, if
+     * the jumps in the flow block are not yet resolved.  But it has
+     * a special precondition:  The succ must be a simple instruction block,
+     * mustn't have another predecessor and all structured blocks in this
+     * flow block must be simple instruction blocks.
+     */
+    public void doSequentialT1(StructuredBlock succ, int length) {
+        VariableSet succIn = new VariableSet();
+        succ.fillInGenSet(succIn, this.gen);
+
+        succIn.merge(lastModified.jump.gen);
+        succIn.subtract(lastModified.jump.kill);
+        succ.jump.gen.mergeGenKill(lastModified.jump.gen, succ.jump.kill);
+        succ.jump.kill.add(lastModified.jump.kill);
+        this.in.unionExact(succIn);
+
+        lastModified.removeJump();
+        lastModified = lastModified.appendBlock(succ);
+        this.length += length;
+        doTransformations();
+    }
+
     /**
      * Do a T1 transformation with succ if possible.  It is possible,
      * iff succ has exactly this block as predecessor.
@@ -619,19 +639,25 @@ public class FlowBlock {
 
         /* Update the in/out-Vectors now */
         updateInOut(succ, jumps);
+        if (Decompiler.isFlowDebugging)
+            System.err.println("before Optimize: "+this);
 
         /* Try to eliminate as many jumps as possible.
          */
         jumps = optimizeJumps(jumps, succ);
+        if (Decompiler.isFlowDebugging)
+            System.err.println("before Remaining: "+this);
         resolveRemaining(jumps);
+        if (Decompiler.isFlowDebugging)
+            System.err.println("after Optimize: "+this);
 
         /* Now unify the blocks.
          */
-        lastModified.appendBlock(succ.block);
+        lastModified = lastModified.appendBlock(succ.block);
         mergeSuccessors(succ);
 
-        /* Set last modified to the new correct value.  */
-        lastModified = succ.lastModified;
+        /* This will also set last modified to the new correct value.  */
+        doTransformations();
 
         /* Set addr+length to correct value. */
         if (succ.addr < addr)
@@ -643,6 +669,44 @@ public class FlowBlock {
         return true;
     }
 
+    /**
+     * Find the exit condition of a for/while block.  The loop block
+     * mustn't have an exit condition yet.
+     */
+    public void mergeCondition() {
+        /* If the first instruction of a while is a conditional
+         * block, which jumps to the next address use the condition
+         * as while condition.  
+         */
+        LoopBlock loopBlock = (LoopBlock) lastModified;
+        int loopType = loopBlock.getType();
+
+        ConditionalBlock cb = null;
+        if (loopBlock.bodyBlock instanceof ConditionalBlock)
+            cb = (ConditionalBlock) loopBlock.bodyBlock;
+        else if (loopBlock.bodyBlock instanceof SequentialBlock
+                 && loopBlock.bodyBlock.getSubBlocks()[0] 
+                 instanceof ConditionalBlock)
+            cb = (ConditionalBlock) loopBlock.bodyBlock.getSubBlocks()[0];
+        else if (loopBlock.bodyBlock instanceof SequentialBlock
+                 && loopType == LoopBlock.WHILE) {
+            loopType = LoopBlock.DOWHILE;
+            SequentialBlock sequBlock = (SequentialBlock) loopBlock.bodyBlock;
+            while (sequBlock.subBlocks[1] instanceof SequentialBlock)
+                sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
+            if (sequBlock.subBlocks[1] instanceof ConditionalBlock)
+                cb = (ConditionalBlock) sequBlock.subBlocks[1];
+        }
+
+        if (cb != null 
+            && cb.trueBlock.jump.destination.addr == addr + length) {
+            loopBlock.moveJump(cb.trueBlock.jump);
+            loopBlock.setCondition(cb.getInstruction().negate());
+            loopBlock.setType(loopType);
+            loopBlock.moveDefinitions(cb, null);
+            cb.removeBlock();
+        }
+    }
 
     public boolean doT2(int start, int end) {
         /* If there are no jumps to the beginning of this flow block
@@ -800,6 +864,7 @@ public class FlowBlock {
          */
         predecessors.removeElement(this);
         lastModified = block;
+        mergeCondition();
 
         /* T2 analysis succeeded */
         checkConsistent();
@@ -881,20 +946,20 @@ public class FlowBlock {
         checkConsistent();
     }
 
+    public void doTransformations() {
+        if (Decompiler.isFlowDebugging)
+            System.err.println("before Transformation: "+this);
 
-    static Transformation[] exprTrafos = {
-        new RemoveEmpty(),
-        new CreateExpression(),
-        new CreatePrePostIncExpression(),
-        new CreateAssignExpression(),
-        new CreateNewConstructor(),
-        new CombineIfGotoExpressions(),
-        new CreateIfThenElseOperator(),
-        new CreateConstantArray(),
-        new CreateForInitializer(),
-        new CompleteSynchronized(),
-    };
+        while (lastModified instanceof SequentialBlock) {
+            if (!lastModified.getSubBlocks()[0].doTransformations())
+                lastModified = lastModified.getSubBlocks()[1];
+        }
+        while (lastModified.doTransformations())
+            /* empty */;
 
+        if (Decompiler.isFlowDebugging)
+            System.err.println("after Transformation: "+this);
+    }
 
     /**
      * Search for an apropriate successor.
@@ -944,21 +1009,12 @@ public class FlowBlock {
 
         while (true) {
                 
-            if (Decompiler.isFlowDebugging)
-                System.err.println("before Transformation: "+this);
-
-            /* First do some non flow transformations. */
-            int i=0;
-            while (i < exprTrafos.length) {
-                if (exprTrafos[i].transform(this))
-                    i = 0;
-                else
-                    i++;
-                checkConsistent();
-            }
-            
-            if (Decompiler.isFlowDebugging)
-                System.err.println("after Transformation: "+this);
+            if (lastModified instanceof SwitchBlock) {
+                /* analyze the switch first.
+                 */
+                analyzeSwitch(start, end);
+            } 
+
 
             if (doT2(start, end)) {
 
@@ -989,20 +1045,6 @@ public class FlowBlock {
                              + addr + " - " + (addr+length));
                     return changed;
                 } else {
-                    if (succ.block instanceof SwitchBlock) {
-                        /* analyze succ, the new region is the
-                         * continuous region of
-                         * [start,end) \cap \compl [addr, addr+length)
-                         * where succ.addr lies in.
-                         */
-                        int newStart = (succ.addr > addr)
-                            ? addr+length : start;
-                        int newEnd   = (succ.addr > addr)
-                            ? end         : addr;
-                        if (succ.analyzeSwitch(newStart, newEnd))
-                            break;
-
-                    } 
                     if ((succ.addr == addr+length 
                          || succ.addr+succ.length == addr)
                         /* Only do T1 transformation if the blocks are
@@ -1058,14 +1100,14 @@ public class FlowBlock {
      * regions.  Only blocks whose address lies in the given address
      * range are considered and it is taken care of, that the switch
      * is never leaved. 

- * The current flow block must contain the switch block as main - * block. + * The current flow block must contain the switch block as lastModified * @param start the start of the address range. * @param end the end of the address range. */ public boolean analyzeSwitch(int start, int end) { - SwitchBlock switchBlock = (SwitchBlock) block; + SwitchBlock switchBlock = (SwitchBlock) lastModified; boolean changed = false; + int last = -1; FlowBlock lastFlow = null; for (int i=0; i < switchBlock.caseBlocks.length; i++) { @@ -1165,8 +1207,10 @@ public class FlowBlock { jump.destination = END_OF_METHOD; else jump.destination = instr[jump.destAddr]; + if (jump.destination == null) + throw new AssertError("Missing dest: "+jump.destAddr); + addSuccessor(jump); } - addSuccessor(jump); } } diff --git a/jode/jode/flow/InstructionContainer.java b/jode/jode/flow/InstructionContainer.java index 1e77d0b..577a959 100644 --- a/jode/jode/flow/InstructionContainer.java +++ b/jode/jode/flow/InstructionContainer.java @@ -56,6 +56,16 @@ public abstract class InstructionContainer extends StructuredBlock { } } + public boolean doTransformations() { + StructuredBlock last = flowBlock.lastModified; + return CreateNewConstructor.transform(this, last) + || CreateExpression.transform(this, last) + || CreatePrePostIncExpression.transform(this, last) + || CreateAssignExpression.transform(this, last) + || CreateIfThenElseOperator.create(this, last) + || CreateConstantArray.transform(this, last); + } + /** * Get the contained instruction. * @return the contained instruction. diff --git a/jode/jode/flow/LoopBlock.java b/jode/jode/flow/LoopBlock.java index 29755b2..9f45eab 100644 --- a/jode/jode/flow/LoopBlock.java +++ b/jode/jode/flow/LoopBlock.java @@ -51,7 +51,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * The increase instruction, only valid if type == FOR. */ Expression incr; - + /** * True, if the initializer is a declaration. */ @@ -253,4 +253,10 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { public boolean jumpMayBeChanged() { return mayChangeJump; } + + public boolean doTransformations() { + return type == FOR && init == null + && CreateForInitializer.transform(this, flowBlock.lastModified); + } } + diff --git a/jode/jode/flow/RemoveEmpty.java b/jode/jode/flow/RemoveEmpty.java index 461c7e9..7b69f5c 100644 --- a/jode/jode/flow/RemoveEmpty.java +++ b/jode/jode/flow/RemoveEmpty.java @@ -21,41 +21,10 @@ package jode.flow; import jode.Expression; import jode.NopOperator; -public class RemoveEmpty implements Transformation { +public class RemoveEmpty { - public boolean transform (FlowBlock fb) { - return (removeNop(fb) || removeSwap(fb) || removeEmpty(fb)); - } - - public boolean removeNop(FlowBlock flow) { - StructuredBlock block = flow.lastModified; - if (block instanceof InstructionContainer - && block.outer instanceof SequentialBlock - && block.outer.getSubBlocks()[0] instanceof InstructionBlock) { - - InstructionContainer ic = (InstructionContainer) block; - - Expression nopInstr = ic.getInstruction(); - if (!(nopInstr instanceof NopOperator) - || nopInstr.getType() == jode.Type.tVoid) - return false; - - InstructionBlock prev = - (InstructionBlock) ic.outer.getSubBlocks()[0]; - - Expression instr = prev.getInstruction(); - if (instr.getType() == jode.Type.tVoid) - return false; - - instr.setType(nopInstr.getType()); - ic.setInstruction(instr); - ic.replace(ic.outer); - return true; - } - return false; - } - - public boolean removeSwap(FlowBlock flow) { + public static boolean removeSwap(SpecialBlock swapBlock, + StructuredBlock last) { /* Remove non needed swaps; convert: * * PUSH expr1 @@ -67,37 +36,43 @@ public class RemoveEmpty implements Transformation { * PUSH expr2 * PUSH expr1 */ - StructuredBlock block = flow.lastModified; - if (block instanceof SpecialBlock - && ((SpecialBlock)block).type == SpecialBlock.SWAP - && block.outer instanceof SequentialBlock - && block.outer.outer instanceof SequentialBlock - && block.outer.getSubBlocks()[0] instanceof InstructionBlock - && block.outer.outer.getSubBlocks()[0] + if (last.outer instanceof SequentialBlock + && last.outer.outer instanceof SequentialBlock + && last.outer.getSubBlocks()[0] instanceof InstructionBlock + && last.outer.outer.getSubBlocks()[0] instanceof InstructionBlock) { InstructionBlock block1 - = (InstructionBlock) block.outer.outer.getSubBlocks()[0]; + = (InstructionBlock) last.outer.outer.getSubBlocks()[0]; InstructionBlock block2 - = (InstructionBlock) block.outer.getSubBlocks()[0]; + = (InstructionBlock) last.outer.getSubBlocks()[0]; + + /* XXX check if blocks may be swapped + * (there mustn't be side effects in one of them). + */ + System.err.println("WARNING: this program contains a SWAP " + +"opcode and may not be translated correctly."); if (block1.getInstruction().isVoid() || block2.getInstruction().isVoid()) return false; + /* PUSH expr1 == block1 * PUSH expr2 * SWAP + * ... */ - block.outer.replace(block1.outer); + last.outer.replace(block1.outer); /* PUSH expr2 * SWAP + * ... */ - block1.replace(block); - block1.moveJump(block.jump); + block1.replace(swapBlock); + block1.moveJump(swapBlock.jump); /* PUSH expr2 * PUSH expr1 */ - flow.lastModified = block1; + block1.flowBlock.lastModified = block1.outer; return true; } return false; diff --git a/jode/jode/flow/SpecialBlock.java b/jode/jode/flow/SpecialBlock.java index 00e8c95..46fd05f 100644 --- a/jode/jode/flow/SpecialBlock.java +++ b/jode/jode/flow/SpecialBlock.java @@ -56,4 +56,9 @@ public class SpecialBlock extends StructuredBlock { + ((count == 1) ? "" : "2") + ((depth == 0) ? "" : "_X"+depth)); } + + public boolean doTransformation() { + return type == SWAP + && RemoveEmpty.removeSwap(this, flowBlock.lastModified); + } } diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index a9265ec..95c88d0 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -191,7 +191,7 @@ public abstract class StructuredBlock { /** * Removes the jump. This does not update the successors vector * of the flow block, you have to do it yourself. */ - public void removeJump() { + public final void removeJump() { if (jump != null) { jump.prev = null; jump = null; @@ -208,21 +208,15 @@ public abstract class StructuredBlock { * will be moved to this block (may be this). */ void moveDefinitions(StructuredBlock from, StructuredBlock sub) { - if (from != sub && from != this) { - /* define(...) will not move from blocks, that are not sub blocks, - * so we do it by hand. - */ - java.util.Enumeration enum = from.used.elements(); - while (enum.hasMoreElements()) { - LocalInfo var = - ((LocalInfo) enum.nextElement()).getLocalInfo(); - if (!used.contains(var)) - used.addElement(var); - } + while (from != sub && from != this) { + used.unionExact(from.used); from.used.removeAllElements(); StructuredBlock[] subs = from.getSubBlocks(); - for (int i=0; i