You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
492 lines
16 KiB
492 lines
16 KiB
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<predecessors.size(); i++) {
|
|
InstructionHeader ih =
|
|
(InstructionHeader)predecessors.elementAt(i);
|
|
if (ih.flowType == GOTO ||
|
|
(ih.flowType == IFGOTO && ih.successors[1] == this))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the unique predecessor or null if there isn't a
|
|
* unique predecessor.
|
|
*/
|
|
public InstructionHeader getUniquePredecessor() {
|
|
return (predecessors.size() == 1 &&
|
|
predecessors.elementAt(0) == prevInstruction) ?
|
|
prevInstruction : null;
|
|
}
|
|
|
|
/**
|
|
* Get the unique predecessor which mustn't be a conditional jump
|
|
* @return the predecessor or null if there isn't a such a thing
|
|
*/
|
|
public InstructionHeader getSimpleUniquePredecessor() {
|
|
InstructionHeader pre = getUniquePredecessor();
|
|
return (pre.getSuccessors().length != 1) ? null : pre;
|
|
}
|
|
|
|
/**
|
|
* Get the predecessors of this instruction. This function mustn't
|
|
* be called before resolveSuccessors is executed for all
|
|
* InstructionHeaders.
|
|
* @return Vector of predecessors.
|
|
*/
|
|
public Vector getPredecessors() {
|
|
return predecessors;
|
|
}
|
|
|
|
/**
|
|
* Resolve the successors and predecessors and build a doubly
|
|
* linked list.
|
|
* @param instHeaders an array of the InstructionHeaders, indexed
|
|
* by addresses.
|
|
*/
|
|
public void resolveSuccessors(InstructionHeader[] instHeaders) {
|
|
if (nextAddr < instHeaders.length) {
|
|
nextInstruction = instHeaders[nextAddr];
|
|
instHeaders[nextAddr].prevInstruction = this;
|
|
} else
|
|
nextInstruction = null;
|
|
successors = new InstructionHeader[succs.length];
|
|
for (int i=0; i< succs.length; i++) {
|
|
successors[i] = instHeaders[succs[i]];
|
|
successors[i].predecessors.addElement(this);
|
|
}
|
|
succs = null;
|
|
}
|
|
|
|
public void dumpDebugging(TabbedPrintWriter writer)
|
|
throws java.io.IOException
|
|
{
|
|
writer.print(""+toString()+
|
|
": <"+addr + " - "+(nextAddr-1)+"> preds: ");
|
|
for (int i=0; i<predecessors.size(); i++) {
|
|
if (i>0) writer.print(", ");
|
|
writer.print(""+predecessors.elementAt(i));
|
|
}
|
|
writer.println("");
|
|
writer.print("out: "+outer+" end: "+endBlock+
|
|
" prev: "+prevInstruction+", next: "+ nextInstruction +
|
|
" succs: ");
|
|
for (int i=0; i<successors.length; i++) {
|
|
if (i>0) 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 <em>from</em> to
|
|
* the current instruction. The current predecessors are overwritten
|
|
* and you must make sure that no live InstructionHeader points to
|
|
* the current. <p>
|
|
* The predecessors of <em>from</em> 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; j<pre.successors.length; j++)
|
|
if (pre.successors[j] == from)
|
|
pre.successors[j] = this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method replaces multiple InstructionHeaders by a single one.
|
|
* The next count Instructions must be unique.
|
|
* @param count the number of InstructionHeaders that should be replaced.
|
|
* @param instr the new instruction; this should be equivalent to the
|
|
* old <em>count</em instructions.
|
|
* @return the InstructionHeader representing the combined instructions.
|
|
*/
|
|
public InstructionHeader combine(int count, Instruction newInstr) {
|
|
InstructionHeader ih = this;
|
|
for (int i=1; i < count; i++) {
|
|
ih = ih.nextInstruction;
|
|
}
|
|
ih.instr = newInstr;
|
|
ih.movePredecessors(this);
|
|
return ih;
|
|
}
|
|
|
|
public InstructionHeader doTransformations(Transformation[] trafo) {
|
|
for (int i=0; i<trafo.length; i++) {
|
|
InstructionHeader newInstr = trafo[i].transform(this);
|
|
if (newInstr != null)
|
|
return newInstr;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* This method replaces two conditional InstructionHeaders by a
|
|
* single one. You must make sure that this and the next instruction
|
|
* are both conditional Instructions and the destinations matches.
|
|
*
|
|
* @param newCondition the new instruction; this should be equivalent
|
|
* to the old two conditions.
|
|
*/
|
|
public InstructionHeader combineConditional(Instruction newCondition) {
|
|
successors[1].predecessors.removeElement(this);
|
|
InstructionHeader next = nextInstruction;
|
|
next.instr = newCondition;
|
|
next.movePredecessors(this);
|
|
return next;
|
|
}
|
|
}
|
|
|