DragomanSignals.mesa
Last Edited by: Sweet, February 8, 1985 4:12:02 pm PST
Bertrand Serlet July 27, 1985 9:51:32 pm PDT
DIRECTORY
DragomanPrivate USING [RestartInterpreter],
Basics USING [BYTE],
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 [RegisterUncaughtSignalHandler, ResumeError, SendMsgSignal, UCSProc, UNCAUGHT];
DragomanSignals: MONITOR
IMPORTS PrincOpsUtils, DragomanPrivate, 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;
Language support routines
Error: PROC [signal: SIGNAL ANY RETURNS ANY, message: UNSPECIFIED] = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[signal, message];
ERROR RuntimeError.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 RuntimeError.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 RuntimeError.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 RuntimeError.ResumeError
};
UnnamedError: PROC = {
MarkSignalHandlerFrame[FALSE];
SignalHandler[LOOPHOLE[-1], -1];
ERROR RuntimeError.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: 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;
interpreterFrame: PrincOps.FrameHandle ← PrincOps.NullFrame; -- *** RES addition
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
! RuntimeError.SendMsgSignal => RESUME[message, signal];
DragomanPrivate.RestartInterpreter => TRUSTED {interpreterFrame ← iFrame; RESUME[target]}]; -- *** RES
catchState ← STATE;
SELECT action FROM
reject => NULL;
resume =>
IF unwinding
THEN ERROR RuntimeError.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[RuntimeError.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[RuntimeError.UNCAUGHT, Uncaught][signal, message];
ucsHandler[message, signal, frame];
};
IF interpreterFrame # PrincOps.NullFrame THEN   -- *** RES addition
self.returnlink ← [frame[interpreterFrame]];     -- *** RES addition
};
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 ← 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: PROCEDURE = {
pSD: POINTER TO ARRAY [0..0) OF UNSPECIFIEDLOOPHOLE[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;
ucsHandler ← RuntimeError.RegisterUncaughtSignalHandler[NIL];
[] ← RuntimeError.RegisterUncaughtSignalHandler[ucsHandler];
};
Initialize[];
END.