/** * Get a <code>Local</code> instance to represent a value of a given type that will be * stored/loaded to/from a given local variable. * * @param type the type of the value * @param index the index of the local variable * @param isParameter true if the local is a parameter * @return the variable at index <code>index</code> in which values of type <code>type</code> are * stored */ private Local allocateLocalPrim(Klass type, int index, boolean isParameter) { Assert.that(localTypes.length < 0xFFFF); Assert.that( index >= 0 && index < localTypes.length, "index=" + index + " localTypes.length=" + localTypes.length); Klass localType = getLocalTypeFor(type); int key = localType.getSuiteID(); /* We need a hard partition between uses of a slot as a reference vs. an Address, Offset, or UWord. * The partitioning of java primitives and objects is accomplished not only by the type passed in here, but * by the bytecode verifier. We can't be sure that some bytecodes are refering to the same local variable * as both a reference and as a Squawk primitive. Without that kind of support we are conservative here * and force a clash whenever javac uses the same local index for a reference and a Squawk primitive. */ if (localType.isSquawkPrimitive()) { key = Klass.REFERENCE.getSuiteID(); } key = key << 16 | index; if (localValues == null) { localValues = new IntHashtable(); } Local local = (Local) localValues.get(key); if (local == null) { local = new Local(localType, index, isParameter); localValues.put(key, local); } /* * Ensure that the original class file does not use the same local variable * for both a Squawk primitive value and any other reference value. This prevents the * translator from having to do a complete liveness analysis to de-multiplex * such a local variable slot. Such de-multiplexing is required as Squawk primitives * are 'magically' translated into integers (or longs on a 64 bit system). */ if (localType.isSquawkPrimitive() || local.getType().isSquawkPrimitive()) { if (localType != local.getType()) { throw codeParser.verifyError( getBadAddressLocalVariableMessage(index, localType, local.getType())); } } // System.out.println("allocated: "+local+" index "+index); /// *if[SCOPEDLOCALVARIABLES]*/ codeParser.localVariableAllocated(codeParser.getCurrentIP(), local); /// *end[SCOPEDLOCALVARIABLES]*/ return local; }
/** * 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); } }
/** * 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; } }