SignalsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin on September 20, 1983 11:14 am
Russ Atkinson (RRA) February 19, 1985 1:14:45 pm PST
DIRECTORY
Basics USING [BYTE],
MesaRuntimeInit USING [],
PrincOps USING [BytePC, ControlLink, --FieldDescriptor, --Frame, FrameHandle, localbase, markOffset, NullFrame, NullLink, RawBytes, SD, sError, sErrorList, sReturnError, sReturnErrorList, sSignal, sSignalList, StateVector, sUnnamedError, zCATCH, zJ2, zJ9, zJB, zJW, zLADRB, zPORTI, zWF],
PrincOpsUtils USING [Alloc, Codebase, Free, GetReturnFrame, GetReturnLink, MyGlobalFrame, MyLocalFrame, SetReturnLink],
RuntimeError USING [UCSProc];
SignalsImpl: MONITOR
IMPORTS PrincOpsUtils
EXPORTS MesaRuntimeInit, RuntimeError
= BEGIN
Types and Related Declarations
BYTE: TYPE = Basics.BYTE;
CatchPointer: TYPE = POINTER TO catch PrincOps.Frame;
CatchCall: TYPE = PROC [SIGNAL ANY RETURNS ANY] RETURNS [ActionCode];
CatchContinue: TYPE = PROC;
ActionCode: TYPE = INTEGER;
reject: ActionCode = 0;
resume: ActionCode = 1;
exit: ActionCode = -1;
Global Variables (protected by monitor)
ucsHandler: RuntimeError.UCSProc ← NIL;
Exported to RuntimeError
SendMsgSignal: PUBLIC SIGNAL RETURNS [message: WORD, signal: SIGNAL ANY RETURNS ANY] = CODE;
ResumeError: PUBLIC SIGNAL = CODE;
UNCAUGHT: PUBLIC ERROR [signal: SIGNAL ANY RETURNS ANY, parameters: WORD] = CODE;
InformationalSignal: PUBLIC SAFE PROC [signal: SIGNAL] = TRUSTED {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, LOOPHOLE[-1], TRUE];
};
RegisterUncaughtSignalHandler: PUBLIC ENTRY PROC [proc: RuntimeError.UCSProc] RETURNS [old: RuntimeError.UCSProc] = {
old ← ucsHandler;
ucsHandler ← proc;
};
Language support routines
Error: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message];
ERROR ResumeError
};
ErrorList: PROC [signal: SIGNAL ANY RETURNS ANY, message: POINTER TO WORD] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, LOOPHOLE[message] ! UNWIND => PrincOpsUtils.Free[message]];
PrincOpsUtils.Free[message];
ERROR ResumeError
};
ReturnError: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD] = {
caller: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[];
PrincOpsUtils.SetReturnLink[caller.returnlink];
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message ! UNWIND => PrincOpsUtils.Free[caller]];
PrincOpsUtils.Free[caller];
ERROR ResumeError
};
ReturnErrorList: PROC [signal: SIGNAL ANY RETURNS ANY, message: POINTER TO WORD] = {
caller: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[];
PrincOpsUtils.SetReturnLink[caller.returnlink];
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, LOOPHOLE[message]
! UNWIND => {PrincOpsUtils.Free[caller]; PrincOpsUtils.Free[message]}
];
PrincOpsUtils.Free[caller];
PrincOpsUtils.Free[message];
ERROR ResumeError
};
UnnamedError: PROC = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[LOOPHOLE[-1], LOOPHOLE[-1]];
ERROR ResumeError
};
Signal: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message];
};
SignalList: PROC [signal: SIGNAL ANY RETURNS ANY, message: POINTER TO WORD] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, LOOPHOLE[message] ! UNWIND => PrincOpsUtils.Free[message]];
PrincOpsUtils.Free[message];
};
Internal Procedures
MarkSignalHandlerFrame: PROC [value: BOOL] = MACHINE CODE {
PrincOps.zLADRB, 0;
PrincOps.zWF,
--PrincOps.FieldDescriptor[offset: PrincOps.markOffset, posn: 0, size: 1]--
PrincOps.markOffset, 0;
};
SignalHandler: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD, informational: BOOLFALSE] = {
SignalFrame: TYPE = POINTER TO FRAME[SignalHandler];
frame, nextFrame: PrincOps.FrameHandle;
target, nextTarget: PrincOps.FrameHandle;
self: PrincOps.FrameHandle = PrincOpsUtils.MyLocalFrame[];
start: PrincOps.FrameHandle;
catchFrame: CatchPointer;
action: ActionCode;
unwinding: BOOL;
catchPhrase: BOOL;
catchFSIndex: BYTE;
catchPC, exitPC: PrincOps.BytePC;
catchState: PrincOps.StateVector;
MarkSignalHandlerFrame[TRUE]; unwinding ← FALSE;
start ← GetFrame[self.returnlink]; target ← PrincOps.NullFrame;
DO
nextFrame ← start;
UNTIL nextFrame = target DO
frame ← nextFrame;
IF frame.accesslink = PrincOpsUtils.MyGlobalFrame[] AND frame.mark THEN {
OPEN thisSignaller: LOOPHOLE[frame, SignalFrame];
IF unwinding THEN {
IF signal = thisSignaller.signal THEN
nextTarget ← IF thisSignaller.unwinding
THEN thisSignaller.nextTarget
ELSE thisSignaller.nextFrame;
IF thisSignaller.unwinding THEN {
IF thisSignaller.frame = LOOPHOLE[frame.returnlink] THEN
frame.returnlink ← [frame[thisSignaller.nextFrame]];
PrincOpsUtils.Free[thisSignaller.frame];
};
nextFrame ← GetFrame[frame.returnlink];
}
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;
}
ELSE nextFrame ← GetFrame[frame.returnlink];
IF unwinding AND nextTarget = frame THEN nextTarget ← nextFrame;
[catchPhrase, catchFSIndex, catchPC] ← CheckCatch[frame];
IF catchPhrase THEN {
catchFrame ← PrincOpsUtils.Alloc[catchFSIndex];
catchFrame^ ← PrincOps.Frame[
accesslink: frame.accesslink,
pc: catchPC,
returnlink: [frame[self]],
extensions: catch[unused: ,
staticlink: frame+PrincOps.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 {
catchState.dest ← PrincOpsUtils.GetReturnLink[];
catchState.source ← PrincOps.NullLink;
RETURN WITH catchState
};
exit =>
IF ~informational THEN {
catchFrame is waiting to execute its exit jump
exitPC ← catchFrame.pc;
PrincOpsUtils.Free[catchFrame];
target ← LOOPHOLE[catchState.stk[0]-PrincOps.localbase];
nextTarget ← nextFrame;
unwinding ← TRUE;
message ← 0;
GO TO StartUnwind;
};
ENDCASE;
};
IF unwinding THEN {
IF frame = start THEN start ← nextFrame;
IF frame = LOOPHOLE[self.returnlink] THEN self.returnlink ← [frame[nextFrame]];
PrincOpsUtils.Free[frame];
};
REPEAT
StartUnwind => NULL;
FINISHED => EXIT
ENDLOOP;
ENDLOOP;
SELECT TRUE FROM
unwinding => target.pc ← exitPC;
informational OR signal = LOOPHOLE[UNCAUGHT] => NULL; -- does an implicit RESUME
ENDCASE => {
We want to be able to RESUME UNCAUGHT, but we don't want a random catch phrase to do so. So, we declare it to be an ERROR in the interface, but raise it as a SIGNAL here. When (if) UNCAUGHT percolates to the top of the stack, it is implicitly resumed (see the preceding line of code). Control then passes to the statement following the invocation of UNCAUGHT, which calls the debugger (or whatever).
Uncaught: TYPE = SIGNAL [SIGNAL ANY RETURNS ANY, WORD];
LOOPHOLE[UNCAUGHT, Uncaught][signal, message];
ucsHandler[message, signal, frame];
};
};
CheckCatch: PROC [frame: PrincOps.FrameHandle] RETURNS [catchPhrase: BOOL, fsIndex: BYTE, pc: PrincOps.BytePC] = {
code: LONG POINTER TO PrincOps.RawBytes;
MarkSignalHandlerFrame[FALSE];
code ← LOOPHOLE[PrincOpsUtils.Codebase[frame.accesslink]];
pc ← [frame.pc];
DO
SELECT code[pc] FROM
PrincOps.zCATCH => {catchPhrase ← TRUE; EXIT};
PrincOps.zPORTI => pc ← [pc + 1];
ENDCASE => {catchPhrase ← FALSE; EXIT};
ENDLOOP;
IF catchPhrase THEN {
code[pc] points at zCatch
fsIndex ← code[pc+1];
SELECT code[pc ← [pc+2]] FROM
PrincOps.zJB => pc ← [pc + 2];
IN [PrincOps.zJ2..PrincOps.zJ9] => pc ← [pc + 1];
PrincOps.zJW => pc ← [pc + 3];
ENDCASE;
};
};
GetFrame: PROC [link: PrincOps.ControlLink] RETURNS [PrincOps.FrameHandle] = {
MarkSignalHandlerFrame[FALSE];
DO
IF ~link.proc
THEN IF link.indirect THEN link ← link.link^ ELSE --frame link-- RETURN[link.frame]
ELSE RETURN[PrincOps.NullFrame];
ENDLOOP;
};
Initialization
Initialize: PROC = {
pSD: POINTER TO ARRAY NAT OF PROC ANY RETURNS ANYLOOPHOLE[PrincOps.SD];
pSD[PrincOps.sSignalList] ← SignalList;
pSD[PrincOps.sSignal] ← Signal;
pSD[PrincOps.sErrorList] ← ErrorList;
pSD[PrincOps.sError] ← Error;
pSD[PrincOps.sReturnErrorList] ← ReturnErrorList;
pSD[PrincOps.sReturnError] ← ReturnError;
pSD[PrincOps.sUnnamedError] ← UnnamedError;
};
Initialize[];
END.