:TITLE[Return.0mc, August 12, 1982 3:10 PM, van Melle]; * Things to do when returning from one frame to its caller: * Free my FX * Free my BF, if I am its sole user * * Ordinarily, the caller, my BF and my FX are contiguous and all usecounts * are zero. In this case, all I have to do is turn my BF/FX into a big * free block and set up to resume execution in the caller. * It is this case that we optimize for. * If things are at all out of the ordinary, my slow return flag is on. @Return: T ← (lspEp) - (11c), opcode[020]; PFetch1[lspStkBr, lspEp]; * Get my alink, slow flg lspL4 ← T, loadpage[pgReturn]; * Save FX+1 for hard return * (No bypass effect because lspStkBr=0) T ← Stack&-1; * Save return value in L0,1 onpage[pgReturn]; lspL1 ← T; * memory is busy fetching lspEp, so this is free... T ← Stack&-1; lspL0 ← T; lspEp ← (lspEp) - (14c), goto[SlowReturn, R Odd]; * Ep -> ALink-2 (quad aligned) lspDefx0 ← 0c, goto[RetnTail]; * no flags for fast return RV2[Blink, Clink, IP[lspDefx0]]; SlowReturn: * Come here with slow bit on * lspL4 = returner's FX+1 * lspEp = my Alink field - 14 (= returnee's FX-2 + 1 for slow bit) * L0, 1 have return value to save! * * Things to worry about: my alink and clink must be the same * (if not, punt to software to patch things up). * Returnee's usecount must be zero (we can never run in a frame * with nonzero usecount; punt will copy frame). * returnee must be followed by a free block (possibly created by the return, * when my BF immediately follows returnee). T ← (lspL4) + (7c); PFetch2[lspStkBr, Blink], call[retLBL]; * Get returner's b/clinks T ← (lspEp) + 1, loadpage[pgReturnA]; * returnee's FX (my adjusted alink) lspLN ← T; * save it for lspRtn2 onpage[pgReturnA]; PFetch1[lspStkBr, lspL2], call[retLBL]; * L2 ← returnee's FX flags CLink ← (CLink) - (12c); * My clink, adjusted to FX T ← (CLink) xor T; * is it same as my alink? lu ← (rhmask[lspL2]) or T; * & returnee's usecount zero? T ← BLink, skip[alu=0]; goto[RetUfn]; * Alink # Clink, or returnee's FX usecount not zero PFetch2[lspStkBr, lspL2]; * Fetch returner's BF base words: * L2 = flags,,usecount, L3 = ivar T ← (lspLN) + (4c), call[retLBL]; PFetch1[lspStkBr, RTemp], call[retLBL]; * Get returnee's Next T ← RTemp; lu ← (lspL3) xor T; * is my BF start = Returnee's Next? lu ← rhmask[lspL2], skip[alu#0]; dblgoto[RetUfn, DoReturn, alu#0]; * if usecount zero, is fine, since it will then * become a free block; if nonzero, is hard PFetch1[lspStkBr, RTemp]; * fetch first word beyond returnee lu ← (RTemp) xor (FreeStackBlock); * is it a free block? dblgoto[RetUfn, DoReturn, alu#0]; * if so, fine, else hard RetUfn: * Punt T ← (lspL4) + (11c); * Restore my Ep lspEp ← T, loadpage[pgUfnx]; lspUFN ← 20c, gotop[lspUfnxP4]; DoReturn: * At this point, Blink points at my BF, LspL2 are its flags,,count, * L3 is my Ivar. L4 is still my FX+1 T ← (lspL4) - (3c); PFetch2[lspStkBr, xBuf]; * Fetch the two words before my FX * Either my BF or a residual BF lu ← rhmask[lspL2]; * Test BF usecount T ← (lspL3) - (2c), goto[BFinUse, alu#0]; T ← (BLink) - T; * Usecount is zero, here is BF length RTemp1 ← T; RTemp ← (freeStackBlock); * Construct free block of right length T ← lspL3; PStore2[lspStkBr, RTemp], goto[freeFX]; * Store it in front of BF BFinUse: * If BF usecount > 0, just decrement it lspL2 ← (lspL2) - 1; T ← BLink; PStore1[lspStkBr, lspL2], goto[freeFX]; freeFX: * Time to turn my FX, and possibly my dummy BF, into a free block T ← lspEsp; * end of stack xBuf3 ← T; T ← xBuf ← ldf[xBuf, 6, 1]; * Fetch residual bit T ← xBuf ← (xBuf) + T; * Times 2 => 0 or 2 T ← (lspL4) - T - 1; * Point at my FX or FX-2 xBuf2 ← (freeStackBlock); xBuf3 ← (xBuf3) - T, loadpage[pgReturn]; * length of FX or FX+dummyBF PStore2[lspStkBr, xBuf2], gotop[lspRtn2]; * make a free block of out of someone **** General Return to frame. LspLN = FX, L0,1 = value onpage[pgReturn]; lspRtn2: T ← (lspLN) - (2c); * Get FX-2 (= BF) lspEp ← T, call[retLBL]; * Wait for Ep writeback PFetch1[lspEp, lspEsp, 6], call[retLBL]; * fetch Next of returnee PFetch1[lspEp, lspDefx0, 2]; * Get FX flags,,usecount for later T ← lspEsp, call[.+1]; ExtendStk: PFetch2[lspStkBr, lspL2]; * get next stack block lu ← (lspL2) xor (freeStackBlock); T ← lspL3, skip[alu#0]; * if it's free, gobble it T ← lspEsp ← (lspEsp) + T, return; * to ExtendStk * goto[RetnTail]; **** Common Return tail. **** Come here with lspEp pointing at returnee's FX-2 = BF **** lspDefx0 has FX flags, if it is possible that InCall or NoPush is on onpage[pgReturn]; RetnTail: PFetch4[lspEp, lspIfuBr, 4]; * Get IfuBr, Next, PC of returnee * MC1 busy for 4 cycles, MC2 4 more StkState ← 377c; StkState ← (StkState) or (140000c); * StkState ← rcy[1777,2] PFetch1[lspEp, lspIbasex, 1]; * Get IVAR pointer lspEp ← (lspEp) + (14c); * Returnee's EP T ← (lspNext) - (2c); * TOS lspTsp ← T; T ← rhmask[lspIfuBrHi], task; T ← lspIfuBrHi ← (lsh[lspIfuBrHi, 10]) or T; * maybe redundant PCBhi ← T, loadpage[pgJump]; T ← rsh[lspPC, 1]; onpage[pgJump]; PFetch4[lspIfuBr, IBUF]; * Must be on page pgJump PCB ← T; * Bypass kludge: PCB← addr of what we just fetched PCB ← (PCB) and not (3c); * Remove low-order bits of PCB PCF ← lspPC; * since IfuBr is quad-aligned, PC's low bits are correct for PCF :IF[StatsMode]; lspStatsPtr, goto[ReturnStat, R>=0]; :ENDIF; ReturnStatDone: * Tsp now points at top element of stack. We want * it to be quadodd; if it is, we will start out with * 2 elts on stack (StkState = 3776), else one (1777) lu ← (lspTsp) and (2c); T ← IP[HStack0]c, goto[rsodd2, alu#0]; lspTsp ← (lspTsp) + (2c); * Do a push T ← (ldf[lspTsp, 14, 4]) + T + 1; lspL4 ← T, loadpage[pgHstack]; Stkp ← lspL4, callp[HStkUndflw]; * Get 2 elements, 1 of them garbage Stack&-2, goto[rsodd3]; * compensate for the LspTsp+2 * StkState = 1777 = 1 elt rsodd2: * tsp is odd, as we like it T ← (ldf[lspTsp, 14, 4]) + T + 1; lspL4 ← T, loadpage[pgHstack]; Stkp ← lspL4, callp[HStkUndflw]; * Get 2 elements StkState ← lsh[StkState, 1], goto[rsodd3]; * StkState = 3776 = 2 elts rsodd3: * stack fine, now check cases lu ← (lspDefx0) and (OR[FxInCall!, FxNoPushReturn!]c); T ← lspL0, goto[RetFunny, alu#0]; Stack&+1 ← T; * Push result (L0,1) and return T ← lspL1; Stack&+1 ← T; StkState ← lcy[StkState, 1], goto[IFE[StatsMode, 1, CheckStatOvfl, nxiLBL]]; RetFunny: lu ← (lspDefx0) and (FxInCall); T ← (lspEp) - (12c), goto[RetCall, alu#0]; * no push case lspDefx0 ← (lspDefx0) and not (FxNoPushReturn); * turn off bit, store back PStore1[lspStkBr, lspDefx0], goto[IFE[StatsMode, 1, CheckStatOvfl, nxiLBL]]; * Point back at Pvars RetCall: * Call in progress lspDefx0 ← (lspDefx0) and not (FxInCall); loadpage[pgCallOps]; PStore1[lspStkBr, lspDefx0], gotop[ApplyFn]; * store updated flags :END[Return];