-- Signaller.Mesa Edited by Sandman on May 22, 1980 11:11 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [BYTE], ControlDefs USING [ ControlLink, Frame, FrameHandle, GlobalFrameHandle, InstWord, localbase, NullFrame, StateVector, WordPC], FrameDefs USING [SwapInCode], FrameOps USING [ Alloc, Free, GetReturnLink, MyGlobalFrame, MyLocalFrame, ReleaseCode], ImageDefs USING [PuntMesa], Mopcodes USING [zCATCH, zJ2, zJ9, zJB, zJW, zKFCB, zNOOP, zPORTI, zRBL, zSLB], NucleusOps USING [], SDOps USING [], SDDefs USING [SD, sUncaughtSignal], TrapDefs USING []; Signaller: PROGRAM IMPORTS FrameDefs, FrameOps, ImageDefs EXPORTS NucleusOps, SDOps, TrapDefs =PUBLIC BEGIN OPEN ControlDefs; BYTE: TYPE = AltoDefs.BYTE; CatchPointer: TYPE = POINTER TO catch Frame; CatchCall: TYPE = PROCEDURE [SIGNAL] RETURNS [ActionCode]; CatchContinue: TYPE = PROCEDURE; ActionCode: TYPE = INTEGER; reject: ActionCode = 0; resume: ActionCode = 1; exit: ActionCode = -1; SendMsgSignal: PUBLIC SIGNAL RETURNS [UNSPECIFIED, UNSPECIFIED] = CODE; signalling: CARDINAL = 177777B; notSignalling: CARDINAL = 0; MarkSignalFrame: PROCEDURE [value: CARDINAL] = MACHINE CODE BEGIN Mopcodes.zSLB, 3 --OFFSET[mark]-- END; SignalHandler: PROCEDURE [signal: SIGNAL, message: UNSPECIFIED] = BEGIN SignalFrame: TYPE = POINTER TO FRAME[SignalHandler]; frame, nextFrame: FrameHandle; target, nextTarget: FrameHandle; self: FrameHandle = FrameOps.MyLocalFrame[]; start: FrameHandle; catchFrame: CatchPointer; action: ActionCode; unwinding: BOOLEAN; catchPhrase: BOOLEAN; catchFSIndex: BYTE; catchPC, exitPC: WordPC; catchState: ControlDefs.StateVector; MarkSignalFrame[signalling]; unwinding ← FALSE; start ← GetFrame[self.returnlink]; target ← NullFrame; DO nextFrame ← start; UNTIL nextFrame = target DO frame ← nextFrame; IF frame.accesslink = FrameOps.MyGlobalFrame[] AND frame.mark THEN BEGIN OPEN thisSignaller: LOOPHOLE[frame, SignalFrame]; IF unwinding THEN BEGIN IF signal = thisSignaller.signal THEN nextTarget ← IF thisSignaller.unwinding THEN thisSignaller.nextTarget ELSE thisSignaller.nextFrame; IF thisSignaller.unwinding THEN BEGIN IF thisSignaller.frame = LOOPHOLE[frame.returnlink] THEN frame.returnlink ← [frame[thisSignaller.nextFrame]]; FrameOps.Free[thisSignaller.frame]; END; nextFrame ← GetFrame[frame.returnlink]; END ELSE nextFrame ← IF signal # thisSignaller.signal THEN IF thisSignaller.unwinding THEN thisSignaller.nextFrame ELSE GetFrame[frame.returnlink] ELSE IF thisSignaller.unwinding THEN thisSignaller.nextTarget ELSE thisSignaller.nextFrame; END ELSE nextFrame ← GetFrame[frame.returnlink]; IF unwinding AND nextTarget = frame THEN nextTarget ← nextFrame; [catchPhrase, catchFSIndex, catchPC] ← CheckCatch[frame]; IF catchPhrase THEN BEGIN catchFrame ← FrameOps.Alloc[catchFSIndex]; catchFrame↑ ← Frame[ accesslink: frame.accesslink, pc: catchPC, returnlink: [frame[self]], extensions: catch[ unused:, staticlink: frame + localbase, messageval: message]]; action ← LOOPHOLE[catchFrame, CatchCall][ IF unwinding THEN LOOPHOLE[UNWIND] ELSE signal ! SendMsgSignal => RESUME [message, signal]]; catchState ← STATE; SELECT action FROM reject => NULL; resume => IF unwinding THEN ERROR ResumeError ELSE BEGIN catchState.dest ← FrameOps.GetReturnLink[]; catchState.source ← 0; RETURN WITH catchState; END; exit => BEGIN -- catchFrame is waiting to execute its exit jump exitPC ← catchFrame.pc; FrameOps.Free[catchFrame]; target ← LOOPHOLE[catchState.stk[0] - ControlDefs.localbase]; nextTarget ← nextFrame; unwinding ← TRUE; message ← NIL; GO TO StartUnwind; END; ENDCASE; END; IF unwinding THEN BEGIN IF frame = start THEN start ← nextFrame; IF frame = LOOPHOLE[self.returnlink] THEN self.returnlink ← [frame[nextFrame]]; FrameOps.Free[frame]; END; REPEAT StartUnwind => NULL; FINISHED => EXIT ENDLOOP; ENDLOOP; IF unwinding THEN target.pc ← exitPC ELSE BEGIN IF SDDefs.SD[SDDefs.sUncaughtSignal] = 0 THEN ImageDefs.PuntMesa[]; UncaughtSignal[message, signal, frame]; END; RETURN END; ReadWord0: PROCEDURE [LONG POINTER] RETURNS [InstWord] = MACHINE CODE BEGIN Mopcodes.zRBL, 0 END; ReadWord1: PROCEDURE [LONG POINTER] RETURNS [InstWord] = MACHINE CODE BEGIN Mopcodes.zRBL, 1 END; ReadWord2: PROCEDURE [LONG POINTER] RETURNS [InstWord] = MACHINE CODE BEGIN Mopcodes.zRBL, 2 END; CheckCatch: PROCEDURE [frame: FrameHandle] RETURNS [catchPhrase: BOOLEAN, fsIndex: BYTE, pc: WordPC] = BEGIN OPEN Mopcodes; ThreeWords: TYPE = ARRAY [0..3) OF InstWord; -- worst case XFER NOOP CATCH 0 codeWords: ThreeWords; -- worst case is XFER NOOP CATCH 0 code: POINTER TO ThreeWords ← @codeWords; c: [0..3); inst: [0..377B]; g: GlobalFrameHandle ← frame.accesslink; parity: {even, odd}; MarkSignalFrame[notSignalling]; FrameDefs.SwapInCode[g]; pc ← [ABS[frame.pc]]; IF g.code.highByte = 0 THEN BEGIN lp: LONG POINTER TO InstWord ← pc + g.code.longbase; code[0] ← ReadWord0[lp]; code[1] ← ReadWord1[lp]; code[2] ← ReadWord2[lp]; END ELSE code↑ ← LOOPHOLE[pc + g.code.shortbase, POINTER TO ThreeWords]↑; c ← 0; parity ← IF frame.pc < 0 THEN odd ELSE even; DO inst ← IF parity = even THEN code[c].evenbyte ELSE code[c].oddbyte; SELECT inst FROM zCATCH => BEGIN catchPhrase ← parity = even; EXIT END; zPORTI, zNOOP => IF parity = even THEN parity ← odd ELSE BEGIN c ← c + 1; parity ← even; END; ENDCASE => BEGIN catchPhrase ← FALSE; EXIT END; ENDLOOP; IF catchPhrase THEN BEGIN -- [c, parity] points at zCatch (note: parity must be even) pc ← WordPC[pc + c + 1]; fsIndex ← code[c].oddbyte; SELECT code[c + 1].evenbyte FROM zJB => BEGIN pc ← [pc + 1]; GO TO evenPC END; IN [zJ2..zJ9] => GO TO oddPC; zJW => -- always padded ! BEGIN pc ← [pc + 2]; GO TO evenPC END; ENDCASE; EXITS evenPC => NULL; oddPC => pc ← [-pc]; END; FrameOps.ReleaseCode[g]; RETURN END; GetFrame: PROCEDURE [link: ControlLink] RETURNS [FrameHandle] = BEGIN -- MarkSignalFrame[notSignalling]; DO WITH cl: link SELECT link.tag FROM frame => RETURN[cl.frame]; indirect => link ← cl.link↑; ENDCASE => RETURN[NullFrame]; ENDLOOP; END; Signal: PROCEDURE [signal: SIGNAL, message: UNSPECIFIED] = SignalHandler; SignalList: PROCEDURE [signal: SIGNAL, message: POINTER TO UNSPECIFIED] = BEGIN MarkSignalFrame[notSignalling]; SignalHandler[signal, message ! UNWIND => FrameOps.Free[message]]; FrameOps.Free[message]; RETURN END; ResumeError: PUBLIC SIGNAL = CODE; Error: PROCEDURE [signal: SIGNAL, message: UNSPECIFIED] = BEGIN MarkSignalFrame[notSignalling]; SignalHandler[signal, message]; ERROR ResumeError END; ErrorList: PROCEDURE [signal: SIGNAL, message: POINTER TO UNSPECIFIED] = BEGIN MarkSignalFrame[notSignalling]; SignalHandler[signal, message ! UNWIND => FrameOps.Free[message]]; FrameOps.Free[message]; ERROR ResumeError END; UnnamedError: PROCEDURE = BEGIN MarkSignalFrame[notSignalling]; SignalHandler[LOOPHOLE[-1], -1]; ERROR ResumeError END; UncaughtSignal: PROCEDURE [msg, signal: UNSPECIFIED, frame: FrameHandle] = MACHINE CODE BEGIN Mopcodes.zKFCB, SDDefs.sUncaughtSignal END; END.