From a4dc6e4427b7d8b8417d5126b5dc1cd722db1111 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 2 Jun 1999 20:20:18 +0000 Subject: [PATCH] getStackPopPush git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@820 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/bytecode/Instruction.java | 165 +++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) diff --git a/jode/jode/bytecode/Instruction.java b/jode/jode/bytecode/Instruction.java index 0d59b8c..7e99057 100644 --- a/jode/jode/bytecode/Instruction.java +++ b/jode/jode/bytecode/Instruction.java @@ -20,6 +20,8 @@ package jode.bytecode; import java.util.Vector; import java.util.Enumeration; +import jode.type.Type; +import jode.type.MethodType; /** * This class represents an instruction in the byte code. @@ -274,6 +276,105 @@ public class Instruction implements Opcodes{ } } + /** + * This returns the number of stack entries this instruction + * pushes and pops from the stack. The result fills the given + * array. + * + * @param poppush an array of two ints. The first element will + * get the number of pops, the second the number of pushes. + */ + public void getStackPopPush(int[] poppush) + /*{ require { poppush != null && poppush.length == 2 + :: "poppush must be an array of two ints" } } */ + { + byte delta = stackDelta[opcode]; + if (delta < 0x40) { + poppush[0] = delta & 7; + poppush[1] = delta >> 3; + } else { + switch (opcode) { + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + case opc_invokeinterface: { + Reference ref = (Reference) objData; + MethodType mt = (MethodType) Type.tType(ref.getType()); + poppush[1] = mt.getReturnType().stackSize(); + + poppush[0] = opcode != opc_invokestatic ? 1 : 0; + for (int i = mt.getParameterTypes().length-1; i >= 0; i--) + poppush[0] += mt.getParameterTypes()[i].stackSize(); + break; + } + + case opc_putfield: + case opc_putstatic: { + Reference ref = (Reference) objData; + poppush[1] = 0; + poppush[0] = Type.tType(ref.getType()).stackSize(); + if (opcode == opc_putfield) + poppush[0]++; + break; + } + case opc_getstatic: + case opc_getfield: { + Reference ref = (Reference) objData; + poppush[1] = Type.tType(ref.getType()).stackSize(); + poppush[0] = opcode == opc_getfield ? 1 : 0; + break; + } + + case opc_multianewarray: { + poppush[1] = 1; + poppush[0] = prevByAddr.intData; + break; + } + default: + throw new jode.AssertError("Unknown Opcode: "+opcode); + } + } + } + + public Instruction findMatchingPop() { + int poppush[] = new int[2]; + getStackPopPush(poppush); + + int count = poppush[1]; + Instruction instr = this; + while (true) { + if (instr.succs != null || instr.alwaysJumps) + return null; + instr = instr.nextByAddr; + if (instr.preds != null) + return null; + + instr.getStackPopPush(poppush); + if (count == poppush[0]) + return instr; + count += poppush[1] - poppush[0]; + } + } + + public Instruction findMatchingPush() { + int count = 0; + Instruction instr = this; + int poppush[] = new int[2]; + while (true) { + if (instr.preds != null) + return null; + instr = instr.prevByAddr; + if (instr == null || instr.succs != null || instr.alwaysJumps) + return null; + + instr.getStackPopPush(poppush); + if (count < poppush[1]) { + return count == 0 ? instr : null; + } + count += poppush[0] - poppush[1]; + } + } + public String getDescription() { StringBuffer result = new StringBuffer(String.valueOf(addr)) .append('_').append(Integer.toHexString(hashCode())) @@ -325,5 +426,67 @@ public class Instruction implements Opcodes{ public String toString() { return ""+addr+"_"+Integer.toHexString(hashCode()); } -} + public final static byte[] stackDelta; + + static { + stackDelta = new byte[202]; + for (int i=0; i < 202; i++) { + stackDelta[i] = (byte) "\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010".charAt(i); + } + } + + /* stackDelta contains \100 if stack count of opcode is variable + * \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise + * The above values are extracted from following list with: + * perl -ne'/"(.*)"/ and print $1' + * + * "\000" // nop + * "\010\010\010\010\010\010\010\010" // aconst_null, iconst_m?[0-5] + * "\020\020\010\010\010\020\020" // [lfd]const_[0-2] + * "\010\010\010\010\020" // sipush bipush ldcx + * "\010\020\010\020\010" // [ilfda]load + * "\010\010\010\010" + * "\020\020\020\020" + * "\010\010\010\010" + * "\020\020\020\020" + * "\010\010\010\010" + * "\012\022\012\022\012\012\012\012" // [ilfdabcs]aload + * "\001\002\001\002\001" // [ilfda]store + * "\001\001\001\001" + * "\002\002\002\002" + * "\001\001\001\001" + * "\002\002\002\002" + * "\001\001\001\001" + * "\003\004\003\004\003\003\003\003" // [ilfdabcs]astore + * "\001\002" // pop + * "\021\032\043\042\053\064" // dup2?(_x[12])? + * "\022" // swap + * "\012\024\012\024" // [ilfd]add + * "\012\024\012\024" // [ilfd]sub + * "\012\024\012\024" // [ilfd]mul + * "\012\024\012\024" // [ilfd]div + * "\012\024\012\024" // [ilfd]rem + * "\011\022\011\022" // [ilfd]neg + * "\012\023\012\023\012\023" // [il]u?sh[lr] + * "\012\024\012\024\012\024" // [il](and|or|xor) + * "\000" // opc_iinc + * "\021\011\021" // i2[lfd] + * "\012\012\022" // l2[ifd] + * "\011\021\021" // f2[ild] + * "\012\022\012" // d2[ilf] + * "\011\011\011" // i2[bcs] + * "\014\012\012\014\014" // [lfd]cmp.? + * "\001\001\001\001\001\001" // if.. + * "\002\002\002\002\002\002" // if_icmp.. + * "\002\002" // if_acmp.. + * "\000\010\000\001\001" // goto,jsr,ret, .*switch + * "\001\002\001\002\001\000" // [ilfda]?return + * "\100\100\100\100" // (get/put)(static|field) + * "\100\100\100\100" // invoke.* + * "\177\010\011\011\011" // 186 - 190 + * "\001\011\011\001\001" // 191 - 195 + * "\177\100\001\001" // 196 - 199 + * "\000\010" // goto_w, jsr_w + */ +}