/** * 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; }
/** * Returns the internal name of the top type on the stack. * * @return the name */ private String tosKlassName() { StackProducer top = stack[sp - (isTopDoubleWord() ? 2 : 1)]; if (top == null) { return "null"; } return top.getType().getInternalName(); }
/** * Changes the type of any object in a local variable or on the operand stack whose current type * is matches <code>fromType</code> to be <code>toType</code>. */ public void replaceTypeWithType(Klass fromType, Klass toType) { for (int i = 0; i < localTypes.length; i++) { if (localTypes[i] == fromType) { localTypes[i] = toType; } } for (int i = 0; i < sp; i++) { StackProducer producer = stack[i]; if (producer != null && producer.getType() == fromType) { producer.updateType(toType); } } }
/** * Determines if the operand stack or local variable array currently contains an entry whose type * is equal to or a subtype of a given type. * * @param type the type to search for * @return true if an entry was found */ public boolean containsType(Klass type) { for (int i = 0; i < localTypes.length; i++) { if (type.isAssignableFrom(localTypes[i])) { return true; } } for (int i = 0; i < sp; i++) { StackProducer producer = stack[i]; if (producer != null && type.isAssignableFrom(producer.getType())) { return true; } } return false; }
/** * 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; } }
/** * Allocate local that is used for spilling. * * @param producer the instruction producing the value that needs to be spilled * @return a unique local to be used to hold the value */ public Local allocateLocalForSpill(StackProducer producer) { Klass type = getLocalTypeFor(producer.getType()); return new Local(type, --nextSpillLocalId, false); }