:TITLE[Fvarlookup.0mc, October 23, 1983  4:48 PM, van Melle];

onpage[pgFvar];

RM[FVep, IP[lspDefx1]];
RM[Cnt, IP[lspDefx0]];
RM[NamePtr, IP[lspGenBr]];
RM[NamePtrHi, IP[lspGenBrHi]];

*
* Called with name (litatom) to lookup in FVarName
* Returns in FVarBinding/Hi a binding pointer
* Important that FVarName ne 0 !!
*
FVarLookupName:
	T ← (lspEp) - (12c);
	FVep ← T, UseCtask;			* FVep ← current FX
	T ← APC&APCTask;
:IF[FvarStatsMode];
	lspStatsPtr, goto[FvStartStat, R>=0];
:ENDIF;
	FVarReturnAddress ← T;			* save return link

NewFrame:
	T ← (FVep) + (1c);
	PFetch1[lspStkBr, FVep], task;		* FVep ← FVep:#Alink
	FVep ← (FVep) - (12c);
	T ← FVep ← (FVep) and not (1c);		* FVep ← FX base
	goto[EndOfStack, alu=0];

	PFetch1[lspStkBr, Cnt];			* get frame flags,,usecount
	lu ← (Cnt) and (10000c);		* Test F bit
	lu ← (Cnt) and (1000c), skip[alu=0];	* test V = nametab valid bit
	  goto[NewFrame];			* skip frame if binds no vars

	T ← (FVep) + (2c), skip[alu=0];	* T ← offset of Fnheader (V=0)
	  T ← (FVep) + (6c);		* T ← offset of name table (V=1)
	PFetch2[lspStkBr, NamePtr];	* get one or the other
	T ← rhmask[NamePtrHi];
	NamePtrHi ← (lsh[NamePtrHi, 10]) or T;
				* why bother putting it in both halves?
	T ← Cnt ← 10c;		* Offset of names in nametable

SearchLoop:
	PFetch4[NamePtr, xBuf], call[retLBL];
				* Fetch next 4 words of nametable
	T ← FVarName;		* Name to compare against
				* Now compare T against each item in xBuf
				* DispTable arrangement is for Dispatch
				* following PVar1, which dispatches to the
				* odd locations
