///Users/CHauser.pa/Dragonware/DragonRuntimeSupport.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) January 27, 1987 7:30:51 pm PST
Carl Hauser, April 17, 1987 11:32:59 am PDT
This definitions file describes the runtime support assumed by the compiler. There is a Dragon flavor right now, but we will slowly get this stuff to be machine independent.
DragonRuntimeSupport: CEDAR DEFINITIONS = BEGIN
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 = LONG POINTER TO Word;
Word: TYPE = PACKED ARRAY [0..bitsPerWord) OF BOOL;
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
These definitions are partial. For more details, see DragonProcesses.mesa.
RegArrayPtr: TYPE = LONG POINTER TO RegArray;
RegArray: TYPE = ARRAY [0..15] OF Word;
ExceptAny: TYPE = SIGNAL ANY RETURNS ANY;
Denotes any SIGNAL or ERROR
For locks & processes
These definitions are partial. For details, see DragonProcesses.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
Process: TYPE = LONG POINTER TO ProcessRep; -- for PROCESS
ProcessRep: TYPE;
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)
RealCompare: PROC [x, y: REAL] RETURNS [Comparison];
compares x and y
raises RealException as specified by the IEEE standard
RealAdd: PROC [x, y: REAL] RETURNS [REAL];
returns x + y
raises RealException as specified by the IEEE standard
RealSub: PROC [x, y: REAL] RETURNS [REAL];
returns x - y
raises RealException as specified by the IEEE standard
RealMul: PROC [x, y: REAL] RETURNS [REAL];
returns x * y
raises RealException as specified by the IEEE standard
RealDiv: PROC [x, y: REAL] RETURNS [REAL];
returns x / y
raises RealException as specified by the IEEE standard
RealMod: PROC [x, y: REAL] RETURNS [REAL];
returns x MOD y == x - Trunc[x/y]*y
raises RealException as specified by the IEEE standard
RealScale: PROC [r: REAL, scale: INTEGER] RETURNS [REAL];
returns r*(2**scale)
raises RealException as specified by the IEEE standard
Float: PROC [int: INT] RETURNS [REAL];
returns the real number most closely corresponding to int
raises RealException as specified by the IEEE standard
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: ERROR;
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).
Vectors
Moving
Multi-word variables are transferred via these built-in routines.
MoveWords: PROC [src: PTR, dst: PTR, nWords: INT];
Moves words from the source to the destination. No words are moved if nWords d 0. Increasing addresses are used. If the variables overlap, words are transferred singly, otherwise MoveWords is the same as MoveWordsDisjoint.
MoveWordsDisjoint: PROC [src: PTR, dst: PTR, nWords: INT];
Moves words from the source to the destination. No words are moved if nWords d 0. Increasing addresses are used. For efficiency, no check is made for overlapping variables, but the caller assures disjointness.
Filling
The ALL construct allows for filling of arrays. Assignment of some kinds of constant multi-word variables can be handled similarly. For sub-word arrays, the compiler promotes the filling to word or field assignment.
FillWords: PROC [src: Word, dst: PTR, nWords: INT];
Initializes words in the destination to the src word. No words are moved if nWords d 0. Increasing dst addresses are used. Useful for ALL[foo].
FillMultiWords: PROC [src: PTR, srcSize: INT, dst: PTR, nTimes: INT];
Initializes words in the destination to the src words (starting at src for srcSize words). No words are moved if nTimes d 0. Increasing addresses are used. Useful for ALL[foo].
Equality
Multi-word variables need multi-word equality testing.
EqualWords: PROC [x: PTR, y: PTR, nWords: INT] RETURNS [BOOL];
Tests the two multi-word variables for equality.
Fields
When the compiler encounters really difficult cases it emits calls to these routines.
ExtractField: PROC [base: PTR, offset: INT, bits: [0..bitsPerWord]] RETURNS [Word];
Extracts the field from any base pointer at any reasonable 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 reasonable bit offset. The word given has the bits right-justified.
MoveFields: PROC [
src: PTR, srcOffset: INT, dst: PTR, dstOffset: PTR,
bits: [0..bitsPerWord], times: INT];
Moves fields that are bits wide from the src address (plus srcOffset bits) to the dst address (plus dstOffset bits) for times number of fields. Increasing addresses will be used. If the source and destination overlap then single-field transfers will be used.
FillFields: PROC [dst: PTR, dstOffset: PTR, bits: [0..bitsPerWord], times: INT, value: Word];
Fills fields that are bits wide in the dst address (plus dstOffset bits) for times number of fields. Increasing addresses will be used. The fill value will be right-justified in value.
Monitors & Processes
Fork: PROC [proc: ProcAny, args: PTR] RETURNS [Process];
Takes a procedure and pointer to the arguments and forks a new process to execute the procedure.
Join: PROC [process: Process] RETURNS [rets: PTR];
Takes a process, waits for it to finish, and returns a pointer to the return record.
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, lock: LockPtr];
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, lock: LockPtr];
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 Extensions
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.
ExtensionAlloc: PROC [nWords: INT] RETURNS [PTR];
Allocates a frame extension large enough to hold nWords worth of data.
ExtensionFree: PROC [ptr: PTR] RETURNS [PTRNIL];
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 [module: PTR, args: PTR];
Starts a module (with given arguments). Used to implement START prog.
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
The signaller finds the appropriate handler by looking in tables passed from the compiler to the runtime system via the loader. These tables provide a PC to handler map, where the handler is given as a PC.
For signals and errors, argument and return records are always passed by reference, rather than sometimes by value (as in current PrincOps). We think that the added uniformity is worth the slight additional runtime cost.
HandlerAction: TYPE = {reject, resume, exit};
BytePC: TYPE = WORD;
HandlerType: TYPE = PROC
[regsPtr: RegArrayPtr, except: ExceptAny, rtnPtr: PTR, argPtr: PTR] RETURNS[action: HandlerAction, pc: BytePC, levels: NAT];
This is the type of the handler procedure. The regsPtr passed in gives the saved registers for the frame containing the handler. The signal denotes which exception is being raised, and the args give the argument record for the signal.
The return values generated by RESUME are assigned to rtns^.
pc and levels are significant only if action=exit, corresponding to the source constructs GO TO, RETRY, and CONTINUE from within catch phrases. pc denotes the program counter to be used by the frame containing the target of the GOTO out of the catch phrase, and levels deenotes the number of levels of nested catch phrases to be unwound. In the simplest possible situation
p[args ! err => CONTINUE]
levels should be 1.
RaiseSignal: PROC [which: ExceptAny, rtns: PTR, args: PTR];
Raises the named signal with the given argument record. Used for result ← SIGNAL which[args]. rtns^ is assigned the return record supplied by RESUME.
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.
AbortedError: ERROR;
Corresponds to ABORTED.
UnwindError: ERROR;
Corresponds to UNWIND.
UnnamedError: ERROR;
Corresponds to unnamed ERROR.
UnnamedSignal: SIGNAL;
Corresponds to unnamed SIGNAL.
UncaughtError: ERROR;
Corresponds to RuntimeError.UNCAUGHT, which may be built-in some day.
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.
AssignNil: PROC [dstPtr: RefPtr];
Atomically assigns NIL to a reference-containing cell.
AssignRefComposite: 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).
AssignRefCompositeFault: ERROR;
Here for completeness. Not actually used by the compiler.
IncRC: PROC [ref: REF];
Increments the RC of a given reference. Useful when initializing a newly allocated object.
DecRC: PROC [ref: REF];
Decrements the RC of a given reference. Useful??
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 ...
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.
NarrowFault: ERROR [ref: REF, type: Type];
This error is raised by Narrow when the type of the reference is not equal to the expected type.
AssignProc: PROC [dstPtr: ProcPtr, src: ProcAny];
Assigns the procedure to the given cell, checking for scope violations (only NIL or outer-level procedures can be assigned). Performs reference-counting if src or dstPtr^ is a valid REF. Raises NestedProcError if assigning a nested procedure.
CheckProc: PROC [proc: ProcAny];
Checks the procedure for being assignable. Raises NestedProcError if the proc is nested.
NestedProcError: ERROR [proc: ProcAny];
Raised if the procedure described by proc is a nested procedure.
NewObject: PROC [nWords: 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.
END.