12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
- package javassist.bytecode.analysis;
-
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.NotFoundException;
- import javassist.bytecode.BadBytecode;
- import javassist.bytecode.CodeIterator;
- import javassist.bytecode.ConstPool;
- import javassist.bytecode.Descriptor;
- import javassist.bytecode.MethodInfo;
- import javassist.bytecode.Opcode;
-
- /**
- * Executor is responsible for modeling the effects of a JVM instruction on a frame.
- *
- * @author Jason T. Greene
- */
- public class Executor implements Opcode {
- private final ConstPool constPool;
- private final ClassPool classPool;
- private final Type STRING_TYPE;
- private final Type CLASS_TYPE;
- private final Type THROWABLE_TYPE;
- private int lastPos;
-
- public Executor(ClassPool classPool, ConstPool constPool) {
- this.constPool = constPool;
- this.classPool = classPool;
-
- try {
- STRING_TYPE = getType("java.lang.String");
- CLASS_TYPE = getType("java.lang.Class");
- THROWABLE_TYPE = getType("java.lang.Throwable");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-
- /**
- * Execute the instruction, modeling the effects on the specified frame and subroutine.
- * If a subroutine is passed, the access flags will be modified if this instruction accesses
- * the local variable table.
- *
- * @param method the method containing the instruction
- * @param pos the position of the instruction in the method
- * @param iter the code iterator used to find the instruction
- * @param frame the frame to modify to represent the result of the instruction
- * @param subroutine the optional subroutine this instruction belongs to.
- * @throws BadBytecode if the bytecode violates the jvm spec
- */
- public void execute(MethodInfo method, int pos, CodeIterator iter, Frame frame, Subroutine subroutine) throws BadBytecode {
- this.lastPos = pos;
- int opcode = iter.byteAt(pos);
-
-
- // Declared opcode in order
- switch (opcode) {
- case NOP:
- break;
- case ACONST_NULL:
- frame.push(Type.UNINIT);
- break;
- case ICONST_M1:
- case ICONST_0:
- case ICONST_1:
- case ICONST_2:
- case ICONST_3:
- case ICONST_4:
- case ICONST_5:
- frame.push(Type.INTEGER);
- break;
- case LCONST_0:
- case LCONST_1:
- frame.push(Type.LONG);
- frame.push(Type.TOP);
- break;
- case FCONST_0:
- case FCONST_1:
- case FCONST_2:
- frame.push(Type.FLOAT);
- break;
- case DCONST_0:
- case DCONST_1:
- frame.push(Type.DOUBLE);
- frame.push(Type.TOP);
- break;
- case BIPUSH:
- case SIPUSH:
- frame.push(Type.INTEGER);
- break;
- case LDC:
- evalLDC(iter.byteAt(pos + 1), frame);
- break;
- case LDC_W :
- case LDC2_W :
- evalLDC(iter.u16bitAt(pos + 1), frame);
- break;
- case ILOAD:
- evalLoad(Type.INTEGER, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case LLOAD:
- evalLoad(Type.LONG, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case FLOAD:
- evalLoad(Type.FLOAT, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case DLOAD:
- evalLoad(Type.DOUBLE, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case ALOAD:
- evalLoad(Type.OBJECT, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case ILOAD_0:
- case ILOAD_1:
- case ILOAD_2:
- case ILOAD_3:
- evalLoad(Type.INTEGER, opcode - ILOAD_0, frame, subroutine);
- break;
- case LLOAD_0:
- case LLOAD_1:
- case LLOAD_2:
- case LLOAD_3:
- evalLoad(Type.LONG, opcode - LLOAD_0, frame, subroutine);
- break;
- case FLOAD_0:
- case FLOAD_1:
- case FLOAD_2:
- case FLOAD_3:
- evalLoad(Type.FLOAT, opcode - FLOAD_0, frame, subroutine);
- break;
- case DLOAD_0:
- case DLOAD_1:
- case DLOAD_2:
- case DLOAD_3:
- evalLoad(Type.DOUBLE, opcode - DLOAD_0, frame, subroutine);
- break;
- case ALOAD_0:
- case ALOAD_1:
- case ALOAD_2:
- case ALOAD_3:
- evalLoad(Type.OBJECT, opcode - ALOAD_0, frame, subroutine);
- break;
- case IALOAD:
- evalArrayLoad(Type.INTEGER, frame);
- break;
- case LALOAD:
- evalArrayLoad(Type.LONG, frame);
- break;
- case FALOAD:
- evalArrayLoad(Type.FLOAT, frame);
- break;
- case DALOAD:
- evalArrayLoad(Type.DOUBLE, frame);
- break;
- case AALOAD:
- evalArrayLoad(Type.OBJECT, frame);
- break;
- case BALOAD:
- case CALOAD:
- case SALOAD:
- evalArrayLoad(Type.INTEGER, frame);
- break;
- case ISTORE:
- evalStore(Type.INTEGER, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case LSTORE:
- evalStore(Type.LONG, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case FSTORE:
- evalStore(Type.FLOAT, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case DSTORE:
- evalStore(Type.DOUBLE, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case ASTORE:
- evalStore(Type.OBJECT, iter.byteAt(pos + 1), frame, subroutine);
- break;
- case ISTORE_0:
- case ISTORE_1:
- case ISTORE_2:
- case ISTORE_3:
- evalStore(Type.INTEGER, opcode - ISTORE_0, frame, subroutine);
- break;
- case LSTORE_0:
- case LSTORE_1:
- case LSTORE_2:
- case LSTORE_3:
- evalStore(Type.LONG, opcode - LSTORE_0, frame, subroutine);
- break;
- case FSTORE_0:
- case FSTORE_1:
- case FSTORE_2:
- case FSTORE_3:
- evalStore(Type.FLOAT, opcode - FSTORE_0, frame, subroutine);
- break;
- case DSTORE_0:
- case DSTORE_1:
- case DSTORE_2:
- case DSTORE_3:
- evalStore(Type.DOUBLE, opcode - DSTORE_0, frame, subroutine);
- break;
- case ASTORE_0:
- case ASTORE_1:
- case ASTORE_2:
- case ASTORE_3:
- evalStore(Type.OBJECT, opcode - ASTORE_0, frame, subroutine);
- break;
- case IASTORE:
- evalArrayStore(Type.INTEGER, frame);
- break;
- case LASTORE:
- evalArrayStore(Type.LONG, frame);
- break;
- case FASTORE:
- evalArrayStore(Type.FLOAT, frame);
- break;
- case DASTORE:
- evalArrayStore(Type.DOUBLE, frame);
- break;
- case AASTORE:
- evalArrayStore(Type.OBJECT, frame);
- break;
- case BASTORE:
- case CASTORE:
- 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));
- break;
- case CHECKCAST:
- verifyAssignable(Type.OBJECT, simplePop(frame));
- frame.push(typeFromDesc(constPool.getClassInfo(iter.u16bitAt(pos + 1))));
- break;
- case INSTANCEOF:
- verifyAssignable(Type.OBJECT, simplePop(frame));
- frame.push(Type.INTEGER);
- break;
- case MONITORENTER:
- case MONITOREXIT:
- verifyAssignable(Type.OBJECT, simplePop(frame));
- break;
- case WIDE:
- evalWide(pos, iter, frame, subroutine);
- break;
- case MULTIANEWARRAY:
- evalNewObjectArray(pos, iter, frame);
- break;
- case IFNULL:
- case IFNONNULL:
- verifyAssignable(Type.OBJECT, simplePop(frame));
- break;
- case GOTO_W:
- break;
- case JSR_W:
- frame.push(Type.RETURN_ADDRESS);
- break;
- }
- }
-
- private Type zeroExtend(Type type) {
- if (type == Type.SHORT || type == Type.BYTE || type == Type.CHAR || type == Type.BOOLEAN)
- return Type.INTEGER;
-
- return type;
- }
-
- private void evalArrayLoad(Type expectedComponent, Frame frame) throws BadBytecode {
- Type index = frame.pop();
- Type array = frame.pop();
-
- // Special case, an array defined by aconst_null
- // TODO - we might need to be more inteligent about this
- if (array == Type.UNINIT) {
- verifyAssignable(Type.INTEGER, index);
- if (expectedComponent == Type.OBJECT) {
- simplePush(Type.UNINIT, frame);
- } else {
- simplePush(expectedComponent, frame);
- }
- return;
- }
-
- Type component = array.getComponent();
-
- if (component == null)
- throw new BadBytecode("Not an array! [pos = " + lastPos + "]: " + component);
-
- component = zeroExtend(component);
-
- verifyAssignable(expectedComponent, component);
- verifyAssignable(Type.INTEGER, index);
- simplePush(component, frame);
- }
-
- private void evalArrayStore(Type expectedComponent, Frame frame) throws BadBytecode {
- Type value = simplePop(frame);
- Type index = frame.pop();
- Type array = frame.pop();
-
- if (array == Type.UNINIT) {
- verifyAssignable(Type.INTEGER, index);
- return;
- }
-
- Type component = array.getComponent();
-
- if (component == null)
- throw new BadBytecode("Not an array! [pos = " + lastPos + "]: " + component);
-
- component = zeroExtend(component);
-
- verifyAssignable(expectedComponent, component);
- verifyAssignable(Type.INTEGER, index);
-
- // This intentionally only checks for Object on aastore
- // downconverting of an array (no casts)
- // e.g. Object[] blah = new String[];
- // blah[2] = (Object) "test";
- // blah[3] = new Integer(); // compiler doesnt catch it (has legal bytecode),
- // // but will throw arraystoreexception
- if (expectedComponent == Type.OBJECT) {
- verifyAssignable(expectedComponent, value);
- } else {
- verifyAssignable(component, value);
- }
- }
-
- private void evalBinaryMath(Type expected, Frame frame) throws BadBytecode {
- Type value2 = simplePop(frame);
- Type value1 = simplePop(frame);
-
- verifyAssignable(expected, value2);
- verifyAssignable(expected, value1);
- simplePush(value1, frame);
- }
-
- private void evalGetField(int opcode, int index, Frame frame) throws BadBytecode {
- String desc = constPool.getFieldrefType(index);
- Type type = zeroExtend(typeFromDesc(desc));
-
- if (opcode == GETFIELD) {
- Type objectType = resolveClassInfo(constPool.getFieldrefClassName(index));
- verifyAssignable(objectType, simplePop(frame));
- }
-
- simplePush(type, frame);
- }
-
- private void evalInvokeIntfMethod(int opcode, int index, Frame frame) throws BadBytecode {
- String desc = constPool.getInterfaceMethodrefType(index);
- Type[] types = paramTypesFromDesc(desc);
- int i = types.length;
-
- while (i > 0)
- verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
-
- String classInfo = constPool.getInterfaceMethodrefClassName(index);
- Type objectType = resolveClassInfo(classInfo);
- verifyAssignable(objectType, simplePop(frame));
-
- Type returnType = returnTypeFromDesc(desc);
- if (returnType != Type.VOID)
- simplePush(zeroExtend(returnType), frame);
- }
-
- private void evalInvokeMethod(int opcode, int index, Frame frame) throws BadBytecode {
- String desc = constPool.getMethodrefType(index);
- Type[] types = paramTypesFromDesc(desc);
- int i = types.length;
-
- while (i > 0)
- verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
-
- if (opcode != INVOKESTATIC) {
- Type objectType = resolveClassInfo(constPool.getMethodrefClassName(index));
- verifyAssignable(objectType, simplePop(frame));
- }
-
- Type returnType = returnTypeFromDesc(desc);
- if (returnType != Type.VOID)
- simplePush(zeroExtend(returnType), frame);
- }
-
-
- private void evalLDC(int index, Frame frame) throws BadBytecode {
- int tag = constPool.getTag(index);
- Type type;
- switch (tag) {
- case ConstPool.CONST_String:
- type = STRING_TYPE;
- break;
- case ConstPool.CONST_Integer:
- type = Type.INTEGER;
- break;
- case ConstPool.CONST_Float:
- type = Type.FLOAT;
- break;
- case ConstPool.CONST_Long:
- type = Type.LONG;
- break;
- case ConstPool.CONST_Double:
- type = Type.DOUBLE;
- break;
- case ConstPool.CONST_Class:
- type = CLASS_TYPE;
- break;
- default:
- throw new BadBytecode("bad LDC [pos = " + lastPos + "]: " + tag);
- }
-
- simplePush(type, frame);
- }
-
- private void evalLoad(Type expected, int index, Frame frame, Subroutine subroutine) throws BadBytecode {
- Type type = frame.getLocal(index);
-
- verifyAssignable(expected, type);
-
- simplePush(type, frame);
- access(index, type, subroutine);
- }
-
- private void evalNewArray(int pos, CodeIterator iter, Frame frame) throws BadBytecode {
- verifyAssignable(Type.INTEGER, simplePop(frame));
- Type type = null;
- int typeInfo = iter.byteAt(pos + 1);
- switch (typeInfo) {
- case T_BOOLEAN:
- type = getType("boolean[]");
- break;
- case T_CHAR:
- type = getType("char[]");
- break;
- case T_BYTE:
- type = getType("byte[]");
- break;
- case T_SHORT:
- type = getType("short[]");
- break;
- case T_INT:
- type = getType("int[]");
- break;
- case T_LONG:
- type = getType("long[]");
- break;
- case T_FLOAT:
- type = getType("float[]");
- break;
- case T_DOUBLE:
- type = getType("double[]");
- break;
- default:
- throw new BadBytecode("Invalid array type [pos = " + pos + "]: " + typeInfo);
-
- }
-
- frame.push(type);
- }
-
- private void evalNewObjectArray(int pos, CodeIterator iter, Frame frame) throws BadBytecode {
- // Convert to x[] format
- Type type = resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1)));
- String name = type.getCtClass().getName();
- int opcode = iter.byteAt(pos);
- int dimensions;
-
- if (opcode == MULTIANEWARRAY) {
- dimensions = iter.byteAt(pos + 3);
- } else {
- name = name + "[]";
- dimensions = 1;
- }
-
- while (dimensions-- > 0) {
- verifyAssignable(Type.INTEGER, simplePop(frame));
- }
-
- simplePush(getType(name), frame);
- }
-
- private void evalPutField(int opcode, int index, Frame frame) throws BadBytecode {
- String desc = constPool.getFieldrefType(index);
- Type type = zeroExtend(typeFromDesc(desc));
-
- verifyAssignable(type, simplePop(frame));
-
- if (opcode == PUTFIELD) {
- Type objectType = resolveClassInfo(constPool.getFieldrefClassName(index));
- verifyAssignable(objectType, simplePop(frame));
- }
- }
-
- private void evalShift(Type expected, Frame frame) throws BadBytecode {
- Type value2 = simplePop(frame);
- Type value1 = simplePop(frame);
-
- verifyAssignable(Type.INTEGER, value2);
- verifyAssignable(expected, value1);
- simplePush(value1, frame);
- }
-
- private void evalStore(Type expected, int index, Frame frame, Subroutine subroutine) throws BadBytecode {
- Type type = simplePop(frame);
-
- // RETURN_ADDRESS is allowed by ASTORE
- if (! (expected == Type.OBJECT && type == Type.RETURN_ADDRESS))
- verifyAssignable(expected, type);
- simpleSetLocal(index, type, frame);
- access(index, type, subroutine);
- }
-
- private void evalWide(int pos, CodeIterator iter, Frame frame, Subroutine subroutine) throws BadBytecode {
- int opcode = iter.byteAt(pos + 1);
- int index = iter.u16bitAt(pos + 2);
- switch (opcode) {
- case ILOAD:
- evalLoad(Type.INTEGER, index, frame, subroutine);
- break;
- case LLOAD:
- evalLoad(Type.LONG, index, frame, subroutine);
- break;
- case FLOAD:
- evalLoad(Type.FLOAT, index, frame, subroutine);
- break;
- case DLOAD:
- evalLoad(Type.DOUBLE, index, frame, subroutine);
- break;
- case ALOAD:
- evalLoad(Type.OBJECT, index, frame, subroutine);
- break;
- case ISTORE:
- evalStore(Type.INTEGER, index, frame, subroutine);
- break;
- case LSTORE:
- evalStore(Type.LONG, index, frame, subroutine);
- break;
- case FSTORE:
- evalStore(Type.FLOAT, index, frame, subroutine);
- break;
- case DSTORE:
- evalStore(Type.DOUBLE, index, frame, subroutine);
- break;
- case ASTORE:
- evalStore(Type.OBJECT, index, frame, subroutine);
- break;
- case IINC:
- verifyAssignable(Type.INTEGER, frame.getLocal(index));
- break;
- case RET:
- verifyAssignable(Type.RETURN_ADDRESS, frame.getLocal(index));
- break;
- default:
- throw new BadBytecode("Invalid WIDE operand [pos = " + pos + "]: " + opcode);
- }
-
- }
-
- private Type getType(String name) throws BadBytecode {
- try {
- return Type.get(classPool.get(name));
- } catch (NotFoundException e) {
- throw new BadBytecode("Could not find class [pos = " + lastPos + "]: " + name);
- }
- }
-
- private Type[] paramTypesFromDesc(String desc) throws BadBytecode {
- CtClass classes[] = null;
- try {
- classes = Descriptor.getParameterTypes(desc, classPool);
- } catch (NotFoundException e) {
- throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
- }
-
- if (classes == null)
- throw new BadBytecode("Could not obtain parameters for descriptor [pos = " + lastPos + "]: " + desc);
-
- Type[] types = new Type[classes.length];
- for (int i = 0; i < types.length; i++)
- types[i] = Type.get(classes[i]);
-
- return types;
- }
-
- private Type returnTypeFromDesc(String desc) throws BadBytecode {
- CtClass clazz = null;
- try {
- clazz = Descriptor.getReturnType(desc, classPool);
- } catch (NotFoundException e) {
- throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
- }
-
- if (clazz == null)
- throw new BadBytecode("Could not obtain return type for descriptor [pos = " + lastPos + "]: " + desc);
-
- return Type.get(clazz);
- }
-
- private Type simplePeek(Frame frame) {
- Type type = frame.peek();
- return (type == Type.TOP) ? frame.getStack(frame.getTopIndex() - 1) : type;
- }
-
- private Type simplePop(Frame frame) {
- Type type = frame.pop();
- return (type == Type.TOP) ? frame.pop() : type;
- }
-
- private void simplePush(Type type, Frame frame) {
- frame.push(type);
- if (type.getSize() == 2)
- frame.push(Type.TOP);
- }
-
- private void access(int index, Type type, Subroutine subroutine) {
- if (subroutine == null)
- return;
- subroutine.access(index);
- if (type.getSize() == 2)
- subroutine.access(index + 1);
- }
-
- private void simpleSetLocal(int index, Type type, Frame frame) {
- frame.setLocal(index, type);
- if (type.getSize() == 2)
- frame.setLocal(index + 1, Type.TOP);
- }
-
- private Type resolveClassInfo(String info) throws BadBytecode {
- CtClass clazz = null;
- try {
- if (info.charAt(0) == '[') {
- clazz = Descriptor.toCtClass(info, classPool);
- } else {
- clazz = classPool.get(info);
- }
-
- } catch (NotFoundException e) {
- throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
- }
-
- if (clazz == null)
- throw new BadBytecode("Could not obtain type for descriptor [pos = " + lastPos + "]: " + info);
-
- return Type.get(clazz);
- }
-
- private Type typeFromDesc(String desc) throws BadBytecode {
- CtClass clazz = null;
- try {
- clazz = Descriptor.toCtClass(desc, classPool);
- } catch (NotFoundException e) {
- throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
- }
-
- if (clazz == null)
- throw new BadBytecode("Could not obtain type for descriptor [pos = " + lastPos + "]: " + desc);
-
- return Type.get(clazz);
- }
-
- private void verifyAssignable(Type expected, Type type) throws BadBytecode {
- if (! expected.isAssignableFrom(type))
- throw new BadBytecode("Expected type: " + expected + " Got: " + type + " [pos = " + lastPos + "]");
- }
- }
|