rlm@10: /*** rlm@10: * ASM: a very small and fast Java bytecode manipulation framework rlm@10: * Copyright (c) 2000-2005 INRIA, France Telecom rlm@10: * All rights reserved. rlm@10: * rlm@10: * Redistribution and use in source and binary forms, with or without rlm@10: * modification, are permitted provided that the following conditions rlm@10: * are met: rlm@10: * 1. Redistributions of source code must retain the above copyright rlm@10: * notice, this list of conditions and the following disclaimer. rlm@10: * 2. Redistributions in binary form must reproduce the above copyright rlm@10: * notice, this list of conditions and the following disclaimer in the rlm@10: * documentation and/or other materials provided with the distribution. rlm@10: * 3. Neither the name of the copyright holders nor the names of its rlm@10: * contributors may be used to endorse or promote products derived from rlm@10: * this software without specific prior written permission. rlm@10: * rlm@10: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" rlm@10: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE rlm@10: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE rlm@10: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE rlm@10: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR rlm@10: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF rlm@10: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS rlm@10: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN rlm@10: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) rlm@10: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF rlm@10: * THE POSSIBILITY OF SUCH DAMAGE. rlm@10: */ rlm@10: package clojure.asm.commons; rlm@10: rlm@10: import java.util.ArrayList; rlm@10: import java.util.HashMap; rlm@10: import java.util.List; rlm@10: import java.util.Map; rlm@10: rlm@10: import clojure.asm.Label; rlm@10: import clojure.asm.MethodAdapter; rlm@10: import clojure.asm.MethodVisitor; rlm@10: import clojure.asm.Opcodes; rlm@10: import clojure.asm.Type; rlm@10: rlm@10: /** rlm@10: * A {@link MethodAdapter} that keeps track of stack map frame changes between rlm@10: * {@link #visitFrame(int,int,Object[],int,Object[]) visitFrame} calls. This rlm@10: * adapter must be used with the rlm@10: * {@link clojure.asm.ClassReader#EXPAND_FRAMES} option. Each visitXXX rlm@10: * instruction delegates to the next visitor in the chain, if any, and then rlm@10: * simulates the effect of this instruction on the stack map frame, represented rlm@10: * by {@link #locals} and {@link #stack}. The next visitor in the chain can get rlm@10: * the state of the stack map frame before each instruction by reading rlm@10: * the value of these fields in its visitXXX methods (this requires a rlm@10: * reference to the AnalyzerAdapter that is before it in the chain). rlm@10: * rlm@10: * @author Eric Bruneton rlm@10: */ rlm@10: public class AnalyzerAdapter extends MethodAdapter{ rlm@10: rlm@10: /** rlm@10: * List of the local variable slots for current execution rlm@10: * frame. Primitive types are represented by {@link Opcodes#TOP}, rlm@10: * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, rlm@10: * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or rlm@10: * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a rlm@10: * two elements, the second one being TOP). Reference types are represented rlm@10: * by String objects (representing internal names, or type descriptors for rlm@10: * array types), and uninitialized types by Label objects (this label rlm@10: * designates the NEW instruction that created this uninitialized value). rlm@10: * This field is null for unreacheable instructions. rlm@10: */ rlm@10: public List locals; rlm@10: rlm@10: /** rlm@10: * List of the operand stack slots for current execution rlm@10: * frame. Primitive types are represented by {@link Opcodes#TOP}, rlm@10: * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, rlm@10: * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or rlm@10: * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a rlm@10: * two elements, the second one being TOP). Reference types are represented rlm@10: * by String objects (representing internal names, or type descriptors for rlm@10: * array types), and uninitialized types by Label objects (this label rlm@10: * designates the NEW instruction that created this uninitialized value). rlm@10: * This field is null for unreacheable instructions. rlm@10: */ rlm@10: public List stack; rlm@10: rlm@10: /** rlm@10: * The labels that designate the next instruction to be visited. May be rlm@10: * null. rlm@10: */ rlm@10: private List labels; rlm@10: rlm@10: /** rlm@10: * Information about uninitialized types in the current execution frame. rlm@10: * This map associates internal names to Label objects. Each label rlm@10: * designates a NEW instruction that created the currently uninitialized rlm@10: * types, and the associated internal name represents the NEW operand, i.e. rlm@10: * the final, initialized type value. rlm@10: */ rlm@10: private Map uninitializedTypes; rlm@10: rlm@10: /** rlm@10: * The maximum stack size of this method. rlm@10: */ rlm@10: private int maxStack; rlm@10: rlm@10: /** rlm@10: * The maximum number of local variables of this method. rlm@10: */ rlm@10: private int maxLocals; rlm@10: rlm@10: /** rlm@10: * Creates a new {@link AnalyzerAdapter}. rlm@10: * rlm@10: * @param owner the owner's class name. rlm@10: * @param access the method's access flags (see {@link Opcodes}). rlm@10: * @param name the method's name. rlm@10: * @param desc the method's descriptor (see {@link Type Type}). rlm@10: * @param mv the method visitor to which this adapter delegates calls. May rlm@10: * be null. rlm@10: */ rlm@10: public AnalyzerAdapter( rlm@10: final String owner, rlm@10: final int access, rlm@10: final String name, rlm@10: final String desc, rlm@10: final MethodVisitor mv){ rlm@10: super(mv); rlm@10: locals = new ArrayList(); rlm@10: stack = new ArrayList(); rlm@10: uninitializedTypes = new HashMap(); rlm@10: rlm@10: if((access & Opcodes.ACC_STATIC) == 0) rlm@10: { rlm@10: if(name.equals("")) rlm@10: { rlm@10: locals.add(Opcodes.UNINITIALIZED_THIS); rlm@10: } rlm@10: else rlm@10: { rlm@10: locals.add(owner); rlm@10: } rlm@10: } rlm@10: Type[] types = Type.getArgumentTypes(desc); rlm@10: for(int i = 0; i < types.length; ++i) rlm@10: { rlm@10: Type type = types[i]; rlm@10: switch(type.getSort()) rlm@10: { rlm@10: case Type.BOOLEAN: rlm@10: case Type.CHAR: rlm@10: case Type.BYTE: rlm@10: case Type.SHORT: rlm@10: case Type.INT: rlm@10: locals.add(Opcodes.INTEGER); rlm@10: break; rlm@10: case Type.FLOAT: rlm@10: locals.add(Opcodes.FLOAT); rlm@10: break; rlm@10: case Type.LONG: rlm@10: locals.add(Opcodes.LONG); rlm@10: locals.add(Opcodes.TOP); rlm@10: break; rlm@10: case Type.DOUBLE: rlm@10: locals.add(Opcodes.DOUBLE); rlm@10: locals.add(Opcodes.TOP); rlm@10: break; rlm@10: case Type.ARRAY: rlm@10: locals.add(types[i].getDescriptor()); rlm@10: break; rlm@10: // case Type.OBJECT: rlm@10: default: rlm@10: locals.add(types[i].getInternalName()); rlm@10: } rlm@10: } rlm@10: } rlm@10: rlm@10: public void visitFrame( rlm@10: final int type, rlm@10: final int nLocal, rlm@10: final Object[] local, rlm@10: final int nStack, rlm@10: final Object[] stack){ rlm@10: if(type != Opcodes.F_NEW) rlm@10: { // uncompressed frame rlm@10: throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag"); rlm@10: } rlm@10: rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitFrame(type, nLocal, local, nStack, stack); rlm@10: } rlm@10: rlm@10: if(this.locals != null) rlm@10: { rlm@10: this.locals.clear(); rlm@10: this.stack.clear(); rlm@10: } rlm@10: else rlm@10: { rlm@10: this.locals = new ArrayList(); rlm@10: this.stack = new ArrayList(); rlm@10: } rlm@10: visitFrameTypes(nLocal, local, this.locals); rlm@10: visitFrameTypes(nStack, stack, this.stack); rlm@10: maxStack = Math.max(maxStack, this.stack.size()); rlm@10: } rlm@10: rlm@10: private void visitFrameTypes( rlm@10: final int n, rlm@10: final Object[] types, rlm@10: final List result){ rlm@10: for(int i = 0; i < n; ++i) rlm@10: { rlm@10: Object type = types[i]; rlm@10: result.add(type); rlm@10: if(type == Opcodes.LONG || type == Opcodes.DOUBLE) rlm@10: { rlm@10: result.add(Opcodes.TOP); rlm@10: } rlm@10: } rlm@10: } rlm@10: rlm@10: public void visitInsn(final int opcode){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitInsn(opcode); rlm@10: } rlm@10: execute(opcode, 0, null); rlm@10: if((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) rlm@10: || opcode == Opcodes.ATHROW) rlm@10: { rlm@10: this.locals = null; rlm@10: this.stack = null; rlm@10: } rlm@10: } rlm@10: rlm@10: public void visitIntInsn(final int opcode, final int operand){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitIntInsn(opcode, operand); rlm@10: } rlm@10: execute(opcode, operand, null); rlm@10: } rlm@10: rlm@10: public void visitVarInsn(final int opcode, final int var){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitVarInsn(opcode, var); rlm@10: } rlm@10: execute(opcode, var, null); rlm@10: } rlm@10: rlm@10: public void visitTypeInsn(final int opcode, final String desc){ rlm@10: if(opcode == Opcodes.NEW) rlm@10: { rlm@10: if(labels == null) rlm@10: { rlm@10: Label l = new Label(); rlm@10: labels = new ArrayList(3); rlm@10: labels.add(l); rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitLabel(l); rlm@10: } rlm@10: } rlm@10: for(int i = 0; i < labels.size(); ++i) rlm@10: { rlm@10: uninitializedTypes.put(labels.get(i), desc); rlm@10: } rlm@10: } rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitTypeInsn(opcode, desc); rlm@10: } rlm@10: execute(opcode, 0, desc); rlm@10: } rlm@10: rlm@10: public void visitFieldInsn( rlm@10: final int opcode, rlm@10: final String owner, rlm@10: final String name, rlm@10: final String desc){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitFieldInsn(opcode, owner, name, desc); rlm@10: } rlm@10: execute(opcode, 0, desc); rlm@10: } rlm@10: rlm@10: public void visitMethodInsn( rlm@10: final int opcode, rlm@10: final String owner, rlm@10: final String name, rlm@10: final String desc){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitMethodInsn(opcode, owner, name, desc); rlm@10: } rlm@10: pop(desc); rlm@10: if(opcode != Opcodes.INVOKESTATIC) rlm@10: { rlm@10: Object t = pop(); rlm@10: if(opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') rlm@10: { rlm@10: Object u; rlm@10: if(t == Opcodes.UNINITIALIZED_THIS) rlm@10: { rlm@10: u = owner; rlm@10: } rlm@10: else rlm@10: { rlm@10: u = uninitializedTypes.get(t); rlm@10: } rlm@10: for(int i = 0; i < locals.size(); ++i) rlm@10: { rlm@10: if(locals.get(i) == t) rlm@10: { rlm@10: locals.set(i, u); rlm@10: } rlm@10: } rlm@10: for(int i = 0; i < stack.size(); ++i) rlm@10: { rlm@10: if(stack.get(i) == t) rlm@10: { rlm@10: stack.set(i, u); rlm@10: } rlm@10: } rlm@10: } rlm@10: } rlm@10: pushDesc(desc); rlm@10: labels = null; rlm@10: } rlm@10: rlm@10: public void visitJumpInsn(final int opcode, final Label label){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitJumpInsn(opcode, label); rlm@10: } rlm@10: execute(opcode, 0, null); rlm@10: if(opcode == Opcodes.GOTO) rlm@10: { rlm@10: this.locals = null; rlm@10: this.stack = null; rlm@10: } rlm@10: } rlm@10: rlm@10: public void visitLabel(final Label label){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitLabel(label); rlm@10: } rlm@10: if(labels == null) rlm@10: { rlm@10: labels = new ArrayList(3); rlm@10: } rlm@10: labels.add(label); rlm@10: } rlm@10: rlm@10: public void visitLdcInsn(final Object cst){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitLdcInsn(cst); rlm@10: } rlm@10: if(cst instanceof Integer) rlm@10: { rlm@10: push(Opcodes.INTEGER); rlm@10: } rlm@10: else if(cst instanceof Long) rlm@10: { rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: } rlm@10: else if(cst instanceof Float) rlm@10: { rlm@10: push(Opcodes.FLOAT); rlm@10: } rlm@10: else if(cst instanceof Double) rlm@10: { rlm@10: push(Opcodes.DOUBLE); rlm@10: push(Opcodes.TOP); rlm@10: } rlm@10: else if(cst instanceof String) rlm@10: { rlm@10: push("java/lang/String"); rlm@10: } rlm@10: else if(cst instanceof Type) rlm@10: { rlm@10: push("java/lang/Class"); rlm@10: } rlm@10: else rlm@10: { rlm@10: throw new IllegalArgumentException(); rlm@10: } rlm@10: labels = null; rlm@10: } rlm@10: rlm@10: public void visitIincInsn(final int var, final int increment){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitIincInsn(var, increment); rlm@10: } rlm@10: execute(Opcodes.IINC, var, null); rlm@10: } rlm@10: rlm@10: public void visitTableSwitchInsn( rlm@10: final int min, rlm@10: final int max, rlm@10: final Label dflt, rlm@10: final Label labels[]){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitTableSwitchInsn(min, max, dflt, labels); rlm@10: } rlm@10: execute(Opcodes.TABLESWITCH, 0, null); rlm@10: this.locals = null; rlm@10: this.stack = null; rlm@10: } rlm@10: rlm@10: public void visitLookupSwitchInsn( rlm@10: final Label dflt, rlm@10: final int keys[], rlm@10: final Label labels[]){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitLookupSwitchInsn(dflt, keys, labels); rlm@10: } rlm@10: execute(Opcodes.LOOKUPSWITCH, 0, null); rlm@10: this.locals = null; rlm@10: this.stack = null; rlm@10: } rlm@10: rlm@10: public void visitMultiANewArrayInsn(final String desc, final int dims){ rlm@10: if(mv != null) rlm@10: { rlm@10: mv.visitMultiANewArrayInsn(desc, dims); rlm@10: } rlm@10: execute(Opcodes.MULTIANEWARRAY, dims, desc); rlm@10: } rlm@10: rlm@10: public void visitMaxs(final int maxStack, final int maxLocals){ rlm@10: if(mv != null) rlm@10: { rlm@10: this.maxStack = Math.max(this.maxStack, maxStack); rlm@10: this.maxLocals = Math.max(this.maxLocals, maxLocals); rlm@10: mv.visitMaxs(this.maxStack, this.maxLocals); rlm@10: } rlm@10: } rlm@10: rlm@10: // ------------------------------------------------------------------------ rlm@10: rlm@10: private Object get(final int local){ rlm@10: maxLocals = Math.max(maxLocals, local); rlm@10: return local < locals.size() ? locals.get(local) : Opcodes.TOP; rlm@10: } rlm@10: rlm@10: private void set(final int local, final Object type){ rlm@10: maxLocals = Math.max(maxLocals, local); rlm@10: while(local >= locals.size()) rlm@10: { rlm@10: locals.add(Opcodes.TOP); rlm@10: } rlm@10: locals.set(local, type); rlm@10: } rlm@10: rlm@10: private void push(final Object type){ rlm@10: stack.add(type); rlm@10: maxStack = Math.max(maxStack, stack.size()); rlm@10: } rlm@10: rlm@10: private void pushDesc(final String desc){ rlm@10: int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; rlm@10: switch(desc.charAt(index)) rlm@10: { rlm@10: case'V': rlm@10: return; rlm@10: case'Z': rlm@10: case'C': rlm@10: case'B': rlm@10: case'S': rlm@10: case'I': rlm@10: push(Opcodes.INTEGER); rlm@10: return; rlm@10: case'F': rlm@10: push(Opcodes.FLOAT); rlm@10: return; rlm@10: case'J': rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: return; rlm@10: case'D': rlm@10: push(Opcodes.DOUBLE); rlm@10: push(Opcodes.TOP); rlm@10: return; rlm@10: case'[': rlm@10: if(index == 0) rlm@10: { rlm@10: push(desc); rlm@10: } rlm@10: else rlm@10: { rlm@10: push(desc.substring(index, desc.length())); rlm@10: } rlm@10: break; rlm@10: // case 'L': rlm@10: default: rlm@10: if(index == 0) rlm@10: { rlm@10: push(desc.substring(1, desc.length() - 1)); rlm@10: } rlm@10: else rlm@10: { rlm@10: push(desc.substring(index + 1, desc.length() - 1)); rlm@10: } rlm@10: return; rlm@10: } rlm@10: } rlm@10: rlm@10: private Object pop(){ rlm@10: return stack.remove(stack.size() - 1); rlm@10: } rlm@10: rlm@10: private void pop(final int n){ rlm@10: int size = stack.size(); rlm@10: int end = size - n; rlm@10: for(int i = size - 1; i >= end; --i) rlm@10: { rlm@10: stack.remove(i); rlm@10: } rlm@10: } rlm@10: rlm@10: private void pop(final String desc){ rlm@10: char c = desc.charAt(0); rlm@10: if(c == '(') rlm@10: { rlm@10: int n = 0; rlm@10: Type[] types = Type.getArgumentTypes(desc); rlm@10: for(int i = 0; i < types.length; ++i) rlm@10: { rlm@10: n += types[i].getSize(); rlm@10: } rlm@10: pop(n); rlm@10: } rlm@10: else if(c == 'J' || c == 'D') rlm@10: { rlm@10: pop(2); rlm@10: } rlm@10: else rlm@10: { rlm@10: pop(1); rlm@10: } rlm@10: } rlm@10: rlm@10: private void execute(final int opcode, final int iarg, final String sarg){ rlm@10: if(this.locals == null) rlm@10: { rlm@10: return; rlm@10: } rlm@10: Object t1, t2, t3, t4; rlm@10: switch(opcode) rlm@10: { rlm@10: case Opcodes.NOP: rlm@10: case Opcodes.INEG: rlm@10: case Opcodes.LNEG: rlm@10: case Opcodes.FNEG: rlm@10: case Opcodes.DNEG: rlm@10: case Opcodes.I2B: rlm@10: case Opcodes.I2C: rlm@10: case Opcodes.I2S: rlm@10: case Opcodes.GOTO: rlm@10: case Opcodes.RETURN: rlm@10: break; rlm@10: case Opcodes.ACONST_NULL: rlm@10: push(Opcodes.NULL); rlm@10: break; rlm@10: case Opcodes.ICONST_M1: rlm@10: case Opcodes.ICONST_0: rlm@10: case Opcodes.ICONST_1: rlm@10: case Opcodes.ICONST_2: rlm@10: case Opcodes.ICONST_3: rlm@10: case Opcodes.ICONST_4: rlm@10: case Opcodes.ICONST_5: rlm@10: case Opcodes.BIPUSH: rlm@10: case Opcodes.SIPUSH: rlm@10: push(Opcodes.INTEGER); rlm@10: break; rlm@10: case Opcodes.LCONST_0: rlm@10: case Opcodes.LCONST_1: rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.FCONST_0: rlm@10: case Opcodes.FCONST_1: rlm@10: case Opcodes.FCONST_2: rlm@10: push(Opcodes.FLOAT); rlm@10: break; rlm@10: case Opcodes.DCONST_0: rlm@10: case Opcodes.DCONST_1: rlm@10: push(Opcodes.DOUBLE); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.ILOAD: rlm@10: case Opcodes.FLOAD: rlm@10: case Opcodes.ALOAD: rlm@10: push(get(iarg)); rlm@10: break; rlm@10: case Opcodes.LLOAD: rlm@10: case Opcodes.DLOAD: rlm@10: push(get(iarg)); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.IALOAD: rlm@10: case Opcodes.BALOAD: rlm@10: case Opcodes.CALOAD: rlm@10: case Opcodes.SALOAD: rlm@10: pop(2); rlm@10: push(Opcodes.INTEGER); rlm@10: break; rlm@10: case Opcodes.LALOAD: rlm@10: case Opcodes.D2L: rlm@10: pop(2); rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.FALOAD: rlm@10: pop(2); rlm@10: push(Opcodes.FLOAT); rlm@10: break; rlm@10: case Opcodes.DALOAD: rlm@10: case Opcodes.L2D: rlm@10: pop(2); rlm@10: push(Opcodes.DOUBLE); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.AALOAD: rlm@10: pop(1); rlm@10: t1 = pop(); rlm@10: pushDesc(((String) t1).substring(1)); rlm@10: break; rlm@10: case Opcodes.ISTORE: rlm@10: case Opcodes.FSTORE: rlm@10: case Opcodes.ASTORE: rlm@10: t1 = pop(); rlm@10: set(iarg, t1); rlm@10: if(iarg > 0) rlm@10: { rlm@10: t2 = get(iarg - 1); rlm@10: if(t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) rlm@10: { rlm@10: set(iarg - 1, Opcodes.TOP); rlm@10: } rlm@10: } rlm@10: break; rlm@10: case Opcodes.LSTORE: rlm@10: case Opcodes.DSTORE: rlm@10: pop(1); rlm@10: t1 = pop(); rlm@10: set(iarg, t1); rlm@10: set(iarg + 1, Opcodes.TOP); rlm@10: if(iarg > 0) rlm@10: { rlm@10: t2 = get(iarg - 1); rlm@10: if(t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) rlm@10: { rlm@10: set(iarg - 1, Opcodes.TOP); rlm@10: } rlm@10: } rlm@10: break; rlm@10: case Opcodes.IASTORE: rlm@10: case Opcodes.BASTORE: rlm@10: case Opcodes.CASTORE: rlm@10: case Opcodes.SASTORE: rlm@10: case Opcodes.FASTORE: rlm@10: case Opcodes.AASTORE: rlm@10: pop(3); rlm@10: break; rlm@10: case Opcodes.LASTORE: rlm@10: case Opcodes.DASTORE: rlm@10: pop(4); rlm@10: break; rlm@10: case Opcodes.POP: rlm@10: case Opcodes.IFEQ: rlm@10: case Opcodes.IFNE: rlm@10: case Opcodes.IFLT: rlm@10: case Opcodes.IFGE: rlm@10: case Opcodes.IFGT: rlm@10: case Opcodes.IFLE: rlm@10: case Opcodes.IRETURN: rlm@10: case Opcodes.FRETURN: rlm@10: case Opcodes.ARETURN: rlm@10: case Opcodes.TABLESWITCH: rlm@10: case Opcodes.LOOKUPSWITCH: rlm@10: case Opcodes.ATHROW: rlm@10: case Opcodes.MONITORENTER: rlm@10: case Opcodes.MONITOREXIT: rlm@10: case Opcodes.IFNULL: rlm@10: case Opcodes.IFNONNULL: rlm@10: pop(1); rlm@10: break; rlm@10: case Opcodes.POP2: rlm@10: case Opcodes.IF_ICMPEQ: rlm@10: case Opcodes.IF_ICMPNE: rlm@10: case Opcodes.IF_ICMPLT: rlm@10: case Opcodes.IF_ICMPGE: rlm@10: case Opcodes.IF_ICMPGT: rlm@10: case Opcodes.IF_ICMPLE: rlm@10: case Opcodes.IF_ACMPEQ: rlm@10: case Opcodes.IF_ACMPNE: rlm@10: case Opcodes.LRETURN: rlm@10: case Opcodes.DRETURN: rlm@10: pop(2); rlm@10: break; rlm@10: case Opcodes.DUP: rlm@10: t1 = pop(); rlm@10: push(t1); rlm@10: push(t1); rlm@10: break; rlm@10: case Opcodes.DUP_X1: rlm@10: t1 = pop(); rlm@10: t2 = pop(); rlm@10: push(t1); rlm@10: push(t2); rlm@10: push(t1); rlm@10: break; rlm@10: case Opcodes.DUP_X2: rlm@10: t1 = pop(); rlm@10: t2 = pop(); rlm@10: t3 = pop(); rlm@10: push(t1); rlm@10: push(t3); rlm@10: push(t2); rlm@10: push(t1); rlm@10: break; rlm@10: case Opcodes.DUP2: rlm@10: t1 = pop(); rlm@10: t2 = pop(); rlm@10: push(t2); rlm@10: push(t1); rlm@10: push(t2); rlm@10: push(t1); rlm@10: break; rlm@10: case Opcodes.DUP2_X1: rlm@10: t1 = pop(); rlm@10: t2 = pop(); rlm@10: t3 = pop(); rlm@10: push(t2); rlm@10: push(t1); rlm@10: push(t3); rlm@10: push(t2); rlm@10: push(t1); rlm@10: break; rlm@10: case Opcodes.DUP2_X2: rlm@10: t1 = pop(); rlm@10: t2 = pop(); rlm@10: t3 = pop(); rlm@10: t4 = pop(); rlm@10: push(t2); rlm@10: push(t1); rlm@10: push(t4); rlm@10: push(t3); rlm@10: push(t2); rlm@10: push(t1); rlm@10: break; rlm@10: case Opcodes.SWAP: rlm@10: t1 = pop(); rlm@10: t2 = pop(); rlm@10: push(t1); rlm@10: push(t2); rlm@10: break; rlm@10: case Opcodes.IADD: rlm@10: case Opcodes.ISUB: rlm@10: case Opcodes.IMUL: rlm@10: case Opcodes.IDIV: rlm@10: case Opcodes.IREM: rlm@10: case Opcodes.IAND: rlm@10: case Opcodes.IOR: rlm@10: case Opcodes.IXOR: rlm@10: case Opcodes.ISHL: rlm@10: case Opcodes.ISHR: rlm@10: case Opcodes.IUSHR: rlm@10: case Opcodes.L2I: rlm@10: case Opcodes.D2I: rlm@10: case Opcodes.FCMPL: rlm@10: case Opcodes.FCMPG: rlm@10: pop(2); rlm@10: push(Opcodes.INTEGER); rlm@10: break; rlm@10: case Opcodes.LADD: rlm@10: case Opcodes.LSUB: rlm@10: case Opcodes.LMUL: rlm@10: case Opcodes.LDIV: rlm@10: case Opcodes.LREM: rlm@10: case Opcodes.LAND: rlm@10: case Opcodes.LOR: rlm@10: case Opcodes.LXOR: rlm@10: pop(4); rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.FADD: rlm@10: case Opcodes.FSUB: rlm@10: case Opcodes.FMUL: rlm@10: case Opcodes.FDIV: rlm@10: case Opcodes.FREM: rlm@10: case Opcodes.L2F: rlm@10: case Opcodes.D2F: rlm@10: pop(2); rlm@10: push(Opcodes.FLOAT); rlm@10: break; rlm@10: case Opcodes.DADD: rlm@10: case Opcodes.DSUB: rlm@10: case Opcodes.DMUL: rlm@10: case Opcodes.DDIV: rlm@10: case Opcodes.DREM: rlm@10: pop(4); rlm@10: push(Opcodes.DOUBLE); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.LSHL: rlm@10: case Opcodes.LSHR: rlm@10: case Opcodes.LUSHR: rlm@10: pop(3); rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.IINC: rlm@10: set(iarg, Opcodes.INTEGER); rlm@10: break; rlm@10: case Opcodes.I2L: rlm@10: case Opcodes.F2L: rlm@10: pop(1); rlm@10: push(Opcodes.LONG); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.I2F: rlm@10: pop(1); rlm@10: push(Opcodes.FLOAT); rlm@10: break; rlm@10: case Opcodes.I2D: rlm@10: case Opcodes.F2D: rlm@10: pop(1); rlm@10: push(Opcodes.DOUBLE); rlm@10: push(Opcodes.TOP); rlm@10: break; rlm@10: case Opcodes.F2I: rlm@10: case Opcodes.ARRAYLENGTH: rlm@10: case Opcodes.INSTANCEOF: rlm@10: pop(1); rlm@10: push(Opcodes.INTEGER); rlm@10: break; rlm@10: case Opcodes.LCMP: rlm@10: case Opcodes.DCMPL: rlm@10: case Opcodes.DCMPG: rlm@10: pop(4); rlm@10: push(Opcodes.INTEGER); rlm@10: break; rlm@10: case Opcodes.JSR: rlm@10: case Opcodes.RET: rlm@10: throw new RuntimeException("JSR/RET are not supported"); rlm@10: case Opcodes.GETSTATIC: rlm@10: pushDesc(sarg); rlm@10: break; rlm@10: case Opcodes.PUTSTATIC: rlm@10: pop(sarg); rlm@10: break; rlm@10: case Opcodes.GETFIELD: rlm@10: pop(1); rlm@10: pushDesc(sarg); rlm@10: break; rlm@10: case Opcodes.PUTFIELD: rlm@10: pop(sarg); rlm@10: pop(); rlm@10: break; rlm@10: case Opcodes.NEW: rlm@10: push(labels.get(0)); rlm@10: break; rlm@10: case Opcodes.NEWARRAY: rlm@10: pop(); rlm@10: switch(iarg) rlm@10: { rlm@10: case Opcodes.T_BOOLEAN: rlm@10: pushDesc("[Z"); rlm@10: break; rlm@10: case Opcodes.T_CHAR: rlm@10: pushDesc("[C"); rlm@10: break; rlm@10: case Opcodes.T_BYTE: rlm@10: pushDesc("[B"); rlm@10: break; rlm@10: case Opcodes.T_SHORT: rlm@10: pushDesc("[S"); rlm@10: break; rlm@10: case Opcodes.T_INT: rlm@10: pushDesc("[I"); rlm@10: break; rlm@10: case Opcodes.T_FLOAT: rlm@10: pushDesc("[F"); rlm@10: break; rlm@10: case Opcodes.T_DOUBLE: rlm@10: pushDesc("[D"); rlm@10: break; rlm@10: // case Opcodes.T_LONG: rlm@10: default: rlm@10: pushDesc("[J"); rlm@10: break; rlm@10: } rlm@10: break; rlm@10: case Opcodes.ANEWARRAY: rlm@10: pop(); rlm@10: if(sarg.charAt(0) == '[') rlm@10: { rlm@10: pushDesc("[" + sarg); rlm@10: } rlm@10: else rlm@10: { rlm@10: pushDesc("[L" + sarg + ";"); rlm@10: } rlm@10: break; rlm@10: case Opcodes.CHECKCAST: rlm@10: pop(); rlm@10: if(sarg.charAt(0) == '[') rlm@10: { rlm@10: pushDesc(sarg); rlm@10: } rlm@10: else rlm@10: { rlm@10: push(sarg); rlm@10: } rlm@10: break; rlm@10: // case Opcodes.MULTIANEWARRAY: rlm@10: default: rlm@10: pop(iarg); rlm@10: pushDesc(sarg); rlm@10: break; rlm@10: } rlm@10: labels = null; rlm@10: } rlm@10: }