Look0:	lu ← (xBuf) xor T, disptable[10];			* [0]
Look1:	lu ← (xBuf1) xor T, dblgoto[Look2, Found0, alu#0];	* [1]
Found0:	T ← Cnt, goto[Found];					* [2]
Look2:	lu ← (xBuf2) xor T, dblgoto[Look3, Found1, alu#0];	* [3]
Found1:	T ← Cnt ← (Cnt) + (1c), goto[Found];			* [4]
Look3:	lu ← (xBuf3) xor T, dblgoto[Look4, Found2, alu#0];	* [5]
Found2:	T ← Cnt ← (Cnt) + (2c), goto[Found];			* [6]
Look4:	lu ← xBuf3, dblgoto[EndTest, Found3, alu#0];		* [7]
Found3:	T ← Cnt ← (Cnt) + (3c), goto[Found];
EndTest:
	T ← Cnt ← (Cnt) + (4c), dblgoto[SearchLoop, NewFrame, alu#0];
					* Nametable ends in zeroes


Found:
	PFetch1[NamePtr, lspL4, 6], call[retLBL];	* L4 ← NTSIZE,
						* avoiding passaround failure
	T ← (lspL4) + T;			* offset of second NT slot
	PFetch1[NamePtr, lspL4];		* L4 ← flag,,offset
	T ← rhmask[lspL4];			* offset of var wherever
	lspL4 ← (lspL4) + T, goto[FoundAsIVar, R>=0];	* word offset

FPvar:						* L4[0:1] = 10 or 11
	T ← (FVep) + (12c);			* Find start of Pvars
	T ← (rhmask[lspL4]) + T;		* Look at Nth Pvar
	PFetch2[lspStkBr, FVarBinding];	* Fetch pvar value or fvar binding
	lu ← (lspL4) and (40000c);		* which are we looking at?
	goto[FoundAsPVar, alu=0];
	lu ← FVarBinding, goto[FoundVal, R Even];	* has been looked up
						* May want to create chain
	goto[NewFrame];

FoundAsPVar:			* fetched FVarBinding out of a PVAR slot
	lu ← FVarBinding, goto[FailedAsPVar, R<0];	* unbound if high bit on
	FVarBinding ← T, goto[LookStackPtr];	* return ptr to this binding

FailedAsPVar:
	* unbound pvar--loop, since there may be a bound one in same frame
	* Need to get back into the main loop where we left off.  Cnt is
	* offset of this instance of FVarName.  We shift Cnt left one and
	* dispatch to 1 + that value of Cnt; e.g., if Cnt mod 4 = 2, then
	* go to Look3.

	T ← (lsh[Cnt, 1]) + 1;
	lspL4 ← T;
	Cnt ← (Cnt) and not (3c);	* Restore Cnt mod 4
	Dispatch[lspL4, 15, 3];		* Always odd
	T ← FVarName, disp[Look0];
			* Note that alu#0, so the first goto works right

FoundAsIVar:
	T ← (FVep) - 1;
	PFetch1[lspStkBr, FVarBinding];		* Fetch ptr to Ivar start
	T ← rhmask[lspL4];			* Add in offset
	FVarBinding ← (FVarBinding) + T;
LookStackPtr:
	T ← FVarBindingHi ← (StackSpaceR);
LookPtrHi:
	FVarBindingHi ← (lsh[FVarBindingHi, 10]) or T, goto[FoundVal];


EndOfStack:				* stack exhausted, point at value cell
	T ← lsh[FVarName, 1];		* atomnumber * 2
	FVarBinding ← T;
	T ← FVarBindingHi ← (VALspaceR), goto[LookPtrHi];	* Say it is global

:IF[FvarStatsMode];
FoundVal:
	lspStatsPtr, goto[FVExitStat, R>=0];
	APC&APCTask ← FVarReturnAddress;
:ELSE;
FoundVal:
	APC&APCTask ← FVarReturnAddress;
:ENDIF;
FVLookupExit:
	T ← SavedFvarOffset, return;	* T for benefit of FVar and FVar←

* Eval, op 54

Eval:
	call[lspTyp], opcode[54];	* get type in LN, pop TOS into L3,2
	loadpage[pgEval];
	T ← (lspType) - (listType);	* is it Listp?
onpage[pgEval];
	FreezeResult, goto[EvalList, alu=0];	* yes, do evalform
	skip[alu<0], lu ← (lspType) - (atomType);	* is TOS atom or less?
	  lspUFN ← 54c, goto[ufnLBL];	* types greater than listp punt
	T ← lspL2, skip[alu=0];		* Skip if type atom
	  NextOpCode;			* Smallp, fixp, floatp eval to self

					* TOS is atom.  Thus L3=0, L2 = atom#
	lu ← (lspL2) - (KtVal), skip[alu#0];
	  NextOpCode;			* NIL evals to self
	skip[alu#0];
	  NextOpCode;			* so does T
	loadpage[pgFvar];
	FVarName ← T, callp[FVarLookupName];
					* Returns FVarBinding = binding slot
	PFetch2[FVarBinding, lspL2, 0];
	T ← lspL2;			* test L2,3 = NOBIND
	lu ← (lspL3) - (atomNOBIND), goto[EvalOk, alu#0];
	skip[alu#0];
	  lspUFN ← (54c), goto[ufnLBL];	* punt if var's value is NOBIND
				* Note this is not right if var is
				* actually BOUND to NOBIND, but who cares?
	nop;			* allocation constraint
EvalOk:
	Stack&-1 ← T;		* = L2, hi half of value
	T ← lspL3;
	Stack&+1 ← T, goto[nxiLBL];

EvalList:			* Eval a list.  Do this by calling a
				* special fn, rather than normal ufn, thus
				* saving a frame in the interpreter.
				* T is conveniently zero from previous lu
	lspDefx1 ← atomEVALFORM;
	lspDefx0 ← T, loadpage[pgFrame];	* ← 0
	lspNargs ← 1c, gotop[lspCallFn];



* StkScan, op 57: TOS -> binding pointer of TOS

StkScan:
	T ← Stack&-1, opcode[057];
	lu ← Stack&-1, goto[StkScanNil, alu=0];
	skip[alu=0];				* Is hiloc of TOS zero?
	  lspUFN ← 57c, goto[ufnLBL];		* no, punt
	loadpage[pgFvar];
	FVarName ← T, callp[FVarLookupName];
	T ← rsh[FVarBindingHi, 10];			* hiloc of binding ptr
	Stack&+1 ← T;
	T ← FVarBinding;
StkScanPush:
	Stack&+1 ← T, goto[nxiLBL];
StkScanNil:
	Stack&+1 ← (ValSpaceR), goto[StkScanPush];	* Note that T = 0

	:END[Fvarlookup];