diff --git a/jode/jode/bytecode/Opcodes.java b/jode/jode/bytecode/Opcodes.java index 8236e26..01a48ca 100644 --- a/jode/jode/bytecode/Opcodes.java +++ b/jode/jode/bytecode/Opcodes.java @@ -18,14 +18,15 @@ */ package jode; +import jode.flow.*; import java.io.*; import sun.tools.java.*; /** - * This is an abstract class which creates InstructionHeader for the - * opcodes in an byte stream. + * This is an abstract class which creates flow blocks for the + * opcodes in a byte stream. */ -public abstract class Opcodes implements RuntimeConstants{ +public abstract class Opcodes implements RuntimeConstants { public final static Type ALL_INT_TYPE = MyType.tUInt; public final static Type INT_TYPE = Type.tInt; @@ -47,62 +48,97 @@ public abstract class Opcodes implements RuntimeConstants{ }; + public static FlowBlock createNormal(int addr, int length, + Instruction instr) + { + return new FlowBlock(addr, length, + new InstructionBlock(instr, + new Jump(addr+length))); + } + + public static FlowBlock createGoto(int addr, int length, + int destAddr) + { + return new FlowBlock(addr, length, new EmptyBlock(new Jump(destAddr))); + } + + public static FlowBlock createIfGoto(int addr, int length, + int destAddr, Instruction instr) + { + ConditionalBlock ifBlock = + new ConditionalBlock(instr, + new Jump(destAddr), + new Jump(addr+length)); + return new FlowBlock(addr, length, ifBlock); + } + + public static FlowBlock createSwitch(int addr, int length, + int[] cases, int[] dests) + { + return new FlowBlock(addr, length, new SwitchBlock(cases, dests)); + } + + public static FlowBlock createBlock(int addr, int length, + StructuredBlock block) + { + return new FlowBlock(addr, length, block); + } + /** * Read an opcode out of a data input stream containing the bytecode. * @param addr The current address. * @param stream The stream containing the java byte code. * @param ca The Code Analyzer * (where further information can be get from). - * @return The InstructionHeader representing this opcode + * @return The FlowBlock representing this opcode * or null if the stream is empty. * @exception IOException if an read error occured. * @exception ClassFormatError if an invalid opcode is detected. */ - public static - InstructionHeader readOpcode(int addr, DataInputStream stream, - CodeAnalyzer ca) - throws IOException, ClassFormatError + public static FlowBlock readOpcode(int addr, DataInputStream stream, + CodeAnalyzer ca) + throws IOException, ClassFormatError { try { int opcode = stream.readUnsignedByte(); switch (opcode) { case opc_nop: - return InstructionHeader.createNormal(addr, 1, new NopOperator()); + return createNormal(addr, 1, new NopOperator()); case opc_aconst_null: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConstOperator(OBJECT_TYPE, "null")); case opc_iconst_m1: case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConstOperator (ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); case opc_lconst_0: case opc_lconst_1: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConstOperator (LONG_TYPE, Integer.toString(opcode - opc_lconst_0) + "L")); case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConstOperator (FLOAT_TYPE, Integer.toString(opcode - opc_fconst_0) + ".0F")); case opc_dconst_0: case opc_dconst_1: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConstOperator (DOUBLE_TYPE, Integer.toString(opcode - opc_dconst_0) + ".0")); case opc_bipush: - return InstructionHeader.createNormal + return createNormal (addr, 2, new ConstOperator (ALL_INT_TYPE, Integer.toString(stream.readByte()))); case opc_sipush: - return InstructionHeader.createNormal + return createNormal (addr, 3, new ConstOperator (ALL_INT_TYPE, Integer.toString(stream.readShort()))); case opc_ldc: { int index = stream.readUnsignedByte(); - return InstructionHeader.createNormal + return createNormal (addr, 2, new ConstOperator (ca.env.getConstantType(index), ca.env.getConstant(index).toString())); @@ -110,38 +146,38 @@ public abstract class Opcodes implements RuntimeConstants{ case opc_ldc_w: case opc_ldc2_w: { int index = stream.readUnsignedShort(); - return InstructionHeader.createNormal + return createNormal (addr, 3, new ConstOperator (ca.env.getConstantType(index), ca.env.getConstant(index).toString())); } case opc_iload: case opc_lload: case opc_fload: case opc_dload: case opc_aload: - return InstructionHeader.createNormal + return createNormal (addr, 2, new LocalLoadOperator (types[0][opcode-opc_iload], - stream.readUnsignedByte())); + new LocalInfo(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 InstructionHeader.createNormal + return createNormal (addr, 1, new LocalLoadOperator (types[0][(opcode-opc_iload_0)/4], - (opcode-opc_iload_0) & 3)); + new LocalInfo((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 InstructionHeader.createNormal + return createNormal (addr, 1, new ArrayLoadOperator (types[1][opcode - opc_iaload])); case opc_istore: case opc_lstore: case opc_fstore: case opc_dstore: case opc_astore: - return InstructionHeader.createNormal + return createNormal (addr, 2, new LocalStoreOperator (types[0][opcode-opc_istore], - stream.readUnsignedByte(), + new LocalInfo(stream.readUnsignedByte()), Operator.ASSIGN_OP)); case opc_istore_0: case opc_istore_1: case opc_istore_2: case opc_istore_3: @@ -153,51 +189,51 @@ public abstract class Opcodes implements RuntimeConstants{ case opc_dstore_2: case opc_dstore_3: case opc_astore_0: case opc_astore_1: case opc_astore_2: case opc_astore_3: - return InstructionHeader.createNormal + return createNormal (addr, 1, new LocalStoreOperator (types[0][(opcode-opc_istore_0)/4], - (opcode-opc_istore_0) & 3, + new LocalInfo((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 InstructionHeader.createNormal + return createNormal (addr, 1, new ArrayStoreOperator (types[1][opcode - opc_iastore])); case opc_pop: case opc_pop2: - return InstructionHeader.createNormal + return createNormal (addr, 1, new PopOperator(opcode - opc_pop + 1)); case opc_dup: case opc_dup_x1: case opc_dup_x2: case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: - return InstructionHeader.createNormal + return createNormal (addr, 1, new DupOperator ((opcode - opc_dup)%3, (opcode - opc_dup)/3+1)); case opc_swap: - return InstructionHeader.createNormal(addr, 1, new SwapOperator()); + return createNormal(addr, 1, new SwapOperator()); case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: case opc_irem: case opc_lrem: case opc_frem: case opc_drem: - return InstructionHeader.createNormal + return createNormal (addr, 1, new BinaryOperator (types[0][(opcode - opc_iadd)%4], (opcode - opc_iadd)/4+Operator.ADD_OP)); case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: - return InstructionHeader.createNormal + return createNormal (addr, 1, new UnaryOperator (types[0][opcode - opc_ineg], Operator.NEG_OP)); case opc_ishl: case opc_lshl: case opc_ishr: case opc_lshr: case opc_iushr: case opc_lushr: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ShiftOperator (types[0][(opcode - opc_ishl)%2], (opcode - opc_ishl)/2 + Operator.SHIFT_OP)); case opc_iand: case opc_land: case opc_ior : case opc_lor : case opc_ixor: case opc_lxor: - return InstructionHeader.createNormal + return createNormal (addr, 1, new BinaryOperator (types[0][(opcode - opc_iand)%2], (opcode - opc_iand)/2 + Operator.AND_OP)); @@ -209,9 +245,10 @@ public abstract class Opcodes implements RuntimeConstants{ value = -value; operation = Operator.NEG_OP; } - return InstructionHeader.createNormal + LocalInfo li = new LocalInfo(local); + return createNormal (addr, 3, new IIncOperator - (local, Integer.toString(value), + (li, Integer.toString(value), operation + Operator.OPASSIGN_OP)); } case opc_i2l: case opc_i2f: case opc_i2d: @@ -222,48 +259,48 @@ public abstract class Opcodes implements RuntimeConstants{ int to = (opcode-opc_i2l)%3; if (to >= from) to++; - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConvertOperator(types[0][from], types[0][to])); } case opc_i2b: case opc_i2c: case opc_i2s: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ConvertOperator (ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5])); case opc_lcmp: case opc_fcmpl: case opc_fcmpg: case opc_dcmpl: case opc_dcmpg: - return InstructionHeader.createNormal + return createNormal (addr, 1, new CompareToIntOperator (types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2)); case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: - return InstructionHeader.createIfGoto + return createIfGoto (addr, 3, addr+stream.readShort(), new CompareUnaryOperator (ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP)); case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: - return InstructionHeader.createIfGoto + return createIfGoto (addr, 3, addr+stream.readShort(), new CompareBinaryOperator (ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP)); case opc_if_acmpeq: case opc_if_acmpne: - return InstructionHeader.createIfGoto + return createIfGoto (addr, 3, addr+stream.readShort(), new CompareBinaryOperator (OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); case opc_goto: - return InstructionHeader.createGoto + return createGoto (addr, 3, addr+stream.readShort()); - case opc_jsr: - return InstructionHeader.createGoto //XXX - (addr, 3, addr+stream.readShort()); - case opc_ret: - return InstructionHeader.createReturn //XXX - (addr, 2, - new LocalLoadOperator - (OBJECT_TYPE, stream.readUnsignedByte())); +// case opc_jsr: +// return createGoto //XXX +// (addr, 3, addr+stream.readShort()); +// case opc_ret: +// return createReturn //XXX +// (addr, 2, +// new LocalLoadOperator +// (OBJECT_TYPE, new LocalInfo(stream.readUnsignedByte()))); case opc_tableswitch: { int length = 3-(addr % 4); stream.skip(length); @@ -278,8 +315,8 @@ public abstract class Opcodes implements RuntimeConstants{ } dests[cases.length] = def; length += 13 + 4 * cases.length; - return InstructionHeader.createSwitch - (addr, length, new NopOperator(), cases, dests); + return createSwitch + (addr, length, cases, dests); } case opc_lookupswitch: { int length = 3-(addr % 4); @@ -294,31 +331,31 @@ public abstract class Opcodes implements RuntimeConstants{ } dests[npairs] = def; length += 9 + 8 * npairs; - return InstructionHeader.createSwitch - (addr, length, new NopOperator(), cases, dests); + return createSwitch + (addr, length, cases, dests); } case opc_ireturn: case opc_lreturn: case opc_freturn: case opc_dreturn: case opc_areturn: { Type retType = MyType.intersection (ca.getMethod().mdef.getType().getReturnType(), types[0][opcode-opc_ireturn]); - return InstructionHeader.createReturn - (addr, 1, new ReturnOperator(retType)); + return createBlock + (addr, 1, new ReturnBlock(new NopOperator(retType))); } - case opc_return: { - return InstructionHeader.createReturn - (addr, 1, null); - } + case opc_return: + /* Address -1 is interpreted as end of method */ + return createBlock + (addr, 1, new EmptyBlock(new Jump(-1))); case opc_getstatic: case opc_getfield: - return InstructionHeader.createNormal + return createNormal (addr, 3, new GetFieldOperator (ca, opcode == opc_getstatic, (FieldDefinition)ca.env.getConstant (stream.readUnsignedShort()))); case opc_putstatic: case opc_putfield: - return InstructionHeader.createNormal + return createNormal (addr, 3, new PutFieldOperator (ca, opcode == opc_putstatic, (FieldDefinition)ca.env.getConstant @@ -326,26 +363,26 @@ public abstract class Opcodes implements RuntimeConstants{ case opc_invokevirtual: case opc_invokespecial: case opc_invokestatic : - return InstructionHeader.createNormal + return createNormal (addr, 3, new InvokeOperator (ca, opcode == opc_invokestatic, opcode == opc_invokespecial, (FieldDefinition)ca.env.getConstant (stream.readUnsignedShort()))); case opc_invokeinterface: { - InstructionHeader ih = InstructionHeader.createNormal + FlowBlock fb = createNormal (addr, 5, new InvokeOperator (ca, false, false, (FieldDefinition)ca.env.getConstant (stream.readUnsignedShort()))); int reserved = stream.readUnsignedShort(); - return ih; + return fb; } case opc_new: { ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant(stream.readUnsignedShort()); Type type = MyType.tClassOrArray(cldec.getName()); - return InstructionHeader.createNormal + return createNormal (addr, 3, new NewOperator(type, ca.env.getTypeString(type))); } case opc_newarray: { @@ -362,7 +399,7 @@ public abstract class Opcodes implements RuntimeConstants{ default: throw new ClassFormatError("Invalid newarray operand"); } - return InstructionHeader.createNormal + return createNormal (addr, 2, new NewArrayOperator(MyType.tArray(type), type.toString(), 1)); @@ -372,21 +409,22 @@ public abstract class Opcodes implements RuntimeConstants{ (stream.readUnsignedShort()); Identifier ident = cldec.getName(); Type type = MyType.tClassOrArray(cldec.getName()); - return InstructionHeader.createNormal + return createNormal (addr, 3, new NewArrayOperator (MyType.tArray(type), ca.env.getTypeString(type),1)); } case opc_arraylength: - return InstructionHeader.createNormal + return createNormal (addr, 1, new ArrayLengthOperator()); case opc_athrow: - return InstructionHeader.createReturn - (addr, 1, new ThrowOperator()); + return createBlock + (addr, 1, + new ThrowBlock(new NopOperator(MyType.tUObject))); case opc_checkcast: { ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant (stream.readUnsignedShort()); Type type = MyType.tClassOrArray(cldec.getName()); - return InstructionHeader.createNormal + return createNormal (addr, 3, new CheckCastOperator (type, ca.env.getTypeString(type))); } @@ -394,31 +432,33 @@ public abstract class Opcodes implements RuntimeConstants{ ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant (stream.readUnsignedShort()); Type type = MyType.tClassOrArray(cldec.getName()); - return InstructionHeader.createNormal + return createNormal (addr, 3, new InstanceOfOperator(type, ca.env.getTypeString(type))); } case opc_monitorenter: - return InstructionHeader.createNormal(addr, 1, + return createNormal(addr, 1, new MonitorEnterOperator()); case opc_monitorexit: - return InstructionHeader.createNormal(addr, 1, + return createNormal(addr, 1, new MonitorExitOperator()); case opc_wide: { switch (opcode=stream.readUnsignedByte()) { case opc_iload: case opc_lload: case opc_fload: case opc_dload: case opc_aload: - return InstructionHeader.createNormal + return createNormal (addr, 4, new LocalLoadOperator(types[0][opcode-opc_iload], - stream.readUnsignedShort())); + new LocalInfo + (stream.readUnsignedShort()))); case opc_istore: case opc_lstore: case opc_fstore: case opc_dstore: case opc_astore: - return InstructionHeader.createNormal + return createNormal (addr, 4, - new LocalStoreOperator(types[0][opcode-opc_istore], - stream.readUnsignedShort(), - Operator.ASSIGN_OP)); + new LocalStoreOperator + (types[0][opcode-opc_istore], + new LocalInfo(stream.readUnsignedShort()), + Operator.ASSIGN_OP)); case opc_iinc: { int local = stream.readUnsignedShort(); int value = stream.readShort(); @@ -427,16 +467,18 @@ public abstract class Opcodes implements RuntimeConstants{ value = -value; operation = Operator.NEG_OP; } - return InstructionHeader.createNormal + LocalInfo li = new LocalInfo(local); + return createNormal (addr, 6, new IIncOperator - (local, Integer.toString(value), + (li, Integer.toString(value), operation + Operator.OPASSIGN_OP)); } - case opc_ret: - return new RetInstructionHeader - (addr, 4, - new LocalLoadOperator - (INT_TYPE, stream.readUnsignedShort())); +// case opc_ret: +// return new RetInstructionHeader +// (addr, 4, +// new LocalLoadOperator +// (INT_TYPE, +// new LocalInfo(stream.readUnsignedShort()))); default: throw new ClassFormatError("Invalid wide opcode "+opcode); } @@ -449,22 +491,22 @@ public abstract class Opcodes implements RuntimeConstants{ Type baseType = type; for (int i=0; i + * Sequ[expr_1, Sequ[expr_2, ..., Sequ[expr_n, op] ...]] + * + * to + *
+ *  expr(op, [ expr_1, ..., expr_n ])
+ * 
+ */ public class CreateExpression implements Transformation { - public StructuredBlock transform(StructuredBlock block) { + /** + * This does the transformation. + * @param FlowBlock the flow block to transform. + * @return true if flow block was simplified. + */ + public boolean transform(FlowBlock flow) { Operator op; Expression exprs[]; int params; + StructuredBlock block; + + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + System.err.println("Transformation on: "+flow.getLabel()); + flow.block.dumpSource(writer); + flow.checkConsistent(); + System.err.println("; lastModified is: "); + flow.lastModified.dumpSource(writer); + } catch (java.io.IOException ex) {} try { - op = (Operator) block.getInstruction(); + SequentialBlock sequBlock; + block = flow.lastModified; + op = (Operator) ((InstructionContainer)block).getInstruction(); params = op.getOperandCount(); exprs = new Expression[params]; + for (int i = params-1; i>=0; i--) { - block = block.getSimpleUniquePredecessor(); - exprs[i] = (Expression) ih.getInstruction(); + sequBlock = (SequentialBlock)block.outer; + if (i == params-1 && + sequBlock.getSubBlocks()[1] != block) + return false; + + block = sequBlock.getSubBlocks()[0]; + if (block.jump != null) + return false; + exprs[i] = + (Expression) ((InstructionBlock)block).getInstruction(); if (exprs[i].isVoid()) { if (i == params-1) - return null; + return false; Expression e = exprs[i+1].tryToCombine(exprs[i]); if (e == null) - return null; + return false; i++; + SequentialBlock subExprBlock = + (SequentialBlock) sequBlock.getSubBlocks()[1]; + subExprBlock.replace(sequBlock); + sequBlock = subExprBlock; + ((InstructionContainer)subExprBlock.getSubBlocks()[0]). + setInstruction(e); exprs[i] = e; - ih = ih.combine(2, e); } + block = sequBlock; } } catch (NullPointerException ex) { - return null; + return false; } catch (ClassCastException ex) { - return null; + return false; } - if(Decompiler.isVerbose && params > 0) + if(jode.Decompiler.isVerbose && params > 0) System.err.print("x"); - return ih.combine(params+1, new Expression(op, exprs)); + + ((InstructionContainer) flow.lastModified).setInstruction + (new Expression(op, exprs)); + flow.lastModified.replace(block); + return true; } } + diff --git a/jode/jode/flow/EmptyBlock.java b/jode/jode/flow/EmptyBlock.java index 05ec219..a33e0f9 100644 --- a/jode/jode/flow/EmptyBlock.java +++ b/jode/jode/flow/EmptyBlock.java @@ -18,27 +18,20 @@ */ package jode.flow; +import jode.TabbedPrintWriter; /** * This is the structured block for an empty block. */ public class EmptyBlock extends StructuredBlock { - Instruction instr; + public EmptyBlock() { + } - SimpleInstruction(Instruction instr) { - in = new Vector(); - out = new Vector(); - this.instr = instr; - if (instr instanceof LocalVarOperator) { - LocalVarOperator varOp = (LocalVarOperator) instr; - if (varOp.isRead()) - in.addElement(varOp.getLocalInfo()); - else /* if (varOp.isWrite()) */ - out.addElement(varOp.getLocalInfo()); - } + public EmptyBlock(Jump jump) { + setJump(jump); } - public void dumpSource(TabbedPrintWriter writer) + public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { writer.println("/* empty */"); diff --git a/jode/jode/flow/FinallyBlock.java b/jode/jode/flow/FinallyBlock.java index 3f844c0..134602d 100644 --- a/jode/jode/flow/FinallyBlock.java +++ b/jode/jode/flow/FinallyBlock.java @@ -17,6 +17,7 @@ */ package jode.flow; +import jode.TabbedPrintWriter; /** * A FinallyBlock represents the instructions and try catch regions @@ -28,5 +29,9 @@ package jode.flow; * region, so we have to take care of this. */ -public FinallyBlock extends StructuredBlock { +public class FinallyBlock extends StructuredBlock { + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException { + writer.println("IMPLEMENT FINALLY"); + } } diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index bfb5478..095c84a 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -18,6 +18,9 @@ */ package jode.flow; +import java.util.*; +import jode.TabbedPrintWriter; +import jode.Expression; /** * A flow block is the structure of which the flow graph consists. A @@ -30,12 +33,24 @@ package jode.flow; */ public class FlowBlock { + static FlowBlock END_OF_METHOD = + new FlowBlock(Integer.MAX_VALUE, 0, new EmptyBlock()); + + static { + END_OF_METHOD.label = "END_OF_METHOD"; + } + /** * The starting address of this flow block. This is mainly used * to produce the source code in code order. */ int addr; + /** + * The length of the structured block, only needed at the beginning. + */ + int length; + /** * The outermost structructed block in this flow block. */ @@ -57,6 +72,25 @@ public class FlowBlock { * moved into the preceding flow block. */ Vector predecessors; + + /** + * The default constructor. Creates a new flowblock containing + * only the given structured block. + */ + public FlowBlock(int addr, int length, StructuredBlock block) { + this.addr = addr; + this.length = length; + this.block = block; + lastModified = block; + predecessors = new Vector(); // filled in later + successors = new Vector(); + block.setFlowBlock(this); + block.fillSuccessors(successors); + } + + public int getNextAddr() { + return addr+length; + } /** * This method optimizes the jumps to successor. @@ -65,109 +99,188 @@ public class FlowBlock { public StructuredBlock optimizeJumps(FlowBlock successor, StructuredBlock appendBlock) { Enumeration enum = successors.elements(); + next_jump: while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); if (jump == null || jump.destination != successor) - continue; + continue next_jump; + same_jump: while(true) { /* if the jump is the jump of the appendBlock, skip it. */ - if (jump == appendBlock.jump) - continue; + if (jump.prev == appendBlock) + continue next_jump; - /* Note: jump.parent.outer != null, since appendBlock is - * an outer block of jump.parent + /* Note: jump.prev.outer != null, since appendBlock is + * an outer block of jump.prev */ /* remove all jumps to the successor which have the successor - * as getNextFlowBlock(). */ - if (jump.parent.outer.getNextFlowBlock(jump.parent) == successor) - jump.parent.removeJump(); + * as getNextFlowBlock(). + */ + if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) { + jump.prev.removeJump(); + continue next_jump; + } /* replace all conditional jumps to the successor, which * are followed by a block which has the end of the block * as normal successor, with "if (not condition) block". */ - if (jump.parent instanceof ConditionalBlock && - jump.parent.outer instanceof SequentialBlock && - jump.parent.outer.getSubBlocks()[0] = jump.parent && - jump.parent.outer.getNextFlowBlock() == successor) { + if (jump.prev instanceof EmptyBlock && + jump.prev.outer instanceof ConditionalBlock) { - ConditionalBlock cb = (ConditionalBlock) jump.parent; - cb.removeJump(); + StructuredBlock prev = jump.prev; + ConditionalBlock cb = (ConditionalBlock) prev.outer; + jode.Instruction instr = cb.getInstruction(); - SequentialBlock sequBlock = - (SequentialBlock) cb.outer; - IfThenElseBlock newIfBlock = - new IfThenElseBlock(cb.getCondition().negate(), - sequBlock.getSubBlocks()[1], null); + if ((cb == appendBlock || + cb.outer.getNextFlowBlock(cb) == successor + /*XXX jumpMayBeChanged()??? */) && + instr instanceof jode.Expression) { - newIfBlock.replace(sequBlock); + cb.setInstruction(((jode.Expression)instr).negate()); + prev.removeJump(); + prev.moveJump(cb); + continue next_jump; + } - if (appendBlock == sequBlock) - appendBlock = newIfBlock; - continue; + /* cb.outer is not null, + * since appendBlock outers cb */ + + if (cb.outer instanceof SequentialBlock && + cb.outer.getSubBlocks()[0] == cb && + (cb.outer.getNextFlowBlock() == successor || + cb.outer.jumpMayBeChanged()) && + instr instanceof jode.Expression) { + SequentialBlock sequBlock = + (SequentialBlock) cb.outer; + + IfThenElseBlock newIfBlock = + new IfThenElseBlock(((jode.Expression)instr).negate()); + + newIfBlock.replace(sequBlock); + newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]); + + newIfBlock.moveJump(sequBlock); + if (appendBlock == sequBlock) + appendBlock = newIfBlock; + + if (newIfBlock.getNextFlowBlock() != successor && + newIfBlock != appendBlock) { + newIfBlock.moveJump(prev); + continue same_jump; + } else { + prev.removeJump(); + continue next_jump; + } + } + } + + /* if there are jumps in an if-then block, which + * have as normal successor the end of the if-then block, and + * the if-then block is followed by a single block, then replace + * the if-then block with a if-then-else block and remove the + * unconditional jump. + */ + StructuredBlock elseBlock = + jump.prev.outer.getNextBlock(jump.prev); + if (elseBlock != null && + elseBlock.outer != null && + elseBlock.outer instanceof SequentialBlock && + elseBlock.outer.getSubBlocks()[0] instanceof IfThenElseBlock && + (elseBlock.outer.getNextFlowBlock() == successor || + elseBlock.outer.jumpMayBeChanged())) { + IfThenElseBlock ifBlock = + (IfThenElseBlock)elseBlock.outer.getSubBlocks()[0]; + if (ifBlock.getSubBlocks().length == 1) { + + elseBlock.outer.removeJump(); + ifBlock.replace(elseBlock.outer); + if (appendBlock == elseBlock.outer) + appendBlock = ifBlock; + ifBlock.moveJump(jump.prev); + ifBlock.setElseBlock(elseBlock); + continue same_jump; + } } /* if the successor is the dummy return instruction, replace all * jumps with a return. */ - if (successor.block.instanceof ReturnBlock) { + if (successor == END_OF_METHOD) { SequentialBlock sequBlock = new SequentialBlock(); - StructuredBlock prevBlock = jump.parent; + StructuredBlock prevBlock = jump.prev; prevBlock.removeJump(); sequBlock.replace(prevBlock); sequBlock.setFirst(prevBlock); sequBlock.setSecond(new ReturnBlock()); - continue; + continue next_jump; } /* If this is a conditional jump, the first instruction of * a while and the condition of the while is true, use * the condition as while condition. */ - - /* This is the first instruction in a while block */ - if (jump.parent instanceof ConditionalBlock && - jump.parent.outer instanceof SequentialBlock && - jump.parent.outer.getSubBlocks()[0] == this && - jump.parent.outer.outer instanceof LoopBlock) { - ConditionalBlock cb = (ConditionalBlock) jump.parent; - LoopBlock loopBlock = (LoopBlock) cb.outer.outer; - if (loopBlock.getCondition() == LoopBlock.TRUE && - loopBlock.getType() != LoopBlock.DOWHILE && - loopBlock.getNextFlowBlock() == successor) { - - cb.removeJump(); - loopBlock.setCondition(cb); - cb.outer.getSubBlocks()[1].replace(cb.outer); - /* cb and cb.outer are not used any more */ - /* Note that cb.outer != appendBlock because - * appendBlock contains loopBlock - */ + if (jump.prev instanceof EmptyBlock && + jump.prev.outer instanceof ConditionalBlock && + jump.prev.outer.jump == null) { + + StructuredBlock prev = jump.prev; + ConditionalBlock cb = (ConditionalBlock) prev.outer; + jode.Instruction instr = cb.getInstruction(); + + /* This is the first instruction in a while block */ + if (cb.outer instanceof SequentialBlock && + cb.outer.getSubBlocks()[0] == cb && + cb.outer.outer instanceof LoopBlock) { + + LoopBlock loopBlock = (LoopBlock) cb.outer.outer; + if (loopBlock.getCondition() == LoopBlock.TRUE && + loopBlock.getType() != LoopBlock.DOWHILE && + loopBlock.getNextFlowBlock() == successor && + instr instanceof Expression) { + + prev.removeJump(); + loopBlock.setCondition(((Expression)instr).negate()); + if (cb.outer.jump != null) { + if (cb.outer.getSubBlocks()[1].jump != null) + cb.outer.removeJump(); + else + cb.outer.getSubBlocks()[1].moveJump(cb.outer); + } + cb.outer.getSubBlocks()[1].replace(cb.outer); + /* cb and cb.outer are not used any more */ + /* Note that cb.outer != appendBlock because + * appendBlock contains loopBlock + */ + continue next_jump; + } } - } - /* Now the same for the empty loop. In this case there is - * no sequential block. - */ - if (jump.parent instanceof ConditionalBlock && - jump.parent.outer instanceof LoopBlock) { - ConditionalBlock cb = (ConditionalBlock) jump.parent; - LoopBlock loopBlock = (LoopBlock) cb.outer; - if (loopBlock.getCondition() == LoopBlock.TRUE && - loopBlock.getType() != LoopBlock.DOWHILE && - loopBlock.getNextFlowBlock() == successor) { - - cb.removeJump(); - loopBlock.setCondition(cb); - EmptyBlock empty = new EmptyBlock(); - empty.replace(cb); - /* cb is not used any more */ + + /* Now the same for the empty loop. In this case there is + * no sequential block. + */ + if (cb.outer instanceof LoopBlock) { + LoopBlock loopBlock = (LoopBlock) cb.outer; + if (loopBlock.getCondition() == LoopBlock.TRUE && + loopBlock.getType() != LoopBlock.DOWHILE && + loopBlock.getNextFlowBlock() == successor && + instr instanceof Expression) { + + prev.removeJump(); + loopBlock.setCondition(((Expression)instr).negate()); + + EmptyBlock empty = new EmptyBlock(); + empty.replace(cb); + /* cb is not used any more */ + continue next_jump; + } } } - + /* if there are jumps in a while block or switch block and the * while/switch block is followed by a jump to successor or has * successor as getNextFlowBlock(), replace jump with break to @@ -178,91 +291,62 @@ public class FlowBlock { * succesor, so that the above succeeds. */ int breaklevel = 0; - for (StructuredBlock surrounder = jump.parent.outer; - surrounder != null; surrounder = surrounder.outer) { + for (StructuredBlock surrounder = jump.prev.outer; + surrounder != null && surrounder != appendBlock.outer; + surrounder = surrounder.outer) { if (surrounder instanceof BreakableBlock) { breaklevel++; if (surrounder.getNextFlowBlock() == successor || surrounder.jumpMayBeChanged()) { SequentialBlock sequBlock = new SequentialBlock(); - StructuredBlock prevBlock = jump.parent; - if (surrounder.getNextFlowBlock() != successor) { - surrounder.jump = jump; - prevBlock.jump = null; - jump.parent = surrounder; - } else { + StructuredBlock prevBlock = jump.prev; + if (surrounder.getNextFlowBlock() != successor) + surrounder.moveJump(prevBlock); + else prevBlock.removeJump(); - } + sequBlock.replace(prevBlock); sequBlock.setFirst(prevBlock); - sequBlock.setSecond(new BreakBlock(surrounder, - breaklevel > 1)); - continue; + sequBlock.setSecond + (new BreakBlock((BreakableBlock) surrounder, + breaklevel > 1)); + continue next_jump; } } } - - /* if there are jumps in an if-then block, which - * have as normal successor the end of the if-then block, and - * the if-then block is followed by a single block, then replace - * the if-then block with a if-then-else block and remove the - * unconditional jump. - */ - StructuredBlock elseBlock = - jump.parent.outer.getNextBlock(jump.parent); - if (elseBlock != null && - elseBlock.outer != null && - elseBlock.outer instanceof SequentialBlock && - elseBlock.outer.getSubBlocks()[0] instanceof IfThenElseBlock && - (elseBlock.outer.getNextFlowBlock() == successor || - elseBlock.outer.jumpMayBeChanged())) { - IfThenElseBlock ifBlock = - (IfThenElseBlock)elseBlock.outer.getSubBlocks()[0]; - if (ifBlock.getElseBlock() == null) { - if (elseBlock.getNextFlowBlock() != successor) { - elseBlock.outer.jump = jump; - jump.parent.jump = null; - jump.parent = elseBlock.outer; - } else { - jump.parent.removeJump(); - } - ifBlock.replace(elseBlock.outer); - ifBlock.setElseBlock(elseBlock); - if (appendBlock = elseBlock.outer) - appendBlock = ifBlock; - } - } + continue next_jump; + } } return appendBlock; } /** * Updates the in/out-Vectors of the structured block of the - * successing flow block simultanous to a T1 transformation. - * @param successor The flow block which is unified with this flow - * block. - */ + * successing flow block simultanous to a T1 transformation. + * @param successor The flow block which is unified with this flow + * block. + */ void updateInOut (FlowBlock successor, boolean t1Transformation) { /* First get the out vectors of all jumps to successor and * calculate the intersection. */ VariableSet allOuts = new VariableSet(); VariableSet intersectOut = null; - Enumeration enum = successors; - while (enum.hasMoreElement()) { + Enumeration enum = successors.elements(); + while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); if (jump == null || jump.destination != successor) continue; - - allOuts.union(jump.parent.out); + + allOuts.union(jump.prev.out); if (intersectOut == null) - intersectOut = jump.parent.out; + intersectOut = jump.prev.out; else - intersectOut = intersectOut.intersect(jump.parent.out); + intersectOut = intersectOut.intersect(jump.prev.out); } - + /* Now work on each block of the successor */ Stack todo = new Stack(); todo.push(successor.block); @@ -271,7 +355,7 @@ public class FlowBlock { StructuredBlock[] subBlocks = block.getSubBlocks(); for (int i=0; i 1)); } + if (doWhileFalse != null) { + doWhileFalse.replace(appendBlock); + doWhileFalse.setBody(appendBlock); + } + /* Believe it or not: Now the rule, that the first part of a * SequentialBlock shouldn't be another SequentialBlock is * fulfilled.

@@ -466,6 +679,22 @@ public class FlowBlock { /* Set last modified to correct value. */ lastModified = succ.lastModified; + + /* Set addr+length to (semi-)correct value */ + if (succ.addr < addr) + addr = succ.addr; + length += succ.length; + + /* T1 transformation succeeded */ + try { + TabbedPrintWriter writer = + new TabbedPrintWriter(System.err, " "); + writer.tab(); + System.err.println("T1 succeeded:"); + block.dumpSource(writer); + checkConsistent(); + } catch (java.io.IOException ex) {} + return true; } public boolean doT2() { @@ -474,9 +703,21 @@ public class FlowBlock { * considered yet, return false. The second condition make * sure that the while isn't created up to the first continue. */ + if (!predecessors.contains(this) + /* || complicated second condition XXX */ ) + return false; + + try { + TabbedPrintWriter writer = + new TabbedPrintWriter(System.err, " "); + writer.tab(); + System.err.println("doing T2 analysis on: "+getLabel()); + block.dumpSource(writer); + checkConsistent(); + } catch (java.io.IOException ex) {} /* Update the in/out-Vectors now */ - updateInOut(successor, false); + updateInOut(this, false); /* If there is only one jump to the beginning and it is the * last jump and (there is a do/while(0) block surrounding @@ -485,26 +726,145 @@ public class FlowBlock { * do/while(0) with a for(;;last_instr) resp. create a new one * and replace breaks to do/while with continue to for. */ + /* XXX implement above */ + /* XXX condition for do/while(cond) blocks */ { /* Otherwise: */ /* create a new while(true) block. */ + StructuredBlock bodyBlock = block; + + /* Prepare the unification of the blocks: Make sure that + * bodyBlock has a jump. */ + if (bodyBlock.jump == null) { + Jump jump = new Jump(this); + bodyBlock.setJump(jump); + successors.addElement(jump); + } + + LoopBlock whileBlock = + new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE); + + whileBlock.replace(bodyBlock); + whileBlock.setBody(bodyBlock); /* Try to eliminate as many jumps as possible. */ - optimizeJumps(this, block); + bodyBlock = optimizeJumps(this, bodyBlock); /* Now remove the jump of block if it points to this. */ + if (bodyBlock.jump != null && + bodyBlock.jump.destination == this) + bodyBlock.removeJump(); /* if there are further jumps to this, replace every jump with a * continue to while block and return true. */ + Enumeration enum = successors.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + + if (jump == null || jump.destination != this) + continue; + + int continuelevel = 1; + for (StructuredBlock surrounder = jump.prev.outer; + surrounder != null; + surrounder = surrounder.outer) { + if (surrounder instanceof LoopBlock) { + continuelevel++; + } + } + + SequentialBlock sequBlock = new SequentialBlock(); + StructuredBlock prevBlock = jump.prev; + prevBlock.removeJump(); + + sequBlock.replace(prevBlock); + sequBlock.setFirst(prevBlock); + sequBlock.setSecond(new ContinueBlock(whileBlock, + continuelevel > 1)); + } + lastModified = whileBlock; + } + + /* remove ourself from the predecessor list. + */ + predecessors.removeElement(this); + + /* T2 analysis succeeded */ + try { + TabbedPrintWriter writer = + new TabbedPrintWriter(System.err, " "); + writer.tab(); + System.err.println("T2 succeded:"); + block.dumpSource(writer); + checkConsistent(); + } catch (java.io.IOException ex) {} + + return true; + } + + /** + * Resolves the destinations of all jumps. + */ + public void resolveJumps(FlowBlock[] instr) { + Enumeration enum = successors.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump.destAddr == -1) + jump.destination = END_OF_METHOD; + else + jump.destination = instr[jump.destAddr]; + if (!jump.destination.predecessors.contains(this)) + jump.destination.predecessors.addElement(this); } } public void removeSuccessor(Jump jump) { successors.setElementAt(null, successors.indexOf(jump)); } + + + /** + * Print the source code for this structured block. This handles + * everything that is unique for all structured blocks and calls + * dumpInstruction afterwards. + * @param writer The tabbed print writer, where we print to. + */ + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (label != null) { + writer.untab(); + writer.println(label+":"); + writer.tab(); + } + block.dumpSource(writer); + FlowBlock succ = getSuccessor(); + if (succ != null) + succ.dumpSource(writer); + } + + /** + * The serial number for labels. + */ + static int serialno = 0; + + /** + * The label of this instruction, or null if it needs no label. + */ + String label = null; + + /** + * Returns the label of this block and creates a new label, if + * there wasn't a label previously. + */ + public String getLabel() { + if (label == null) + label = "flow_"+(serialno++)+"_"; + return label; + } } diff --git a/jode/jode/flow/IfThenElseBlock.java b/jode/jode/flow/IfThenElseBlock.java index 3a7b869..0777600 100644 --- a/jode/jode/flow/IfThenElseBlock.java +++ b/jode/jode/flow/IfThenElseBlock.java @@ -16,6 +16,8 @@ * $Id$ */ package jode.flow; +import jode.Instruction; +import jode.TabbedPrintWriter; /** * An IfThenElseBlock is the structured block representing an if @@ -53,6 +55,7 @@ public class IfThenElseBlock extends StructuredBlock { public void setThenBlock(StructuredBlock thenBlock) { this.thenBlock = thenBlock; thenBlock.outer = this; + thenBlock.setFlowBlock(flowBlock); } /** @@ -62,6 +65,7 @@ public class IfThenElseBlock extends StructuredBlock { public void setElseBlock(StructuredBlock elseBlock) { this.elseBlock = elseBlock; elseBlock.outer = this; + elseBlock.setFlowBlock(flowBlock); } /* The implementation of getNext[Flow]Block is the standard @@ -73,7 +77,7 @@ public class IfThenElseBlock extends StructuredBlock { * @param newBlock the new sub block. * @return false, if oldBlock wasn't a direct sub block. */ - boolean replaceSubBlock(StructuredBlock oldBlock, + public boolean replaceSubBlock(StructuredBlock oldBlock, StructuredBlock newBlock) { if (thenBlock == oldBlock) thenBlock = newBlock; @@ -89,21 +93,28 @@ public class IfThenElseBlock extends StructuredBlock { * called only once, because it remembers which local variables * were declared. */ - public void dumpSource(TabbedPrintWriter writer) + public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { boolean needBrace = ! (thenBlock instanceof InstructionBlock); - writer.println("if ("+cond.toString()+")"+needBrace?" {":""); + writer.println("if ("+cond.toString()+")"+(needBrace?" {":"")); writer.tab(); thenBlock.dumpSource(writer); writer.untab(); if (elseBlock != null) { - writer.print(needBrace?"} ":""); - needBrace = ! (thenBlock instanceof InstructionBlock); - writer.println("else"+needBrace?" {":""); - writer.tab(); - elseBlock.dumpSource(writer); - writer.untab(); + writer.print(needBrace ? "} " : ""); + if (elseBlock instanceof IfThenElseBlock + /* XXX && No variables are declared XXX*/) { + needBrace = false; + writer.print("else "); + elseBlock.dumpSource(writer); + } else { + needBrace = ! (elseBlock instanceof InstructionBlock); + writer.println("else" + (needBrace ? " {" : "")); + writer.tab(); + elseBlock.dumpSource(writer); + writer.untab(); + } } if (needBrace) writer.println("}"); @@ -112,12 +123,12 @@ public class IfThenElseBlock extends StructuredBlock { /** * Returns all sub block of this structured block. */ - StructuredBlock[] getSubBlocks() { + public StructuredBlock[] getSubBlocks() { if (elseBlock == null) { - StructuredBlock result = { thenBlock }; + StructuredBlock[] result = { thenBlock }; return result; } else { - StructuredBlock result = { thenBlock, elseBlock }; + StructuredBlock[] result = { thenBlock, elseBlock }; return result; } } @@ -132,7 +143,7 @@ public class IfThenElseBlock extends StructuredBlock { return false; if (elseBlock != null && elseBlock.jump == null && - !elseBlock.jumpMayBeChanged) + !elseBlock.jumpMayBeChanged()) return false; return true; } diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java index d72a8e8..7cd4206 100644 --- a/jode/jode/flow/InstructionBlock.java +++ b/jode/jode/flow/InstructionBlock.java @@ -16,33 +16,52 @@ * $Id$ */ package jode.flow; +import jode.*; /** * This is the structured block for atomic instructions. */ -public class InstructionBlock extends StructuredBlock { +public class InstructionBlock extends StructuredBlock + implements InstructionContainer { Instruction instr; - InstructionBlock(Instruction instr) { - in = new Vector(); - out = new Vector(); + public InstructionBlock(Instruction instr) { this.instr = instr; if (instr instanceof LocalVarOperator) { LocalVarOperator varOp = (LocalVarOperator) instr; - if (varOp.isRead()) + if (varOp.isRead()) { in.addElement(varOp.getLocalInfo()); - else /* if (varOp.isWrite()) */ - out.addElement(varOp.getLocalInfo()); + } + out.addElement(varOp.getLocalInfo()); } } - public void dumpSource(TabbedPrintWriter writer) + public InstructionBlock(Instruction instr, Jump jump) { + this(instr); + setJump(jump); + } + + /** + * Get the underlying instruction. + * @return the underlying instruction. + */ + public Instruction getInstruction() { + return instr; + } + + /** + * Change the underlying instruction. + * @param instr the new underlying instruction. + */ + public void setInstruction(Instruction instr) { + this.instr = instr; + } + + public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { - if (!(instr instanceof NopOperator)) { - if (instr.getType() != MyType.tVoid) - writer.print("push "); - writer.println(instr.toString()+";"); - } + if (instr.getType() != MyType.tVoid) + writer.print("push "); + writer.println(instr.toString()+";"); } } diff --git a/jode/jode/flow/InstructionContainer.java b/jode/jode/flow/InstructionContainer.java new file mode 100644 index 0000000..1a85217 --- /dev/null +++ b/jode/jode/flow/InstructionContainer.java @@ -0,0 +1,34 @@ +/* InstructionContainer (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ +package jode.flow; + +/** + * This is a method for block containing a single instruction. + */ +public interface InstructionContainer { + /** + * Get the contained instruction. + * @return the contained instruction. + */ + public jode.Instruction getInstruction(); + /** + * Set the contained instruction. + * @param instr the new instruction. + */ + public void setInstruction(jode.Instruction instr); +} diff --git a/jode/jode/flow/Jump.java b/jode/jode/flow/Jump.java index 4fd71e0..ad02af2 100644 --- a/jode/jode/flow/Jump.java +++ b/jode/jode/flow/Jump.java @@ -25,19 +25,35 @@ public class Jump { * The structured block that precedes this jump. */ StructuredBlock prev; - /** - * The flow block, where this jump lies in - */ - FlowBlock parent; /** * The destination block of this jump. */ FlowBlock destination; + /** + * The destination address, in case the destination block is not yet + * known. + */ + int destAddr; + + public Jump (int destAddr) { + this.destAddr = destAddr; + } + + public Jump (FlowBlock dest) { + this.destination = dest; + } /** * Returns true if this jump has jsr or monitorexit attachments. */ boolean hasAttachments() { + return false; } -} + /** + * Returns a string describing the jsr or monitorexit attachments. + */ + String describeAttachments() { + return ""; + } +} diff --git a/jode/jode/flow/LoopBlock.java b/jode/jode/flow/LoopBlock.java new file mode 100644 index 0000000..45f2bdd --- /dev/null +++ b/jode/jode/flow/LoopBlock.java @@ -0,0 +1,156 @@ +/* + * LoopBlock (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import jode.*; + +/** + * This is the structured block for an Loop block. + */ +public class LoopBlock extends BreakableBlock { + + public static final int WHILE = 0; + public static final int DOWHILE = 1; + public static final int FOR = 2; + + public static final Instruction TRUE = + new Expression(new ConstOperator(MyType.tBoolean, "1"), + new Expression[0]); + + public static final Instruction FALSE = + new Expression(new ConstOperator(MyType.tBoolean, "0"), + new Expression[0]); + + /** + * The condition. Must be of boolean type. + */ + Instruction cond; + /** + * The init instruction, only valid if type == FOR. + */ + Instruction init; + /** + * The increase instruction, only valid if type == FOR. + */ + Instruction incr; + + /** + * The type of the loop. This must be one of DOWHILE, WHILE or FOR. + */ + int type; + + /** + * The body of this loop. This is always a valid block and not null + */ + StructuredBlock bodyBlock; + + /** + * Returns the block where the control will normally flow to, when + * the given sub block is finished (not ignoring the jump + * after this block). (This is overwritten by SequentialBlock and + * SwitchBlock). If this isn't called with a direct sub block, + * the behaviour is undefined, so take care. + * @return null, if the control flows to another FlowBlock. */ + public StructuredBlock getNextBlock(StructuredBlock subBlock) { + return this; + } + + public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { + return null; + } + + public LoopBlock(int type, Instruction cond) { + this.type = type; + this.cond = cond; + this.mayChangeJump = (cond == TRUE); + } + + public void setBody(StructuredBlock body) { + bodyBlock = body; + bodyBlock.outer = this; + body.setFlowBlock(flowBlock); + } + + public Instruction getCondition() { + return cond; + } + + public void setCondition(Instruction cond) { + this.cond = cond; + mayChangeJump = false; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + /** + * Replaces the given sub block with a new block. + * @param oldBlock the old sub block. + * @param newBlock the new sub block. + * @return false, if oldBlock wasn't a direct sub block. + */ + public boolean replaceSubBlock(StructuredBlock oldBlock, + StructuredBlock newBlock) { + if (bodyBlock == oldBlock) + bodyBlock = newBlock; + else + return false; + return true; + } + + /** + * Returns all sub block of this structured block. + */ + public StructuredBlock[] getSubBlocks() { + StructuredBlock[] result = { bodyBlock }; + return result; + } + + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException + { + boolean needBrace = ! (bodyBlock instanceof InstructionBlock); + switch (type) { + case WHILE: + writer.print("while ("+cond.toString()+")"); + break; + case DOWHILE: + writer.print("do"); + break; + case FOR: + writer.print("for ("+(init != null ? init.toString() : "") + + "; "+cond.toString()+"; "+incr.toString()+")"); + break; + } + writer.println( needBrace?" {": ""); + writer.tab(); + bodyBlock.dumpSource(writer); + writer.untab(); + if (type == DOWHILE) + writer.println((needBrace?"} ": "")+ + "while ("+cond.toString()+")"); + else if (needBrace) + writer.println("}"); + } +} diff --git a/jode/jode/flow/RawTryCatchBlock.java b/jode/jode/flow/RawTryCatchBlock.java index c18bfff..6490f49 100644 --- a/jode/jode/flow/RawTryCatchBlock.java +++ b/jode/jode/flow/RawTryCatchBlock.java @@ -17,6 +17,7 @@ */ package jode.flow; +import jode.TabbedPrintWriter; /** * A RawTryCatchBlock is created for each exception in the @@ -39,7 +40,7 @@ package jode.flow; * @see SynchronizedBlock */ -public RawTryCatchBlock extends StructuredBlock { +public class RawTryCatchBlock extends StructuredBlock { /** * An unconditional jump to the EndBlock. @@ -55,5 +56,10 @@ public RawTryCatchBlock extends StructuredBlock { * The type of the exception that is catched. This is null for a * synchronized/finally block */ - Type type; + jode.MyType type; + + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException { + writer.println("IMPLEMENT FINALLY"); + } } diff --git a/jode/jode/flow/RemoveEmpty.java b/jode/jode/flow/RemoveEmpty.java new file mode 100644 index 0000000..1c51d6a --- /dev/null +++ b/jode/jode/flow/RemoveEmpty.java @@ -0,0 +1,85 @@ +/* + * RemoveEmpty (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import jode.Instruction; +import jode.NopOperator; + +public class RemoveEmpty implements Transformation { + + public boolean transform (FlowBlock fb) { + return (removeNop(fb) || removeEmpty(fb)); + } + + public boolean removeNop(FlowBlock flow) { + StructuredBlock block; + SequentialBlock sequBlock; + Instruction instr; + try { + block = flow.lastModified; + if (!(((InstructionContainer)block).getInstruction() + instanceof NopOperator)) + return false; + + sequBlock = (SequentialBlock)block.outer; + if (sequBlock.getSubBlocks()[1] != block) + return false; + + InstructionBlock prev = + (InstructionBlock) sequBlock.getSubBlocks()[0]; + if (prev.jump != null) + return false; + instr = (Instruction) prev.getInstruction(); + } catch (NullPointerException ex) { + return false; + } catch (ClassCastException ex) { + return false; + } + ((InstructionContainer)block).setInstruction(instr); + block.replace(sequBlock); + flow.lastModified = block; + return true; + } + + public boolean removeEmpty(FlowBlock flow) { + StructuredBlock lastBlock = flow.lastModified; + if (lastBlock instanceof EmptyBlock && + lastBlock.outer instanceof SequentialBlock && + lastBlock.outer.getSubBlocks()[1] == lastBlock) { + + StructuredBlock block = lastBlock.outer.getSubBlocks()[0]; + block.replace(block.outer); + if (block.jump == null) + block.moveJump(lastBlock); + else + lastBlock.removeJump(); + flow.lastModified = block; + return true; + } + if (lastBlock.outer instanceof SequentialBlock && + lastBlock.outer.getSubBlocks()[0] instanceof EmptyBlock && + lastBlock.outer.getSubBlocks()[0].jump == null) { + + lastBlock.replace(lastBlock.outer); + flow.lastModified = lastBlock; + return true; + } + return false; + } +} diff --git a/jode/jode/flow/ReturnBlock.java b/jode/jode/flow/ReturnBlock.java new file mode 100644 index 0000000..1dfa518 --- /dev/null +++ b/jode/jode/flow/ReturnBlock.java @@ -0,0 +1,42 @@ +/* + * ReturnBlock (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import jode.TabbedPrintWriter; +import jode.Instruction; + +/** + * This is the structured block for an Return block. + */ +public class ReturnBlock extends StructuredBlock { + Instruction instr = null; + + public ReturnBlock() { + } + + public ReturnBlock(Instruction instr) { + this.instr = instr; + } + + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException + { + writer.println("return" + (instr == null ? "" : " " + instr) + ";"); + } +} diff --git a/jode/jode/flow/SequentialBlock.java b/jode/jode/flow/SequentialBlock.java index 84caee1..206260c 100644 --- a/jode/jode/flow/SequentialBlock.java +++ b/jode/jode/flow/SequentialBlock.java @@ -16,6 +16,7 @@ * $Id$ */ package jode.flow; +import jode.TabbedPrintWriter; /** * A sequential block combines exactly two structured blocks to a new @@ -24,21 +25,23 @@ package jode.flow; * condition is temporarily violated, while the t1 transformation is * done. */ -public class SequentialBlock { +public class SequentialBlock extends StructuredBlock { StructuredBlock[] subBlocks; public SequentialBlock() { subBlocks = new StructuredBlock[2]; } - public setFirst(StructuredBlock sb) { + public void setFirst(StructuredBlock sb) { subBlocks[0] = sb; sb.outer = this; + sb.setFlowBlock(flowBlock); } - public setSecond(StructuredBlock sb) { + public void setSecond(StructuredBlock sb) { subBlocks[1] = sb; sb.outer = this; + sb.setFlowBlock(flowBlock); } /** @@ -48,25 +51,32 @@ public class SequentialBlock { * SwitchBlock). If this isn't called with a direct sub block, * the behaviour is undefined, so take care. * @return null, if the control flows to another FlowBlock. */ - StructuredBlock getNextBlock(StructuredBlock subBlock) { + public StructuredBlock getNextBlock(StructuredBlock subBlock) { if (subBlock == subBlocks[0]) return subBlocks[1]; return getNextBlock(); } - FlowBlock getNextFlowBlock(StructuredBlock subBlock) { + public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { if (subBlock == subBlocks[0]) return null; return getNextFlowBlock(); } + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException + { + subBlocks[0].dumpSource(writer); + subBlocks[1].dumpSource(writer); + } + /** * Replaces the given sub block with a new block. * @param oldBlock the old sub block. * @param newBlock the new sub block. * @return false, if oldBlock wasn't a direct sub block. */ - boolean replaceSubBlock(StructuredBlock oldBlock, + public boolean replaceSubBlock(StructuredBlock oldBlock, StructuredBlock newBlock) { for (int i=0; i<2; i++) { if (subBlocks[i] == oldBlock) { @@ -80,7 +90,7 @@ public class SequentialBlock { /** * Returns all sub block of this structured block. */ - StructuredBlock[] getSubBlocks() { + public StructuredBlock[] getSubBlocks() { return subBlocks; } @@ -93,7 +103,3 @@ public class SequentialBlock { return (subBlocks[1].jump != null || subBlocks[1].jumpMayBeChanged()); } } - - - - diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index cf25948..67563e9 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -18,6 +18,7 @@ */ package jode.flow; +import jode.TabbedPrintWriter; /** * A structured block is the building block of the source programm. @@ -49,8 +50,8 @@ package jode.flow; public abstract class StructuredBlock { /* Invariants: * in.intersection(out) = empty - * outer != null => flowblock = outer.flowblock - * outer == null => flowblock.block = this + * outer != null => flowBlock = outer.flowBlock + * outer == null => flowBlock.block = this * jump == null => outer != null * either getNextBlock() != null * or getNextFlowBlock() != null or outer == null @@ -65,7 +66,7 @@ public abstract class StructuredBlock { * path from the start of the current flow block, on which the * local variable is never assigned */ - VariableSet in; + VariableSet in = new VariableSet(); /** * The out locals. This are the locals, which must be overwritten @@ -74,14 +75,14 @@ public abstract class StructuredBlock { * structured block contain a (unconditional) assignment to this * local */ - VariableSet out; + VariableSet out = new VariableSet(); /** * The variable set containing all variables that must be defined * in this block (or maybe an outer block, this changes as the * blocks are put together). */ - VariableSet defineHere; + VariableSet defineHere = new VariableSet(); /** * The surrounding structured block. If this is the outermost @@ -91,7 +92,7 @@ public abstract class StructuredBlock { /** * The flow block in which this structured block lies. */ - FlowBlock flowblock; + FlowBlock flowBlock; /** * The jump that follows on this block, or null if there is no @@ -104,13 +105,17 @@ public abstract class StructuredBlock { * Returns the block where the control will normally flow to, when * this block is finished (not ignoring the jump after this block). */ - StructuredBlock getNextBlock() { + public StructuredBlock getNextBlock() { if (jump != null) return null; if (outer != null) - outer.getNextBlock(this); - else - return null; + return outer.getNextBlock(this); + return null; + } + + public void setJump(Jump jump) { + this.jump = jump; + jump.prev = this; } /** @@ -120,13 +125,12 @@ public abstract class StructuredBlock { * @return null, if the control flows into a non empty structured * block or if this is the outermost block. */ - FlowBlock getNextFlowBlock() { + public FlowBlock getNextFlowBlock() { if (jump != null) return jump.destination; if (outer != null) - outer.getNextFlowBlock(this); - else - return null; + return outer.getNextFlowBlock(this); + return null; } /** @@ -135,13 +139,12 @@ public abstract class StructuredBlock { * @return null, if everything is okay, and a diagnostic message that * should be put in a comment otherwise. */ - String checkJump(Jump jump) { + public String checkJump(Jump jump) { if (outer != null) return outer.checkJump(jump); - else if (jump.hasAttachments()) - return "Unknown attachments: "+jump.describeAttachments() - else - return null; + if (jump.hasAttachments()) + return "Unknown attachments: "+jump.describeAttachments(); + return null; } /** @@ -151,11 +154,11 @@ public abstract class StructuredBlock { * SwitchBlock). If this isn't called with a direct sub block, * the behaviour is undefined, so take care. * @return null, if the control flows to another FlowBlock. */ - StructuredBlock getNextBlock(StructuredBlock subBlock) { + public StructuredBlock getNextBlock(StructuredBlock subBlock) { return getNextBlock(); } - FlowBlock getNextFlowBlock(StructuredBlock subBlock) { + public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { return getNextFlowBlock(); } @@ -165,15 +168,15 @@ public abstract class StructuredBlock { * @param newBlock the new sub block. * @return false, if oldBlock wasn't a direct sub block. */ - boolean replaceSubBlock(StructuredBlock oldBlock, - StructuredBlock newBlock) { + public boolean replaceSubBlock(StructuredBlock oldBlock, + StructuredBlock newBlock) { return false; } /** * Returns all sub block of this structured block. */ - StructuredBlock[] getSubBlocks() { + public StructuredBlock[] getSubBlocks() { return new StructuredBlock[0]; } @@ -182,19 +185,21 @@ public abstract class StructuredBlock { * @param child the block which should be contained by this block. * @return false, if child is null, or is not contained in this block. */ - boolean contains(StructuredBlock child) { + public boolean contains(StructuredBlock child) { while (child != this && child != null) child = child.outer; return (child == this); } - /** - * Removes the jump after this structured block. This does also update - * the successors vector of the flow block. + * Removes the given jump if it is our jump. This does also + * update the successors vector of the flow block. + * + * @param jump The jump that should be removed. */ public void removeJump() { if (jump != null) { + jump.prev = null; flowBlock.removeSuccessor(jump); jump = null; } @@ -202,24 +207,17 @@ public abstract class StructuredBlock { /** * This function replaces sb with this block. It copies outer and - * the following jump from sb, and updates them, so they know that - * sb was replaced. - * The jump field of sb is removed afterwards. You have to replace - * sb.outer or mustn't use sb anymore. - * @param sb The structured block that should be replaced. - */ + * from sb, and updates the outer block, so it knows that sb was + * replaced. You have to replace sb.outer or mustn't use sb + * anymore. + * @param sb The structured block that should be replaced. */ public void replace(StructuredBlock sb) { in = sb.in; out = sb.out; defineHere = sb.defineHere; outer = sb.outer; flowBlock = sb.flowBlock; - jump = sb.jump; - if (jump != null) { - jump.parent = this; - sb.jump = null; - } if (outer != null) { outer.replaceSubBlock(sb, this); } else { @@ -227,6 +225,19 @@ public abstract class StructuredBlock { } } + /** + * This function moves the jumps from sb to this block. + * The jump field of sb is removed afterwards. + * @param sb The structured block whose jump is copied. + */ + public void moveJump(StructuredBlock sb) { + jump = sb.jump; + if (jump != null) { + jump.prev = this; + sb.jump = null; + } + } + /** * Determines if there is a sub block, that flows through to the end * of this block. If this returns true, you know that jump is null. @@ -236,25 +247,78 @@ public abstract class StructuredBlock { return false; } + public void checkConsistent() { + StructuredBlock[] subs = getSubBlocks(); + for (int i=0; inot ignoring the jump + * after this block). (This is overwritten by SequentialBlock and + * SwitchBlock). If this isn't called with a direct sub block, + * the behaviour is undefined, so take care. + * @return null, if the control flows to another FlowBlock. */ + public StructuredBlock getNextBlock(StructuredBlock subBlock) { + /*XXX*/ + return getNextBlock(); + } + + public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { + /*XXX*/ + return getNextFlowBlock(); + } + + /** + * Returns all sub block of this structured block. + */ + public StructuredBlock[] getSubBlocks() { + return caseBlocks; + } +} + diff --git a/jode/jode/flow/ThrowBlock.java b/jode/jode/flow/ThrowBlock.java new file mode 100644 index 0000000..73c710f --- /dev/null +++ b/jode/jode/flow/ThrowBlock.java @@ -0,0 +1,42 @@ +/* + * ThrowBlock (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import jode.TabbedPrintWriter; +import jode.Instruction; + +/** + * This is the structured block for an Throw block. + */ +public class ThrowBlock extends StructuredBlock { + Instruction instr = null; + + public ThrowBlock() { + } + + public ThrowBlock(Instruction instr) { + this.instr = instr; + } + + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException + { + writer.println("throw" + (instr == null ? "" : " " + instr) + ";"); + } +} diff --git a/jode/jode/flow/Transformation.java b/jode/jode/flow/Transformation.java new file mode 100644 index 0000000..8faa0f5 --- /dev/null +++ b/jode/jode/flow/Transformation.java @@ -0,0 +1,24 @@ +/* + * Transformation (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; + +public interface Transformation { + public boolean transform(FlowBlock flowBlock); +} diff --git a/jode/jode/flow/VariableSet.java b/jode/jode/flow/VariableSet.java index 3d8b15d..5ac1af5 100644 --- a/jode/jode/flow/VariableSet.java +++ b/jode/jode/flow/VariableSet.java @@ -15,7 +15,8 @@ * * $Id$ */ -package jode.Flow; +package jode.flow; +import jode.LocalInfo; /** * This class represents a set of Variables, which are mainly used in @@ -39,7 +40,7 @@ public class VariableSet extends java.util.Vector { * Adds a local variable to the variable set. * @param li The local variable of type LocalInfo. */ - public addElement(LocalInfo li) { + public void addElement(LocalInfo li) { super.addElement((Object)li); } @@ -54,7 +55,7 @@ public class VariableSet extends java.util.Vector { LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo(); for (int j=0; j=0; i--) { LocalInfo li1 = (LocalInfo) elementData[i]; for (int j=0; j