-- CheckPoint.Mesa Edited by Sandman on September 24, 1980 10:44 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AllocDefs USING [ AddSwapStrategy, RemoveSwapStrategy, SwappingProcedure, SwapStrategy], AltoDefs USING [BytesPerPage, PageCount, PageNumber, PageSize], AltoFileDefs USING [CFA, FA, fillinDA, FP, NullFP, vDA], BcdDefs USING [VersionStamp], BFSDefs USING [ActOnPages, GetNextDA], ControlDefs USING [ AllocationVector, AllocationVectorSize, AV, ControlLink, EntryVectorItem, FrameHandle, FrameVec, GFT, GFTIndex, GlobalFrameHandle, LargeReturnSlot, LastAVSlot, PrefixHandle, ProcDesc, SpecialReturnSlot, StateVector, SVPointer], CoreSwapDefs USING [PuntInfo, level], DiskDefs USING [DA, DiskRequest, RealDA], DiskKDDefs USING [CloseDiskKD], FrameDefs USING [GlobalFrame, MakeCodeResident, SwapInCode], FrameOps USING [CodeHandle, Free, FlushLargeFrames, MyLocalFrame], ImageDefs USING [ImageVersion, PuntMesa, UserCleanupProc], ImageFormat USING [ FirstImageDataPage, HeaderPages, ImageHeader, ImagePrefix, MapItem, VersionID], InlineDefs USING [BITAND, COPY], LoadStateFormat USING [LoadState], LoadStateOps USING [initstate, InputLoadState, ReleaseLoadState, state], MiscDefs USING [CurrentTime, GetNetworkNumber, SetBlock, Zero], NucleusOps USING [ BFS, Directory, DiskKD, Faults, Files, FSP, HyperRegion, LoadState, MesaInit, Miscellaneous, Modules, NonResident, OurProcess, SegmentsA, SegmentsB, StreamsA, StreamsB, StreamsC, StringsA, StringsB], OsStaticDefs USING [OsStatics], ProcessDefs USING [ CV, DisableInterrupts, DIW, EnableInterrupts, Priority, SetPriority], ProcessOps USING [ ActiveWord, CurrentPSB, CurrentState, FirstProcess, LastProcess, NullQueueHandle, Queue, ReadWDC, ReadyList, Requeue, WakeupsWaiting, WriteWDC], PSBDefs USING [ProcessHandle, PSB], Region USING [Node, NodeObject], SDDefs USING [sAllocTrap, SD, sSwapTrap, sXferTrap], SegmentDefs USING [ AddressFromPage, Append, CloseFile, DataSegmentAddress, DataSegmentHandle, DefaultBase, DefaultVersion, DeleteDataSegment, EnumerateDataSegments, EnumerateFiles, EnumerateFileSegments, FileError, FileHandle, FileSegmentAddress, FileSegmentHandle, GetFileSegmentDA, JumpToPage, MapFileSegment, NewDataSegment, NewFile, Object, ObjectHandle, Read, SetEndOfFile, SwapIn, SwapOut, Unlock, Write], Storage USING [Pages, FreePages, Prune], SwapperOps USING [ AllocateObject, LiberateObject, mdsNodes, MoveCode, DisableHyperspace, EnableHyperspace, InitMemoryConfig], TrapOps USING [ReadATP, ReadOTP, ReadXTS, WriteXTS]; CheckPoint: PROGRAM IMPORTS BFSDefs, CoreSwapDefs, AllocDefs, SwapperOps, DiskDefs, DiskKDDefs, FrameDefs, FrameOps, ImageDefs, InlineDefs, LoadStateOps, MiscDefs, NucleusOps, ProcessDefs, ProcessOps, SegmentDefs, Storage, TrapOps EXPORTS ImageDefs SHARES DiskDefs, SegmentDefs = BEGIN OPEN ImageFormat, ControlDefs; CFA: TYPE = AltoFileDefs.CFA; DataSegmentHandle: TYPE = SegmentDefs.DataSegmentHandle; FP: TYPE = AltoFileDefs.FP; FileHandle: TYPE = SegmentDefs.FileHandle; FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle; PageSize: CARDINAL = AltoDefs.PageSize; PageCount: TYPE = AltoDefs.PageCount; PageNumber: TYPE = AltoDefs.PageNumber; vDA: TYPE = AltoFileDefs.vDA; SwapTrapDuringMakeCheck: PUBLIC SIGNAL = CODE; SwapErrorDuringMakeCheck: PUBLIC SIGNAL = CODE; SwapOutDuringMakeCheck: PUBLIC SIGNAL = CODE; NoRoomInCheckMap: PUBLIC SIGNAL = CODE; SwapTrapError: PROCEDURE = BEGIN dest: ControlLink; s: StateVector; ProcessDefs.DisableInterrupts[]; s ← STATE; dest ← TrapOps.ReadOTP[]; ProcessDefs.EnableInterrupts[]; SIGNAL SwapTrapDuringMakeCheck; RETURN WITH s; END; SwapOutError: AllocDefs.SwappingProcedure = BEGIN SIGNAL SwapOutDuringMakeCheck; RETURN[TRUE]; END; -- File Segment Transfer Routines LockCodeSegment: PROCEDURE [frame: GlobalFrameHandle] = BEGIN FrameDefs.MakeCodeResident[frame]; FrameDefs.SwapInCode[frame]; SegmentDefs.Unlock[FrameOps.CodeHandle[frame]]; END; UnlockCodeSegment: PROCEDURE [frame: GlobalFrameHandle] = BEGIN SegmentDefs.Unlock[FrameOps.CodeHandle[frame]]; END; DAofPage: PROCEDURE [file: FileHandle, page: PageNumber] RETURNS [next: vDA] = BEGIN cfa: CFA; buf: POINTER = Storage.Pages[1]; cfa.fp ← file.fp; cfa.fa ← AltoFileDefs.FA[file.fp.leaderDA, 0, 0]; next ← SegmentDefs.JumpToPage[@cfa, page - 1, buf].next; Storage.FreePages[buf]; RETURN END; FillInCAs: PROCEDURE [ Image: POINTER TO ImageHeader, mapindex: CARDINAL, ca: POINTER] = BEGIN i: CARDINAL; map: POINTER TO ARRAY [0..0) OF normal MapItem = LOOPHOLE[@Image.map]; addr: POINTER; FOR i IN [0..mapindex) DO addr ← SegmentDefs.AddressFromPage[map[i].page]; THROUGH [0..map[i].count) DO ca↑ ← addr; ca ← ca + 1; addr ← addr + AltoDefs.PageSize; ENDLOOP; ENDLOOP; END; EnumerateNeededModules: PROCEDURE [proc: PROCEDURE [GlobalFrameHandle]] = BEGIN proc[FrameDefs.GlobalFrame[EnumerateNeededModules]]; proc[LOOPHOLE[NucleusOps.BFS]]; proc[LOOPHOLE[NucleusOps.SegmentsA]]; proc[LOOPHOLE[NucleusOps.SegmentsB]]; proc[LOOPHOLE[NucleusOps.Files]]; proc[LOOPHOLE[NucleusOps.Faults]]; proc[LOOPHOLE[NucleusOps.DiskKD]]; proc[LOOPHOLE[NucleusOps.Miscellaneous]]; proc[LOOPHOLE[NucleusOps.Directory]]; proc[LOOPHOLE[NucleusOps.StreamsA]]; proc[LOOPHOLE[NucleusOps.StreamsB]]; proc[LOOPHOLE[NucleusOps.StreamsC]]; proc[LOOPHOLE[NucleusOps.FSP]]; proc[LOOPHOLE[NucleusOps.StringsA]]; proc[LOOPHOLE[NucleusOps.StringsB]]; proc[LOOPHOLE[NucleusOps.LoadState]]; proc[LOOPHOLE[NucleusOps.MesaInit]]; proc[LOOPHOLE[NucleusOps.NonResident]]; proc[LOOPHOLE[NucleusOps.OurProcess]]; proc[LOOPHOLE[NucleusOps.HyperRegion]]; proc[LOOPHOLE[NucleusOps.Modules]]; END; AdjustLoadState: PROCEDURE [state: FileSegmentHandle] = BEGIN OPEN SegmentDefs; imageFile: FileHandle = FrameOps.CodeHandle[ LOOPHOLE[NucleusOps.MesaInit]].file; loadstate: LoadStateFormat.LoadState = FileSegmentAddress[state]; i: CARDINAL; FOR i IN [0..loadstate.nBcds) DO WITH b: loadstate.bcds[i] SELECT FROM alto => IF b.fp = AltoFileDefs.NullFP THEN b.fp ← imageFile.fp; ENDCASE; ENDLOOP; RETURN END; AssureObjects: PROCEDURE = { OPEN SwapperOps, SegmentDefs; a: FileHandle; b: DataSegmentHandle; c: FileSegmentHandle; a ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file Object]]]; a↑ ← [,file[,,,,,,,,,,,]]; b ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[data segment Object]]]; b↑ ← [,segment[,data[,]]]; c ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file segment Object]]]; c↑ ← [,segment[,file[,,,,,,,,]]]; SwapperOps.LiberateObject[a]; SwapperOps.LiberateObject[b]; SwapperOps.LiberateObject[c]}; MakeCheckPoint: PUBLIC PROCEDURE [name: STRING] RETURNS [restart: BOOLEAN] = BEGIN OPEN SegmentDefs, DiskDefs, AltoFileDefs; wdc: CARDINAL; diskrequest: DiskRequest; savealloctrap, saveswaptrap: ControlLink; auxtrapFrame: FrameHandle; saveAllocationVector: AllocationVector; saveXferTrap, saveXferTrapStatus: UNSPECIFIED; savePuntData: POINTER; datapages: PageCount ← 0; SwapOutErrorStrategy: AllocDefs.SwapStrategy ← AllocDefs.SwapStrategy[ link:, proc: SwapOutError]; mapindex: CARDINAL ← 0; maxFileSegPages: CARDINAL ← 0; endofdatamapindex: CARDINAL; HeaderSeg, daMapSeg: DataSegmentHandle; Image: POINTER TO ImageHeader; HeaderDA: vDA; checkFile: FileHandle; saveDIW: WORD; savePV: ARRAY [0..15] OF UNSPECIFIED; saveReadyList: ProcessOps.Queue; savePriority: ProcessDefs.Priority; saveCurrentPSB: PSBDefs.ProcessHandle; saveCurrentState: SVPointer; initstateseg: FileSegmentHandle ← LoadStateOps.initstate; stateseg: FileSegmentHandle ← LoadStateOps.state; net: CARDINAL ← MiscDefs.GetNetworkNumber[]; segs: DESCRIPTOR FOR ARRAY OF FileSegmentHandle; maxnumbersegments: CARDINAL ← 0; nextpage: PageNumber; level: CARDINAL ← 0; wordsForDAMap: CARDINAL ← 0; mdsFreeList: DESCRIPTOR FOR ARRAY OF Region.NodeObject; SaveMDSFreeList: PROCEDURE = BEGIN OPEN SwapperOps; nNodes, i: CARDINAL; node: Region.Node; nNodes ← 0; FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO nNodes ← nNodes + 1; ENDLOOP; IF nNodes = 0 THEN BEGIN mdsFreeList ← DESCRIPTOR[NIL, 0]; RETURN END; mdsFreeList ← DESCRIPTOR[auxalloc[nNodes*SIZE[Region.NodeObject]], nNodes]; i ← 0; FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO mdsFreeList[i] ← node↑; i ← i + 1; ENDLOOP; END; RestoreMDSFreeList: PROCEDURE = BEGIN OPEN SwapperOps; i: CARDINAL ← 0; node: Region.Node; IF LENGTH[mdsFreeList] = 0 THEN RETURN; FOR i IN [0..LENGTH[mdsFreeList]) DO node ← AddressFromPage[mdsFreeList[i].base]; node↑ ← mdsFreeList[i]; ENDLOOP; END; SaveProcesses: PROCEDURE = BEGIN OPEN ProcessOps; saveDIW ← ProcessDefs.DIW↑; savePV ← ProcessDefs.CV↑; ProcessDefs.DIW↑ ← 0; WakeupsWaiting↑ ← 0; saveReadyList ← ReadyList↑; saveCurrentPSB ← CurrentPSB↑; savePriority ← CurrentPSB.priority; saveCurrentState ← CurrentState↑; END; RestoreProcesses: PROCEDURE = BEGIN OPEN ProcessDefs, ProcessOps; p: PSBDefs.ProcessHandle; ActiveWord↑ ← 77777B; ProcessDefs.DIW↑ ← saveDIW; ProcessDefs.CV↑ ← savePV; ReadyList↑ ← saveReadyList; CurrentPSB↑ ← saveCurrentPSB; CurrentPSB.priority ← LAST[Priority]; CurrentState↑ ← saveCurrentState; FOR p ← FirstProcess↑, p + SIZE[PSBDefs.PSB] UNTIL p = LastProcess↑ DO IF p.state = alive AND p.timeout # 0 AND p.waitingOnCV THEN BEGIN p.waitingOnCV ← FALSE; Requeue[from: NullQueueHandle, to: ReadyList, p: p]; END; ENDLOOP; SetPriority[savePriority]; RETURN END; EnterNormalMapItem: PROCEDURE [vmpage: PageNumber, pages: PageCount] = BEGIN map: POINTER TO normal MapItem = LOOPHOLE[@Image.map]; IF pages > 127 THEN SIGNAL SwapErrorDuringMakeCheck; IF mapindex >= PageSize*HeaderPages - SIZE[ImagePrefix] - SIZE[normal MapItem] THEN SIGNAL NoRoomInCheckMap; (map + mapindex)↑ ← MapItem[vmpage, pages, normal[]]; mapindex ← mapindex + SIZE[normal MapItem]; END; CountDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF s # HeaderSeg AND s # daMapSeg THEN datapages ← datapages + s.pages; RETURN[FALSE]; END; MapDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF s # HeaderSeg AND s # daMapSeg THEN BEGIN EnterNormalMapItem[s.VMpage, s.pages]; nextpage ← nextpage + s.pages; END; RETURN[FALSE]; END; CountMaxSegmentsPerFile: PROCEDURE [f: FileHandle] RETURNS [BOOLEAN] = BEGIN maxnumbersegments ← MAX[maxnumbersegments, f.swapcount]; RETURN[FALSE]; END; EnterSwappedInPerFile: PROCEDURE [f: FileHandle] RETURNS [BOOLEAN] = BEGIN nsegs: CARDINAL ← 0; next: PageNumber ← DefaultBase; i: CARDINAL; OrganizeSegments: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN i, j: CARDINAL; IF ~s.swappedin OR s.file # f THEN RETURN[FALSE]; FOR i IN [0..nsegs) DO IF segs[i].base > s.base THEN GOTO insert; REPEAT insert => BEGIN FOR j DECREASING IN [i..nsegs) DO segs[j + 1] ← segs[j]; ENDLOOP; segs[i] ← s; END; FINISHED => segs[nsegs] ← s; ENDLOOP; RETURN[(nsegs ← nsegs + 1) = f.swapcount]; END; IF f = checkFile OR f.swapcount = 0 THEN RETURN[FALSE]; [] ← EnumerateFileSegments[OrganizeSegments]; FOR i IN [0..nsegs) DO IF segs[i].base # next THEN EnterChangeMapItem[segs[i]] ELSE EnterNormalMapItem[segs[i].VMpage, segs[i].pages]; next ← segs[i].base + segs[i].pages; ENDLOOP; RETURN[FALSE]; END; EnterChangeMapItem: PROCEDURE [s: FileSegmentHandle] = BEGIN map: POINTER TO change MapItem = LOOPHOLE[@Image.map]; da: DiskDefs.DA ← DiskDefs.RealDA[GetFileSegmentDA[s]]; IF s.pages > 127 THEN SIGNAL SwapErrorDuringMakeCheck; IF mapindex >= PageSize*HeaderPages - SIZE[ImagePrefix] - SIZE[change MapItem] THEN SIGNAL NoRoomInCheckMap; (map + mapindex)↑ ← MapItem[s.VMpage, s.pages, change[da, s.base]]; mapindex ← mapindex + SIZE[change MapItem]; END; checkFile ← NewFile[name, Read + Write + Append, DefaultVersion]; ProcessDefs.DisableInterrupts[]; wdc ← ProcessOps.ReadWDC[]; level ← CoreSwapDefs.level; CoreSwapDefs.level ← -1; SaveProcesses[]; ImageDefs.UserCleanupProc[Checkpoint]; SwapperOps.MoveCode[direction: intoMDS]; SwapperOps.DisableHyperspace[]; SwapIn[initstateseg]; [] ← LoadStateOps.InputLoadState[]; -- bring it in for first time AdjustLoadState[stateseg]; [] ← Storage.Prune[]; SetupAuxStorage[]; EnumerateNeededModules[LockCodeSegment]; HeaderDA ← DAofPage[checkFile, 1]; -- set up private frame allocation trap FrameOps.FlushLargeFrames[]; savealloctrap ← SDDefs.SD[SDDefs.sAllocTrap]; SDDefs.SD[SDDefs.sAllocTrap] ← auxtrapFrame ← auxtrap[]; saveAllocationVector ← AV↑; AV↑ ← LOOPHOLE[DataSegmentAddress[AuxSeg], POINTER TO AllocationVector]↑; HeaderSeg ← NewDataSegment[DefaultBase, 1]; daMapSeg ← NewDataSegment[DefaultBase, 3]; AssureObjects[]; [] ← EnumerateDataSegments[CountDataSegments]; SetEndOfFile[ checkFile, datapages + stateseg.pages*2 + FirstImageDataPage - 1, AltoDefs.BytesPerPage]; [] ← DiskKDDefs.CloseDiskKD[]; Image ← DataSegmentAddress[HeaderSeg]; MiscDefs.Zero[Image, AltoDefs.PageSize*HeaderPages]; Image.prefix.versionident ← ImageFormat.VersionID; --Image.prefix.options ← 0; --Image.prefix.state.stk[0] ← Image.prefix.state.stk[1] ← 0; Image.prefix.state.stkptr ← 2; Image.prefix.state.dest ← FrameOps.MyLocalFrame[]; Image.prefix.type ← checkfile; Image.prefix.leaderDA ← checkFile.fp.leaderDA; Image.prefix.diskAddresses ← DataSegmentAddress[daMapSeg]; Image.prefix.version ← BcdDefs.VersionStamp[ time: MiscDefs.CurrentTime[], net: net, host: OsStaticDefs.OsStatics.SerialNumber]; Image.prefix.creator ← ImageDefs.ImageVersion[]; -- version stamp of currently running image nextpage ← FirstImageDataPage; [] ← EnumerateDataSegments[MapDataSegments]; IF nextpage # FirstImageDataPage + datapages THEN ERROR; endofdatamapindex ← mapindex; -- Move LoadStates InlineDefs.COPY[ from: FileSegmentAddress[stateseg], to: FileSegmentAddress[initstateseg], nwords: initstateseg.pages*PageSize]; MapFileSegment[stateseg, checkFile, datapages + FirstImageDataPage]; EnterNormalMapItem[stateseg.VMpage, stateseg.pages]; MapFileSegment[ initstateseg, checkFile, datapages + FirstImageDataPage + stateseg.pages]; EnterNormalMapItem[initstateseg.VMpage, stateseg.pages]; Image.prefix.loadStateBase ← stateseg.base; Image.prefix.initialLoadStateBase ← initstateseg.base; Image.prefix.loadStatePages ← initstateseg.pages; -- now disable swapping savePuntData ← CoreSwapDefs.PuntInfo↑; saveswaptrap ← SDDefs.SD[SDDefs.sSwapTrap]; SDDefs.SD[SDDefs.sSwapTrap] ← SwapTrapError; AllocDefs.AddSwapStrategy[@SwapOutErrorStrategy]; [] ← EnumerateFiles[CountMaxSegmentsPerFile]; segs ← DESCRIPTOR[auxalloc[maxnumbersegments], maxnumbersegments]; [] ← EnumerateFiles[EnterSwappedInPerFile]; SegmentDefs.CloseFile[checkFile ! SegmentDefs.FileError => RESUME ]; checkFile.write ← checkFile.append ← FALSE; diskrequest ← DiskRequest[ ca: auxalloc[datapages + 3], da: auxalloc[datapages + 3], fixedCA: FALSE, fp: auxalloc[SIZE[FP]], firstPage: FirstImageDataPage - 1, lastPage: FirstImageDataPage + datapages - 1, action: WriteD, lastAction: WriteD, signalCheckError: FALSE, option: update[BFSDefs.GetNextDA]]; diskrequest.fp↑ ← checkFile.fp; (diskrequest.ca + 1)↑ ← Image; FillInCAs[Image, endofdatamapindex, diskrequest.ca + 2]; MiscDefs.SetBlock[diskrequest.da, fillinDA, datapages + 3]; (diskrequest.da + 1)↑ ← HeaderDA; SaveMDSFreeList[]; saveXferTrap ← SDDefs.SD[SDDefs.sXferTrap]; SDDefs.SD[SDDefs.sXferTrap] ← FrameOps.MyLocalFrame[]; saveXferTrapStatus ← TrapOps.ReadXTS[]; restart ← BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]].page = 0; ProcessOps.WriteWDC[wdc]; AV↑ ← saveAllocationVector; SDDefs.SD[SDDefs.sAllocTrap] ← savealloctrap; SDDefs.SD[SDDefs.sXferTrap] ← saveXferTrap; TrapOps.WriteXTS[saveXferTrapStatus]; FrameOps.Free[auxtrapFrame]; RestoreMDSFreeList[]; SwapperOps.InitMemoryConfig[]; DeleteDataSegment[daMapSeg]; DeleteDataSegment[HeaderSeg]; -- turn swapping back on AllocDefs.RemoveSwapStrategy[@SwapOutErrorStrategy]; SDDefs.SD[SDDefs.sSwapTrap] ← saveswaptrap; SwapperOps.EnableHyperspace[]; RestoreProcesses[]; CoreSwapDefs.PuntInfo↑ ← savePuntData; ProcessDefs.EnableInterrupts[]; InlineDefs.COPY[ to: FileSegmentAddress[stateseg], from: FileSegmentAddress[initstateseg], nwords: initstateseg.pages*PageSize]; LoadStateOps.ReleaseLoadState[]; Unlock[initstateseg]; SwapOut[initstateseg]; DeleteDataSegment[AuxSeg]; EnumerateNeededModules[UnlockCodeSegment]; SwapperOps.MoveCode[direction: outofMDS]; ImageDefs.UserCleanupProc[IF restart THEN Restart ELSE Continue]; RETURN END; -- auxillary storage for frames and non-saved items AuxSeg: DataSegmentHandle; freepointer: POINTER; wordsleft: CARDINAL; SetupAuxStorage: PROCEDURE = BEGIN OPEN SegmentDefs; av: POINTER; i: CARDINAL; AuxSeg ← NewDataSegment[DefaultBase, 5]; av ← freepointer ← DataSegmentAddress[AuxSeg]; wordsleft ← 10*PageSize; [] ← auxalloc[AllocationVectorSize]; freepointer ← freepointer + 3; wordsleft ← wordsleft - 3; FOR i IN [0..LastAVSlot] DO (av + i)↑ ← (i + 1)*4 + 2; ENDLOOP; (av + 6)↑ ← (av + LargeReturnSlot)↑ ← (av + SpecialReturnSlot + 1)↑ ← 1; END; auxalloc: PROCEDURE [n: CARDINAL] RETURNS [p: POINTER] = BEGIN -- allocate in multiples of 4 words p ← freepointer; n ← InlineDefs.BITAND[n + 3, 177774B]; freepointer ← freepointer + n; IF wordsleft < n THEN ImageDefs.PuntMesa[]; wordsleft ← wordsleft - n; RETURN END; auxtrap: PROCEDURE RETURNS [myframe: FrameHandle] = BEGIN state: StateVector; newframe: FrameHandle; eventry: POINTER TO EntryVectorItem; fsize, findex: CARDINAL; newG: GlobalFrameHandle; dest, tempdest: ControlLink; alloc: BOOLEAN; gfi: GFTIndex; ep: CARDINAL; myframe ← LOOPHOLE[FrameOps.MyLocalFrame[]]; state.dest ← myframe.returnlink; state.source ← 0; state.instbyte ← 0; state.stk[0] ← myframe; state.stkptr ← 1; ProcessDefs.DisableInterrupts[]; DO ProcessDefs.EnableInterrupts[]; TRANSFER WITH state; ProcessDefs.DisableInterrupts[]; state ← STATE; dest ← TrapOps.ReadATP[]; myframe.returnlink ← state.source; tempdest ← dest; DO SELECT tempdest.tag FROM frame => BEGIN alloc ← TRUE; findex ← LOOPHOLE[tempdest, CARDINAL]/4; EXIT END; procedure => BEGIN OPEN proc: LOOPHOLE[tempdest, ProcDesc]; gfi ← proc.gfi; ep ← proc.ep; [frame: newG, epbase: findex] ← GFT[gfi]; eventry ← @LOOPHOLE[newG.code.shortbase, PrefixHandle].entry[ findex + ep]; findex ← eventry.info.framesize; alloc ← FALSE; EXIT END; indirect => tempdest ← tempdest.link↑; ENDCASE => ImageDefs.PuntMesa[]; ENDLOOP; IF findex > LastAVSlot THEN ImageDefs.PuntMesa[]; fsize ← FrameVec[findex]; IF fsize MOD 4 # 0 THEN fsize ← fsize + 1; newframe ← LOOPHOLE[freepointer + 1]; freepointer↑ ← findex; freepointer ← freepointer + fsize; IF wordsleft < fsize THEN ImageDefs.PuntMesa[] ELSE wordsleft ← wordsleft - fsize; IF alloc THEN BEGIN state.dest ← myframe.returnlink; state.stk[state.stkptr] ← newframe; state.stkptr ← state.stkptr + 1; END ELSE BEGIN state.dest ← dest; newframe.accesslink ← LOOPHOLE[AV[findex].frame]; AV[findex].frame ← newframe; state.source ← myframe.returnlink; END; ENDLOOP; END; END.