case SASTORE:
evalArrayStore(Type.INTEGER, frame);
break;
case POP:
if (frame.pop() == Type.TOP)
throw new BadBytecode("POP can not be used with a category 2 value, pos = " + pos);
break;
case POP2:
frame.pop();
frame.pop();
break;
case DUP: {
Type type = frame.peek();
if (type == Type.TOP)
throw new BadBytecode("DUP can not be used with a category 2 value, pos = " + pos);
frame.push(frame.peek());
break;
}
case DUP_X1:
case DUP_X2: {
Type type = frame.peek();
if (type == Type.TOP)
throw new BadBytecode("DUP can not be used with a category 2 value, pos = " + pos);
int end = frame.getTopIndex();
int insert = end - (opcode - DUP_X1) - 1;
frame.push(type);
while (end > insert) {
frame.setStack(end, frame.getStack(end - 1));
end--;
}
frame.setStack(insert, type);
break;
}
case DUP2:
frame.push(frame.getStack(frame.getTopIndex() - 1));
frame.push(frame.getStack(frame.getTopIndex() - 1));
break;
case DUP2_X1:
case DUP2_X2: {
int end = frame.getTopIndex();
int insert = end - (opcode - DUP2_X1) - 1;
Type type1 = frame.getStack(frame.getTopIndex() - 1);
Type type2 = frame.peek();
frame.push(type1);
frame.push(type2);
while (end > insert) {
frame.setStack(end, frame.getStack(end - 2));
end--;
}
frame.setStack(insert, type2);
frame.setStack(insert - 1, type1);
break;
}
case SWAP: {
Type type1 = frame.pop();
Type type2 = frame.pop();
if (type1.getSize() == 2 || type2.getSize() == 2)
throw new BadBytecode("Swap can not be used with category 2 values, pos = " + pos);
frame.push(type1);
frame.push(type2);
break;
}
// Math
case IADD:
evalBinaryMath(Type.INTEGER, frame);
break;
case LADD:
evalBinaryMath(Type.LONG, frame);
break;
case FADD:
evalBinaryMath(Type.FLOAT, frame);
break;
case DADD:
evalBinaryMath(Type.DOUBLE, frame);
break;
case ISUB:
evalBinaryMath(Type.INTEGER, frame);
break;
case LSUB:
evalBinaryMath(Type.LONG, frame);
break;
case FSUB:
evalBinaryMath(Type.FLOAT, frame);
break;
case DSUB:
evalBinaryMath(Type.DOUBLE, frame);
break;
case IMUL:
evalBinaryMath(Type.INTEGER, frame);
break;
case LMUL:
evalBinaryMath(Type.LONG, frame);
break;
case FMUL:
evalBinaryMath(Type.FLOAT, frame);
break;
case DMUL:
evalBinaryMath(Type.DOUBLE, frame);
break;
case IDIV:
evalBinaryMath(Type.INTEGER, frame);
break;
case LDIV:
evalBinaryMath(Type.LONG, frame);
break;
case FDIV:
evalBinaryMath(Type.FLOAT, frame);
break;
case DDIV:
evalBinaryMath(Type.DOUBLE, frame);
break;
case IREM:
evalBinaryMath(Type.INTEGER, frame);
break;
case LREM:
evalBinaryMath(Type.LONG, frame);
break;
case FREM:
evalBinaryMath(Type.FLOAT, frame);
break;
case DREM:
evalBinaryMath(Type.DOUBLE, frame);
break;
// Unary
case INEG:
verifyAssignable(Type.INTEGER, simplePeek(frame));
break;
case LNEG:
verifyAssignable(Type.LONG, simplePeek(frame));
break;
case FNEG:
verifyAssignable(Type.FLOAT, simplePeek(frame));
break;
case DNEG:
verifyAssignable(Type.DOUBLE, simplePeek(frame));
break;
// Shifts
case ISHL:
evalShift(Type.INTEGER, frame);
break;
case LSHL:
evalShift(Type.LONG, frame);
break;
case ISHR:
evalShift(Type.INTEGER, frame);
break;
case LSHR:
evalShift(Type.LONG, frame);
break;
case IUSHR:
evalShift(Type.INTEGER,frame);
break;
case LUSHR:
evalShift(Type.LONG, frame);
break;
// Bitwise Math
case IAND:
evalBinaryMath(Type.INTEGER, frame);
break;
case LAND:
evalBinaryMath(Type.LONG, frame);
break;
case IOR:
evalBinaryMath(Type.INTEGER, frame);
break;
case LOR:
evalBinaryMath(Type.LONG, frame);
break;
case IXOR:
evalBinaryMath(Type.INTEGER, frame);
break;
case LXOR:
evalBinaryMath(Type.LONG, frame);
break;
case IINC: {
int index = iter.byteAt(pos + 1);
verifyAssignable(Type.INTEGER, frame.getLocal(index));
access(index, Type.INTEGER, subroutine);
break;
}
// Conversion
case I2L:
verifyAssignable(Type.INTEGER, simplePop(frame));
simplePush(Type.LONG, frame);
break;
case I2F:
verifyAssignable(Type.INTEGER, simplePop(frame));
simplePush(Type.FLOAT, frame);
break;
case I2D:
verifyAssignable(Type.INTEGER, simplePop(frame));
simplePush(Type.DOUBLE, frame);
break;
case L2I:
verifyAssignable(Type.LONG, simplePop(frame));
simplePush(Type.INTEGER, frame);
break;
case L2F:
verifyAssignable(Type.LONG, simplePop(frame));
simplePush(Type.FLOAT, frame);
break;
case L2D:
verifyAssignable(Type.LONG, simplePop(frame));
simplePush(Type.DOUBLE, frame);
break;
case F2I:
verifyAssignable(Type.FLOAT, simplePop(frame));
simplePush(Type.INTEGER, frame);
break;
case F2L:
verifyAssignable(Type.FLOAT, simplePop(frame));
simplePush(Type.LONG, frame);
break;
case F2D:
verifyAssignable(Type.FLOAT, simplePop(frame));
simplePush(Type.DOUBLE, frame);
break;
case D2I:
verifyAssignable(Type.DOUBLE, simplePop(frame));
simplePush(Type.INTEGER, frame);
break;
case D2L:
verifyAssignable(Type.DOUBLE, simplePop(frame));
simplePush(Type.LONG, frame);
break;
case D2F:
verifyAssignable(Type.DOUBLE, simplePop(frame));
simplePush(Type.FLOAT, frame);
break;
case I2B:
case I2C:
case I2S:
verifyAssignable(Type.INTEGER, frame.peek());
break;
case LCMP:
verifyAssignable(Type.LONG, simplePop(frame));
verifyAssignable(Type.LONG, simplePop(frame));
frame.push(Type.INTEGER);
break;
case FCMPL:
case FCMPG:
verifyAssignable(Type.FLOAT, simplePop(frame));
verifyAssignable(Type.FLOAT, simplePop(frame));
frame.push(Type.INTEGER);
break;
case DCMPL:
case DCMPG:
verifyAssignable(Type.DOUBLE, simplePop(frame));
verifyAssignable(Type.DOUBLE, simplePop(frame));
frame.push(Type.INTEGER);
break;
// Control flow
case IFEQ:
case IFNE:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
verifyAssignable(Type.INTEGER, simplePop(frame));
break;
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ICMPLE:
verifyAssignable(Type.INTEGER, simplePop(frame));
verifyAssignable(Type.INTEGER, simplePop(frame));
break;
case IF_ACMPEQ:
case IF_ACMPNE:
verifyAssignable(Type.OBJECT, simplePop(frame));
verifyAssignable(Type.OBJECT, simplePop(frame));
break;
case GOTO:
break;
case JSR:
frame.push(Type.RETURN_ADDRESS);
break;
case RET:
verifyAssignable(Type.RETURN_ADDRESS, frame.getLocal(iter.byteAt(pos + 1)));
break;
case TABLESWITCH:
case LOOKUPSWITCH:
case IRETURN:
verifyAssignable(Type.INTEGER, simplePop(frame));
break;
case LRETURN:
verifyAssignable(Type.LONG, simplePop(frame));
break;
case FRETURN:
verifyAssignable(Type.FLOAT, simplePop(frame));
break;
case DRETURN:
verifyAssignable(Type.DOUBLE, simplePop(frame));
break;
case ARETURN:
try {
CtClass returnType = Descriptor.getReturnType(method.getDescriptor(), classPool);
verifyAssignable(Type.get(returnType), simplePop(frame));
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
break;
case RETURN:
break;
case GETSTATIC:
evalGetField(opcode, iter.u16bitAt(pos + 1), frame);
break;
case PUTSTATIC:
evalPutField(opcode, iter.u16bitAt(pos + 1), frame);
break;
case GETFIELD:
evalGetField(opcode, iter.u16bitAt(pos + 1), frame);
break;
case PUTFIELD:
evalPutField(opcode, iter.u16bitAt(pos + 1), frame);
break;
case INVOKEVIRTUAL:
case INVOKESPECIAL:
case INVOKESTATIC:
evalInvokeMethod(opcode, iter.u16bitAt(pos + 1), frame);
break;
case INVOKEINTERFACE:
evalInvokeIntfMethod(opcode, iter.u16bitAt(pos + 1), frame);
break;
case 186:
throw new RuntimeException("Bad opcode 186");
case NEW:
frame.push(resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1))));
break;
case NEWARRAY:
evalNewArray(pos, iter, frame);
break;
case ANEWARRAY:
evalNewObjectArray(pos, iter, frame);
break;
case ARRAYLENGTH: {
Type array = simplePop(frame);
if (! array.isArray() && array != Type.UNINIT)
throw new BadBytecode("Array length passed a non-array [pos = " + pos + "]: " + array);
frame.push(Type.INTEGER);
break;
}
case ATHROW:
verifyAssignable(THROWABLE_TYPE, simplePop(frame));