RTTypesBridgeImpl.Mesa
last modified on November 16, 1983 10:39 pm by Paul Rovner
Russ Atkinson, January 30, 1984 2:33:39 pm PST
RRA: fixed TVEqual for bogus world check
Richard Koo, July 2, 1984 5:01:47 pm PDT
DIRECTORY
AMBridge USING[TVHeadType, GetWorld, OctalRead, Loophole, WordSequence, RemotePointer, WordSequenceRecord],
AMTypes,
Atom USING[MakeAtom],
Basics USING[BITSHIFT, bitsPerWord, LongNumber, LowHalf],
PrincOpsUtils USING[LongCOPY],
RCMap USING[nullIndex],
Rope USING[ROPE],
RTCommon USING
[FetchField, FetchFieldLong, StoreFieldLong, ShortenLongCardinal, ShortenLongInteger, Field],
RTSymbolDefs USING[SymbolTableBase, symbolIndexForTYPE],
RTSymbolOps USING[AcquireType],
RTSymbols USING[GetTypeSymbols, ReleaseSTB],
RTTypesBasicPrivate USING[MapTiRcmx],
RTTypesPrivate USING[TypedVariableRec, BitsForType, ValueAddress, FieldDescriptor, GetOrigin, GetValueAddress],
RTTypesRemotePrivate USING
[GetRemoteGFHeader, GetRemoteWords, RemoteStoreWord, RemoteStoreDoubleWord, RemoteStoreFieldLong, GetRemoteWord, GetRemoteLC],
SafeStorage USING[GetReferentType, Type, nullType, anyType],
SafeStoragePrivate USING[ValidateRef],
WorldVM USING[CurrentIncarnation, Long, LocalWorld, World, Write, CopyWrite];
RTTypesBridgeImpl: PROGRAM
IMPORTS
AMBridge, AMTypes, Atom, Basics, PrincOpsUtils, RTCommon, RTSymbolOps, RTSymbols, RTTypesBasicPrivate, RTTypesPrivate, RTTypesRemotePrivate, SafeStorage, SafeStoragePrivate, WorldVM
EXPORTS
AMTypes, AMBridge, RTTypesPrivate
= BEGIN OPEN
AMBridge, AMTypes, Basics, Rope, tp: RTTypesPrivate, RTCommon, SafeStorage, RTTypesRemotePrivate, WorldVM;
T Y P E S
TypedVariableRec: TYPE = tp.TypedVariableRec;
Pointer: TYPE = LONG POINTER --TO UNSPECIFIED--;
checkMutable: BOOLTRUE;
PROCs exported to AMTypes
IsAtom: PUBLIC SAFE PROC
[tv: TypedVariable--ref any--] RETURNS[ans: BOOLTRUE] = TRUSTED {
[] ← Coerce[tv, CODE[ATOM] ! Error => {ans ← FALSE; CONTINUE}]};
IsRope: PUBLIC SAFE PROC
[tv: TypedVariable--ref any--] RETURNS[ans: BOOLTRUE] = TRUSTED {
[] ← Coerce[tv, CODE[ROPE] ! Error => {ans ← FALSE; CONTINUE}];
};
IsRefAny: PUBLIC SAFE PROC[type: Type--ref--] RETURNS[ans: BOOLTRUE] = TRUSTED {
type ← UnderType[type];
RETURN[TypeClass[type] = ref AND Range[type] = anyType];
};
TVHead: PUBLIC PROC[tv: TypedVariable] RETURNS[AMBridge.TVHeadType] = {
IF tv = NIL THEN RETURN[notTVRecord];
WITH tv SELECT FROM
tvr: REF TypedVariableRec => RETURN[tvr.head.tag];
ENDCASE => RETURN[notTVRecord];
};
TVType: PUBLIC SAFE PROC[tv: TypedVariable] RETURNS[type: Type] = TRUSTED {
raises badTV
IF tv = NIL THEN RETURN[nullType];
WITH tv SELECT FROM
tr: REF TypedVariableRec => RETURN[tr.referentType.type];
ENDCASE => ERROR;
};
TVStatus: PUBLIC SAFE PROC[tv: TypedVariable] RETURNS[Status] = TRUSTED {
IF tv = NIL THEN RETURN[readOnly];
WITH tv SELECT FROM
tr: REF TypedVariableRec => RETURN[tr.status];
ENDCASE => ERROR
};
TVForReferent: PUBLIC PROC
[ref: REF, status: Status ← mutable] RETURNS[tv: TypedVariable] = {
makes a REF ANY accessible as a TypedVariable.
type: Type;
bitsForType: LONG CARDINAL;
WITH ref SELECT FROM
a: ATOM => ERROR Error[reason: typeFault, type: CODE[ATOM]];
r: ROPE => ERROR Error[reason: typeFault, type: CODE[ROPE]];
ENDCASE;
type ← GetReferentType[ref];
IF type = nullType THEN RETURN[NIL];
bitsForType ← tp.BitsForType[type].bft;
IF bitsForType IN [1..bitsPerWord)
THEN
tv ← NEW[TypedVariableRec ← [
referentType: [type],
head: [reference[ref: ref]],
status: status,
field: embedded
[fd: [
wordOffset: 0,
extent: small[
field: [bitFirst: bitsPerWord-bitsForType, bitCount: bitsForType]]]]]]
ELSE
tv ← NEW[TypedVariableRec ← [
referentType: [type],
head: [reference[ref: ref]],
status: status,
field: entire[]]]};
TVForReadOnlyReferent: PUBLIC PROC
[ref: REF READONLY ANY] RETURNS[TypedVariable] = {
makes a TypedVariable accessible as a REF ANY.
RETURN[TVForReferent[ref: LOOPHOLE[ref], status: readOnly]]};
RefFromTV: PUBLIC PROC[tv: TypedVariable] RETURNS[REF ANY] = {
Raises internalTV if value is not a collectible object, notMutable if TVStatus[tv] # mutable. NOTE the result may carry a wider (narrower?) type!
WITH tv SELECT FROM
tr: REF TypedVariableRec =>
SELECT TRUE FROM
tr.tag # entire => ERROR Error[reason: internalTV];
checkMutable AND tr.status # mutable => ERROR Error[reason: notMutable];
ENDCASE =>
WITH head: tr.head SELECT FROM
reference => RETURN[head.ref];
ENDCASE => ERROR Error[reason: internalTV];
ENDCASE => ERROR;
};
ReadOnlyRefFromTV: PUBLIC PROC[tv: TypedVariable --, status: readOnly--]
RETURNS[REF READONLY ANY] = {
raises internalTV Like RefFromTV, but accepts only readOnly TVs, returns REF READONLY.
WITH tv SELECT FROM
tr: REF TypedVariableRec => {
IF tr.tag # entire
THEN ERROR Error[reason: internalTV]
ELSE WITH head: tr.head SELECT FROM
reference => RETURN[LOOPHOLE[head.ref]];
ENDCASE => ERROR Error[reason: internalTV]};
ENDCASE => ERROR};
SomeRefFromTV: PUBLIC PROC[tv: TypedVariable] RETURNS[REF ANY] = {
Like RefFromTV, but copies instead of raising an error.
WITH tv SELECT FROM
tr: REF TypedVariableRec =>
IF tr.tag # entire OR (checkMutable AND tr.status # mutable) OR tr.head.tag # reference
THEN WITH Copy[tv] SELECT FROM
tr: REF TypedVariableRec =>
WITH head: tr.head SELECT FROM
reference => RETURN[head.ref];
ENDCASE => ERROR Error[reason: internalTV, msg: "not a REF head"];
ENDCASE => ERROR
ELSE RETURN[RefFromTV[tv]];
ENDCASE => ERROR};
TVForATOM: PUBLIC PROC[atom: ATOM] RETURNS[TypedVariable--atom--] = {
RETURN[TVForReadOnlyReferent[NEW[ATOM ← atom]]]};
TVToATOM: PUBLIC PROC[tv: TypedVariable--atom--] RETURNS[ATOM] = {
raises typeFault
type: Type = UnderType[TVType[tv]];
SELECT TypeClass[type] FROM
ref =>
IF Range[type] = anyType THEN RETURN [TVToATOM[Coerce[tv, CODE[ATOM]]]];
atom => RETURN [Atom.MakeAtom[TVToName[tv]]];
ENDCASE;
ERROR Error[reason: typeFault, type: type];
};
TVForROPE: PUBLIC PROC[rope: ROPE] RETURNS[TypedVariable--rope--] = {
use TVToName to get the ROPE back
RETURN[TVForReadOnlyReferent[NEW[ROPE ← rope]]]};
TVForPointerReferent: PUBLIC PROC[ptr: Pointer, type: Type, status: Status ← mutable]
RETURNS[tv: TypedVariable] = {
These procedures map Pointers, proc descs and frames to TypedVariables and vice versa.
bitsForType: LONG CARDINAL ← bitsPerWord--not smaller than a word--;
IF ptr = NIL THEN RETURN[NIL];
bitsForType ← tp.BitsForType[
type
! Error => IF reason = typeFault THEN CONTINUE; -- not smaller than a word
].bft;
IF bitsForType IN [1..bitsPerWord)
THEN
tv ← NEW[TypedVariableRec ← [
referentType: [type],
head: [pointer[ptr: ptr]],
status: status,
field: embedded[fd: [
wordOffset: 0,
extent: small[field: [bitFirst: bitsPerWord-bitsForType,
bitCount: ShortenLongCardinal[bitsForType]]]]]]]
ELSE
tv ← NEW[TypedVariableRec ← [
referentType: [type],
head: [pointer[ptr: ptr]],
status: status,
field: entire[]]]};
PointerFromTV: PUBLIC PROC[tv: TypedVariable] RETURNS[Pointer] = {
raises typeFault
Raises internalTV if tv is embedded and not word aligned
Raises notMutable if TVStatus[tv] # mutable.
GetHeadPointer: PROC[tr: REF TypedVariableRec] RETURNS[p: Pointer] = INLINE {
WITH head: tr.head SELECT FROM
pointer => p ← head.ptr;
reference => ERROR Error[reason: typeFault, type: nullType];
gfh => p ← head.gfh;
fh => p ← head.fh;
ENDCASE => ERROR Error[reason: typeFault, type: nullType];
};
IF tv = NIL THEN RETURN[NIL];
WITH tv SELECT FROM
tr: REF TypedVariableRec => {
IF checkMutable AND tr.status # mutable THEN ERROR Error[reason: notMutable];
WITH etr: tr SELECT FROM
embedded =>
WITH fd: etr.fd SELECT FROM
large => RETURN[GetHeadPointer[tr] + fd.wordOffset];
small => IF fd.field.bitFirst = 0
THEN RETURN[GetHeadPointer[tr] + fd.wordOffset]
ELSE ERROR Error[reason: internalTV];
ENDCASE => ERROR;
entire => RETURN[GetHeadPointer[tr]]; --may have been narrowed--
ENDCASE => ERROR}
ENDCASE => ERROR Error[reason: typeFault, type: nullType]};
GetValueAddress: PUBLIC PROC
[tv: TypedVariable, mutableOnly: BOOLEANFALSE] RETURNS[tp.ValueAddress] = {
Raises notMutable
IF tv = NIL
THEN IF mutableOnly
THEN ERROR Error[reason: notMutable]
ELSE {
ws: WordSequence = NEW[WordSequenceRecord[2]];
LOOPHOLE[@ws[0], LONG POINTER TO LONG POINTER] ^ ← NIL;
RETURN[[constant[value: ws]]]};
IF mutableOnly
THEN WITH tv SELECT FROM
tr: REF TypedVariableRec =>
WITH h: tr.head SELECT FROM
gfh => IF NOT h.gfh.started THEN ERROR Error[reason: notMutable];
remoteGFH
=> IF NOT GetRemoteGFHeader[h.remoteGlobalFrameHandle].started
THEN ERROR Error[reason: notMutable];
ENDCASE;
ENDCASE => ERROR;
WITH tv SELECT FROM
tr: REF TypedVariableRec => {
IF mutableOnly AND checkMutable AND tr.status # mutable
THEN ERROR Error[reason: notMutable];
WITH head: tr.head SELECT FROM
pointer => {
ptr: Pointer ← head.ptr;
WITH etr: tr SELECT FROM
embedded => RETURN[[pointer[ptr: ptr + etr.fd.wordOffset, fd: etr.fd]]];
entire => RETURN[[pointer[ptr: ptr,
fd: [wordOffset: 0, extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
reference => {
ptr: Pointer ← LOOPHOLE[head.ref];
WITH etr: tr SELECT FROM
embedded => RETURN[[pointer[ptr: ptr + etr.fd.wordOffset, fd: etr.fd]]];
entire => RETURN[[pointer[ptr: ptr,
fd: [wordOffset: 0, extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
gfh => {
ptr: Pointer ← head.gfh;
WITH etr: tr SELECT FROM
embedded => RETURN[[pointer[ptr: ptr + etr.fd.wordOffset, fd: etr.fd]]];
entire => RETURN[[pointer[ptr: ptr,
fd: [wordOffset: 0, extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
fh => {
ptr: Pointer ← head.fh;
WITH etr: tr SELECT FROM
embedded => RETURN[[pointer[ptr: ptr + etr.fd.wordOffset, fd: etr.fd]]];
entire => RETURN[[pointer[ptr: ptr,
fd: [wordOffset: 0, extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
constant => WITH etr: tr SELECT FROM
constant => RETURN[[constant[value: etr.value]]];
ENDCASE => ERROR;
remotePointer => {
ptr: RemotePointer ← head.remotePointer;
WITH etr: tr SELECT FROM
embedded => {ptr.ptr ← ptr.ptr + etr.fd.wordOffset;
RETURN[[remotePointer[ptr: ptr, fd: etr.fd]]]};
entire => RETURN[[remotePointer[ptr: ptr,
fd: [wordOffset: 0,
extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
remoteReference => {
ptr: RemotePointer ← [world: head.remoteRef.world,
worldIncarnation: CurrentIncarnation[head.remoteRef.world],
ptr: head.remoteRef.ref];
WITH etr: tr SELECT FROM
embedded => {ptr.ptr ← ptr.ptr + etr.fd.wordOffset;
RETURN[[remotePointer[ptr: ptr, fd: etr.fd]]]};
entire => RETURN[[remotePointer[ptr: ptr,
fd: [wordOffset: 0,
extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
copiedRemoteObject => {
ptr: Pointer ← @head.copy[0];
WITH etr: tr SELECT FROM
embedded =>
RETURN[[copiedRemoteObject[ptr: ptr + etr.fd.wordOffset, fd: etr.fd]]];
entire =>
RETURN[[copiedRemoteObject
   [ptr: ptr, fd: [wordOffset: 0, extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
remoteGFH => {
ptr: RemotePointer ← [world: head.remoteGlobalFrameHandle.world,
worldIncarnation: CurrentIncarnation[head.remoteGlobalFrameHandle.world],
ptr: Long[world: head.remoteGlobalFrameHandle.world,
addr: head.remoteGlobalFrameHandle.gfh]];
WITH etr: tr SELECT FROM
embedded => {
ptr.ptr ← ptr.ptr + etr.fd.wordOffset;
RETURN[[remotePointer[ptr: ptr, fd: etr.fd]]];
};
entire =>
RETURN[[remotePointer[ptr: ptr, fd: [wordOffset: 0,
          extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
remoteFH => {
ptr: RemotePointer ← [world: head.remoteFrameHandle.world,
worldIncarnation: CurrentIncarnation[head.remoteFrameHandle.world],
ptr: Long[world: head.remoteFrameHandle.world, addr: head.remoteFrameHandle.fh]];
WITH etr: tr SELECT FROM
embedded => {
ptr.ptr ← ptr.ptr + etr.fd.wordOffset;
RETURN[[remotePointer[ptr: ptr, fd: etr.fd]]];
};
entire =>
RETURN[[remotePointer[ptr: ptr, fd: [wordOffset: 0,
          extent: large[size: TVSize[tv]]]]]];
ENDCASE => ERROR Error[reason: notMutable]};
remoteConstant => WITH etr: tr SELECT FROM
constant => RETURN[[constant[value: etr.value]]];
ENDCASE => ERROR;
ENDCASE => ERROR Error[reason: notMutable]};
ENDCASE => ERROR;
}; -- end GetValueAddress
TVEq: PUBLIC SAFE PROC[tv1, tv2: TypedVariable] RETURNS [BOOLEAN] = TRUSTED {
Two TypedVariables are Eq if they address the same bits.
Two TypedVariables are Equal if their values have the same size and the same bits.
NOTE there is no type checking in these comparisons.
RETURN[EQValueAddress[GetValueAddress[tv1], GetValueAddress[tv2]]]};
EQValueAddress: PROC[a1, a2: tp.ValueAddress] RETURNS[BOOLEAN] = {
fd1, fd2: tp.FieldDescriptor;
WITH t: a1 SELECT FROM
constant => {
IF a2.tag # constant
OR t.value.size # NARROW[a2, constant tp.ValueAddress].value.size
THEN RETURN[FALSE];
FOR i: NAT IN [0..t.value.size)
DO IF t.value[i] # NARROW[a2, constant tp.ValueAddress].value[i]
THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE]};
pointer => {
IF a2.tag # pointer THEN RETURN[FALSE];
IF t.ptr # NARROW[a2, pointer tp.ValueAddress].ptr
THEN RETURN[FALSE];
fd1 ← t.fd;
fd2 ← NARROW[a2, pointer tp.ValueAddress].fd;
};
remotePointer => {
IF a2.tag # remotePointer THEN RETURN[FALSE];
IF t.ptr # NARROW[a2, remotePointer tp.ValueAddress].ptr
THEN RETURN[FALSE];
fd1 ← t.fd;
fd2 ← NARROW[a2, remotePointer tp.ValueAddress].fd;
};
copiedRemoteObject => {
IF a2.tag # copiedRemoteObject THEN RETURN[FALSE];
IF t.ptr # NARROW[a2, copiedRemoteObject tp.ValueAddress].ptr
THEN RETURN[FALSE];
fd1 ← t.fd;
fd2 ← NARROW[a2, copiedRemoteObject tp.ValueAddress].fd;
};
ENDCASE;
WITH f1: fd1 SELECT FROM
small => WITH f2: fd2 SELECT FROM
small => IF f1.field # f2.field THEN RETURN[FALSE];
ENDCASE => RETURN[FALSE];
large => WITH f2: fd2 SELECT FROM
large => IF f1.size # f2.size THEN RETURN[FALSE];
ENDCASE => RETURN[FALSE];
ENDCASE;
RETURN[TRUE]};
TVEqual: PUBLIC SAFE PROC[tv1, tv2: TypedVariable] RETURNS [BOOLEAN] = TRUSTED {
class1: Class ← AMTypes.UnderClass[AMTypes.TVType[tv1]];
class2: Class ← AMTypes.UnderClass[AMTypes.TVType[tv2]];
size1,size2: INT;
IF TVEq[tv1, tv2] THEN RETURN [TRUE];
SELECT class1 FROM
localFrame, globalFrame => RETURN [FALSE];
ENDCASE;
SELECT class2 FROM
localFrame, globalFrame => RETURN [FALSE];
ENDCASE;
size1 ← AMTypes.TVSize[tv1];
size2 ← AMTypes.TVSize[tv2];
IF size1 # size2 THEN RETURN [FALSE];
IF size1 <= 2 THEN RETURN[TVToLC[tv1] = TVToLC[tv2]];
FOR i: INT IN [0..size1) DO
IF AMBridge.OctalRead[tv1, i] # AMBridge.OctalRead[tv2, i]
THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
TVForType: PUBLIC PROC [type: Type] RETURNS [ntv: TVNIL] = {
stb: RTSymbolDefs.SymbolTableBase = RTSymbols.GetTypeSymbols[type].stb;
{ ENABLE UNWIND => RTSymbols.ReleaseSTB[stb];
ntv ← AMBridge.Loophole[
tv: TVForReferent[NEW[CARDINAL ← type]],
type: RTSymbolOps.AcquireType[stb, LOOPHOLE[RTSymbolDefs.symbolIndexForTYPE]]];
};
RTSymbols.ReleaseSTB[stb];
};
TVToLC: PUBLIC PROC[tv: TypedVariable] RETURNS[lc: LONG CARDINAL] = {
These procedures make 1 or 2 word values available as bit patterns, and vice versa.
raises typeFault if the field is bigger than 2 words, else PUNs its value (right justified, zero filled) into a LONG CARDINAL.
a: tp.ValueAddress = GetValueAddress[tv];
ptr: Pointer;
fd: tp.FieldDescriptor;
WITH t: a SELECT FROM
constant =>
RETURN[
SELECT t.value.size FROM
1 => LONG[LOOPHOLE[t.value[0], CARDINAL]] + tp.GetOrigin[TVType[tv]],
2 => LOOPHOLE[@t.value[0], LONG POINTER TO LONG CARDINAL]^
 + tp.GetOrigin[TVType[tv]],
ENDCASE => ERROR Error[reason: typeFault, type: TVType[tv]]
];
pointer => {ptr ← t.ptr; fd ← t.fd};
remotePointer => {
WITH f: t.fd SELECT FROM
large => {
SELECT f.size FROM
1 => lc ← LONG[LOOPHOLE[GetRemoteWord[remotePointer: t.ptr], CARDINAL]];
2 => lc ← GetRemoteLC[remotePointer: t.ptr];
ENDCASE => ERROR Error[reason: typeFault, type: TVType[tv]];
lc ← LOOPHOLE[LOOPHOLE[lc, LONG INTEGER] + tp.GetOrigin[TVType[tv]],
     LONG CARDINAL];
RETURN};
small => {
word: WORD ← GetRemoteWord[remotePointer: t.ptr];
RETURN[FetchFieldLong[@word, f.field] + tp.GetOrigin[TVType[tv]]]};
ENDCASE => ERROR};
copiedRemoteObject => {ptr ← t.ptr; fd ← t.fd};
ENDCASE;
WITH f: fd SELECT FROM
large => {
SELECT f.size FROM
1 => lc ← LONG[LOOPHOLE[ptr, LONG POINTER TO CARDINAL]^];
2 => lc ← LOOPHOLE[ptr, LONG POINTER TO LONG CARDINAL]^;
ENDCASE => ERROR Error[reason: typeFault, type: TVType[tv]];
lc ← LOOPHOLE[LOOPHOLE[lc, LONG INTEGER] + tp.GetOrigin[TVType[tv]],
     LONG CARDINAL];
RETURN};
small => lc ← FetchFieldLong[ptr, f.field] + tp.GetOrigin[TVType[tv]];
ENDCASE => ERROR;
};
TVToInteger: PUBLIC PROC[tv: TypedVariable] RETURNS[INTEGER] = {
RETURN[ShortenLongInteger[TVToLI[tv]]]
};
TVToLI: PUBLIC PROC[tv: TypedVariable] RETURNS[LONG INTEGER] = {
lc: LONG CARDINAL ← TVToLC[tv];
IF TVSize[tv] = 1 AND TypeClass[GroundStar[TVType[tv]]] = integer
THEN RETURN[LONG[LOOPHOLE[Basics.LowHalf[lc], INTEGER]]]
sign extend.
ELSE RETURN[LOOPHOLE[lc, LONG INTEGER]]};
TVToRef: PUBLIC PROC[tv: TV] RETURNS[ref: REF] = {
IF GetWorld[tv] # LocalWorld[] THEN
ERROR Error[reason: typeFault, msg: "Can't get a local REF for a remote object"];
SELECT TypeClass[UnderType[TVType[tv]]] FROM
nil => ref ← NIL;
atom, rope, list, ref => {
ref ← LOOPHOLE[TVToLC[tv], REF ANY];
IF TVHead[tv] = fh THEN SafeStoragePrivate.ValidateRef[ref];
};
ENDCASE => ERROR Error[reason: typeFault, type: TVType[tv]];
};
TVToReal: PUBLIC PROC[tv: TypedVariable] RETURNS[REAL] = {
RETURN[LOOPHOLE[TVToLC[tv], REAL]]};
TVToCardinal: PUBLIC PROC[tv: TypedVariable] RETURNS[CARDINAL] = {
RETURN[ShortenLongCardinal[TVToLC[tv]]]};
TVToCharacter: PUBLIC PROC[tv: TypedVariable] RETURNS[CHARACTER] = {
raises rangeFault
ans: INTEGER = TVToInteger[tv];
IF ans IN [(FIRST[CHARACTER] - 0C)..(LAST[CHARACTER] - 0C)]
THEN RETURN[LOOPHOLE[ans, CHARACTER]]
ELSE ERROR Error[reason: rangeFault]};
TVToWordSequence: PUBLIC PROC[tv: TypedVariable] RETURNS [s: WordSequence] = {
ptr: Pointer;
words: CARDINAL = TVSize[tv];
SELECT words FROM
0 => s ← NEW[WordSequenceRecord[0]];
1 => {
s ← NEW[WordSequenceRecord[1]];
s[0] ← ShortenLongCardinal[TVToLC[tv]];
RETURN;
};
2 => {
s ← NEW[WordSequenceRecord[2]];
LOOPHOLE[@s[0], LONG POINTER TO LONG CARDINAL]^ ← TVToLC[tv];
RETURN;
};
ENDCASE => {
a: tp.ValueAddress ← GetValueAddress[tv];
WITH t: a SELECT FROM
constant => RETURN[t.value];
pointer => ptr ← t.ptr;
remotePointer => RETURN[GetRemoteWords[remotePointer: t.ptr, nWords: words]];
copiedRemoteObject => ptr ← t.ptr;
ENDCASE => ERROR;
s ← NEW[WordSequenceRecord[words]];
PrincOpsUtils.LongCOPY[from: ptr, nwords: words, to: @s[0]];
};
};
SetTVFromWordSequence: PUBLIC PROC[tv: AMTypes.TV, ws: WordSequence] = {
type: Type = AMTypes.TVType[tv];
a: tp.ValueAddress = tp.GetValueAddress[tv: tv, mutableOnly: TRUE];
WITH t: a SELECT FROM
remotePointer => {
IF IsRC[type] THEN
ERROR AMTypes.Error
  [reason: typeFault, msg: "can't do remote RC assignment", type: type];
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
0 => {};
1 => { -- target size
origin: INTEGER = tp.GetOrigin[type];
c: CARDINAL ← ws[0];
IF ws.size # 1 THEN ERROR;
IF origin # 0 THEN c ← LONG[LOOPHOLE[c, INTEGER] - origin];
WorldVM.Write[
world: AMBridge.GetWorld[tv],
addr: t.ptr.ptr,
value: c
];
};
ENDCASE =>
WorldVM.CopyWrite[
world: AMBridge.GetWorld[tv],
from: @ws[0],
nwords: ws.size,
to: t.ptr.ptr
];
small => {
lc: LONG CARDINALLOOPHOLE[
(LONG[LOOPHOLE[ws[0], INTEGER]] - tp.GetOrigin[type]),
LONG CARDINAL];
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc THEN ERROR Error[reason: rangeFault];
RTTypesRemotePrivate.RemoteStoreFieldLong[ptr: t.ptr, field: fd.field, value: lc]};
ENDCASE => ERROR};
copiedRemoteObject =>
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
0 => {};
1 => {
lc: LONG CARDINALLOOPHOLE[
(LONG[LOOPHOLE[ws[0], INTEGER]] - tp.GetOrigin[type]),
LONG CARDINAL];
LOOPHOLE[t.ptr, LONG POINTER TO CARDINAL]^
← RTCommon.ShortenLongCardinal[lc]};
ENDCASE => PrincOpsUtils.LongCOPY[from: @ws[0], nwords: ws.size, to: t.ptr];
small => {
lc: LONG CARDINALLOOPHOLE[
(LONG[LOOPHOLE[ws[0], INTEGER]] - tp.GetOrigin[type]),
LONG CARDINAL];
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc
THEN ERROR Error[reason: rangeFault];
RTCommon.StoreFieldLong[t.ptr, fd.field, lc]};
ENDCASE => ERROR;
pointer => {
IF IsRC[type] THEN ERROR AMTypes.Error[reason: typeFault, type: type];
WITH fd: t.fd SELECT FROM
large =>
SELECT fd.size FROM
1 => {
lc: LONG CARDINAL
LOOPHOLE[(LONG[LOOPHOLE[ws[0], INTEGER]]
- tp.GetOrigin[type]),
LONG CARDINAL];
LOOPHOLE[t.ptr, LONG POINTER TO CARDINAL]^
← RTCommon.ShortenLongCardinal[lc]};
ENDCASE => PrincOpsUtils.LongCOPY[from: @ws[0], nwords: ws.size, to: t.ptr];
small => {
lc: LONG CARDINAL
LOOPHOLE[
(LONG[LOOPHOLE[ws[0], INTEGER]] - tp.GetOrigin[type]),
LONG CARDINAL];
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc
THEN ERROR AMTypes.Error[reason: rangeFault];
RTCommon.StoreFieldLong[t.ptr, fd.field, lc]};
ENDCASE => ERROR};
ENDCASE => ERROR;
};
SetTVFromLC: PUBLIC PROC[tv: TypedVariable, lc: LONG CARDINAL] = {
raises typeFault, rangeFault
raises NotMutable if TVStatus[tv] # mutable; raises TypeFault if the tv type is RC or its value is bigger than 2 words, else PUNs lc into TVType[tv] and assigns it to the field specified by tv. NOTE this is a LOOPHOLE which may cause bounds checking to miss a bounds violation NOTE what about immutable variant records?
a: tp.ValueAddress ← GetValueAddress[tv, TRUE];
type: Type = TVType[tv];
lc ← LOOPHOLE[(LOOPHOLE[lc, LONG INTEGER] - tp.GetOrigin[type]), LONG CARDINAL];
WITH t: a SELECT FROM
pointer => {
IF IsRC[type] THEN ERROR Error[reason: typeFault, type: type];
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
1 => LOOPHOLE[t.ptr, LONG POINTER TO CARDINAL]^ ← ShortenLongCardinal[lc];
2 => LOOPHOLE[t.ptr, LONG POINTER TO LONG CARDINAL]^ ← lc;
ENDCASE => ERROR Error[reason: typeFault, type: type];
small => {
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc THEN ERROR Error[reason: rangeFault];
StoreFieldLong[t.ptr, fd.field, lc]};
ENDCASE => ERROR};
remotePointer => {
IF IsRC[type] THEN ERROR Error[reason: typeFault, type: type];
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
1 => RemoteStoreWord[t.ptr, ShortenLongCardinal[lc]];
2 => RemoteStoreDoubleWord[t.ptr, lc];
ENDCASE => ERROR Error[reason: typeFault, type: type];
small => {
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc THEN ERROR Error[reason: rangeFault];
RemoteStoreFieldLong[ptr: t.ptr, field: fd.field, value: lc]};
ENDCASE => ERROR};
copiedRemoteObject =>
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
1 => LOOPHOLE[t.ptr, LONG POINTER TO CARDINAL]^ ← ShortenLongCardinal[lc];
2 => LOOPHOLE[t.ptr, LONG POINTER TO LONG CARDINAL]^ ← lc;
ENDCASE => ERROR Error[reason: typeFault, type: type];
small => {
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc THEN ERROR Error[reason: rangeFault];
StoreFieldLong[t.ptr, fd.field, lc]};
ENDCASE => ERROR;
ENDCASE => ERROR;
};
SetTVFromLI: PUBLIC PROC[tv: TypedVariable, li: LONG INTEGER] = {
raises typeFault, rangeFault
a: tp.ValueAddress ← GetValueAddress[tv, TRUE];
type: Type = TVType[tv];
li ← li - tp.GetOrigin[type];
WITH t: a SELECT FROM
pointer => {
IF IsRC[type] THEN ERROR Error[reason: typeFault, type: type];
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
1 => LOOPHOLE[t.ptr, LONG POINTER TO INTEGER]^ ← ShortenLongInteger[li];
2 => LOOPHOLE[t.ptr, LONG POINTER TO LONG INTEGER]^ ← li;
ENDCASE => ERROR Error[reason: typeFault, type: type];
small => {lc: LONG CARDINAL = LOOPHOLE[li];
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc
THEN ERROR Error[reason: rangeFault];
StoreFieldLong[t.ptr, fd.field, lc]};
ENDCASE => ERROR};
remotePointer => {
IF IsRC[type] THEN ERROR Error[reason: typeFault, type: type];
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
1 => RemoteStoreWord[t.ptr, ShortenLongInteger[li]];
2 => RemoteStoreDoubleWord[t.ptr, li];
ENDCASE => ERROR Error[reason: typeFault, type: type];
small => {lc: LONG CARDINAL = LOOPHOLE[li];
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc
THEN ERROR Error[reason: rangeFault];
RemoteStoreFieldLong[ptr: t.ptr, field: fd.field, value: lc]};
ENDCASE => ERROR};
copiedRemoteObject =>
WITH fd: t.fd SELECT FROM
large => SELECT fd.size FROM
1 => LOOPHOLE[t.ptr, LONG POINTER TO INTEGER]^ ← ShortenLongInteger[li];
2 => LOOPHOLE[t.ptr, LONG POINTER TO LONG INTEGER]^ ← li;
ENDCASE => ERROR Error[reason: typeFault, type: type];
small => {
lc: LONG CARDINAL = LOOPHOLE[li];
IF Basics.BITSHIFT[1, fd.field.bitCount] <= lc THEN ERROR Error[reason: rangeFault];
StoreFieldLong[t.ptr, fd.field, lc]};
ENDCASE => ERROR;
ENDCASE => ERROR;
};
IsRC: PROC[type: Type] RETURNS[ans: BOOL] = {
RETURN[RTTypesBasicPrivate.MapTiRcmx[type] # RCMap.nullIndex]};
END.