|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package jdk.internal.org.objectweb.asm.commons; |
|
|
|
import java.util.ArrayList; |
|
import java.util.HashMap; |
|
import java.util.List; |
|
import java.util.Map; |
|
|
|
import jdk.internal.org.objectweb.asm.Handle; |
|
import jdk.internal.org.objectweb.asm.Label; |
|
import jdk.internal.org.objectweb.asm.MethodVisitor; |
|
import jdk.internal.org.objectweb.asm.Opcodes; |
|
import jdk.internal.org.objectweb.asm.Type; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class AnalyzerAdapter extends MethodVisitor { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public List<Object> locals; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public List<Object> stack; |
|
|
|
|
|
|
|
|
|
*/ |
|
private List<Label> labels; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Map<Object, Object> uninitializedTypes; |
|
|
|
|
|
|
|
*/ |
|
private int maxStack; |
|
|
|
|
|
|
|
*/ |
|
private int maxLocals; |
|
|
|
|
|
|
|
*/ |
|
private String owner; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AnalyzerAdapter(final String owner, final int access, |
|
final String name, final String desc, final MethodVisitor mv) { |
|
this(Opcodes.ASM5, owner, access, name, desc, mv); |
|
if (getClass() != AnalyzerAdapter.class) { |
|
throw new IllegalStateException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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<Object>(); |
|
stack = new ArrayList<Object>(); |
|
uninitializedTypes = new HashMap<Object, Object>(); |
|
|
|
if ((access & Opcodes.ACC_STATIC) == 0) { |
|
if ("<init>".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; |
|
|
|
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) { |
|
throw new IllegalStateException( |
|
"ClassReader.accept() should be called with EXPAND_FRAMES flag"); |
|
} |
|
|
|
if (mv != null) { |
|
mv.visitFrame(type, nLocal, local, nStack, stack); |
|
} |
|
|
|
if (this.locals != null) { |
|
this.locals.clear(); |
|
this.stack.clear(); |
|
} else { |
|
this.locals = new ArrayList<Object>(); |
|
this.stack = new ArrayList<Object>(); |
|
} |
|
visitFrameTypes(nLocal, local, this.locals); |
|
visitFrameTypes(nStack, stack, this.stack); |
|
maxStack = Math.max(maxStack, this.stack.size()); |
|
} |
|
|
|
private static void visitFrameTypes(final int n, final Object[] types, |
|
final List<Object> 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) { |
|
if (mv != null) { |
|
mv.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) { |
|
if (mv != null) { |
|
mv.visitIntInsn(opcode, operand); |
|
} |
|
execute(opcode, operand, null); |
|
} |
|
|
|
@Override |
|
public void visitVarInsn(final int opcode, final int var) { |
|
if (mv != null) { |
|
mv.visitVarInsn(opcode, var); |
|
} |
|
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<Label>(3); |
|
labels.add(l); |
|
if (mv != null) { |
|
mv.visitLabel(l); |
|
} |
|
} |
|
for (int i = 0; i < labels.size(); ++i) { |
|
uninitializedTypes.put(labels.get(i), type); |
|
} |
|
} |
|
if (mv != null) { |
|
mv.visitTypeInsn(opcode, type); |
|
} |
|
execute(opcode, 0, type); |
|
} |
|
|
|
@Override |
|
public void visitFieldInsn(final int opcode, final String owner, |
|
final String name, final String desc) { |
|
if (mv != null) { |
|
mv.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) { |
|
if (mv != null) { |
|
mv.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) { |
|
if (mv != null) { |
|
mv.visitJumpInsn(opcode, label); |
|
} |
|
execute(opcode, 0, null); |
|
if (opcode == Opcodes.GOTO) { |
|
this.locals = null; |
|
this.stack = null; |
|
} |
|
} |
|
|
|
@Override |
|
public void visitLabel(final Label label) { |
|
if (mv != null) { |
|
mv.visitLabel(label); |
|
} |
|
if (labels == null) { |
|
labels = new ArrayList<Label>(3); |
|
} |
|
labels.add(label); |
|
} |
|
|
|
@Override |
|
public void visitLdcInsn(final Object cst) { |
|
if (mv != null) { |
|
mv.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) { |
|
if (mv != null) { |
|
mv.visitIincInsn(var, increment); |
|
} |
|
execute(Opcodes.IINC, var, null); |
|
} |
|
|
|
@Override |
|
public void visitTableSwitchInsn(final int min, final int max, |
|
final Label dflt, final Label... labels) { |
|
if (mv != null) { |
|
mv.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) { |
|
if (mv != null) { |
|
mv.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) { |
|
if (mv != null) { |
|
mv.visitMultiANewArrayInsn(desc, dims); |
|
} |
|
execute(Opcodes.MULTIANEWARRAY, dims, desc); |
|
} |
|
|
|
@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; |
|
|
|
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 { |
|
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; |
|
|
|
default: |
|
pushDesc("[J"); |
|
break; |
|
} |
|
break; |
|
case Opcodes.ANEWARRAY: |
|
pop(); |
|
pushDesc("[" + Type.getObjectType(sarg)); |
|
break; |
|
case Opcodes.CHECKCAST: |
|
pop(); |
|
pushDesc(Type.getObjectType(sarg).getDescriptor()); |
|
break; |
|
|
|
default: |
|
pop(iarg); |
|
pushDesc(sarg); |
|
break; |
|
} |
|
labels = null; |
|
} |
|
} |