DIRECTORY AMBridge USING [GetWorld, GetWorldIncarnation, GFHFromTV, IsRemote, Loophole, RemoteGFHFromTV, RemotePointer, RemoteRef, SetTVFromLC, SetTVFromLI, TVForPointerReferent, TVForReadOnlyReferent, TVForReferent, TVForRemotePointerReferent, TVForRemoteReferent, TVToCardinal, TVToLC, TVToLI, TVToProc, TVToRemoteProc, TVToRemoteSignal, TVToRef, TVToSignal, TVToWordSequence, WordSequence, WordSequenceRecord], AMTypes USING [Assign, Class, Coerce, Domain, Error, First, Globals, GroundStar, IndexToName, IndexToType, IsAtom, IsComputed, IsOverlaid, IsRope, Last, Locals, NameToIndex, NComponents, Range, ReferentStatus, Size, Status, TVStatus, TVType, TypeClass, UnderType, VariableType, TV, Index], AtomPrivate USING[AtomRec], Basics USING[bitsPerWord], List USING[AList], LoaderOps USING[GetFrame, IR, IRRecord, IsNullLink], PrincOps USING[GlobalFrameHandle, ProcDesc, SignalDesc], RemoteRope USING[RemoteFetch, RemoteLength, RopeFromTV], Rope USING[Fetch, Length, ROPE, RopeRep], RTCommon USING[FetchField, FetchFieldLong], RTSymbolDefs USING [SymbolConstructorIndex, SymbolIdIndex, SymbolIndex, SymbolRecordIndex, SymbolTableBase], RTSymbolOps USING [AcquireSequenceType, AcquireType, IDCardinalInfo, IDCardinalValue, ISEConstant, ISEImmutable, ISEType, IsSequence, SEBitsForType, SEUnderType, IsTypeSEI], RTSymbols USING[GetTypeSymbols, ReleaseSTB], RTTCache USING[FillIntEntry, IntEntry, LookupInt], RTTypesPrivate, RTTypesRemotePrivate USING [GetRemoteReferentType, GetRemoteWord, RemoteGFHToName, RemotePDToName, RemoteSEDToName, RemoteTypeToLocal], SafeStorage USING [anyType, EquivalentTypes, fhType, GetCanonicalType, GetReferentType, gfhType, nullType, Type, unspecType], SafeStoragePrivate USING[NewObject], WorldVM USING[Address, CurrentIncarnation, LocalWorld, Long, World]; RTTypedVariablesImpl: PROGRAM IMPORTS AMBridge, AMTypes, LoaderOps, RemoteRope, Rope, RTCommon, RTSymbolOps, RTSymbols, RTTCache, RTTypesPrivate, RTTypesRemotePrivate, SafeStorage, SafeStoragePrivate, WorldVM EXPORTS AMTypes, AMBridge, RTTypesPrivate SHARES Rope = BEGIN OPEN AMBridge, AMTypes, Basics, PrincOps, RTTypesPrivate, RTCommon, SafeStoragePrivate, RTSymbolDefs, RTSymbolOps, RTSymbols, RTTCache, SafeStorage, RTTypesRemotePrivate, WorldVM; Pointer: TYPE = LONG POINTER; ROPE: TYPE = Rope.ROPE; TypedVariableRec: TYPE = RTTypesPrivate.TypedVariableRec; TypedVariableRef: TYPE = REF TypedVariableRec; underTYPE: Type = UnderType[CODE[Type]]; New: PUBLIC SAFE PROC [type: Type, status: Status _ mutable, world: WorldVM.World _ NIL, tag: TV _ NIL] RETURNS [newTV: TV] = 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 _ NEW[WordSequenceRecord[Size[type, length]]]; newTV: TV _ 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, TypedVariableRef].status _ mutable; Assign[lhs: newTag, rhs: tag]; NARROW[newTag, TypedVariableRef].status _ readOnly; RETURN[newTV]; } ELSE RETURN [ NEW[TypedVariableRec _ [ referentType: [type], head: [copiedRemoteObject [ world: world, worldIncarnation: CurrentIncarnation[world], copy: NEW[WordSequenceRecord[Size[type]]]]], status: status, field: entire[]]]]} -- end make a new remote TV ELSE { canon: Type = SafeStorage.GetCanonicalType[type]; newRef: REF = NewObject[type: canon, size: Size[type, length]]; internalTV: TypedVariableRef = NARROW[TVForReferent[newRef]]; internalTV.referentType _ [type]; newTV _ internalTV; IF tag # NIL AND (variantClass = union OR variantClass = sequence) THEN IF IsComputed[type] OR (variantClass = union AND IsOverlaid[type]) THEN internalTV.referentType.tag _ tag ELSE { newTag: TypedVariableRef _ NARROW[Tag[LastComponent[newTV, type]]]; IF newTag # NIL THEN { newTag.status _ mutable; Assign[lhs: newTag, rhs: tag]; newTag.status _ readOnly; }; }; RETURN[newTV]; }; }; TVTag: PROC [tv: TV] RETURNS [TV] = { RETURN[NARROW[tv, TypedVariableRef].referentType.tag]; }; TVSize: PUBLIC SAFE PROC [tv: TV] 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: TV--union, sequence--] RETURNS [ans: TV] = 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 _ NEW[TypedVariableRec _ [ referentType: [Domain[type]], head: (WITH tv SELECT FROM tr: TypedVariableRef => 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]; }; Variant: PUBLIC SAFE PROC [tv: TV--union--] RETURNS [ans: TV _ 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]; }; IF LocalUnderClass[type] # union THEN ERROR Error[reason: typeFault, type: type]; RTTypesPrivate.ComponentISEI[type, NameToIndex[type, TVToName[Tag[tv]]], p]; }; IndexToTV: PUBLIC SAFE PROC [tv: TV--record, structure--, index: Index] RETURNS [TV] = TRUSTED { cType: Type; type: Type _ UnderType[TVType[tv]]; et: TypedVariableRef; 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 - 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] AND NOT IsTypeSEI[ISEType[stb, isei]] THEN et _ NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [remoteConstant [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv]]], status: const, field: constant[value: RTTypesPrivate.GetIdConstantValue[tv, stb, isei]] ]] ELSE et _ NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [constant[]], status: const, field: constant[value: RTTypesPrivate.GetIdConstantValue[tv, stb, isei]] ]]; EXITS nimp => et _ NIL}; interfaceRec AND NOT IsInterfaceElementType[cType] => { fD: RTTypesPrivate.FieldDescriptor; headP: Pointer; ptr: POINTER; status: Status _ mutable; ir: LoaderOps.IR; IF IsRemote[tv] THEN ERROR Error[reason: notImplemented, msg: "remote interface variables"]; WITH tv SELECT FROM tr: TypedVariableRef => WITH head: tr.head SELECT FROM reference => ir _ NARROW[head.ref, LoaderOps.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 LoaderOps.IsNullLink[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: GlobalFrameHandle = LoaderOps.GetFrame[ interface: ir, index: fD.wordOffset - SIZE[LoaderOps.IRRecord]]; et _ 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 _ NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: [remoteConstant [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv]]], status: const, field: constant[value: ws] ]] ELSE et _ 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 _ NEW[TypedVariableRec _ [ referentType: [cType, TVTag[tv]], head: (WITH tv SELECT FROM tr: TypedVariableRef => 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]]; }; }}; [bitsForTV, argRec, interfaceRec] _ RTTypesPrivate.BitsForType[type]; RTTypesPrivate.RecordComponentISEI[type, index, BuildEmbeddedTV]; RETURN[et]; }; GetSequenceOffset: SAFE PROC [type: Type] RETURNS [offset: INT] = TRUSTED { 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: TV--type--] RETURNS [rtn: Type] = TRUSTED { type: Type = UnderType[TVType[tv]]; class: Class _ TypeClass[type]; IF type = underTYPE THEN class _ type; SELECT class 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: TV--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 AtomPrivate.AtomRec]], NameToIndex[CODE[AtomPrivate.AtomRec], "propList"]], CODE[List.AList]]; ENDCASE => ERROR Error[reason: typeFault, type: type]; }; TVToName: PUBLIC SAFE PROC [tv: TV] 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 _ NARROW[TVToRef[tv], REF AtomPrivate.AtomRec].pName; ENDCASE; rope => IF IsRemote[tv] THEN ans _ RemoteRope.RopeFromTV[tv] ELSE ans _ NARROW[TVToRef[tv], ROPE]; subrange => { ans _ TVToName[AMTypes.Coerce[tv, AMTypes.GroundStar[type]]]; }; 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 _ RTTypesPrivate.PDToName[LOOPHOLE[TVToProc[tv], ProcDesc]]; signal, error => IF IsRemote[tv] THEN ans _ RemoteSEDToName[TVToRemoteSignal[tv]] ELSE ans _ RTTypesPrivate.SEDToName[LOOPHOLE[TVToSignal[tv], SignalDesc]]; globalFrame => IF IsRemote[tv] THEN ans _ RemoteGFHToName[RemoteGFHFromTV[tv]] ELSE ans _ RTTypesPrivate.GFHToName[GFHFromTV[tv]]; ENDCASE; }; Apply: PUBLIC SAFE PROC [mapper: TV, 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]; SELECT class FROM descriptor, longDescriptor => { 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]]]}; ENDCASE; [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: RTTypesPrivate.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]; }; WITH stb SELECT FROM t: SymbolTableBase.x => bitsPerElement _ t.e.BitsPerElement[type: NARROW[eltTypeEi, SymbolIndex.x].e, packed: isPacked]; t: SymbolTableBase.y => bitsPerElement _ 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,,] _ RTTypesPrivate.BitsForType[type]; IF bitsForTV < bitsPerWord THEN bitOffset _ bitOffset + bitsPerWord - 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)]; { -- for defn of mapperTVRec mapperTVRec: TypedVariableRef = NARROW[mapper, TypedVariableRef]; WITH h: mapperTVRec.head SELECT FROM constant, remoteConstant => { -- can't have an embedded const tvrec (sigh) ws: WordSequence; value: WordSequence = WITH mtvr: mapperTVRec SELECT FROM constant => mtvr.value, ENDCASE => ERROR; WITH ee: fd SELECT FROM small => { words: CARDINAL = IF ee.field.bitCount <= Basics.bitsPerWord THEN 1 ELSE 2; ws _ NEW[WordSequenceRecord[words]]; IF words = 1 THEN LOOPHOLE[@ws[0], LONG POINTER TO CARDINAL]^ _ RTCommon.FetchField[@value[0] + ee.wordOffset, ee.field] ELSE LOOPHOLE[@ws[0], LONG POINTER TO LONG CARDINAL]^ _ RTCommon.FetchFieldLong[@value[0] + ee.wordOffset, ee.field]; }; large => { words: CARDINAL = ee.size; ws _ NEW[WordSequenceRecord[words]]; FOR i: CARDINAL IN [0..words) DO ws[i] _ value[i + ee.wordOffset] ENDLOOP; }; ENDCASE => ERROR; embeddedTV _ NEW[TypedVariableRec _ [ referentType: [Range[type]], head: h, status: mapperTVRec.status, field: constant[value: ws]]]; } ENDCASE => embeddedTV _ NEW[TypedVariableRec _ [ referentType: [Range[type]], head: h, status: mapperTVRec.status, field: embedded[fd: fd]]]; }; }; ReleaseSTB[stb]; }; Fetch: PUBLIC SAFE PROC [tv: TV--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: TV, offset: INT] RETURNS [ans: CARDINAL] = TRUSTED { addr: RTTypesPrivate.ValueAddress = RTTypesPrivate.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] 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: TV, type: Type, tag: TV _ NIL] RETURNS [TV] = { 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: TypedVariableRef => WITH tvr: tvr SELECT FROM entire => RETURN[NEW[TypedVariableRec _ [ referentType: [type, tag], head: tvr.head, status: tvr.status, field: entire[]]]]; embedded => RETURN[NEW[TypedVariableRec _ [ referentType: [type, tag], head: tvr.head, status: tvr.status, field: embedded[fd: tvr.fd]]]]; constant => RETURN[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: TV] RETURNS [ans: TV _ 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 _ GetReferentType[TVToRef[tv]]; 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: TV--address--] RETURNS [BOOL _ FALSE] = 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; }; Referent: PUBLIC SAFE PROC [ tv: TV, base: TV _ NIL] RETURNS [TV _ NIL] = TRUSTED { type: Type _ TVType[tv]; referentType: Type _ Range[type]; -- raises Error[typeFault] status: Status _ mutable; ptr: Pointer; stb: SymbolTableBase; sei: SymbolIndex; CauseFault: PROC = {ERROR Error[reason: typeFault, type: type]}; BadReferent: PROC = {ERROR Error[reason: typeFault, type: referentType]}; [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 => CauseFault[]}; 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 => CauseFault[]}; ENDCASE => ERROR; ReleaseSTB[stb]; IF referentType = unspecType THEN BadReferent[]; 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]]; bType: Type = TVType[base]; IF NOT LocalUnderClass[bType] = basePointer THEN ERROR Error[reason: typeFault, type: bType]; RETURN[TVForRemotePointerReferent [remotePointer: ptr, type: referentType, status: status]]}; ref, list => { world: World = GetWorld[tv]; ref: RemoteRef = [world: world, worldIncarnation: CurrentIncarnation[world], ref: TVToLC[tv]]; 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 BadReferent[]; RETURN[TVForRemotePointerReferent [remotePointer: ptr, type: referentType, status: status]]}; longPointer, basePointer => { world: World = GetWorld[tv]; IF LocalUnderClass[referentType] = opaque THEN BadReferent[]; RETURN[TVForRemotePointerReferent [ remotePointer: [world: world, worldIncarnation: CurrentIncarnation[world], ptr: TVToLC[tv]], type: referentType, status: status]]}; ENDCASE; } ELSE { SELECT LocalUnderClass[type] FROM relativePointer => { bType: Type = TVType[base]; IF NOT LocalUnderClass[bType] = basePointer THEN ERROR Error[reason: typeFault, type: bType]; ptr _ LOOPHOLE[TVToLC[base] + TVToCardinal[tv], Pointer]; RETURN[TVForPointerReferent[ptr: ptr, type: referentType, status: status]]}; ref, list => RETURN[TVForReferent[ref: TVToRef[tv], status: status]]; pointer => { ptr _ LONG[LOOPHOLE[TVToCardinal[tv], POINTER]]; IF LocalUnderClass[referentType] = opaque THEN BadReferent[]; RETURN[TVForPointerReferent[ ptr: ptr, type: referentType, status: status]]}; longPointer, basePointer => { ptr _ LOOPHOLE[TVToLC[tv], Pointer]; IF LocalUnderClass[referentType] = opaque THEN BadReferent[]; RETURN[TVForPointerReferent[ ptr: ptr, type: referentType, status: status]]}; ENDCASE => ERROR; }; CauseFault[]; }; Coerce: PUBLIC SAFE PROC [tv: TV, targetType: Type] RETURNS [newTV: TV] = TRUSTED { type: Type; {-- block for common errors tvr: TypedVariableRef; -- utility targetClass, sourceClass: Class; DO type _ TVType[tv]; 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; tv _ element; LOOP; }; 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 { tv _ Loophole[tv, CODE[REF ANY]]; LOOP; }; EXIT; ENDLOOP; 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 _ NEW[TypedVariableRec _ [ referentType: [targetType], head: [copiedRemoteObject [ world: GetWorld[tv], worldIncarnation: GetWorldIncarnation[tv], copy: 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 _ GetReferentType[TVToRef[tv]]}; 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[AtomPrivate.AtomRec]] THEN GO TO badRange; rope => IF NOT EquivalentTypes[realSourceRangeType, CODE[Rope.RopeRep]] THEN GO TO badRange; countedZone => NULL; 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]) 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 _ NEW[TypedVariableRec _ [ referentType: [targetType], head: [copiedRemoteObject [ world: world, worldIncarnation: CurrentIncarnation[world], copy: ws]], status: readOnly, field: entire[]]]; } ELSE { newTV _ New[type: targetType, status: readOnly]; tvr _ NARROW[newTV, TypedVariableRef]; WITH hd: tvr.head SELECT FROM reference => LOOPHOLE[hd.ref, REF REF ANY]^ _ TVToRef[tv]; 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, TypedVariableRef].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, groundTV: TV] RETURNS [val: BOOL _ TRUE] = TRUSTED { [] _ Coerce[groundTV, type ! Error => IF reason = rangeFault THEN val _ FALSE]; }; Next: PUBLIC SAFE PROC [tv: TV] RETURNS [new: TV] = TRUSTED { val: INT = TVToLI[tv]; type: Type = TVType[tv]; IF val = TVToLI[Last[type]] THEN RETURN[NIL]; new _ New[type]; SetTVFromLC[new, LOOPHOLE[val + 1, LONG CARDINAL]]; -- NOTE mach dep enum? }; Prev: PUBLIC SAFE PROC [tv: TV] RETURNS [new: TV] = TRUSTED { val: INT = TVToLI[tv]; type: Type = TVType[tv]; IF val = TVToLI[First[type]] THEN RETURN[NIL]; new _ New[type]; SetTVFromLC[new, LOOPHOLE[val - 1, LONG CARDINAL]]; -- NOTE mach dep enum? }; LocalUnderClass: SAFE PROC [type: Type] RETURNS [class: Class] = TRUSTED { class _ TypeClass[UnderType[type]]; }; LastComponent: PROC [tv: TV, type: Type _ nullType] RETURNS [TV] = { IF type = nullType THEN type _ TVType[tv]; RETURN [IndexToTV[tv, NComponents[type]]]; }; Constant: PROC [tv: TV] RETURNS [ans: BOOL _ FALSE] = { WITH tv SELECT FROM rtr: TypedVariableRef => WITH etr: rtr SELECT FROM constant => ans _ TRUE; ENDCASE; ENDCASE; }; Embedded: PROC [tv: TV] RETURNS [ans: BOOL _ FALSE] = { WITH tv SELECT FROM rtr: TypedVariableRef => WITH etr: rtr SELECT FROM embedded => ans _ TRUE; ENDCASE; ENDCASE; }; BuildRecordFieldDescriptor: PUBLIC PROC [parentTV: TV, fieldBitOffset, fieldBits, bitsForType: INT] RETURNS [fD: RTTypesPrivate.FieldDescriptor] = { 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: TypedVariableRef => 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 RTTypesPrivate.FieldDescriptor] = { RETURN[RTTypesPrivate.FieldDescriptor[ wordOffset: bitOffset / bitsPerWord, extent: small[field: [bitFirst: bitOffset MOD bitsPerWord, bitCount: bitCount]]]]; }; BuildLargeFieldDescriptor: PROC [wordOffset, nWords: INT] RETURNS [large RTTypesPrivate.FieldDescriptor] = { RETURN[RTTypesPrivate.FieldDescriptor[wordOffset: wordOffset, extent: large[size: nWords]]]; }; AsGoodAs: PROC [rhsType, lhsType: Type] RETURNS [BOOL] = { RETURN[EquivalentTypes[rhsType, lhsType]]; }; END. ŒRTTypedVariablesImpl.Mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) May 21, 1985 4:02:57 pm PDT T Y P E S V A R I A B L E S PROCs exported to AMTypes raises typeFault variantClass = nil if type not a record or structure, or if non-variant (i.e. does not contain a union or sequence) make a new remote TV here to initialize the tag of the new variant or sequence record Make a new local TV. RRA: Note that the type of the TV should retain the proper definitions level, although the type of the new object must be the canonical type. We do cheat a little here, but I doubt that we will be caught at it. if a new variant or sequence record, initialize the tag COPIED in AMVariablesImpl Could overflow lots of changes by RRA for speed and generality The following hack is courtesy of RRA, who just can't resist. The reason we have this here is that making an embedded TV is no easy task when the TV is a constant (particularly from an interface). In this case, the value container is a word sequence in the 'field' component of the object, rather than in the 'head' component. Blindly using the head component in Tag and Variant has caused problems for people who put variant record values in interfaces. We take advantage of the readonly nature of constants to share the underlying word sequence, although we have to skip the first word in the word sequence to get to the contents (kludge). it is OK to LOOPHOLE the result, since we have checked the tag [1..NComponents[TVType[tv]]] bits for the value in the field bits for the field bit offset of the field within the record NOTE SymbolPack bug workaround if the entire tv is smaller than a word and in an allocated object an interface variable (OUT OF DATE) the 16-bit value in the indicated field of the IR instance is... a (loadstate config index (identifies a BCD), index in linksary of EXPRecord for this interface in that BCD) get the pointer to the interface record pick up the pointer to the global variable. Maybe not bound. old symbol table old symbol table old symbol table old symbol table RRA: this code did not use the offset prior to this change. We are even careful to pad with 0s if the value is not long enough. oddly enough, unions don't take entire words all of the time we may need the offset for later use (filed under the sequence type) Begin IndexToTV Here ... 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! uses the tag field, then adjusts for the bottom of the range raises typeFault raises typeFault requires that tv be a transfer, program, globalFrame, enumerated, atom, rope This is rather dangerous, since it relies on the print name of an atom being at offset 0 in the remote world. Life is hard. If this tv is for a subrange, then it may be a subrange of an enumeration, so we coerce it to the type of the (potential) enumeration, and recurse. This should only recurse one level at most. mapper must have class in {array, sequence, descriptor, longDescriptor} Sequence begins in the word beyond the tag! Currently we have no way to find out what the offset is if the sequence is computed, so we assume 0 (which is wrong for some sequences). See above comment about sequences... RRA: This special value has been squirrelled away by IndexToTV! extra check for sequences! now adjust bitOffset if the entire mapper is smaller than a word and in an allocated object raises typeFault, badTV NOTE no size check. You're on your own. tv must be for a REF ANY NOTE assumption that MDS is in the same place NOTE assumption that MDS is in the same place Raises typeFault, rangeFault. COPIES unless types are equivalent. This loop is here to provide for stripping off of record layers for single-component records and the handling of REF to opaque types. strip off excess layers of record NIL is handled specially (we are overly generous here with different types of NIL) This is a REF to an opaque type. If the target type is REF concrete, then we may win by looking at the referent type carried by the object itself. unspecified matches anything of size = 1 the target type class assignment of a proc to a PROC ANY ANY; copy it the target type class check that a REF ANY tv represents an atom or rope, respectively IF NOT EquivalentTypes[realSourceRangeType, CODE[RTZones.ZoneRec]] THEN GO TO badRange; create a new TV of the specified targetType with the specified value logically, the value of tv (a REF, LIST, ATOM, or ROPE) Procedures private to this module BuildRecordFieldDescriptor is used to build FieldDescriptors for components of TVs. fieldBitOffset and fieldBits specify the component's container location and size relative to the container holding parentTV's value. If the component is smaller than a word, bitsForType specifies its size, which may be smaller than the size of the component's container (if bitsForType >= 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. adjust offsets relative to parent. copied in AMVariablesImpl NOTE freely conforms = Equivalent for now Κ/„˜codešœ™Kšœ ΟmœΟkœ1™BK™/K™—šž ˜ Kšœ žœ…˜“Kšœžœ‰žœ ˜‘Kšœ žœ ˜Kšœžœ˜Kšœžœ˜Kšœ žœ žœ˜4Kšœ žœ*˜8Kšœ žœ(˜8Kšœžœžœ ˜)Kšœ žœ˜+Kšœ žœZ˜lKšœ žœœ˜­Kšœ žœ˜,Kšœ žœ$˜2K˜Kšœžœm˜‡Kšœ žœl˜}Kšœžœ ˜$Kšœžœ7˜DK˜—šœž˜Kšžœ«˜²Kšžœ"˜)Kšžœ˜ K˜šœžœžœ―˜»K˜——šœ ™ K™Kšœ žœžœžœ˜Kšžœžœžœ˜Kšœžœ#˜9Kšœžœžœ˜.—K˜™K™Kšœžœ˜(—K™Kšœ™K˜šΟnœžœžœžœ?žœžœžœž œžœžœ˜‡Kšœ™Kšœ˜Kšœžœ˜K˜Kšžœžœžœžœ˜$Kšžœžœžœžœ&˜SKšžœ žœžœ˜1K˜˜$KšœR™RKšœ ™ K˜—Kšžœžœžœžœ˜Išžœ˜šžœ˜Kšœ™šžœžœžœžœ˜Cšžœ˜Kšœžœ)˜?šœžœžœ˜$šœ˜Kšœ˜šžœžœžœ˜BKšžœ˜Kšžœžœ˜ ——˜K˜ K˜,K˜ —K˜K˜—Kšœžœ˜ K˜šžœžœžœ˜BKšžœžœ˜K˜—Kšœ@™@Kšœ+Οc˜™>Kšœ#˜#šœ˜K˜——Kšžœžœžœ&˜QKšœL˜LK˜K˜—šŸ œžœžœžœž œžœžœžœ˜`Kšœ™K˜ K˜#Kšœ˜Kšœžœ˜ Kšœžœ˜Kšœ žœžœ˜K˜šŸœžœ0˜EKšœ&˜&K˜5šœ žœ˜0Kšœ™—šœ žœ˜0Kšœ™—šœžœžœ˜$šžœžœžœž˜˜Kšœ žœ1˜C—˜Kšœ žœ1˜C—Kšžœžœ˜—šžœžœ ˜Kšžœ'˜+Kšžœ˜ —Kšœ)™)K˜—Kšœ žœžœ˜K˜šžœžœžœ !˜7˜šžœžœ$žœž˜G˜:Kšœ™—Kšžœ˜——˜šžœžœ$žœž˜GK˜:Kšž˜——Kšžœžœ˜K˜—šžœžœžœ˜1KšœB™BKšžœ;˜?K˜—šžœ˜šžœ˜Kšœ˜K˜K˜(˜Kšœžœ˜5Kšœžœ˜ —Kšœ žœ˜K˜—Kšžœ˜#—šžœžœž˜šœ˜Kšžœ žœžœžœ˜:šžœžœžœ˜5šžœžœ˜"Kšœ!˜!˜K˜K˜,—K˜KšœH˜HK˜—šžœžœ˜"Kšœ!˜!K˜K˜KšœH˜HK˜——Kšžœžœ˜—šœ žœžœ#˜7KšœΡ™ΡKšœ#˜#K˜Kšœžœ˜ K˜Kšœžœ˜K˜šžœž˜KšžœB˜G—šžœžœž˜šœ˜šžœžœž˜Kšœžœžœ˜1Kšžœžœ˜+——Kšžœžœ˜K˜—K˜—K˜K˜—šŸœžœžœžœž  œžœžœžœžœ˜Nšžœž˜'šœš˜šKšžœ˜—Kšœžœžœ˜˜K˜(šžœžœžœž˜Kšœžœžœžœž œžœžœžœžœ˜;——˜K˜(šžœžœžœž˜Kšœžœžœžœž œžœžœžœžœ˜@——Kšžœ˜—K˜K˜—šŸœžœžœžœžœžœžœžœžœžœžœ˜SKšœ˜Kšœ# ˜=K˜K˜ K˜K˜KšŸ œžœžœ'˜@KšŸ œžœžœ/˜IK˜"šžœžœž˜šœ˜Kšžœžœ˜!šžœžœžœž˜Jšœžœ-žœž˜DKšœžœžœ˜/Kšžœžœ&˜6—Kšœžœžœ˜.Kšœ žœ˜Kšžœ˜——šœ˜Kšžœžœ˜!šžœžœžœž˜Jšœžœ-žœž˜DKšœžœžœ˜/Kšžœžœ&˜6—Kšœžœžœ˜.Kšœ žœ˜Kšžœ˜——Kšžœžœ˜—K˜K˜Kšžœžœ˜0šžœ ˜šžœ˜šžœž˜!˜K˜˜K˜ K˜,˜&Kšœ-™-——Kšœ˜šžœžœ%ž˜0Kšžœ'˜,—šžœ˜!K˜;——˜K˜˜K˜,K˜—Kšžœ7˜=—˜ K˜˜K˜ K˜,˜1Kšœ-™-——Kšžœ(žœ˜=šžœ˜!K˜;——šœ˜K˜Kšžœ(žœ˜=šžœ˜#Kšœ˜K˜,K˜K˜K˜——Kšžœ˜—K˜—šžœ˜šžœž˜!šœ˜Kšœ˜šžœžœ%ž˜0Kšžœ'˜,—Kšœžœ+˜9KšžœF˜L—Kšœ žœ2˜Ešœ ˜ Kšœžœžœžœ˜0Kšžœ'žœ˜=šžœ˜Kšœ ˜ K˜K˜——šœ˜Kšœžœ˜$Kšžœ(žœ˜=šžœ˜Kšœ ˜ K˜K˜——Kšžœžœ˜—K˜——Kšœ ˜ Kšœ˜K˜—šŸœžœžœžœžœžœ žœžœ˜SKšœ ˜ Kšœ ˜KšœA™AKšœ  ˜!K˜ K˜šž˜Kšœ…™…Kšœ˜Kšžœžœžœ˜%Kšžœ#žœžœžœ ˜9K˜Kšœ*˜*Kšœ$˜$K˜šžœžœžœ˜@Kšœ!™!Kšœ žœ˜šžœ"ž˜,Kšœ$˜$Kšœ žœžœ˜Kšžœ˜—Kšœ ˜ Kšžœ˜K˜—šžœžœžœž˜CKšœR™Ršžœ ž˜šœΘ˜ΘKšžœ˜#——Kšžœžœžœ˜—K˜šžœžœ'žœ˜EKšœ“™“Kšœžœžœžœ˜!Kšžœ˜K˜K˜—Kšžœ˜Kšžœ˜—K˜šžœ ž˜šœ˜Kšœ(™(Kšžœžœžœžœ žœžœžœ˜7—šœ˜Kšœ™šžœ žœ ˜3šœ˜šžœ*˜,Kšžœ)˜,šžœ˜Kšœ/™/šžœ ˜šžœ!˜%Kšœ˜˜K˜K˜*Kšœ#˜#—K˜K˜—Kšžœ˜#—K˜2K˜—Kšžœžœžœ˜—K˜—Kšœžœžœ  ˜5Kšžœžœžœ˜—K˜—šœ'˜'Kšœ™Kšœ!˜!K˜!K˜%Kšœžœžœ˜'Kšœžœžœ˜(K˜šžœ žœ ˜3Kšœ&žœ˜+Kšžœžœžœ˜K˜—šžœ ž˜Kšœ1˜1Kšžœ˜K˜—šžœ ž˜šœ˜Kšœ)˜)šžœ ˜šžœ˜Kšœ$˜$K˜*K˜K˜D—Kšžœ5˜9——Kšžœ˜K˜—šžœ ž˜šœ˜Kšœ@™@Kš žœžœžœžœžœ ˜Fšžœ ž˜šœ˜šžœžœ&žœ˜FKšžœžœžœ ˜——šœ˜šžœžœ&žœ˜?Kšžœžœžœ ˜——šœžœ˜šœB™BKšœ™——Kšžœžœ˜—Kšœžœ˜ Kšœ˜—šžœ˜K˜——šžœ ž˜šœ˜šœ˜˜Kšžœžœ˜@——Kš žœžœžœžœžœ ˜6—šžœ˜K˜——šžœžœ˜8Kšžœ  ˜)Kšžœ  ˜'Kšžœ '˜EKšžœ>  ˜Jšžœžœ˜-KšžœB˜E—šžœ˜KšœD™Dšžœ ˜šžœ˜Kšœ˜Kšœžœ˜.Kš žœ žœžœžœžœžœ˜>šœžœ˜ Kšœ˜˜K˜ K˜,K˜ —K˜K˜—K˜—šžœ˜Kšœ7™7K˜0Kšœžœ˜&šžœžœž˜Kš œ žœ žœžœžœ˜:Kšžœžœ˜————Kšžœžœžœ ˜K˜——˜RKšœžœ˜šžœ ž˜Kš œžœžœžœžœ ˜.Kšœ žœžœžœžœžœžœžœ ˜AK˜Kšœ žœžœžœžœžœžœžœžœžœ ˜LKš œ žœžœ žœžœžœ ˜8šžœ˜ šžœ žœ˜BKšžœžœžœ ˜———K˜/Kšœ˜Kšžœ,˜2Kšœ˜K˜—˜ Kšœžœ˜Kš œžœžœžœžœ˜Kšžœ'˜-Kšœ˜K˜—Kšžœžœžœ˜—šž˜Kšœ žœ˜.Kšœ žœ,˜:Kšœ žœ˜+—šœ  ˜K˜——šŸœžœžœžœžœžœžœžœžœ˜[Kšœ&žœžœžœ˜OKšœ˜K˜—šŸœžœžœžœžœžœžœžœ˜=Kšœžœ˜K˜Kšžœžœžœžœ˜-Kšœ˜Kšœžœ žœžœ ˜KKšœ˜K˜—šŸœžœžœžœžœžœžœžœ˜=Kšœžœ˜K˜Kšžœžœžœžœ˜.Kšœ˜Kšœžœ žœžœ ˜KKšœ˜K˜—šœ!™!K˜—š Ÿœžœžœžœžœ˜JKšœ#˜#Kšœ˜K˜—š Ÿ œžœžœžœžœ˜DKšžœžœ˜*Kšžœ$˜*Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜7šžœžœž˜šœ˜šžœ žœž˜Kšœžœ˜Kšžœ˜——Kšžœ˜—Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜7šžœžœž˜šœ˜šžœ žœž˜Kšœžœ˜Kšžœ˜——Kšžœ˜—šœ˜K˜——š Ÿœžœžœ žœ*žœžœ)˜”Kšœ ™ šœžœ˜!KšžœQ˜UšžœR˜VK˜——Kšžœ žœžœžœ˜K˜Kšœ"™"šžœ žœž˜šœ˜šžœžœž˜"˜ K˜6šžœžœž˜$šœ˜šžœžœž˜K˜EKšžœžœ˜——Kšžœ˜ ——Kšžœ˜——Kšžœž˜—šœ˜K˜——š Ÿœžœžœžœ)žœ˜mšžœ ˜&Kšœ$˜$Kšœ*žœ%˜R—šœ˜K˜——š Ÿœžœžœžœ)žœ˜lKšžœV˜\Kšœ˜K˜—šŸœžœžœžœ˜:Kšœ™Kšœ)™)Kšžœ$˜*Kšœ˜K˜—Kšžœ˜K˜K˜—…—θΥψ