|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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.ConstantDynamic; |
|
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 descriptor, |
|
final MethodVisitor methodVisitor) { |
|
this( Opcodes.ASM8, owner, access, name, descriptor, methodVisitor); |
|
if (getClass() != AnalyzerAdapter.class) { |
|
throw new IllegalStateException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected AnalyzerAdapter( |
|
final int api, |
|
final String owner, |
|
final int access, |
|
final String name, |
|
final String descriptor, |
|
final MethodVisitor methodVisitor) { |
|
super(api, methodVisitor); |
|
this.owner = owner; |
|
locals = new ArrayList<>(); |
|
stack = new ArrayList<>(); |
|
uninitializedTypes = new HashMap<>(); |
|
|
|
if ((access & Opcodes.ACC_STATIC) == 0) { |
|
if ("<init>".equals(name)) { |
|
locals.add(Opcodes.UNINITIALIZED_THIS); |
|
} else { |
|
locals.add(owner); |
|
} |
|
} |
|
for (Type argumentType : Type.getArgumentTypes(descriptor)) { |
|
switch (argumentType.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(argumentType.getDescriptor()); |
|
break; |
|
case Type.OBJECT: |
|
locals.add(argumentType.getInternalName()); |
|
break; |
|
default: |
|
throw new AssertionError(); |
|
} |
|
} |
|
maxLocals = locals.size(); |
|
} |
|
|
|
@Override |
|
public void visitFrame( |
|
final int type, |
|
final int numLocal, |
|
final Object[] local, |
|
final int numStack, |
|
final Object[] stack) { |
|
if (type != Opcodes.F_NEW) { |
|
throw new IllegalArgumentException( |
|
"AnalyzerAdapter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)"); |
|
} |
|
|
|
super.visitFrame(type, numLocal, local, numStack, stack); |
|
|
|
if (this.locals != null) { |
|
this.locals.clear(); |
|
this.stack.clear(); |
|
} else { |
|
this.locals = new ArrayList<>(); |
|
this.stack = new ArrayList<>(); |
|
} |
|
visitFrameTypes(numLocal, local, this.locals); |
|
visitFrameTypes(numStack, stack, this.stack); |
|
maxLocals = Math.max(maxLocals, this.locals.size()); |
|
maxStack = Math.max(maxStack, this.stack.size()); |
|
} |
|
|
|
private static void visitFrameTypes( |
|
final int numTypes, final Object[] frameTypes, final List<Object> result) { |
|
for (int i = 0; i < numTypes; ++i) { |
|
Object frameType = frameTypes[i]; |
|
result.add(frameType); |
|
if (frameType == Opcodes.LONG || frameType == 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 label = new Label(); |
|
labels = new ArrayList<>(3); |
|
labels.add(label); |
|
if (mv != null) { |
|
mv.visitLabel(label); |
|
} |
|
} |
|
for (Label label : labels) { |
|
uninitializedTypes.put(label, type); |
|
} |
|
} |
|
super.visitTypeInsn(opcode, type); |
|
execute(opcode, 0, type); |
|
} |
|
|
|
@Override |
|
public void visitFieldInsn( |
|
final int opcode, final String owner, final String name, final String descriptor) { |
|
super.visitFieldInsn(opcode, owner, name, descriptor); |
|
execute(opcode, 0, descriptor); |
|
} |
|
|
|
@Override |
|
public void visitMethodInsn( |
|
final int opcodeAndSource, |
|
final String owner, |
|
final String name, |
|
final String descriptor, |
|
final boolean isInterface) { |
|
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) { |
|
|
|
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); |
|
return; |
|
} |
|
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); |
|
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK; |
|
|
|
if (this.locals == null) { |
|
labels = null; |
|
return; |
|
} |
|
pop(descriptor); |
|
if (opcode != Opcodes.INVOKESTATIC) { |
|
Object value = pop(); |
|
if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) { |
|
Object initializedValue; |
|
if (value == Opcodes.UNINITIALIZED_THIS) { |
|
initializedValue = this.owner; |
|
} else { |
|
initializedValue = uninitializedTypes.get(value); |
|
} |
|
for (int i = 0; i < locals.size(); ++i) { |
|
if (locals.get(i) == value) { |
|
locals.set(i, initializedValue); |
|
} |
|
} |
|
for (int i = 0; i < stack.size(); ++i) { |
|
if (stack.get(i) == value) { |
|
stack.set(i, initializedValue); |
|
} |
|
} |
|
} |
|
} |
|
pushDescriptor(descriptor); |
|
labels = null; |
|
} |
|
|
|
@Override |
|
public void visitInvokeDynamicInsn( |
|
final String name, |
|
final String descriptor, |
|
final Handle bootstrapMethodHandle, |
|
final Object... bootstrapMethodArguments) { |
|
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); |
|
if (this.locals == null) { |
|
labels = null; |
|
return; |
|
} |
|
pop(descriptor); |
|
pushDescriptor(descriptor); |
|
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 value) { |
|
super.visitLdcInsn(value); |
|
if (this.locals == null) { |
|
labels = null; |
|
return; |
|
} |
|
if (value instanceof Integer) { |
|
push(Opcodes.INTEGER); |
|
} else if (value instanceof Long) { |
|
push(Opcodes.LONG); |
|
push(Opcodes.TOP); |
|
} else if (value instanceof Float) { |
|
push(Opcodes.FLOAT); |
|
} else if (value instanceof Double) { |
|
push(Opcodes.DOUBLE); |
|
push(Opcodes.TOP); |
|
} else if (value instanceof String) { |
|
push("java/lang/String"); |
|
} else if (value instanceof Type) { |
|
int sort = ((Type) value).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 (value instanceof Handle) { |
|
push("java/lang/invoke/MethodHandle"); |
|
} else if (value instanceof ConstantDynamic) { |
|
pushDescriptor(((ConstantDynamic) value).getDescriptor()); |
|
} 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 descriptor, final int numDimensions) { |
|
super.visitMultiANewArrayInsn(descriptor, numDimensions); |
|
execute(Opcodes.MULTIANEWARRAY, numDimensions, descriptor); |
|
} |
|
|
|
@Override |
|
public void visitLocalVariable( |
|
final String name, |
|
final String descriptor, |
|
final String signature, |
|
final Label start, |
|
final Label end, |
|
final int index) { |
|
char firstDescriptorChar = descriptor.charAt(0); |
|
maxLocals = |
|
Math.max( |
|
maxLocals, index + (firstDescriptorChar == 'J' || firstDescriptorChar == '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 pushDescriptor(final String fieldOrMethodDescriptor) { |
|
String descriptor = |
|
fieldOrMethodDescriptor.charAt(0) == '(' |
|
? Type.getReturnType(fieldOrMethodDescriptor).getDescriptor() |
|
: fieldOrMethodDescriptor; |
|
switch (descriptor.charAt(0)) { |
|
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 '[': |
|
push(descriptor); |
|
break; |
|
case 'L': |
|
push(descriptor.substring(1, descriptor.length() - 1)); |
|
break; |
|
default: |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
private Object pop() { |
|
return stack.remove(stack.size() - 1); |
|
} |
|
|
|
private void pop(final int numSlots) { |
|
int size = stack.size(); |
|
int end = size - numSlots; |
|
for (int i = size - 1; i >= end; --i) { |
|
stack.remove(i); |
|
} |
|
} |
|
|
|
private void pop(final String descriptor) { |
|
char firstDescriptorChar = descriptor.charAt(0); |
|
if (firstDescriptorChar == '(') { |
|
int numSlots = 0; |
|
Type[] types = Type.getArgumentTypes(descriptor); |
|
for (Type type : types) { |
|
numSlots += type.getSize(); |
|
} |
|
pop(numSlots); |
|
} else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') { |
|
pop(2); |
|
} else { |
|
pop(1); |
|
} |
|
} |
|
|
|
private void execute(final int opcode, final int intArg, final String stringArg) { |
|
if (opcode == Opcodes.JSR || opcode == Opcodes.RET) { |
|
throw new IllegalArgumentException("JSR/RET are not supported"); |
|
} |
|
if (this.locals == null) { |
|
labels = null; |
|
return; |
|
} |
|
Object value1; |
|
Object value2; |
|
Object value3; |
|
Object 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(intArg)); |
|
break; |
|
case Opcodes.LLOAD: |
|
case Opcodes.DLOAD: |
|
push(get(intArg)); |
|
push(Opcodes.TOP); |
|
break; |
|
case Opcodes.LALOAD: |
|
case Opcodes.D2L: |
|
pop(2); |
|
push(Opcodes.LONG); |
|
push(Opcodes.TOP); |
|
break; |
|
case Opcodes.DALOAD: |
|
case Opcodes.L2D: |
|
pop(2); |
|
push(Opcodes.DOUBLE); |
|
push(Opcodes.TOP); |
|
break; |
|
case Opcodes.AALOAD: |
|
pop(1); |
|
value1 = pop(); |
|
if (value1 instanceof String) { |
|
pushDescriptor(((String) value1).substring(1)); |
|
} else if (value1 == Opcodes.NULL) { |
|
push(value1); |
|
} else { |
|
push("java/lang/Object"); |
|
} |
|
break; |
|
case Opcodes.ISTORE: |
|
case Opcodes.FSTORE: |
|
case Opcodes.ASTORE: |
|
value1 = pop(); |
|
set(intArg, value1); |
|
if (intArg > 0) { |
|
value2 = get(intArg - 1); |
|
if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) { |
|
set(intArg - 1, Opcodes.TOP); |
|
} |
|
} |
|
break; |
|
case Opcodes.LSTORE: |
|
case Opcodes.DSTORE: |
|
pop(1); |
|
value1 = pop(); |
|
set(intArg, value1); |
|
set(intArg + 1, Opcodes.TOP); |
|
if (intArg > 0) { |
|
value2 = get(intArg - 1); |
|
if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) { |
|
set(intArg - 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: |
|
value1 = pop(); |
|
push(value1); |
|
push(value1); |
|
break; |
|
case Opcodes.DUP_X1: |
|
value1 = pop(); |
|
value2 = pop(); |
|
push(value1); |
|
push(value2); |
|
push(value1); |
|
break; |
|
case Opcodes.DUP_X2: |
|
value1 = pop(); |
|
value2 = pop(); |
|
value3 = pop(); |
|
push(value1); |
|
push(value3); |
|
push(value2); |
|
push(value1); |
|
break; |
|
case Opcodes.DUP2: |
|
value1 = pop(); |
|
value2 = pop(); |
|
push(value2); |
|
push(value1); |
|
push(value2); |
|
push(value1); |
|
break; |
|
case Opcodes.DUP2_X1: |
|
value1 = pop(); |
|
value2 = pop(); |
|
value3 = pop(); |
|
push(value2); |
|
push(value1); |
|
push(value3); |
|
push(value2); |
|
push(value1); |
|
break; |
|
case Opcodes.DUP2_X2: |
|
value1 = pop(); |
|
value2 = pop(); |
|
value3 = pop(); |
|
t4 = pop(); |
|
push(value2); |
|
push(value1); |
|
push(t4); |
|
push(value3); |
|
push(value2); |
|
push(value1); |
|
break; |
|
case Opcodes.SWAP: |
|
value1 = pop(); |
|
value2 = pop(); |
|
push(value1); |
|
push(value2); |
|
break; |
|
case Opcodes.IALOAD: |
|
case Opcodes.BALOAD: |
|
case Opcodes.CALOAD: |
|
case Opcodes.SALOAD: |
|
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.FALOAD: |
|
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(intArg, 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.GETSTATIC: |
|
pushDescriptor(stringArg); |
|
break; |
|
case Opcodes.PUTSTATIC: |
|
pop(stringArg); |
|
break; |
|
case Opcodes.GETFIELD: |
|
pop(1); |
|
pushDescriptor(stringArg); |
|
break; |
|
case Opcodes.PUTFIELD: |
|
pop(stringArg); |
|
pop(); |
|
break; |
|
case Opcodes.NEW: |
|
push(labels.get(0)); |
|
break; |
|
case Opcodes.NEWARRAY: |
|
pop(); |
|
switch (intArg) { |
|
case Opcodes.T_BOOLEAN: |
|
pushDescriptor("[Z"); |
|
break; |
|
case Opcodes.T_CHAR: |
|
pushDescriptor("[C"); |
|
break; |
|
case Opcodes.T_BYTE: |
|
pushDescriptor("[B"); |
|
break; |
|
case Opcodes.T_SHORT: |
|
pushDescriptor("[S"); |
|
break; |
|
case Opcodes.T_INT: |
|
pushDescriptor("[I"); |
|
break; |
|
case Opcodes.T_FLOAT: |
|
pushDescriptor("[F"); |
|
break; |
|
case Opcodes.T_DOUBLE: |
|
pushDescriptor("[D"); |
|
break; |
|
case Opcodes.T_LONG: |
|
pushDescriptor("[J"); |
|
break; |
|
default: |
|
throw new IllegalArgumentException("Invalid array type " + intArg); |
|
} |
|
break; |
|
case Opcodes.ANEWARRAY: |
|
pop(); |
|
pushDescriptor("[" + Type.getObjectType(stringArg)); |
|
break; |
|
case Opcodes.CHECKCAST: |
|
pop(); |
|
pushDescriptor(Type.getObjectType(stringArg).getDescriptor()); |
|
break; |
|
case Opcodes.MULTIANEWARRAY: |
|
pop(intArg); |
|
pushDescriptor(stringArg); |
|
break; |
|
default: |
|
throw new IllegalArgumentException("Invalid opcode " + opcode); |
|
} |
|
labels = null; |
|
} |
|
} |