// Pops the a value from the appropriate stack, decrements sp, and returns // the popped value. private short popValue(int stackID) throws ProgramException { short newSP = (short) (getSP() - 1); short value; if (stackID == MAIN_STACK) value = stackSegment.getValueAt(newSP); else value = workingStackSegment.getValueAt(newSP); checkSP(newSP); setSP(newSP); return value; }
// Returns the element at the top of the stack and decrements sp by 1. private short popAndReturn() throws ProgramException { short newSP = (short) (getSP() - 1); checkSP(newSP); setSP(newSP); return stackSegment.getValueAt(newSP); }
/** Returns the value of the function to the top of the stack. */ public void returnFromFunction() throws ProgramException { // make sure that there's somewhere to return to (old local <> 0) if (stackSegment.getValueAt(Definitions.LOCAL_POINTER_ADDRESS) == 0) throw new ProgramException( "Nowhere to return to in " + getCallStack().getTopFunction() + "." + getCurrentInstruction().getIndexInFunction()); // done in order to clear the method stack's contents workingStackSegment.setStartAddress(getSP()); bus.send(ram, Definitions.LOCAL_POINTER_ADDRESS, ram, Definitions.R13_ADDRESS); // R13 = lcl bus.send( stackSegment, stackSegment.getValueAt(Definitions.LOCAL_POINTER_ADDRESS) - 5, ram, Definitions.R14_ADDRESS); // R14 = return address bus.send( stackSegment, getSP() - 1, stackSegment, ram.getValueAt(Definitions.ARG_POINTER_ADDRESS)); // *arg = return value setSP((short) (ram.getValueAt(Definitions.ARG_POINTER_ADDRESS) + 1)); // SP = arg + 1 bus.send( stackSegment, ram.getValueAt(Definitions.R13_ADDRESS) - 1, ram, Definitions.THAT_POINTER_ADDRESS); // that = *(R13 - 1) bus.send( stackSegment, ram.getValueAt(Definitions.R13_ADDRESS) - 2, ram, Definitions.THIS_POINTER_ADDRESS); // this = *(R13 - 2) bus.send( stackSegment, ram.getValueAt(Definitions.R13_ADDRESS) - 3, ram, Definitions.ARG_POINTER_ADDRESS); // arg = *(R13 - 3) bus.send( stackSegment, ram.getValueAt(Definitions.R13_ADDRESS) - 4, ram, Definitions.LOCAL_POINTER_ADDRESS); // lcl = *(R13 - 4) // removes the top function from the call stack callStack.popFunction(); // check whether there is a "calling frame" if (stackFrames.size() > 0) { // retrieve stack frame address of old function int frameAddress = ((Integer) stackFrames.lastElement()).intValue(); stackFrames.removeElementAt(stackFrames.size() - 1); workingStackSegment.setStartAddress(frameAddress); // disable non relevant range of the local segment - enable only the locals // of the function that we returned to. localSegment.setEnabledRange( Math.max(localSegment.getStartAddress(), Definitions.STACK_START_ADDRESS), frameAddress - 1, true); // enable in the arg segment only the number of args that were sent to the function // that we returned to. argSegment.setEnabledRange( argSegment.getStartAddress(), localSegment.getStartAddress() - 6, true); // enable this, that according to their retrieved pointers thisSegment.setEnabledRange( Math.max(thisSegment.getStartAddress(), Definitions.HEAP_START_ADDRESS), Definitions.HEAP_END_ADDRESS, true); thatSegment.setEnabledRange( Math.max(thatSegment.getStartAddress(), Definitions.HEAP_START_ADDRESS), Definitions.SCREEN_END_ADDRESS, true); } /* else { error("Nowhere to return to"); } */ // Allow return if we previously had "function" even with no call - // For the SimpleFunction test short returnAddress = ram.getValueAt(Definitions.R14_ADDRESS); if (returnAddress == VMProgram.BUILTIN_FUNCTION_ADDRESS) { staticSegment.setEnabledRange(0, -1, true); // empty static segment builtInFunctionsRunner.returnToBuiltInFunction(popValue(METHOD_STACK)); } else if (returnAddress >= 0 && returnAddress < program.getSize()) { // sets the static segment range if (stackFrames.size() > 0) { setStaticRange(callStack.getTopFunction()); } else { staticSegment.setStartAddress(Definitions.VAR_START_ADDRESS); staticSegment.setEnabledRange( Definitions.VAR_START_ADDRESS, Definitions.VAR_END_ADDRESS - 1, true); } program.setPC((short) (returnAddress - 1)); // set previousPC correctly program.setPC(returnAddress); // pc = *sp } else { error("Illegal return address"); } }