/** * 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; }
/** * 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; }
/** * 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; } }
/** * Spill the result of an instruction. * * @param producer the instruction producing the value */ public void spill(StackProducer producer) { if (!producer.isSpilt()) { producer.spill(allocateLocalForSpill(producer)); } }
/** * 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); }
/** * Emulate the semantics of the <i>dup...</i> and <i>swap</i> bytecodes. * * @param opcode the opcode of an untyped stack manipulation instruction */ public void doStackOp(int opcode) { switch (opcode) { case Opcode.opc_dup: { StackProducer x1 = pop(Klass.ONE_WORD); push(x1); push(x1); x1.setDuped(this); break; } case Opcode.opc_dup2: { if (!isTopDoubleWord()) { /* * Form 1: */ StackProducer x1 = pop(Klass.ONE_WORD); StackProducer x2 = pop(Klass.ONE_WORD); push(x2); push(x1); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); } else { /* * Form 2: */ StackProducer x1 = pop(Klass.TWO_WORD); push(x1); push(x1); x1.setDuped(this); } break; } case Opcode.opc_dup_x1: { StackProducer x1 = pop(Klass.ONE_WORD); StackProducer x2 = pop(Klass.ONE_WORD); push(x1); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); break; } case Opcode.opc_dup_x2: { StackProducer x1 = pop(Klass.ONE_WORD); if (!isTopDoubleWord()) { /* * Form 1: */ StackProducer x2 = pop(Klass.ONE_WORD); StackProducer x3 = pop(Klass.ONE_WORD); push(x1); push(x3); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); x3.setDuped(this); } else { /* * Form 2: */ StackProducer x2 = pop(Klass.TWO_WORD); push(x1); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); } break; } case Opcode.opc_dup2_x1: { if (!isTopDoubleWord()) { /* * Form 1: */ StackProducer x1 = pop(Klass.ONE_WORD); StackProducer x2 = pop(Klass.ONE_WORD); StackProducer x3 = pop(Klass.ONE_WORD); push(x2); push(x1); push(x3); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); x3.setDuped(this); } else { /* * Form 2: */ StackProducer x1 = pop(Klass.TWO_WORD); StackProducer x2 = pop(Klass.ONE_WORD); push(x1); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); } break; } case Opcode.opc_dup2_x2: { if (!isTopDoubleWord()) { StackProducer x1 = pop(Klass.ONE_WORD); StackProducer x2 = pop(Klass.ONE_WORD); if (!isTopDoubleWord()) { /* * Form 1: */ StackProducer x3 = pop(Klass.ONE_WORD); StackProducer x4 = pop(Klass.ONE_WORD); push(x2); push(x1); push(x4); push(x3); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); x3.setDuped(this); x4.setDuped(this); } else { /* * Form 3: */ StackProducer x3 = pop(Klass.TWO_WORD); push(x2); push(x1); push(x3); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); x3.setDuped(this); } } else { StackProducer x1 = pop(Klass.TWO_WORD); if (!isTopDoubleWord()) { /* * Form 2: */ StackProducer x2 = pop(Klass.ONE_WORD); StackProducer x3 = pop(Klass.ONE_WORD); push(x1); push(x3); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); x3.setDuped(this); } else { /* * Form 4: */ StackProducer x2 = pop(Klass.TWO_WORD); push(x1); push(x2); push(x1); x1.setDuped(this); x2.setDuped(this); } } break; } case Opcode.opc_swap: { StackProducer x1 = pop(Klass.ONE_WORD); StackProducer x2 = pop(Klass.ONE_WORD); push(x1); push(x2); x1.setDuped(this); x2.setDuped(this); break; } default: { Assert.that(false, "unknown dup/swap opcode: " + opcode); } } }