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