PortableCedarRuntimeSupport.mesa
Copyright Ó 1985, 1986, 1991 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) January 27, 1987 7:30:51 pm PST
Christian Jacobi, November 17, 1987
Carl Hauser, March 30, 1988 3:20:09 pm PST
These definitions describe the architected, but private, interface between the Cedar compiler and the runtime support routines for compiled code.
If you are not writing the compiler, loader, makeboot, or the runtime initialization you have no business putting this interface in the DIRECTORY clause of anything.
PortableCedarRuntimeSupport: CEDAR DEFINITIONS = BEGIN
Version
The version of PortableCedarRuntimeSupport
Version: CARDINAL = 0;
Types
Basic definitions
ProcAny: TYPE = PROC ANY RETURNS ANY;
ProcPtr: TYPE = LONG POINTER TO ProcAny;
Comparison: TYPE = MACHINE DEPENDENT {less(0), equal(1), greater(2)};
PTR: TYPE = POINTER;
Word: TYPE = PACKED ARRAY [0..bitsPerWord) OF BIT;
bitsPerWord: NAT = 32;
For safe storage
RefPtr: TYPE = LONG POINTER TO REF;
Type: TYPE = MACHINE DEPENDENT {
This definition is likely to be changed somewhat.
nullType (0),
lastType (177777B)
};
For signalling
ExceptAny: TYPE = SIGNAL ANY RETURNS ANY;
Denotes any SIGNAL or ERROR
HandlerAction: TYPE = {reject, resume, exit};
Handler: TYPE = PROC
[context: PTR, except: ExceptAny, rtnPtr: PTR, argPtr: PTR]
RETURNS [action: HandlerAction, exitTo: INT];
This is the type of the handler procedure. context is the frame of the statically containing procedure of the handler. except denotes which exception is being raised, and args^ is the argument record for the signal.
The return values generated by RESUME are assigned to rtns^.
exitTo is significant only if action=exit, corresponding to the source constructs GO TO, RETRY, and CONTINUE from within catch phrases. exitTo denotes the value to be used by the frame containing the target of the GOTO out of the catch phrase in selecting its next action.
For locks & processes
These definitions are partial. For details, see Process.mesa. The compiler DOES NOT know the details of CONDITION, MONITORLOCK, except for their size and initial values.
LockPtr: TYPE = LONG POINTER TO LockRep;
LockRep: TYPE; -- for MONITORLOCK
CondPtr: TYPE = LONG POINTER TO CondRep;
CondRep: TYPE; -- for CONDITION
SecureProcess: TYPE[2*SIZE[INT32]]; -- 64 bits of identification of a PROCESS
Arithmetic
Signed numbers (INT)
MixedMul: PROC [x: CARD, y: INT] RETURNS [INT];
returns x * y
raises
ArithmeticOverflow if the result is not expressible as an INT
note
especially efficient when x is small
how about optional efficient special cases for various machines?
IntMul: PROC [x, y: INT] RETURNS [INT];
returns x * y
raises
ArithmeticOverflow if the result is not expressible as an INT
IntDiv: PROC [x, y: INT] RETURNS [INT];
returns x / y
raises
ZeroDivisor if y = 0
ArithmeticOverflow if the result is not expressible as an INT
IntMod: PROC [x,y: INT] RETURNS [INT];
returns x MOD y (always IN [0..ABS[y]) )
raises
ZeroDivisor if y = 0
ArithmeticOverflow if the result is not expressible as an INT
(i.e. FIRST[INT]/-1)
Signed division note:
let q = IntDiv[x, y], r = IntMod[x, y], with no exceptions
then x = IntMul[q, y] + r, and 0 d r < ABS[y]
Unsigned numbers (CARD)
CardMul: PROC [x, y: CARD] RETURNS [CARD];
returns x * y
note
no overflow checking
CardDiv: PROC [x, y: CARD] RETURNS [CARD];
returns x / y
raises
ZeroDivisor if y = 0
note
no overflow checking
CardMod: PROC [x, y: CARD] RETURNS [CARD];
returns x MOD y
raises
ZeroDivisor if y = 0
note
no overflow checking
Unigned division note:
let q = CardDiv[x, y], r = CardMod[x, y], with no exceptions
then x = CardMul[q, y] + r, and 0 d r < y
Real numbers (32-bit IEEE)
If these routines are implemented as macros, the arguments must not be evaluated twice unless specified.
The compiler generates calls to these procedures using int as type for the parameters or returns; to get the real numbers, the parameter must be loopholed, NOT casted.
By using int the c2c compiler ensures that the C compiler will not convert these parameters to double precision.
Once in the glorious future we will also need 64 bits.
RealNeg: PROC [a: REAL32] RETURNS [REAL32];
RealAbs: PROC [a: REAL32] RETURNS [REAL32];
may re-evaluate arguments
RealCompare: PROC [x, y: REAL] RETURNS [Comparison];
compares x and y
raises RealException as specified by the IEEE standard
RealAdd: PROC [a, b: REAL32] RETURNS [REAL32];
RealSub: PROC [a, b: REAL32] RETURNS [REAL32];
(a-b)
RealMul: PROC [a, b: REAL32] RETURNS [REAL32];
RealDiv: PROC [a, b: REAL32] RETURNS [REAL32];
(a/b)
FloatInt: PROC [i: INT32] RETURNS [REAL32];
FloatCard: PROC [i: CARD32] RETURNS [REAL32];
RealMax: PROC [a, b: REAL32] RETURNS [REAL32];
may re-evaluate arguments
RealGt: PROC [a, b: REAL32] RETURNS [BOOL];
(a>b)
RealGe: PROC [a, b: REAL32] RETURNS [BOOL];
(a>=b)
Fix: PROC [r: REAL, mode: RoundingMode ← rn] RETURNS [INT];
returns the integer closest to r determined by the mode
raises RealException as specified by the IEEE standard
RoundingMode: TYPE = MACHINE DEPENDENT {rn, rz, rm, rp};
rn: Round to nearest (unbiased).
rz: Round to zero (truncate).
rp: Round to plus infinity (round up).
rm: Round to minus infinity (round down).
Arithmetic Exceptions
ArithmeticOverflow: ERROR;
raised on arithmetic overflow; the compiler may raise this explictly when an arithmetic overflow is detected via a comparison rather than an arithmetic instruction.
ZeroDivisor: SIGNAL;
raised when dividing by 0; the compiler may raise this explictly when a division by zero is detected via a comparison rather than a call to divide.
BoundsFault: ERROR;
raised when a bounds check instruction fails; the compiler may raise this explictly when a bounds fault is detected via a comparison rather than via a bounds check instruction.
RealException: ERROR ...; -- is defined in the Real interface.
(The compiler does not know the details, and does not use this error explictly).
Monitors & Processes
Fork: PROC [proc: PROC RETURNS [PTR]] RETURNS [SecureProcess];
For
FORK p
the compiler creates a closure pPrime for the runtime support to call in the new process. pPrime would be declared
PROC RETURNS [retPtr: PTR]
if it were a Mesa procedure. retPtr is to be returned as the value of the corresponding call to Join, when it occurs. If the child process is detached, the runtime support should arrange for retPtr's referent to be freed.
Join: PROC [process: SecureProcess] RETURNS [retPtr: PTR];
Takes a process, waits for it to finish, and returns a pointer to the return record which the runtime obtains as the result of the call to pPrime mentioned above.
Wait: PROC [cond: CondPtr, lock: LockPtr];
Waits for a condition variable to be notified (the condition variable is protected by the given monitor lock).
Notify: PROC [cond: CondPtr];
Notifies the "best" process waiting for the given condition variable (the condition variable is protected by the given monitor lock). If lock # NIL, Notify places the process on the monitor lock's queue, otherwise just allows that process to run.
Broadcast: PROC [cond: CondPtr];
Notifies all processes waiting on the given condition variable (the condition variable is protected by the given monitor lock). If lock # NIL, Broadcast places those processes on the monitor lock's queue, otherwise just allows those processes to run.
MonitorEntry: PROC [lock: LockPtr];
Attempts to enter the monitor protected by the given monitor lock. The executing process will wait until it has possession of the lock.
MonitorExit: PROC [lock: LockPtr];
Releases the monitor lock, allowing the "best" process waiting for the monitor lock to proceed.
Frame allocation
Although frames are normally in registers, there are various cases where frame extensions must be placed in actual storage. The compiler uses these routines to allocate and free the parts of local frames that must be in memory.
Frame extensions are allocated in a LIFO stack per process.
However, currently it is possible that a free operation gets lost. ?
For now its ok to just allocate frame extensions and forget about freeing [or use the garbage collector]
ExtensionAlloc: PROC [nWords: INT] RETURNS [PTR];
Allocates a frame extension large enough to hold nWords worth of data.
ExtensionFree: PROC [ptr: PTR] RETURNS [PTR ¬ NIL];
Frees a frame extension obtained by ExtensionAlloc. Ignores ptr = NIL. Always returns NIL for convenience of assigning back to the link.
Global Frame
Modules can be started, stopped, restarted, and copied through the current language. Although there is some question as to how much of this support should be continued, here are the hooks to support the current semantics.
CopyModule: PROC;
Used to implement NEW prog.
StartModule: PROC [retPtr: PTR, module: PTR, args: PTR];
Starts a module (with given arguments). Used to implement START prog.
Restart and Stop are not currently implemented.
RestartModule: PROC [module: PTR, args: PTR];
Starts a module (with given arguments). Used to implement RESTART prog.
StopModule: PROC;
Used to implement STOP of the current module.
Signaller
For signals and errors, argument and return records are always passed by reference, rather than sometimes by value (as in PrincOps). We think that the added uniformity is worth the slight additional runtime cost.
PushHandler: PROC [context: PTR, handler: Handler] RETURNS [exitTo: INT];
PushHandler returns 0 when initially called, and the exitTo value supplied by handler on subsequent returns (Note that PushHandler may return more than once. That is, PushHandler acts a lot like unix setjmp. The corresponding longjmp occurs in the SignalHandling machinery after it has taken care of UNWINDing.
As a special case, if handle=NIL the signal handling runtime support is responsible for freeing the context when UNWINDing.
Usage: Translate
{
ENABLE {
e1 => goto L1;
e2 => goto L2;
e3 => CONTINUE;
e4 => RETRY;
}
b0
EXITS
L1 => b1;
L2 => b2;
}
into
{
handler: Handler ~ {
SELECT except FROM
LOOPHOLE[e1] => RETURN[exit, 1];
LOOPHOLE[e2] => RETURN[exit, 2];
LOOPHOLE[e3] => RETURN[exit, 3];
LOOPHOLE[e4] => RETURN[exit, 0];
-- note this case: for CONTINUE we return exitTo~0 implying "do the protected body again.
ENDCASE => RETURN[reject, 0];
}
SELECT PushHandler[context, handler] FROM
0 => { b0; PopHandler[] };
1 => { PopHandler[]; goto L1 };
2 => { PopHandler[]; goto L2 };
3 => PopHandler[];
ENDCASE => NULL; -- should never happen, maybe should be ERROR?
EXITS
L1 => b1;
L2 => b2;
};
Further, remember that other GOTOs that exit multiple blocks may have to be preceded by an appropriate number of PopHandler calls.
PopHandler: PROC;
RaiseSignal: PROC [which: ExceptAny, rtns: PTR, args: PTR];
Raises the named signal with the given argument record. Used for
result ← SIGNAL which[args]. The handler assigns the return record to rtns^ if it resumes the signal.
RaiseError: PROC [which: ExceptAny, args: PTR];
Raises the named error with the given argument record. Used for ERROR which[args].
ExceptionBody: PROC;
Used for foo: ERROR = CODE or foo: SIGNAL = CODE. Should never be called.
Aborted: ERROR;
Corresponds to ABORTED.
AbstractionFault: ERROR;
Raised by generated code when it detects the runtime support not playing according to agreement.
Unwind: ERROR;
Corresponds to UNWIND.
UnnamedError: ERROR;
Corresponds to unnamed ERROR.
UnnamedSignal: SIGNAL;
Corresponds to unnamed SIGNAL.
Uncaught: ERROR;
Corresponds to UNCAUGHT, which is now built-in.
RaiseBoundsFault: PROC RETURNS [CARD ¬ 0];
Used by the compiler in place of RaiseError[BoundsFault];
RaiseArithmeticFault: PROC RETURNS [CARD ¬ 0];
Used in conversions signed<->unsigned where the sign bit is set.
RaiseAbstractionFault: PROC;
Used by the compiler in place of RaiseError[AbstractionFault];
SafeStorage
Safe Storage support for Cedar extensions to Mesa performs reference-counting to determine when to automtically reclaim storage.
AssignRef: PROC [dstPtr: RefPtr, src: REF];
Atomically assigns a reference to a reference-containing cell.
increments source RCs, decrements dest RCs, and moves the word
lhs is first argument, and should be the address of the destination
rhs is second argument
AssignRefInit: PROC [dstPtr: RefPtr, src: REF];
Atomically assigns a reference to a reference-containing cell for initialization, without first decrementing RCs of destination.
like simpleAssign, but the destination RCs are not decremented
AssignRefComposite: PROC [dst: PTR, src: PTR, type: Type];
Performs dst^ ← src^, treating the copied variable as being of the specified type (containing refs). Reference-counted fields are treated properly. This operation is definitely not atomic. AssignRefCompositeFault will be raised if an an improper assignment is attempted (i.e. assignment to a variant record).
increments source RCs, decrements dest RCs, and moves the words
lhs is first argument, and should be the address of the destination
rhs is second argument
type of lhs is given by the third argument
AssignRefCompositeInit: PROC [dst: PTR, src: PTR, type: Type];
Performs dst^ ← src^, treating the copied variable as being of the specified type. Reference-counted fields are treated properly. This operation is definitely not atomic. AssignRefCompositeFault will be raised if an an improper assignment is attempted (i.e. assignment to a variant record). Assumes this is an initialization of dst^ and therefore does not decrease RCs of destination.
like complexAssign, but the destination RCs are not decremented
AssignRefCompositeFault: ERROR;
Here for completeness. Not actually used by the compiler.
GetReferentType: PROC [ref: REF] RETURNS [Type];
Gets the referent type of an object from a reference to that object. Returns nullType for ref = NIL. Useful for WITH ref SELECT FROM ...
This operation is used in WITH ref SELECT ... statements and ISTYPE expressions. NIL has a reserved referent type that never matches the type of an object.
Narrow: PROC [ref: REF, type: Type] RETURNS [REF];
Checks to determine that the type of the object is equal to the given type, then returns the original reference. When ref = NIL, NIL is returned and no checking is performed. Raises NarrowFault if the types are different. Useful for NARROW.
This operation raises a NarrowRefFault if ref # NIL and referentType[ref] # T.
NarrowRefFault: ERROR [ref: REF, type: Type];
This error is raised by Narrow when the type of the reference is not equal to the expected type.
NarrowFault: ERROR;
This error is raised by Narrow when the type of the variant is not equal to the expected type. Compiler generated use is naked (not applied)
NilFault: ERROR;
Raised when trying to dereference a pointer either explicitly in the compiled code or as the result of an address fault in the underlying hardware.
CheckProc: PROC [proc: ProcAny] RETURNS [ProcAny];
Returns same procedure.
Checks the procedure for being assignable. Raises NestedProcFault if the proc is nested.
A procedure descriptor must contain enough information to be able to check for safe assignment. In systems that do not support retained frames nested procedures are not safely assignable to locations that may be longer lived than the procedures.
NestedProcFault: ERROR [proc: ProcAny];
Raised if the procedure described by proc is a nested procedure.
NewObject: PROC [nUnits: INT, type: Type] RETURNS [REF];
Allocates a new object of the given type from the default zone, using at least nWords of storage, and initializing the type appropriately.
Storage operations -- from /indigo/mimosa/c2c/C2CProposedRuntimeSupport.tioga
MoveWords: PROC [dst: PTR, src: PTR, nWords: NAT];
Moves nWords words from the source to the destination. The caller does not assure disjointness.
MoveWordsDisjoint: PROC [dst: PTR, src: PTR, nWords: NAT];
Moves nWords words from the source to the destination. For efficiency, no check is made for overlapping variables, but the caller assures disjointness.
EqualWords: PROC [x: PTR, y: PTR, nWords: NAT] RETURNS [BOOL];
Tests the two multi-word variables for equality.
MoveBytesDisjoint: PROC [dst: PTR, src: PTR, nBytes: NAT];
Moves nBytes bytes from the source to the destination. For efficiency, no check is made for overlapping variables, but the caller assures disjointness.
ExtractField: PROC [base: PTR, offset: INT, bits: [0..bitsPerWord]] RETURNS [Word];
Extracts the field from any base pointer (pointer to word) at any bit offset. The word returned is the field right-justified with zero bits on the left.
DepositField: PROC [base: PTR, offset: INT, bits: [0..bitsPerWord], word: Word];
Deposits the field to any base pointer at any bit offset. The word given has the bits right-justified. The other bits are ignored.
MoveField: PROC [dst: PTR, dstOffset: INT, src: PTR, srcOffset: INT, bits: NAT];
Moves field that is bits wide from the src address (plus srcOffset bits) to the dst address (plus dstOffset bits). The caller does not assures disjointness.
EqualFields: PROC [x: PTR, xOffset: INT, y: PTR, yOffset: INT, bits: NAT] RETURNS [BOOL];
Tests fields for equality.
Efficiency matters less, I believe they wont be used in inner most loops
FillFields: PROC [dst: PTR, dstOffset: INT, bits: [0..bitsPerWord], times: NAT, value: Word];
Fills contiguos fields that each are bits wide in the dst address (plus dstOffset bits) for times number of fields. The fill value will be right-justified in value.
FillLongFields: PROC [dst: PTR, dstOffset: INT, src: PTR, srcOffset: INT, bits: NAT, times: NAT];
Fills contiguous fields that each are bits wide in the dst address (plus dstOffset bits) for times number of fields. The fill value is taken from the src address (plus srcOffset bits).
FillWords: PROC [dst: PTR, times: NAT, value: Word];
Fills times words at the destination with value.
FillLongWords: PROC [dst, src: PTR, nWords: NAT, times: NAT];
Fills times nWords fields at the destination (dst) with the nWords field at the source (src).
Debugging Aids
will be removed as soon as the need of such low level debugging features disappears
DebugPutChar: PROC [ch: CHAR];
writes character to some output file/device and flush. The character
appears even if the program crashes immediately afterwards.
END.
Carl Hauser, May 8, 1987 4:51:47 pm PDT
Changed process primitives to operate on SecureProcesses. Fork and Join should now match their implementations at least in number and primitive type of parameters and results.
Changed Notify and Broadcast to not take lock parameters.
Carl Hauser, January 22, 1988 6:38:58 pm PST
Cleaning up the various errors and signals.
changes to: Aborted, AbstractionFault, Uncaught, RaiseBoundsFault, RaiseAbstractionFault, NarrowFault, NilFault, NestedProcFault, DebugPutChar, CheckProc