|
|
|
@ -1,5 +1,25 @@ |
|
|
|
|
/* Instruction Copyright (C) 1999 Jochen Hoenicke. |
|
|
|
|
* |
|
|
|
|
* This program is free software; you can redistribute it and/or modify |
|
|
|
|
* it under the terms of the GNU General Public License as published by |
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option) |
|
|
|
|
* any later version. |
|
|
|
|
* |
|
|
|
|
* This program is distributed in the hope that it will be useful, |
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
|
* GNU General Public License for more details. |
|
|
|
|
* |
|
|
|
|
* You should have received a copy of the GNU General Public License |
|
|
|
|
* along with this program; see the file COPYING. If not, write to |
|
|
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
|
|
* |
|
|
|
|
* $Id$ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
package jode.bytecode; |
|
|
|
|
import java.util.Vector; |
|
|
|
|
import java.util.Enumeration; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This class represents an instruction in the byte code. |
|
|
|
@ -8,6 +28,7 @@ import java.util.Vector; |
|
|
|
|
* many of them, though. |
|
|
|
|
*/ |
|
|
|
|
public class Instruction implements Opcodes{ |
|
|
|
|
public BytecodeInfo codeinfo; |
|
|
|
|
/** |
|
|
|
|
* The opcode of the instruction. We map some opcodes, e.g. |
|
|
|
|
* <pre> |
|
|
|
@ -68,6 +89,131 @@ public class Instruction implements Opcodes{ |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* You can use this field to add some info to each instruction. |
|
|
|
|
* After using, you must set it to null again. |
|
|
|
|
*/ |
|
|
|
|
public Object tmpInfo; |
|
|
|
|
|
|
|
|
|
public Instruction(BytecodeInfo ci) { |
|
|
|
|
this.codeinfo = ci; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Instruction insertInstruction() { |
|
|
|
|
Instruction newInstr = new Instruction(codeinfo); |
|
|
|
|
newInstr.addr = addr; |
|
|
|
|
|
|
|
|
|
newInstr.prevByAddr = prevByAddr; |
|
|
|
|
if (prevByAddr != null) |
|
|
|
|
prevByAddr.nextByAddr = newInstr; |
|
|
|
|
else |
|
|
|
|
codeinfo.firstInstr = newInstr; |
|
|
|
|
newInstr.nextByAddr = this; |
|
|
|
|
prevByAddr = newInstr; |
|
|
|
|
|
|
|
|
|
/* promote the predecessors to newInstr */ |
|
|
|
|
Enumeration enum = preds.elements(); |
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
Instruction pred = (Instruction) enum.nextElement(); |
|
|
|
|
if (pred.succs != null) |
|
|
|
|
for (int i=0; i < pred.succs.length; i++) |
|
|
|
|
if (pred.succs[i] == this) |
|
|
|
|
pred.succs[i] = newInstr; |
|
|
|
|
} |
|
|
|
|
newInstr.preds = preds; |
|
|
|
|
preds = new Vector(); |
|
|
|
|
preds.addElement(newInstr); |
|
|
|
|
|
|
|
|
|
return newInstr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Instruction appendInstruction(boolean nextAlwaysJumps) { |
|
|
|
|
Instruction newInstr = new Instruction(codeinfo); |
|
|
|
|
newInstr.addr = addr; |
|
|
|
|
newInstr.nextByAddr = nextByAddr; |
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.prevByAddr = newInstr; |
|
|
|
|
newInstr.prevByAddr = this; |
|
|
|
|
newInstr.alwaysJumps = nextAlwaysJumps; |
|
|
|
|
|
|
|
|
|
if (nextByAddr != null) { |
|
|
|
|
if (!this.alwaysJumps) |
|
|
|
|
nextByAddr.preds.removeElement(this); |
|
|
|
|
if (!nextAlwaysJumps) |
|
|
|
|
nextByAddr.preds.addElement(newInstr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nextByAddr = newInstr; |
|
|
|
|
if (!this.alwaysJumps) |
|
|
|
|
newInstr.preds.addElement(this); |
|
|
|
|
return newInstr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Removes this instruction (as if it would be replaced by a nop). |
|
|
|
|
*/ |
|
|
|
|
public void removeInstruction() { |
|
|
|
|
/* remove from chained list */ |
|
|
|
|
if (prevByAddr != null) |
|
|
|
|
prevByAddr.nextByAddr = nextByAddr; |
|
|
|
|
else |
|
|
|
|
codeinfo.firstInstr = nextByAddr; |
|
|
|
|
|
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.prevByAddr = prevByAddr; |
|
|
|
|
|
|
|
|
|
/* remove predecessors of successors */ |
|
|
|
|
if (!alwaysJumps && nextByAddr != null) |
|
|
|
|
nextByAddr.preds.removeElement(this); |
|
|
|
|
if (succs != null) { |
|
|
|
|
for (int i=0; i < succs.length; i++) |
|
|
|
|
succs[i].preds.removeElement(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* promote the predecessors to nextByAddr */ |
|
|
|
|
Enumeration enum = preds.elements(); |
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
Instruction pred = (Instruction) enum.nextElement(); |
|
|
|
|
if (pred.succs != null) |
|
|
|
|
for (int i=0; i < pred.succs.length; i++) |
|
|
|
|
if (pred.succs[i] == this) |
|
|
|
|
pred.succs[i] = nextByAddr; |
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.preds.addElement(pred); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* adjust exception handlers */ |
|
|
|
|
Handler[] handlers = codeinfo.getExceptionHandlers(); |
|
|
|
|
for (int i=0; i< handlers.length; i++) { |
|
|
|
|
if (handlers[i].start == this) |
|
|
|
|
handlers[i].start = nextByAddr; |
|
|
|
|
if (handlers[i].end == this) |
|
|
|
|
handlers[i].end = prevByAddr; |
|
|
|
|
if (handlers[i].catcher == this) |
|
|
|
|
handlers[i].catcher = nextByAddr; |
|
|
|
|
|
|
|
|
|
if (handlers[i].start == null |
|
|
|
|
|| handlers[i].end == null |
|
|
|
|
|| handlers[i].end.nextByAddr == handlers[i].start) { |
|
|
|
|
/* Remove the handler. |
|
|
|
|
* This is very seldom, so we can make it slow */ |
|
|
|
|
Handler[] newHandlers = new Handler[handlers.length - 1]; |
|
|
|
|
System.arraycopy(handlers, 0, newHandlers, 0, i); |
|
|
|
|
System.arraycopy(handlers, i+1, newHandlers, i, |
|
|
|
|
handlers.length - (i+1)); |
|
|
|
|
handlers = newHandlers; |
|
|
|
|
codeinfo.setExceptionHandlers(newHandlers); |
|
|
|
|
i--; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String toString() { |
|
|
|
|
String result = ""+addr+"_"+Integer.toHexString(hashCode()); |
|
|
|
|
for (Instruction instr = codeinfo.firstInstr; |
|
|
|
|
instr != null; instr = instr.nextByAddr) { |
|
|
|
|
if (instr == this) |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
return result+"*"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|