package jode; import java.util.Vector; import sun.tools.java.Type; /** * This class maintains the connections between the * InstructionHeaders. They are connected in a doubly linked list * (but a instruction may have multiple successors and predecessors). * @see JumpInstructionHeader * @see SwitchInstructionHeader * @author Jochen Hoenicke */ public class InstructionHeader { public final static int METHOD =-1; public final static int NORMAL = 0; public final static int GOTO = 1; public final static int IFGOTO = 2; public final static int SWITCH = 3; public final static int JSR = 4; public final static int RET = 5; public final static int RETURN = 6; public final static int TRY = 7; public final static int CATCH = 8; public final static int IFSTATEMENT = 10; public final static int WHILESTATEMENT = 11; public final static int DOWHILESTATEMENT = 12; public final static int FORSTATEMENT = 13; public final static int SWITCHSTATEMENT = 14; public final static int TRYCATCHBLOCK = 15; public final static int BREAKSTATEMENT = 19; public final static int EMPTY = 99; /** * The flow type of the instruction header, this is one of the * above constants. */ int flowType; /** * The address of this and the following instruction header. */ int addr, nextAddr; /** * The underlying instruction. This is null for some special * instructions (depends on flowType). */ Instruction instr; /** * The instruction header representing the surrounding block. */ InstructionHeader outer = null; /** * A simple doubly linked list of instructions in code order * (without caring about jump instructions). */ InstructionHeader nextInstruction, prevInstruction; /** * The first instruction after this block. This should be only * set for blocks, that is headers which are outer of other headers. * This gives the instruction where the control flows after this * block. */ InstructionHeader endBlock; /** * A more complex doubly linked list of instructions. The * successors are the possible destinations of jump and switch * instructions. The predecessors are the reverse things. * The predeccors sits in a vector to make it easier to add * or remove one, when creating or manipulating other instruction * headers. */ InstructionHeader[] successors; Vector predecessors = new Vector(); /** * The addresses of the successors of this header. This are * resolved by resolveSuccessors and then deleted. */ int[] succs = null; /** * Create a new InstructionHeader, that must be resolved later. * @param flowType The type of this instruction header. * @param addr The address of this instruction header. * @param nextAddr The address of the next instruction header. * @param instr The underlying Instruction. * @param succs The successors of this instruction header * (the addresses, are resolved later). */ protected InstructionHeader(int flowType, int addr, int nextAddr, Instruction instr, int[] succs) { this.flowType = flowType; this.addr = addr; this.nextAddr = nextAddr; this.instr = instr; this.succs = succs; } /** * Create a new InstructionHeader. * @param flowType The type of this instruction header. * @param addr The address of this instruction header. * @param nextAddr The address of the next instruction header. * @param successors The successors of this instruction header. * @param outer The instruction header of the surrounding block. */ protected InstructionHeader(int flowType, int addr, int nextAddr, InstructionHeader[] successors, InstructionHeader outer) { this.flowType = flowType; this.addr = addr; this.nextAddr = nextAddr; this.instr = instr; this.successors = successors; this.outer = outer; } /** * Create a new InstructionHeader of zero length. * @param flowType The type of this instruction header. * @param addr The address of this Instruction. * @param outer The instruction header of the surrounding block. */ protected InstructionHeader(int flowType, int addr, InstructionHeader outer) { this(flowType, addr, addr, new InstructionHeader[0], outer); } /** * Create an InstructionHeader for a normal instruction. * @param addr The address of this instruction. * @param length The length of this instruction. * @param instr The underlying Instruction. */ public static InstructionHeader createNormal(int addr, int length, Instruction instr) { int[] succs = { addr + length }; return new InstructionHeader(NORMAL, addr, addr + length, instr, succs); } /** * Create an InstructionHeader for a return * @param addr The address of this instruction. * @param length The length of this instruction. * @param instr The underlying Instruction. */ public static InstructionHeader createReturn(int addr, int length, Instruction instr) { return new InstructionHeader(RETURN, addr, addr + length, instr, new int[0]); } /** * Create an InstructionHeader for an unconditional jump. * @param addr The address of this instruction. * @param length The length of this instruction. * @param instr The underlying Instruction. * @param dest The destination address of the jump. */ public static InstructionHeader createGoto(int addr, int length, int dest, Instruction instr) { int [] succs = { dest }; return new InstructionHeader (GOTO, addr, addr + length, instr, succs); } /** * Create an InstructionHeader for a conditional jump. * @param addr The address of this instruction. * @param length The length of this instruction. * @param instr The underlying Instruction. * @param dest The destination address of the jump. */ public static InstructionHeader createIfGoto(int addr, int length, int dest, Instruction instr) { int[] succs = { addr+length , dest }; return new InstructionHeader (IFGOTO, addr, addr + length, instr, succs); } /** * Create an InstructionHeader for a switch. * @param addr The address of this Instruction. * @param length The length of this Instruction. * @param instr The underlying Instruction. * @param cases The possible cases * @param succs The destinations (one longer for default) */ public static InstructionHeader createSwitch(int addr, int length, Instruction instr, int[] cases, int[] succs) { InstructionHeader ih = new SimpleSwitchInstructionHeader(addr, addr+length, instr, cases, succs); return ih; } static int ids =0; int id = -1; public String toString() { if (id == -1) id = ids++; return addr+"__"+id; } /** * Returns the InstructionHeader where a break of this instruction * would jump to. Does only make sense for do/while/for-loops and * switch instructions. */ public InstructionHeader getBreak() { return null; } /** * Returns the InstructionHeader where a continue of this instruction * would jump to. Does only make sense for do/while/for-loops. */ public InstructionHeader getContinue() { return null; } /** * Get the flow type of this instruction. * @return the flow type. */ public int getFlowType() { return flowType; } static int serialnr = 0; String label = null; /** * Get the label of this instruction. It is created on the fly * if it didn't exists before. * @return the label. */ public String getLabel() { if (label == null) label = "label_" + serialnr++; return label; } /** * Get the address of this instruction. This is probably only useful * for debugging purposes. * @return the address. */ public int getAddress() { return addr; } /** * Get the next address in code order. * @return the next instruction */ public int getNextAddr() { return nextAddr; } /** * Get the underlying instruction. * @return the underlying instruction. */ public Instruction getInstruction() { return instr; } /** * Set the underlying instruction. * @param instr the underlying instruction. */ public void setInstruction(Instruction instr) { this.instr = instr; } /** * Get the next instruction in code order. This function mustn't * be called before resolveSuccessors is executed for this * InstructionHeaders. * @return the next instruction */ public InstructionHeader getNextInstruction() { return nextInstruction; } /** * Get the successors of this instructions. This function mustn't * be called before resolveSuccessors is executed for this * InstructionHeaders. * @return Array of successors. */ public InstructionHeader[] getSuccessors() { return successors; } /** * Returns true if this instruction header needs a label. */ protected boolean needsLabel() { if (label != null) return true; /* An instruction my have only one prevInstruction, but * may have more then one predecessor that has its * nextInstruction pointing to us. */ for (int i=0; i preds: "); for (int i=0; i0) writer.print(", "); writer.print(""+predecessors.elementAt(i)); } writer.println(""); writer.print("out: "+outer+" end: "+endBlock+ " prev: "+prevInstruction+", next: "+ nextInstruction + " succs: "); for (int i=0; i0) writer.print(", "); writer.print(""+successors[i]); } writer.println(""); } public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { if (Decompiler.isDebugging) { dumpDebugging(writer); writer.tab(); } if (needsLabel()) { writer.untab(); writer.println(getLabel()+": "); writer.tab(); } if (flowType == IFGOTO) { writer.println("if ("+instr.toString()+") goto "+ successors[1].getLabel()); } else { if (flowType != EMPTY) { if (!(instr instanceof NopOperator)) { if (instr.getType() != MyType.tVoid) writer.print("push "); writer.println(instr.toString()+";"); } if (flowType == GOTO) writer.println("goto "+successors[0].getLabel()); } } if (Decompiler.isDebugging) writer.untab(); } /** * Moves the predecessors from the InstructionHeader from to * the current instruction. The current predecessors are overwritten * and you must make sure that no live InstructionHeader points to * the current.

* The predecessors of from are informed about this change. * @param from The instruction header which predecessors are moved. */ public void movePredecessors(InstructionHeader from) { addr = from.addr; prevInstruction = from.prevInstruction; if (prevInstruction != null) prevInstruction.nextInstruction = this; predecessors = from.predecessors; for (int i=0; i < predecessors.size(); i++) { InstructionHeader pre = (InstructionHeader)predecessors.elementAt(i); for (int j=0; jcount