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+"*";
+    }
 }
+