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: }