: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];