/** * Emulates the storing of a value to a local variable. * * @param index the index of the local variable being stored to * @param type the type of the value * @param local the variable to which the value is stored */ public void store(int index, Klass type, Local local) { Klass localType = local.getType(); Assert.that(localType.isAssignableFrom(type) || localType == getLocalTypeFor(type)); verifyLocalVariableIndex(localType, index); localTypes[index] = type; if (localType.isDoubleWord()) { localTypes[index + 1] = Klass.getSecondWordType(localType); } else { verifyUseOfSquawkPrimitive(localType, type); } }
/** * Verify that a local variable index for a given type is not out of bounds. * * @param type the type of the local variable at <code>index</code> in the local variables array * @param index the index of a local variable */ public void verifyLocalVariableIndex(Klass type, int index) { if (index < 0) { throw codeParser.verifyError("invalid local variable index"); } if (type.isDoubleWord()) { index++; } if (index >= localTypes.length) { throw codeParser.verifyError("invalid local variable index"); } }
/** * Pops a value off the operand stack. * * @param type the type that the value popped off the operand stack must be assignable to * @return the instruction that produced the popped value */ public StackProducer pop(Klass type) { StackProducer producer; if (type.isDoubleWord()) { if (sp < 2) { throw codeParser.verifyError("operand stack underflow"); } if (!isTopDoubleWord()) { throw codeParser.verifyError("incompatible type on operand stack " + tosKlassName()); } sp -= 2; producer = stack[sp]; } else { if (sp < 1) { throw codeParser.verifyError("operand stack underflow"); } if (isTopDoubleWord()) { throw codeParser.verifyError("incompatible type on operand stack " + tosKlassName()); } producer = stack[--sp]; /* * The primitive one-word, non-float types are all assignment compatible with each other */ if (type.isPrimitive() && type != Klass.FLOAT) { type = Klass.INT; } } Assert.that(producer != null); /* * Interfaces are treated as java.lang.Object in the verifier. */ if (type.isInterface()) { type = Klass.OBJECT; } /* * Verify that the instruction is producing the correct type. */ if (!type.isAssignableFrom(producer.getType())) { throw codeParser.verifyError( "incompatible type: '" + type + "' is not assignable from '" + producer.getType() + "'"); } return producer; }
/** * Emulates loading a value of a given type from a local variable. * * @param index the index of the local variable being loaded from * @param localType the expected type of the variable from which the value is loaded * @return the variable from which the value is loaded */ public Local load(int index, Klass localType) { verifyLocalVariableIndex(localType, index); Klass derivedType = localTypes[index]; if (!localType.isAssignableFrom(derivedType)) { throw codeParser.verifyError("incompatible type in local variable"); } if (localType.isDoubleWord()) { Klass secondWordType = Klass.getSecondWordType(localType); if (!secondWordType.isAssignableFrom(localTypes[index + 1])) { throw codeParser.verifyError("incompatible type in local variable"); } } if (derivedType.isSquawkPrimitive()) { localType = derivedType; } return allocateLocal(localType, index); }
/** * Pushes a value to the operand stack. * * @param producer the instruction producing the value being pushed */ public void push(StackProducer producer) { Klass type = producer.getType(); Assert.that(type != Klass.VOID); /* * Check for overflow and push the producer. */ if (sp == maxStack) { throw codeParser.verifyError("operand stack overflow"); } stack[sp++] = producer; /* * For long and double check for overflow and then add a null word to the stack. */ if (type.isDoubleWord()) { if (sp == maxStack) { throw codeParser.verifyError("operand stack overflow"); } stack[sp++] = null; } }
/** * Creates a Frame instance to emulate and verify the execution of a single class file method. * * @param codeParser the parser used to parse the "Code" attribute of the method being emulated * @param extraLocals the number of extra local variables needed */ public Frame(CodeParser codeParser, int extraLocals) { this.maxStack = codeParser.getMaxStack(); this.codeParser = codeParser; /* * Initialize the operand stack */ stack = new StackProducer[maxStack]; /* * Initialize the types in the local variables */ localTypes = new Klass[codeParser.getMaxLocals() + extraLocals]; Method method = codeParser.getMethod(); Klass[] parameterTypes = method.getParameterTypes(); Local[] parameterLocals = null; if (Translator.REVERSE_PARAMETERS && method.isInterpreterInvoked()) { parameterLocals = new Local[parameterTypes.length]; } int javacIndex = 0; /* * Initialize 'this' in non-static methods. The type of 'this' is * UNINITIALIZED_THIS if this method is a constructor in any class * except java.lang.Object otherwise it is the class in which the * method was defined. */ if (!method.isStatic() || method.isConstructor()) { Assert.that(parameterLocals == null); Klass thisType = method.getDefiningClass(); if (method.isConstructor() && thisType != Klass.OBJECT) { thisType = Klass.UNINITIALIZED_THIS; } Local thisLocal = allocateParameter(thisType, javacIndex); store(javacIndex, thisType, thisLocal); javacIndex++; } /* * Initialize locals for the parameters. */ int parameterIndex = javacIndex; for (int i = 0; i < parameterTypes.length; i++) { Klass parameterType = parameterTypes[i]; Local parameterLocal = allocateParameter(parameterType, javacIndex); if (parameterLocals != null) { parameterLocals[i] = parameterLocal; } if (Klass.SQUAWK_64) { if (javacIndex != parameterIndex) { Assert.that(parameterIndex < javacIndex); parameterLocal.setParameterIndex(parameterIndex); } parameterIndex++; } store(javacIndex, parameterType, parameterLocal); javacIndex += (parameterType.isDoubleWord() ? 2 : 1); } parameterLocalsCount = javacIndex; /* * Adjust the parameter offsets for parameter order reversal. */ if (parameterLocals != null) { parameterIndex = 0; for (int i = parameterTypes.length - 1; i >= 0; i--) { Klass parameterType = parameterTypes[i]; parameterLocals[i].setParameterIndex(parameterIndex++); if (!Klass.SQUAWK_64 && parameterType.isDoubleWord()) { parameterIndex++; } } } /* * Initialize the remaining local variables to the TOP type */ while (javacIndex < localTypes.length) { localTypes[javacIndex++] = Klass.TOP; } }