diff --git a/jode/jode/bytecode/Instruction.java b/jode/jode/bytecode/Instruction.java index 0526611..705bd9a 100644 --- a/jode/jode/bytecode/Instruction.java +++ b/jode/jode/bytecode/Instruction.java @@ -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. *
@@ -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+"*"; + } } +