<> <> <> <> <> <> <> <> <> <> <<(like RTSymbolDefs.TreeLink)>> <> <> DIRECTORY AMBridge USING [GetWorld, GetWorldIncarnation, GFHFromTV, IsRemote, Loophole, RemoteGFHFromTV, RemotePointer, RemoteRef, SetTVFromLC, SetTVFromLI, TVForPointerReferent, TVForReadOnlyReferent, TVForReferent, TVForRemotePointerReferent, TVForRemoteReferent, TVToCardinal, TVToLC, TVToLI, TVToProc, TVToRemoteProc, TVToRemoteSignal, TVToSignal, TVToWordSequence, WordSequence, WordSequenceRecord], AMTypes USING [Assign, Class, Domain, Error, First, Globals, IndexToName, IndexToType, IsAtom, IsComputed, IsOverlaid, IsRope, Last, Locals, NameToIndex, NComponents, Range, ReferentStatus, Size, Status, TVStatus, TVType, TypeClass, UnderType, VariableType], AtomsPrivate USING[AtomRec], CedarLinkerOps USING[GetFrame, IR, IRRecord, NullLink], Environment USING[bitsPerWord], Inline USING[BITSHIFT, HighHalf, LongNumber, LowHalf], List USING[AList], PrincOps USING[GlobalFrameHandle, ProcDesc, SignalDesc], RemoteRope USING[RemoteFetch, RemoteLength, RopeFromTV], Rope USING[Fetch, Length, ROPE, RopeRep], RTBasic USING[Index, TV, TypedVariable], RTCommon USING[FetchField, ShortenLongCardinal, ShortenLongInteger], RTStorageOps USING[NewObject, ValidateRef], RTSymbolDefs USING [SymbolConstructorIndex, SymbolIdIndex, SymbolIndex, SymbolRecordIndex, SymbolTableBase], RTSymbolOps USING [AcquireSequenceType, AcquireType, IDCardinalInfo, IDCardinalValue, ISEConstant, ISEImmutable, ISEType, IsSequence, SEBitsForType, SEUnderType], RTSymbols USING[GetTypeSymbols, ReleaseSTB], RTTCache USING[FillIntEntry, IntEntry, LookupInt], RTZones USING[ZoneRec], RTTypesBasic USING [anyType, EquivalentTypes, fhType, GetReferentType, gfhType, nullType, Type, unspecType], RTTypesPrivate, RTTypesRemotePrivate USING [GetRemoteReferentType, GetRemoteWord, RemoteGFHToName, RemotePDToName, RemoteSEDToName, RemoteTypeToLocal, ValidateRemoteRef], SafeStorage USING[NewZone], WorldVM USING[Address, CurrentIncarnation, LocalWorld, Long, World]; RTTypedVariablesImpl: PROGRAM IMPORTS AMBridge, AMTypes, CedarLinkerOps, Inline, RemoteRope, Rope, RTCommon, RTStorageOps, RTSymbolOps, RTSymbols, RTTCache, RTTypesBasic, RTTypesPrivate, RTTypesRemotePrivate, SafeStorage, WorldVM EXPORTS AMTypes, AMBridge, RTTypesPrivate SHARES Rope = BEGIN OPEN AMBridge, AMTypes, Environment, Rope, RTBasic, tp: RTTypesPrivate, RTCommon, RTStorageOps, RTSymbolDefs, RTSymbolOps, RTSymbols, RTTCache, RTTypesBasic, RTTypesRemotePrivate, WorldVM; <> TypedVariableRec: TYPE = tp.TypedVariableRec; Pointer: TYPE = LONG POINTER --TO UNSPECIFIED--; <> tvZone: ZONE = SafeStorage.NewZone[quantized]; tvPrefixedZone: ZONE = SafeStorage.NewZone[]; <> GetTVZones: PUBLIC PROC RETURNS[qz, pz: ZONE] = {RETURN[tvZone, tvPrefixedZone]}; <> New: PUBLIC SAFE PROC [type: Type, status: Status _ mutable, world: WorldVM.World _ NIL, tag: TV _ NIL] RETURNS[newTV: TypedVariable] = TRUSTED { <> variantClass: Class; length: CARDINAL _ 0; IF type = nullType THEN RETURN[NIL]; IF type = fhType OR type = gfhType THEN ERROR Error[reason: typeFault, type: type]; IF world = NIL THEN world _ WorldVM.LocalWorld[]; variantClass _ VariableType[type].c; <> <> IF tag # NIL AND variantClass = sequence THEN length _ TVToCardinal[tag]; IF world # WorldVM.LocalWorld[] THEN { <> IF tag # NIL AND (variantClass = union OR variantClass = sequence) THEN { ws: WordSequence _ tvPrefixedZone.NEW[WordSequenceRecord[Size[type, length]]]; newTV: TV _ tvZone.NEW[TypedVariableRec _ [ referentType: [ type, IF IsComputed[type] OR (variantClass = union AND IsOverlaid[type]) THEN tag ELSE NIL], head: [copiedRemoteObject [ world: world, worldIncarnation: CurrentIncarnation[world], copy: ws]], status: status, field: entire[]]]; newTag: TV; IF IsComputed[type] OR (variantClass = union AND IsOverlaid[type]) THEN RETURN[newTV]; <> newTag _ Tag[LastComponent[newTV, type]]; -- assume sharing NARROW[newTag, REF TypedVariableRec].status _ mutable; Assign[lhs: newTag, rhs: tag]; NARROW[newTag, REF TypedVariableRec].status _ readOnly; RETURN[newTV]; } ELSE RETURN [ tvZone.NEW[TypedVariableRec _ [ referentType: [type], head: [copiedRemoteObject [ world: world, worldIncarnation: CurrentIncarnation[world], copy: tvPrefixedZone.NEW[WordSequenceRecord[Size[type]]]]], status: status, field: entire[]]]]} -- end make a new remote TV ELSE { <> newTV _ TVForReferent[NewObject[type: type, size: Size[type, length]]]; -- cleared <> IF tag # NIL AND (variantClass = union OR variantClass = sequence) THEN IF IsComputed[type] OR (variantClass = union AND IsOverlaid[type]) THEN NARROW[newTV, REF TypedVariableRec].referentType.tag _ tag ELSE { newTag: REF TypedVariableRec _ NARROW[Tag[LastComponent[newTV, type]]]; IF newTag # NIL THEN { newTag.status _ mutable; Assign[lhs: newTag, rhs: tag]; newTag.status _ readOnly; }; }; RETURN[newTV]; }; }; -- end New TVTag: PROC[tv: TypedVariable] RETURNS[TV] = { <> RETURN[NARROW[tv, REF TypedVariableRec].referentType.tag]}; TVSize: PUBLIC SAFE PROC[tv: TypedVariable] RETURNS[INT--words--] = TRUSTED { <> <> type: Type = UnderType[TVType[tv]]; vClass: Class _ nil; class: Class _ TypeClass[type]; SELECT class FROM localFrame => RETURN [TVSize[AMTypes.Locals[tv]]]; globalFrame => RETURN [TVSize[AMTypes.Globals[tv]]]; record, structure, sequence, union => { SELECT class FROM record, structure => vClass _ VariableType[type].c; sequence, union => vClass _ class; ENDCASE; IF vClass # nil THEN { IF (IsOverlaid[type] OR IsComputed[type]) AND TVTag[tv] = NIL THEN RETURN[Size[type: type]]; SELECT vClass FROM union => RETURN [TVSize[Variant[LastComponent[tv, type]]]]; sequence => RETURN [Size[type: type, length: Length[LastComponent[tv, type]]]] ENDCASE; }; }; nil, ref, list, atom, rope, longPointer, basePointer, longCardinal, longInteger, real, countedZone, uncountedZone => RETURN [2]; integer, cardinal, character, pointer, unspecified, process, type, relativePointer, procedure, signal, error, program, port => RETURN [1]; ENDCASE; RETURN[Size[type: type]]; }; Tag: PUBLIC SAFE PROC[tv: TypedVariable--union, sequence--] RETURNS[ans: TypedVariable] = TRUSTED { type: Type = TVType[tv]; stb: SymbolTableBase; sei: SymbolIndex; kludgeBits: NAT _ 0; IF TVTag[tv] # NIL THEN RETURN[TVTag[tv]]; IF IsComputed[type] OR IsOverlaid[type] THEN RETURN[NIL]; [stb, sei] _ GetTypeSymbols[type]; {ENABLE UNWIND => ReleaseSTB[stb]; tagSei: SymbolIdIndex; WITH stb SELECT FROM t: SymbolTableBase.x => WITH ser: t.e.seb[t.e.UnderType[NARROW[sei, SymbolIndex.x].e]] SELECT FROM union => tagSei _ [x[ser.tagSei]]; sequence => tagSei _ [x[ser.tagSei]]; ENDCASE => ERROR Error[reason: typeFault, type: type]; t: SymbolTableBase.y => WITH ser: t.e.seb[t.e.UnderType[NARROW[sei, SymbolIndex.x].e]] SELECT FROM union => tagSei _ [y[ser.tagSei]]; sequence => tagSei _ [y[ser.tagSei]]; ENDCASE => ERROR Error[reason: typeFault, type: type]; ENDCASE => ERROR; IF ISEConstant[stb, tagSei] THEN ERROR; <<>> <> WITH tv SELECT FROM rtr: REF RTTypesPrivate.TypedVariableRec => WITH etr: rtr SELECT FROM constant => { ntv: TV _ AMBridge.TVForReadOnlyReferent[etr.value]; tv _ AMBridge.Loophole[ntv, type]; kludgeBits _ bitsPerWord; }; ENDCASE; ENDCASE; ans _ tvZone.NEW[TypedVariableRec _ [ referentType: [Domain[type]], head: (WITH tv SELECT FROM tr: REF TypedVariableRec => tr.head, ENDCASE => ERROR), status: readOnly, field: embedded[fd: BuildRecordFieldDescriptor [ parentTV: tv, fieldBitOffset: kludgeBits + IDCardinalValue[stb, tagSei], fieldBits: IDCardinalInfo[stb, tagSei], bitsForType: SEBitsForType[stb, ISEType[stb, tagSei]] ]] ]]; }; ReleaseSTB[stb]; }; -- end Tag Variant: PUBLIC SAFE PROC[tv: TypedVariable--union--] RETURNS[ans: TypedVariable _ NIL--record--] = TRUSTED { type: Type = TVType[tv]; p: PROC[stb: SymbolTableBase, isei: SymbolIdIndex] = { wordOffset: NAT _ 0; cType: Type _ AcquireType[ stb, LOOPHOLE[SEUnderType[stb, LOOPHOLE[isei, SymbolIndex]], SymbolIndex]]; <> ans _ AMBridge.Loophole[tv, cType]; }; -- end p IF LocalUnderClass[type] # union THEN ERROR Error[reason: typeFault, type: type]; tp.ComponentISEI[type, NameToIndex[type, TVToName[Tag[tv]]], p]; }; IndexToTV: PUBLIC SAFE PROC[tv: TypedVariable--record, structure--, index: Index] RETURNS[TypedVariable] = TRUSTED { <<[1..NComponents[TVType[tv]]]>> cType: Type; type: Type _ UnderType[TVType[tv]]; et: REF TypedVariableRec; argRec: BOOL; interfaceRec: BOOL; bitsForTV: LONG CARDINAL; BuildEmbeddedTV: PROC[stb: SymbolTableBase, isei: SymbolIdIndex] = { sei: SymbolIndex = ISEType[stb, isei]; csei: SymbolConstructorIndex _ SEUnderType[stb, sei]; bitsForType: CARDINAL _ SEBitsForType[stb, sei]; <> fieldBits: CARDINAL _ IDCardinalInfo[stb, isei]; <> fieldBitOffset: CARDINAL _ IF argRec THEN (WITH stb SELECT FROM t: SymbolTableBase.x => t.e.FnField[NARROW[isei, SymbolIdIndex.x].e].offset.wd*bitsPerWord, t: SymbolTableBase.y => t.e.FnField[NARROW[isei, SymbolIdIndex.y].e].offset.wd*bitsPerWord, ENDCASE => ERROR) ELSE IF interfaceRec THEN IDCardinalValue[stb, isei]*bitsPerWord ELSE IDCardinalValue[stb, isei]; <> isSequence: BOOL _ FALSE; WITH stb SELECT FROM -- NOTE SymbolPack bug workaround t: SymbolTableBase.x => WITH cse: t.e.seb[NARROW[csei, SymbolConstructorIndex.x].e] SELECT FROM relative => bitsForType _ t.e.BitsForType[cse.offsetType]; <> ENDCASE; t: SymbolTableBase.y => WITH cse: t.e.seb[NARROW[csei, SymbolConstructorIndex.y].e] SELECT FROM relative => bitsForType _ t.e.BitsForType[cse.offsetType]; ENDCASE ENDCASE => ERROR; IF (NOT Embedded[tv]) AND bitsForTV < bitsPerWord <> THEN fieldBitOffset _ fieldBitOffset + bitsPerWord - ShortenLongCardinal[bitsForTV]; IF IsSequence[stb, sei] THEN { recstb: SymbolTableBase; recsei: SymbolIndex; [recstb, recsei] _ GetTypeSymbols[type]; cType _ AcquireSequenceType[ stb, sei, recstb, LOOPHOLE[recsei, SymbolRecordIndex] ! UNWIND => ReleaseSTB[recstb]]; isSequence _ TRUE; ReleaseSTB[recstb]} ELSE cType _ AcquireType[stb, sei]; SELECT TRUE FROM ISEConstant[stb, isei] => { ENABLE Error => IF reason = notImplemented THEN GOTO nimp; IF IsRemote[tv] THEN et _ tvZone.NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [remoteConstant [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv]]], status: const, field: constant[value: tp.GetIdConstantValue[tv, stb, isei]] ]] ELSE et _ tvZone.NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [constant[]], status: const, field: constant[value: tp.GetIdConstantValue[tv, stb, isei]] ]]; EXITS nimp => et _ NIL}; interfaceRec AND NOT IsInterfaceElementType[cType] => { <> fD: tp.FieldDescriptor; headP: Pointer; ptr: POINTER; status: Status _ mutable; ir: CedarLinkerOps.IR; IF IsRemote[tv] THEN ERROR Error[reason: notImplemented, msg: "remote interface variables"]; WITH tv SELECT FROM tr: REF TypedVariableRec => WITH head: tr.head SELECT FROM reference => ir _ NARROW[head.ref, CedarLinkerOps.IR]; ENDCASE => ERROR Error[reason: internalTV]; ENDCASE => ERROR; fD _ BuildRecordFieldDescriptor[tv, fieldBitOffset, 16, 16]; <> headP _ LOOPHOLE[ir, Pointer]; <<>> <> ptr _ LOOPHOLE[headP + fD.wordOffset, LONG POINTER TO POINTER]^; IF CedarLinkerOps.NullLink[ptr] THEN {et _ NIL; RETURN}; -- not bound WITH stb SELECT FROM t: SymbolTableBase.x => WITH e: t.e.seb[NARROW[csei, SymbolConstructorIndex.x].e] SELECT FROM ref => IF e.var THEN {cType _ AcquireType[stb, [x[e.refType]]]; IF e.readOnly THEN status _ readOnly} ELSE {IF ISEImmutable[stb, isei] THEN status _ readOnly}; <> ENDCASE => IF ISEImmutable[stb, isei] THEN status _ readOnly; <> t: SymbolTableBase.y => WITH e: t.e.seb[NARROW[csei, SymbolConstructorIndex.y].e] SELECT FROM ref => IF e.var THEN {cType _ AcquireType[stb, [y[e.refType]]]; IF e.readOnly THEN status _ readOnly} ELSE {IF ISEImmutable[stb, isei] THEN status _ readOnly}; <> ENDCASE => IF ISEImmutable[stb, isei] THEN status _ readOnly; <> ENDCASE => ERROR; { gfh: PrincOps.GlobalFrameHandle = CedarLinkerOps.GetFrame[ interface: ir, index: fD.wordOffset - SIZE[CedarLinkerOps.IRRecord]]; et _ tvZone.NEW[TypedVariableRec _ [ referentType: [cType], head: [gfh[gfh: gfh]], status: status, field: embedded [fd: BuildLargeFieldDescriptor[wordOffset: ptr-gfh, nWords: Size[cType]]] ]]; }; }; Constant[tv] => WITH tv SELECT FROM tr: REF constant TypedVariableRec => { wordOffset: CARDINAL _ fieldBitOffset / bitsPerWord; words: CARDINAL _ fieldBits / bitsPerWord; ws: WordSequence _ NEW[WordSequenceRecord[MAX[1, words]]]; IF words > 0 THEN { <> lim: NAT = tr.value.size; FOR i: NAT IN [0..words) DO ws[i] _ IF (i+wordOffset) >= lim THEN 0 ELSE tr.value[i+wordOffset]; ENDLOOP; } ELSE { ws[0] _ FetchField[ @tr.value[wordOffset], [bitFirst: fieldBitOffset MOD bitsPerWord, bitCount: fieldBits]]; }; IF IsRemote[tv] THEN et _ tvZone.NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [remoteConstant [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv]]], status: const, field: constant[value: ws] ]] ELSE et _ tvZone.NEW [TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [constant[]], status: const, field: constant[value: ws] ]]; }; ENDCASE => ERROR ENDCASE => { under: Type = UnderType[cType]; forceWords: BOOL _ FALSE; wordOffset: CARDINAL _ 0; SELECT TypeClass[under] FROM union => { <> IF fieldBits < bitsPerWord THEN bitsForType _ fieldBits ELSE forceWords _ TRUE; }; sequence => forceWords _ TRUE; ENDCASE; IF forceWords THEN WITH tv SELECT FROM embed: REF embedded TypedVariableRec => wordOffset _ embed.fd.wordOffset; ENDCASE; et _ tvZone.NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: (WITH tv SELECT FROM tr: REF TypedVariableRec => tr.head, ENDCASE => ERROR), -- [reference[ref: tv]]), status: ( IF NOT interfaceRec AND ISEImmutable[stb, isei] THEN readOnly ELSE TVStatus[tv]), field: embedded[fd: ( IF forceWords THEN [wordOffset: wordOffset, extent: large[size: Size[type, 0]]] ELSE BuildRecordFieldDescriptor[tv, fieldBitOffset, fieldBits, bitsForType] )]]]; IF isSequence THEN { entry: RTTCache.IntEntry = RTTCache.LookupInt[under, GetSequenceOffset]; words: INT = Size[type, GetSequenceLength[et]]; WITH x: et SELECT FROM embedded => x.fd.extent _ large[size: words]; ENDCASE => ERROR; IF NOT entry.valid THEN <> [] _ RTTCache.FillIntEntry[entry, Size[type, 0]]; }; }}; -- END BuildEmbeddedTV <> [bitsForTV, argRec, interfaceRec] _ tp.BitsForType[type]; tp.RecordComponentISEI[type, index, BuildEmbeddedTV]; RETURN[et]; }; -- end IndexToTV GetSequenceOffset: SAFE PROC [type: Type] RETURNS [offset: INT] = TRUSTED { <<... returns the word offset of the first element of the sequence, -1 if there is no entry (should not happen unless you got the sequence TV without going through IndexToTV). Note that if RTTCache ever changes to allow flushing of entries that entries of this flavor must never be flushed!>> entry: RTTCache.IntEntry _ RTTCache.LookupInt[type, GetSequenceOffset]; offset _ entry.int; }; GetSequenceLength: SAFE PROC [tv: TV] RETURNS [length: INT _ 0] = TRUSTED { <> tag: TV = Tag[tv]; IF tag # NIL THEN { tagType: Type = TVType[tag]; length _ TVToLI[tag]; SELECT LocalUnderClass[tagType] FROM integer, longInteger, cardinal, longCardinal => {}; ENDCASE => length _ length - TVToLI[First[tagType]]; }; }; IsInterfaceElementType: PROC[type: Type] RETURNS[BOOL] = { SELECT LocalUnderClass[type] FROM program, procedure, signal, error => RETURN[TRUE]; ENDCASE => RETURN[FALSE]; }; TVToType: PUBLIC SAFE PROC[tv: TypedVariable--type--] RETURNS[rtn: Type] = TRUSTED { <> type: Type = UnderType[TVType[tv]]; SELECT TypeClass[type] FROM type => IF IsRemote[tv] THEN rtn _ RemoteTypeToLocal[world: GetWorld[tv], remoteType: TVToCardinal[tv]] ELSE rtn _ LOOPHOLE[TVToCardinal[tv], Type]; ENDCASE => ERROR Error[reason: typeFault, type: type]; }; PropertyList: PUBLIC SAFE PROC [tv: TypedVariable--atom--] RETURNS[rtn: TV--list--] = TRUSTED { <> type: Type = UnderType[TVType[tv]]; SELECT TypeClass[type] FROM -- NOTE assumption of remote AtomRec identity atom => rtn _ Loophole[ IndexToTV[ Loophole[tv, CODE[REF AtomsPrivate.AtomRec]], NameToIndex[CODE[AtomsPrivate.AtomRec], "propList"]], CODE[List.AList]]; ENDCASE => ERROR Error[reason: typeFault, type: type]; }; TVToName: PUBLIC SAFE PROC [tv: TypedVariable] RETURNS[ans: ROPE _ NIL] = TRUSTED { <> type: Type = UnderType[TVType[tv]]; world: World = GetWorld[tv]; SELECT TypeClass[type] FROM ref => { target: Type; SELECT TRUE FROM IsAtom[tv] => target _ CODE[ATOM]; IsRope[tv] => target _ CODE[ROPE]; ENDCASE => ERROR Error[reason: typeFault, type: type]; ans _ TVToName[Coerce[tv, target]]; }; atom => SELECT TRUE FROM IsRemote[tv] => <> ans _ RemoteRope.RopeFromTV[ TVForRemotePointerReferent[ remotePointer: [ world: world, worldIncarnation: CurrentIncarnation[world], ptr: TVToLC[tv]], type: CODE[ROPE]]]; TVToLC[tv] # 0 => ans _ LOOPHOLE[TVToLC[tv], REF AtomsPrivate.AtomRec].pName; ENDCASE; rope => IF IsRemote[tv] THEN ans _ RemoteRope.RopeFromTV[tv] ELSE ans _ LOOPHOLE[TVToLC[tv], ROPE]; enumerated => { index: INT = TVToLC[tv] + 1; IF index > LAST[CARDINAL] THEN ERROR Error[reason: notImplemented, msg: "gigantic enumerations", type: type]; ans _ IndexToName[type, index]; }; program, procedure => IF IsRemote[tv] THEN ans _ RemotePDToName[TVToRemoteProc[tv]] ELSE ans _ tp.PDToName[LOOPHOLE[TVToProc[tv], PrincOps.ProcDesc]]; signal, error => IF IsRemote[tv] THEN ans _ RemoteSEDToName[TVToRemoteSignal[tv]] ELSE ans _ tp.SEDToName[LOOPHOLE[TVToSignal[tv], PrincOps.SignalDesc]]; globalFrame => IF IsRemote[tv] THEN ans _ RemoteGFHToName[RemoteGFHFromTV[tv]] ELSE ans _ tp.GFHToName[GFHFromTV[tv]]; ENDCASE; }; Apply: PUBLIC SAFE PROC [mapper: TV--array, sequence, descriptor, longDescriptor--, arg: TV] RETURNS[embeddedTV: TV] = TRUSTED { type: Type _ UnderType[TVType[mapper]]; computed: BOOL _ IsComputed[type]; stb: SymbolTableBase; sei: SymbolIndex; class: Class = TypeClass[type]; IF mapper = NIL THEN ERROR Error[reason: typeFault, type: type]; IF class = descriptor OR class = longDescriptor THEN { ws: WordSequence = TVToWordSequence[mapper]; wsd: LONG POINTER TO DESCRIPTOR FOR ARRAY OF WORD = LOOPHOLE[@ws[0]]; wsld: LONG POINTER TO LONG DESCRIPTOR FOR ARRAY OF WORD = LOOPHOLE[wsd]; length: CARDINAL = IF class = descriptor THEN LENGTH[wsd^] ELSE LENGTH[wsld^]; type _ Range[type]; IF TVToCardinal[arg] >= length THEN ERROR Error[reason: rangeFault]; IF IsRemote[mapper] THEN mapper _ TVForRemotePointerReferent[ remotePointer: [ world: GetWorld[mapper], worldIncarnation: GetWorldIncarnation[mapper], ptr: IF class = descriptor THEN LOOPHOLE[LONG[BASE[wsd^]], WorldVM.Address] ELSE LOOPHOLE [BASE[wsld^], WorldVM.Address]], type: type, status: ReferentStatus[TVType[mapper]]] ELSE mapper _ TVForPointerReferent [ ptr: IF class = descriptor THEN BASE[wsd^] ELSE BASE[wsld^], type: type, status: ReferentStatus[TVType[mapper]]]}; [stb, sei] _ GetTypeSymbols[type]; {ENABLE UNWIND => ReleaseSTB[stb]; eltTypeEi: SymbolIndex; domainType: Type = Domain[type]; upperLimit: INT _ TVToLI[Last[domainType]]; domainOffset: INT _ IF EquivalentTypes[domainType, CODE[INTEGER]] THEN 0 ELSE TVToLI[First[domainType]]; argValue: INT = TVToLI[arg]; bitOffset: INT; bitsPerElement: CARDINAL; tagEndOffset: INTEGER _ 0; isPacked: BOOL _ FALSE; isSequence: BOOL _ FALSE; fd: tp.FieldDescriptor; WITH stb SELECT FROM t: SymbolTableBase.x => WITH ser: t.e.seb[t.e.UnderType[NARROW[sei, SymbolIndex.x].e]] SELECT FROM array => {isPacked _ ser.packed; eltTypeEi _ [x[ser.componentType]]}; sequence => { isPacked _ ser.packed; isSequence _ TRUE; eltTypeEi _ [x[ser.componentType]]; <> tagEndOffset _ IF computed THEN 0 ELSE (t.e.seb[ser.tagSei].idInfo + t.e.seb[ser.tagSei].idValue)}; ENDCASE => ERROR Error[reason: typeFault, type: TVType[mapper]]; t: SymbolTableBase.y => WITH ser: t.e.seb[t.e.UnderType[NARROW[sei, SymbolIndex.y].e]] SELECT FROM array => {isPacked _ ser.packed; eltTypeEi _ [y[ser.componentType]]}; sequence => { isPacked _ ser.packed; isSequence _ TRUE; eltTypeEi _ [y[ser.componentType]]; <> tagEndOffset _ IF computed THEN 0 ELSE (t.e.seb[ser.tagSei].idInfo + t.e.seb[ser.tagSei].idValue)}; ENDCASE => ERROR Error[reason: typeFault, type: TVType[mapper]]; ENDCASE => ERROR; IF isSequence AND computed THEN <> tagEndOffset _ GetSequenceOffset[type] * bitsPerWord; IF NOT computed THEN { IF isSequence THEN upperLimit _ TVToLI[Tag[mapper]] - 1; IF (~InRange[domainType, arg] OR argValue > upperLimit) THEN <> ERROR Error[reason: rangeFault]; }; bitsPerElement _ WITH stb SELECT FROM t: SymbolTableBase.x => t.e.BitsPerElement[type: NARROW[eltTypeEi, SymbolIndex.x].e, packed: isPacked], t: SymbolTableBase.y => t.e.BitsPerElement[type: NARROW[eltTypeEi, SymbolIndex.y].e, packed: isPacked], ENDCASE => ERROR; bitOffset _ tagEndOffset + (argValue - domainOffset) * bitsPerElement; <> IF (class # descriptor) AND (class # longDescriptor) AND (NOT isSequence) AND (NOT Embedded[mapper]) THEN { bitsForTV: LONG CARDINAL _ 0; [bitsForTV,,] _ tp.BitsForType[type]; IF bitsForTV < bitsPerWord THEN bitOffset _ bitOffset + bitsPerWord - ShortenLongCardinal[bitsForTV]; }; fd _ BuildRecordFieldDescriptor [ mapper, bitOffset, bitsPerElement, (WITH stb SELECT FROM t: SymbolTableBase.x =>t.e.BitsForType[type: NARROW[eltTypeEi, SymbolIndex.x].e], t: SymbolTableBase.y =>t.e.BitsForType[type: NARROW[eltTypeEi, SymbolIndex.y].e], ENDCASE => ERROR)]; embeddedTV _ tvZone.NEW[TypedVariableRec _ [ referentType: [Range[type]], head: NARROW[mapper, REF TypedVariableRec].head, status: NARROW[mapper, REF TypedVariableRec].status, field: embedded[fd: fd]]]; ReleaseSTB[stb]; }}; -- end Apply Fetch: PUBLIC SAFE PROC[tv: TypedVariable--rope--, index: INT] RETURNS [CHAR] = TRUSTED { type: Type = TVType[tv]; SELECT LocalUnderClass[type] FROM rope => IF IsRemote[tv] THEN RETURN[RemoteRope.RemoteFetch[tv, index]] ELSE RETURN[Rope.Fetch[TVToName[tv], index]]; ENDCASE; ERROR Error[reason: typeFault, type: type]}; OctalRead: PUBLIC SAFE PROC [tv: TypedVariable, offset: INT] RETURNS[ans: CARDINAL] = TRUSTED { addr: tp.ValueAddress = tp.GetValueAddress[tv]; WITH t: addr SELECT FROM constant => ans _ t.value[offset]; pointer => ans _ LOOPHOLE[t.ptr + offset, LONG POINTER TO CARDINAL]^; remotePointer => ans _ RTTypesRemotePrivate.GetRemoteWord[[ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv], ptr: t.ptr.ptr + offset]]; copiedRemoteObject => ans _ LOOPHOLE[t.ptr + offset, LONG POINTER TO CARDINAL]^; ENDCASE => ERROR; }; Length: PUBLIC SAFE PROC [tv: TV --sequence, rope, descriptor, longDescriptor--] RETURNS[INT] = TRUSTED { type: Type = UnderType[TVType[tv]]; SELECT TypeClass[type] FROM sequence => RETURN[GetSequenceLength[tv]]; rope => IF IsRemote[tv] THEN RETURN[RemoteRope.RemoteLength[tv]] ELSE RETURN[Rope.Length[TVToName[tv]]]; descriptor => { ws: WordSequence = TVToWordSequence[tv]; RETURN[LENGTH[LOOPHOLE[ @ws[0], LONG POINTER TO DESCRIPTOR FOR ARRAY OF WORD]^]]}; longDescriptor => { ws: WordSequence = TVToWordSequence[tv]; RETURN[LENGTH[LOOPHOLE[ @ws[0], LONG POINTER TO LONG DESCRIPTOR FOR ARRAY OF WORD]^]]}; ENDCASE => ERROR Error[reason: typeFault, type: type]; }; Loophole: PUBLIC PROC [tv: TypedVariable, type: Type, tag: TypedVariable _ NIL] RETURNS[TypedVariable] = { <> <> variantClass: Class = VariableType[type].c; IF tag # NIL AND variantClass # union AND variantClass # sequence THEN ERROR Error[reason: typeFault, type: type, msg: "non-NIL tag makes no sense"]; WITH tv SELECT FROM tvr: REF TypedVariableRec => WITH tvr: tvr SELECT FROM entire => RETURN[tvZone.NEW[TypedVariableRec _ [ referentType: [type, tag], head: tvr.head, status: tvr.status, field: entire[]]]]; embedded => RETURN[tvZone.NEW[TypedVariableRec _ [ referentType: [type, tag], head: tvr.head, status: tvr.status, field: embedded[fd: tvr.fd]]]]; constant => RETURN[tvZone.NEW[TypedVariableRec _ [ referentType: [type, tag], head: tvr.head, status: tvr.status, field: constant[value: tvr.value]]]]; ENDCASE => ERROR; ENDCASE => ERROR; }; ConcreteRef: PUBLIC SAFE PROC [tv: TypedVariable--ref any--] RETURNS[ans: TypedVariable _ NIL] = TRUSTED { type: Type _ UnderType[TVType[tv]]; class: Class _ TypeClass[type]; target: Type _ nullType; IF class = nil OR TVToLC[tv] = 0 THEN RETURN[NIL]; IF class = atom OR class = rope OR class = list OR class = countedZone THEN RETURN[tv]; IF class # ref THEN ERROR Error[reason: typeFault, type: type]; IF TypeClass[Range[type]] # any THEN RETURN[tv]; SELECT TRUE FROM IsAtom[tv] => target _ CODE[ATOM]; IsRope[tv] => target _ CODE[ROPE]; ENDCASE => { realSourceRangeType: Type; IF IsRemote[tv] THEN { r: RemoteRef = [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv], ref: TVToLC[tv]]; realSourceRangeType _ RTTypesRemotePrivate.GetRemoteReferentType[r]} ELSE realSourceRangeType _ RTTypesBasic.GetReferentType[LOOPHOLE[TVToLC[tv], REF ANY]]; IF LocalUnderClass[realSourceRangeType] = structure AND NComponents[UnderType[realSourceRangeType]] = 2 AND LocalUnderClass[IndexToType[realSourceRangeType, 2]] = list THEN target _ IndexToType[realSourceRangeType, 2]; }; IF target # nullType THEN RETURN [Coerce[tv, target]]; ERROR Error[ reason: notImplemented, msg: "ConcreteRef for other than ATOM, ROPE or LIST targets"]; }; IsNil: PUBLIC SAFE PROC[tv: TypedVariable--address--] RETURNS [BOOL] = TRUSTED { SELECT LocalUnderClass[TVType[tv]] FROM relativePointer, atom, rope, list, ref, pointer, longPointer, basePointer, countedZone, uncountedZone, process, procedure, signal, error, program, port => RETURN[TVToLC[tv] = 0]; nil => RETURN[TRUE]; descriptor => { ws: WordSequence = TVToWordSequence[tv]; RETURN[NIL = BASE[LOOPHOLE [@ws[0], LONG POINTER TO DESCRIPTOR FOR ARRAY OF WORD]^]]}; longDescriptor => { ws: WordSequence = TVToWordSequence[tv]; RETURN[NIL = BASE[LOOPHOLE [@ws[0], LONG POINTER TO LONG DESCRIPTOR FOR ARRAY OF WORD]^]]}; ENDCASE => ERROR Error[typeFault]; }; Referent: PUBLIC SAFE PROC [ tv: TypedVariable, --ref, list, pointer, longPointer, basePointer, relativePointer-- base: TypedVariable _ NIL <> ] RETURNS[TypedVariable] = TRUSTED { type: Type _ TVType[tv]; referentType: Type _ Range[type]; -- raises Error[typeFault] status: Status _ mutable; ptr: Pointer; stb: SymbolTableBase; sei: SymbolIndex; [stb, sei] _ GetTypeSymbols[type]; WITH stb SELECT FROM t: SymbolTableBase.x => { ENABLE UNWIND => ReleaseSTB[stb]; WITH ser: t.e.seb[t.e.UnderType[NARROW[sei, SymbolIndex.x].e]] SELECT FROM long => WITH ser1: t.e.seb[t.e.UnderType[ser.rangeType]] SELECT FROM ref => IF ser1.readOnly THEN status _ readOnly; ENDCASE => ERROR Error[reason: typeFault, type: type]; ref => IF ser.readOnly THEN status _ readOnly; relative => NULL; ENDCASE => ERROR Error[reason: typeFault, type: type]}; t: SymbolTableBase.y => { ENABLE UNWIND => ReleaseSTB[stb]; WITH ser: t.e.seb[t.e.UnderType[NARROW[sei, SymbolIndex.y].e]] SELECT FROM long => WITH ser1: t.e.seb[t.e.UnderType[ser.rangeType]] SELECT FROM ref => IF ser1.readOnly THEN status _ readOnly; ENDCASE => ERROR Error[reason: typeFault, type: type]; ref => IF ser.readOnly THEN status _ readOnly; relative => NULL; ENDCASE => ERROR Error[reason: typeFault, type: type]}; ENDCASE => ERROR; ReleaseSTB[stb]; IF referentType = unspecType THEN ERROR Error[reason: typeFault, type: referentType]; IF IsRemote[tv] THEN SELECT LocalUnderClass[type] FROM relativePointer => { world: World = GetWorld[tv]; ptr: RemotePointer = [ world: world, worldIncarnation: CurrentIncarnation[world], ptr: TVToLC[base] + TVToCardinal[tv]]; <> IF NOT LocalUnderClass[TVType[base]] = basePointer THEN ERROR Error[reason: typeFault, type: TVType[base]]; RETURN[TVForRemotePointerReferent [remotePointer: ptr, type: referentType, status: status]]}; ref, list => { world: World = GetWorld[tv]; ref: RemoteRef = [world: world, worldIncarnation: CurrentIncarnation[world], ref: TVToLC[tv]]; ValidateRemoteRef[ref]; RETURN[TVForRemoteReferent[remoteRef: ref, status: status]]}; pointer => { world: World = GetWorld[tv]; ptr: RemotePointer = [ world: world, worldIncarnation: CurrentIncarnation[world], ptr: Long[world: world, addr: TVToCardinal[tv]]]; <> IF LocalUnderClass[referentType] = opaque THEN ERROR Error[reason: typeFault, type: referentType]; RETURN[TVForRemotePointerReferent [remotePointer: ptr, type: referentType, status: status]]}; longPointer, basePointer => { world: World = GetWorld[tv]; IF LocalUnderClass[referentType] = opaque THEN ERROR Error[reason: typeFault, type: referentType]; RETURN[TVForRemotePointerReferent [ remotePointer: [world: world, worldIncarnation: CurrentIncarnation[world], ptr: TVToLC[tv]], type: referentType, status: status]]}; ENDCASE => ERROR -- end IsRemote[tv] ELSE -- local tv SELECT LocalUnderClass[type] FROM relativePointer => { IF NOT LocalUnderClass[TVType[base]] = basePointer THEN ERROR Error[reason: typeFault, type: TVType[base]]; ptr _ LOOPHOLE[TVToLC[base] + TVToCardinal[tv], Pointer]; RETURN[TVForPointerReferent[ptr: ptr, type: referentType, status: status]]}; ref, list => { ref: REF ANY = LOOPHOLE[TVToLC[tv], REF ANY]; ValidateRef[ref]; RETURN[TVForReferent[ref: ref, status: status]]}; pointer => { ptr _ LONG[LOOPHOLE[TVToCardinal[tv], POINTER]]; IF LocalUnderClass[referentType] = opaque THEN ERROR Error[reason: typeFault, type: referentType]; RETURN[TVForPointerReferent[ ptr: ptr, type: referentType, status: status]]}; longPointer, basePointer => { ptr _ LOOPHOLE[TVToLC[tv], Pointer]; IF LocalUnderClass[referentType] = opaque THEN ERROR Error[reason: typeFault, type: referentType]; RETURN[TVForPointerReferent[ ptr: ptr, type: referentType, status: status]]}; ENDCASE => ERROR; }; -- end Referent Coerce: PUBLIC SAFE PROC [tv: TypedVariable, targetType: Type] RETURNS[newTV: TypedVariable] = TRUSTED { type: Type = TVType[tv]; {-- block for common errors <> tvr: REF TypedVariableRec; -- utility targetClass, sourceClass: Class; IF type = targetType THEN RETURN[tv]; IF EquivalentTypes[type, targetType] THEN GO TO loophole; targetClass _ LocalUnderClass[targetType]; sourceClass _ LocalUnderClass[type]; IF sourceClass = record AND AMTypes.NComponents[type] = 1 THEN { <> element: TV _ IndexToTV[tv, 1]; SELECT LocalUnderClass[TVType[element]] FROM union => element _ Variant[element]; sequence => GO TO error; ENDCASE; RETURN [Coerce[element, targetType]]; }; IF sourceClass = nil OR (sourceClass = ref AND TVToLC[tv] = 0) THEN <> SELECT targetClass FROM list, procedure, signal, error, program, port, ref, pointer, longPointer, rope, atom, unspecified, countedZone, uncountedZone, process, nil, descriptor, longDescriptor, basePointer, relativePointer => RETURN [New[targetType, readOnly]]; ENDCASE => GO TO error; IF sourceClass = ref AND LocalUnderClass[Range[type]] = opaque THEN RETURN[Coerce[Loophole[tv, CODE[REF ANY]], targetType]]; SELECT targetClass FROM unspecified => <> IF TVSize[tv] = 1 THEN GO TO loophole ELSE GO TO error; procedure => { <> SELECT sourceClass FROM -- look at the source type procedure => { IF LocalUnderClass[Domain[targetType]] = any AND LocalUnderClass[Range[targetType]] = any THEN { <> IF IsRemote[tv] THEN newTV _ tvZone.NEW[TypedVariableRec _ [ referentType: [targetType], head: [copiedRemoteObject [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv], copy: tvZone.NEW[WordSequenceRecord[1]]]], status: mutable, field: entire[]]] ELSE newTV _ New[type: targetType]; Assign[lhs: newTV, rhs: Loophole[tv, targetType]]; } ELSE GO TO error; }; nil => RETURN[NIL]; -- NIL conforms to any PROC type ENDCASE => GO TO error; }; ref, list, atom, rope, countedZone => { <> targetRangeType: Type _ nullType; sourceRangeType: Type _ nullType; realSourceRangeType: Type _ nullType; narrowToAtomOrRopeOrZone: BOOL _ FALSE; widenFromAtomOrRopeOrZone: BOOL _ FALSE; SELECT sourceClass FROM -- look at the source type ref, list, atom, rope, countedZone => NULL; ENDCASE => GO TO error; SELECT targetClass FROM ref, list => targetRangeType _ Range[targetType]; ENDCASE; SELECT sourceClass FROM ref, list => { sourceRangeType _ Range[UnderType[type]]; IF IsRemote[tv] THEN { r: RemoteRef = [world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv], ref: TVToLC[tv]]; realSourceRangeType _ RTTypesRemotePrivate.GetRemoteReferentType[r]} ELSE realSourceRangeType _ RTTypesBasic.GetReferentType[LOOPHOLE[TVToLC[tv], REF ANY]]}; ENDCASE; SELECT targetClass FROM atom, rope, countedZone => { <> IF sourceClass # ref OR sourceRangeType # anyType THEN GO TO badRange; SELECT targetClass FROM atom => IF NOT EquivalentTypes[realSourceRangeType, CODE[AtomsPrivate.AtomRec]] THEN GO TO badRange; rope => IF NOT EquivalentTypes[realSourceRangeType, CODE[Rope.RopeRep]] THEN GO TO badRange; countedZone => IF NOT EquivalentTypes[realSourceRangeType, CODE[RTZones.ZoneRec]] THEN GO TO badRange; ENDCASE => ERROR; narrowToAtomOrRopeOrZone _ TRUE; }; ENDCASE; SELECT sourceClass FROM atom, rope, countedZone => { widenFromAtomOrRopeOrZone _ targetClass = ref AND (targetRangeType = unspecType OR targetRangeType = anyType); IF NOT widenFromAtomOrRopeOrZone THEN GO TO badRange}; ENDCASE; IF narrowToAtomOrRopeOrZone OR widenFromAtomOrRopeOrZone OR targetRangeType = unspecType --widen-- OR targetRangeType = anyType --widen-- OR sourceRangeType = nullType --NIL conforms to any ref target type-- OR AsGoodAs[lhsType: targetRangeType, rhsType: sourceRangeType] --narrow-- OR ((sourceClass = ref OR sourceClass = list) AND AsGoodAs[lhsType: targetRangeType, rhsType: realSourceRangeType]) --narrow-- THEN { <> IF IsRemote[tv] THEN { world: World = GetWorld[tv]; ws: WordSequence = NEW[WordSequenceRecord[2]]; LOOPHOLE[@ws[0], LONG POINTER TO LONG CARDINAL]^ _ TVToLC[tv]; newTV _ tvZone.NEW[TypedVariableRec _ [ referentType: [targetType], head: [copiedRemoteObject [ world: world, worldIncarnation: CurrentIncarnation[world], copy: ws]], status: readOnly, field: entire[]]]; } ELSE { result: REF ANY = LOOPHOLE[TVToLC[tv], REF ANY]; <> newTV _ New[type: targetType, status: readOnly]; tvr _ NARROW[newTV, REF TypedVariableRec]; WITH hd: tvr.head SELECT FROM reference => LOOPHOLE[hd.ref, REF REF ANY]^ _ result; ENDCASE => ERROR}} ELSE GO TO badRange}; subrange, character, enumerated, integer, cardinal, longInteger, longCardinal => { li: INT = TVToLI[tv]; SELECT targetClass FROM longCardinal => IF li < 0 THEN GO TO badRange; cardinal => IF li < 0 OR li > LAST[CARDINAL] THEN GO TO badRange; longInteger => {}; integer => IF li < FIRST[INTEGER] OR li > LAST[INTEGER] THEN GO TO badRange; character => IF li < 0 OR li > 377B THEN GO TO badRange; ENDCASE => IF li < TVToLI[First[targetType]] OR TVToLI[Last[targetType]] < li THEN GO TO badRange; newTV _ New[type: targetType, status: mutable]; SetTVFromLI[newTV, li]; NARROW[newTV, REF TypedVariableRec].status _ readOnly; }; real => { li: INT = TVToLI[tv]; ref: REF REAL _ NEW[REAL _ li]; RETURN [AMBridge.TVForReadOnlyReferent[ref]]; }; ENDCASE => GO TO error; EXITS loophole => RETURN [Loophole[tv, targetType]]; error => ERROR Error[reason: typeFault, type: targetType]; badRange => ERROR Error[reason: rangeFault] }}; -- end Coerce InRange: PUBLIC SAFE PROC[type: Type--subrange--, groundTV: TypedVariable] RETURNS[val: BOOL _ TRUE] = TRUSTED { [] _ Coerce[groundTV, type ! Error => IF reason = rangeFault THEN val _ FALSE]; }; Next: PUBLIC SAFE PROC[tv: TypedVariable--enumerated, subrange, basic--] RETURNS[TypedVariable] = TRUSTED { val: LONG INTEGER = TVToLI[tv]; type: Type = TVType[tv]; newTV: TypedVariable; IF val = TVToLI[Last[type]] THEN RETURN[NIL]; newTV _ New[type]; SetTVFromLC[newTV, LOOPHOLE[val + 1, LONG CARDINAL]]; -- NOTE mach dep enum? RETURN[newTV]}; <> LocalUnderClass: SAFE PROC [type: Type] RETURNS [class: Class] = TRUSTED { class _ TypeClass[UnderType[type]]; }; LastComponent: PROC [tv: TypedVariable, type: Type _ nullType] RETURNS [TypedVariable] = { IF type = nullType THEN type _ TVType[tv]; RETURN [IndexToTV[tv, NComponents[type]]]}; Constant: PROC[tv: TypedVariable] RETURNS[ans: BOOL _ FALSE] = { WITH tv SELECT FROM rtr: REF TypedVariableRec => WITH etr: rtr SELECT FROM constant => ans _ TRUE; ENDCASE; ENDCASE; }; Embedded: PROC[tv: TypedVariable] RETURNS[ans: BOOL _ FALSE] = { WITH tv SELECT FROM rtr: REF TypedVariableRec => WITH etr: rtr SELECT FROM embedded => ans _ TRUE; ENDCASE; ENDCASE; }; BuildRecordFieldDescriptor: PUBLIC PROC [parentTV: TypedVariable, fieldBitOffset, fieldBits, bitsForType: INT] RETURNS[fD: tp.FieldDescriptor] = { <= bitsPerWord, the component size is the same as the container size). The result of BuildRecordFieldDescriptor describes an embedded field WRT parentTV's head wherein the bits of the component reside. Generally, an embedded field of a TV describes where WRT its head the bits of its value reside. >> fD _ IF bitsForType < bitsPerWord THEN BuildSmallFieldDescriptor[fieldBitOffset + fieldBits - bitsForType, bitsForType] ELSE BuildLargeFieldDescriptor[fieldBitOffset / bitsPerWord, fieldBits / bitsPerWord]; IF parentTV = NIL THEN RETURN; <> WITH parentTV SELECT FROM parentTr: REF TypedVariableRec => WITH parentT: parentTr SELECT FROM embedded=> { fD.wordOffset _ fD.wordOffset + parentT.fd.wordOffset; WITH parentF: parentT.fd SELECT FROM small => WITH f: fD SELECT FROM small=> f.field.bitFirst _ f.field.bitFirst + parentF.field.bitFirst; ENDCASE => ERROR; ENDCASE}; ENDCASE; ENDCASE => ERROR; }; BuildSmallFieldDescriptor: PROC[bitOffset, bitCount: INT] RETURNS[small tp.FieldDescriptor] = INLINE { RETURN[tp.FieldDescriptor[ wordOffset: ShortenLongInteger[bitOffset / bitsPerWord], extent: small[field: [bitFirst: ShortenLongInteger [bitOffset MOD bitsPerWord], bitCount: ShortenLongInteger[bitCount]]]]]}; BuildLargeFieldDescriptor: PROC[wordOffset, nWords: INT] RETURNS[large tp.FieldDescriptor] = INLINE { RETURN[tp.FieldDescriptor[ wordOffset: ShortenLongInteger[wordOffset], extent: large[size: ShortenLongInteger[nWords]]]]}; AsGoodAs: PROC[rhsType, lhsType: Type] RETURNS[BOOL] = { <> <> RETURN[EquivalentTypes[rhsType, lhsType]]; }; END.