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:
BOOL ←
FALSE] = {
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 ANY ← LOOPHOLE[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.