SignalsImpl.mesa
last edited by Levin on September 20, 1983 11:14 am
DIRECTORY
Basics USING [BYTE],
MesaRuntimeInit USING [],
PrincOps
USING [
BytePC, ControlLink, --FieldDescriptor, --Frame, FrameHandle, localbase, markOffset, NullFrame, NullLink, 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 = PROCEDURE [SIGNAL ANY RETURNS ANY] RETURNS [ActionCode];
CatchContinue: TYPE = PROCEDURE;
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 [UNSPECIFIED, UNSPECIFIED] = CODE;
ResumeError: PUBLIC SIGNAL = CODE;
UNCAUGHT: PUBLIC ERROR [signal: SIGNAL ANY RETURNS ANY, parameters: UNSPECIFIED] = CODE;
InformationalSignal:
PUBLIC
SAFE
PROC [signal:
SIGNAL] =
TRUSTED {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, -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:
UNSPECIFIED] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message];
ERROR ResumeError
};
ErrorList:
PROC [signal:
SIGNAL
ANY
RETURNS
ANY, message:
POINTER
TO
UNSPECIFIED] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message !
UNWIND => PrincOpsUtils.Free[message]];
PrincOpsUtils.Free[message];
ERROR ResumeError
};
ReturnError:
PROC [signal:
SIGNAL
ANY
RETURNS
ANY, message:
UNSPECIFIED] = {
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 UNSPECIFIED] = {
caller: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[];
PrincOpsUtils.SetReturnLink[caller.returnlink];
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message
! UNWIND => {PrincOpsUtils.Free[caller]; PrincOpsUtils.Free[message]}
];
PrincOpsUtils.Free[caller];
PrincOpsUtils.Free[message];
ERROR ResumeError
};
UnnamedError:
PROC = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[LOOPHOLE[-1], -1];
ERROR ResumeError
};
Signal:
PROC [signal:
SIGNAL
ANY
RETURNS
ANY, message:
UNSPECIFIED] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message];
};
SignalList:
PROC [signal:
SIGNAL
ANY
RETURNS
ANY, message:
POINTER
TO
UNSPECIFIED] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, 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: UNSPECIFIED, 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 ← NIL;
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, UNSPECIFIED];
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 PACKED ARRAY [0..0) OF BYTE;
MarkSignalHandlerFrame[FALSE];
code ← 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:
PROCEDURE = {
pSD: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← 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.