<> <> <> <> <> <> <> DIRECTORY LupineManagerPrivate USING [ ErrorCode, ModuleName, Options, ParamPassingMethod, SHORT, String ], LupineMarshal USING [ AddressInfo, AllocZone, AllocDetails, AllocInfo, EnumerateParams, FalseAddressInfo, FieldInfo, NoAllocations, OverlayParamType, ParamIndex, ParamInfo, ParamInfoNIL, ParamLocation, ParamProcedure, ParamRecordKind, ParamInfoObject, PktSite, SizeInfo, TransferDeclaration, TransferSite, Words, ZeroSizeInfo ], LupineMarshalPrivate USING [ HasEmptyIndex, HasDynamicIndex, MaxPointerDepth, MaxDataSize, MaxShortStringLength, NeedsOperationProc, Warning ], LupineSymbolTable USING [ ComponentProcedure, ComputeArraySize, EnumerateRecord, EnumerateVariants, FullTypeName, GetTypeInfo, SearchTypeDefinition, Size, TransferTypes, TypeHandle, TypeInfo, Types, VariantProcedure ]; LupineMarshalInfoImpl: PROGRAM IMPORTS LupineManagerPrivate, Marshal: LupineMarshal, Private: LupineMarshalPrivate, ST: LupineSymbolTable EXPORTS LupineMarshal, LupineMarshalPrivate SHARES LupineMarshal = BEGIN OPEN LupineManagerPrivate, LupineMarshal; <> NeedsOperationProc: TYPE = Private.NeedsOperationProc; MaxDataSize: Words = Private.MaxDataSize; MaxPointerDepth: INTEGER = Private.MaxPointerDepth; <> <> MakeParamInfo: PUBLIC PROCEDURE [ paramRecord: ST.TypeHandle, paramRecordKind: ParamRecordKind, pktSite: PktSite, RESULTsParamInfo: ParamInfo_ParamInfoNIL, transferType: ST.TransferTypes, transferDeclaration: TransferDeclaration, transferSite: TransferSite, options: Options ] RETURNS[paramInfo: ParamInfo] = BEGIN IsRESULT: PROCEDURE [typeInfo: ST.TypeInfo] RETURNS[--yes:-- BOOLEAN] = BEGIN RETURN[ SELECT DeterminePassingMethod [ typeInfo: typeInfo, paramKind: paramRecordKind, options: options ] FROM Var, Result => TRUE, Value, Handle, InterMds => FALSE, ENDCASE => ERROR ]; END; -- IsRESULT. paramCount, RESULTSubCount: ParamIndex _ 0; BEGIN CountParams: ST.ComponentProcedure = BEGIN paramCount _ componentIndex; IF IsRESULT[ST.GetTypeInfo[componentType]] THEN RESULTSubCount _ RESULTSubCount + 1; END; [] _ ST.EnumerateRecord[recordType: paramRecord, proc: CountParams]; END; SELECT paramRecordKind FROM argument => IF RESULTsParamInfo # ParamInfoNIL THEN ERROR; result => IF RESULTsParamInfo = ParamInfoNIL OR RESULTsParamInfo.paramRecordKind # argument THEN ERROR; ENDCASE => ERROR; paramInfo _ NEW[ ParamInfoObject [ 1 -- The zeroth parameter is unassigned. + paramCount -- Explicit parameters. + (IF RESULTsParamInfo=NIL THEN 0 ELSE RESULTsParamInfo.RESULTCount) <> ] _ [ paramRecord: paramRecord, paramRecordKind: paramRecordKind, pktSite: pktSite, transferType: transferType, transferDeclaration: transferDeclaration, transferSite: transferSite, options: options, alwaysOnePkt: TRUE, alwaysMultiplePkts: FALSE, hasOverlayParams: FALSE, hasOverlayParamType: ALL[FALSE], hasConversation: FALSE, adrInfo: FalseAddressInfo, allocInfo: NoAllocations, sizeOf: ZeroSizeInfo, paramCount: paramCount, RESULTCount: RESULTSubCount, RESULTsParamInfo: RESULTsParamInfo, fields: NULL ]]; BEGIN overlaySize: Words _ OverlayHeaderLength[paramInfo]; <> minDataSize, maxDataSize: Words _ overlaySize; GetFieldInfo: PROCEDURE [ typeInfo: ST.TypeInfo, fieldNumber: ParamIndex, passingMethod: ParamPassingMethod ] RETURNS [fieldInfo: FieldInfo] = BEGIN location: ParamLocation; overlayParamType: OverlayParamType _ other; adrInfo: AddressInfo = ParamAddressInfo[ typeInfo: typeInfo, passingMethod: passingMethod, paramKind: paramRecordKind ]; allocInfo: AllocInfo _ NoAllocations; fieldSize: Words = Size[typeInfo.self]; minFlatSize, maxFlatSize: Words _ 0; IF passingMethod=InterMds AND adrInfo.hasShortPtrs THEN Private.Warning[code: ShortInterMdsPointers, type: typeInfo.self]; IF fieldNumber=1 AND paramRecordKind=argument AND IsConversation[typeInfo.self] THEN location _ inConversation ELSE BEGIN SELECT TRUE FROM adrInfo.isStatic AND overlaySize+fieldSize <= MaxDataSize => {location _ inPktOverlay; overlayParamType _ static}; adrInfo.isAddress => {location _ inFrame; overlayParamType _ address}; ENDCASE => {location _ inFrame}; [minFlatSize, maxFlatSize] _ MarshaledFlatSize[ type: typeInfo.self, passingMethod: passingMethod, paramKind: paramRecordKind ]; allocInfo _ GetAllocInfo[ type: typeInfo.self, passingMethod: passingMethod, paramKind: paramRecordKind ]; END; RETURN[ FieldInfo [ type: typeInfo.type, passingMethod: passingMethod, location: location, overlayParamType: overlayParamType, adrInfo: adrInfo, allocInfo: allocInfo, size: fieldSize, minFlatSize: minFlatSize, maxFlatSize: maxFlatSize ] ]; END; -- GetFieldInfo. UpdateParamInfo: PROCEDURE [ paramInfo: --VAR-- ParamInfo, fieldInfo: FieldInfo, staticIsError: BOOLEAN _ FALSE ] = BEGIN OPEN adrInfo: fieldInfo.adrInfo; IF staticIsError AND adrInfo.isStatic THEN ERROR; SELECT fieldInfo.location FROM inConversation => paramInfo.hasConversation _ TRUE; inPktOverlay, inFrameAndOverlay => BEGIN paramInfo.hasOverlayParams _ TRUE; paramInfo.hasOverlayParamType[fieldInfo.overlayParamType] _ TRUE; overlaySize _ overlaySize + fieldInfo.size; IF overlaySize > MaxDataSize THEN ERROR; END; inFrame, inStream => NULL; ENDCASE => ERROR; <> <> <> <> <> <> <> minDataSize _ minDataSize + fieldInfo.minFlatSize; maxDataSize _ maxDataSize + fieldInfo.maxFlatSize; <> paramInfo.allocInfo _ AddAllocInfo[paramInfo.allocInfo, fieldInfo.allocInfo]; paramInfo.adrInfo _ AddressInfo[ hasStatics: adrInfo.hasStatics OR paramInfo.adrInfo.hasStatics, hasAddresses: adrInfo.hasAddresses OR paramInfo.adrInfo.hasAddresses, hasDynamics: adrInfo.hasDynamics OR paramInfo.adrInfo.hasDynamics, hasTransfers: adrInfo.hasTransfers OR paramInfo.adrInfo.hasTransfers, hasGC: adrInfo.hasGC OR paramInfo.adrInfo.hasGC, hasHeap: adrInfo.hasHeap OR paramInfo.adrInfo.hasHeap, hasMds: adrInfo.hasMds OR paramInfo.adrInfo.hasMds, hasShortPtrs: adrInfo.hasShortPtrs OR paramInfo.adrInfo.hasShortPtrs ]; END; -- UpdateParamInfo. IF paramCount > 0 THEN BEGIN ComputeFieldInfo: ST.ComponentProcedure = BEGIN typeInfo: ST.TypeInfo = ST.GetTypeInfo[componentType]; passingMethod: ParamPassingMethod = DeterminePassingMethod[ typeInfo: typeInfo, paramKind: paramRecordKind, options: options, reportErrors: TRUE ]; fieldInfo: FieldInfo = GetFieldInfo[typeInfo, componentIndex, passingMethod]; paramInfo.fields[componentIndex] _ fieldInfo; UpdateParamInfo[paramInfo, fieldInfo]; END; -- ComputeFieldInfo. [] _ ST.EnumerateRecord[recordType: paramRecord, proc: ComputeFieldInfo]; END; -- Of parameter record processing. IF paramRecordKind=result AND RESULTsParamInfo.RESULTCount > 0 THEN BEGIN resultIndex: ParamIndex _ paramCount; ComputeResultInfo: ParamProcedure = BEGIN SELECT paramFieldInfo.passingMethod FROM Var, Result => BEGIN resultFieldInfo: FieldInfo = GetFieldInfo[ ST.GetTypeInfo[paramType], paramIndex, paramFieldInfo.passingMethod ]; paramInfo.fields[(resultIndex_resultIndex+1)] _ resultFieldInfo; UpdateParamInfo[paramInfo, resultFieldInfo]; END; ENDCASE => NULL; END; -- ComputeResultInfo. Marshal.EnumerateParams[ paramInfo: RESULTsParamInfo, paramProc: ComputeResultInfo ]; IF resultIndex # paramCount+RESULTsParamInfo.RESULTCount THEN ERROR; END; -- Of implicit results processing. paramInfo.sizeOf _ [ overlayHeader: OverlayHeaderLength[paramInfo], overlayParamRecord: overlaySize, pktToAllocate: IF paramInfo.adrInfo.hasDynamics THEN MaxDataSize ELSE MIN[MaxDataSize, maxDataSize] ]; paramInfo.alwaysOnePkt _ ~paramInfo.adrInfo.hasDynamics AND maxDataSize <= MaxDataSize; paramInfo.alwaysMultiplePkts _ minDataSize > MaxDataSize; END; RETURN[--READONLY-- paramInfo]; END; FreeParamInfo: PUBLIC PROCEDURE [paramInfo: ParamInfo] = BEGIN NULL; END; EnumerateParams: PUBLIC PROCEDURE [ paramInfo: ParamInfo, paramProc: ParamProcedure, includeRESULTs: BOOLEAN_FALSE ] = BEGIN <> <> resultInfo: ParamInfo = paramInfo.RESULTsParamInfo; IF paramInfo.paramCount > 0 THEN BEGIN DoParam: ST.ComponentProcedure = BEGIN RETURN[ stop: paramProc[ paramName: component, paramType: componentType, paramIndex: componentIndex, paramFieldInfo: paramInfo.fields[componentIndex]].stop ]; END; -- DoParam. [] _ ST.EnumerateRecord[recordType: paramInfo.paramRecord, proc: DoParam]; END; IF includeRESULTs AND paramInfo.paramRecordKind=result AND resultInfo.RESULTCount > 0 THEN BEGIN resultIndex: ParamIndex _ paramInfo.paramCount; DoParam: ParamProcedure = BEGIN SELECT paramFieldInfo.passingMethod FROM Var, Result => RETURN[ stop: paramProc[ paramName: paramName, paramType: paramType, paramIndex: paramIndex, paramFieldInfo: paramInfo.fields[(resultIndex_resultIndex+1)]].stop ]; ENDCASE => NULL; END; -- DoParam. EnumerateParams[resultInfo, DoParam]; END; END; <
> ParamAddressInfo: PROCEDURE [ typeInfo: ST.TypeInfo, passingMethod: ParamPassingMethod, paramKind: ParamRecordKind ] RETURNS[adrInfo: AddressInfo_FalseAddressInfo] = BEGIN IsAdr: BOOLEAN = SELECT passingMethod FROM Handle, InterMds => FALSE, Var, Value, Result => TRUE, ENDCASE => ERROR; IsTransfer: BOOLEAN = passingMethod # Handle AND typeInfo.passingMethod # handle; <> TraceAddresses: PROC [type: ST.TypeHandle, ptrDepth: INTEGER] = BEGIN info: ST.TypeInfo = ST.GetTypeInfo[type: type]; NoteAddress: PROC [kind: {pointer, ref}] RETURNS [traceAddressFurther: BOOLEAN] = BEGIN IF IsAdr THEN BEGIN adrInfo.hasAddresses _ TRUE; SELECT kind FROM pointer => IF info.long THEN adrInfo.hasHeap _ TRUE ELSE adrInfo.hasMds _ TRUE; ref => adrInfo.hasGC _ TRUE; ENDCASE => ERROR; END ELSE NoteStatic; IF kind=pointer AND ~info.long THEN adrInfo.hasShortPtrs _ TRUE; RETURN[ IsAdr AND ~(passingMethod=Result AND paramKind=argument) ]; END; -- NoteAddress. NoteStatic: PROC = INLINE {adrInfo.hasStatics _ TRUE}; WITH info: info SELECT FROM Null, Basic, RelativePtr, Opaque => NoteStatic; Transfer => IF IsTransfer THEN adrInfo.hasTransfers _ TRUE ELSE NoteStatic; Record => BEGIN -- Monitored is reported elsewhere. CheckField: ST.ComponentProcedure = {TraceAddresses[componentType, ptrDepth]}; NoteStatic; [] _ ST.EnumerateRecord[recordType: type, proc: CheckField]; END; VariantPart => BEGIN -- Computed is reported elsewhere. CheckVariant: ST.VariantProcedure = {TraceAddresses[variantRecordType, ptrDepth]}; [] _ ST.EnumerateVariants[variantPartType: type, proc: CheckVariant]; END; Text, StringBody => adrInfo.hasDynamics _ TRUE; String => IF NoteAddress[pointer] THEN adrInfo.hasDynamics _ adrInfo.hasDynamics OR ~IsShortString[type]; Rope, Atom => IF NoteAddress[ref] THEN adrInfo.hasDynamics _ adrInfo.hasDynamics OR ~IsShortString[type]; Pointer => BEGIN IF ptrDepth > MaxPointerDepth THEN RETURN; IF NoteAddress[pointer] THEN TraceAddresses[info.referentType, ptrDepth+1]; END; Ref => BEGIN IF ptrDepth > MaxPointerDepth THEN RETURN; IF NoteAddress[ref] THEN TraceAddresses[info.referentType, ptrDepth+1]; END; List => IF NoteAddress[ref] THEN BEGIN adrInfo.hasDynamics _ TRUE; TraceAddresses[info.firstType, ptrDepth]; END; Array => BEGIN IF Private.HasEmptyIndex[index: info.indexType] THEN adrInfo.hasDynamics _ TRUE -- Obsolete sequence idiom. ELSE NoteStatic; -- Normal, static array. TraceAddresses[info.elementType, ptrDepth]; END; Descriptor => IF NoteAddress[pointer] THEN BEGIN adrInfo.hasDynamics _ adrInfo.hasDynamics OR Private.HasDynamicIndex[vectorInfo: info]; TraceAddresses[info.elementType, ptrDepth]; END; Sequence => BEGIN -- Computed is reported elsewhere. IF info.kind = Computed THEN RETURN; IF Private.HasDynamicIndex[vectorInfo: info] THEN adrInfo.hasDynamics _ TRUE ELSE NoteStatic; TraceAddresses[info.elementType, ptrDepth]; END; Zone => -- Zones must be handles. {NoteStatic; IF info.mdsZone THEN adrInfo.hasShortPtrs _ TRUE}; Definition, Any, Other => adrInfo.hasAddresses _ TRUE; -- Will cause an error during marshaling. ENDCASE => ERROR; END; -- TraceAddresses. TraceAddresses[type: typeInfo.self, ptrDepth: 0]; WITH typeInfo: typeInfo SELECT FROM Null, Basic, Record, VariantPart, RelativePtr, Zone, Opaque => NULL; Transfer => adrInfo.isTransfer _ IsTransfer; Text, StringBody => adrInfo.isDynamic _ TRUE; String, Rope, Atom, Pointer, Ref, List, Descriptor => adrInfo.isAddress _ IsAdr; Array => adrInfo.isDynamic _ Private.HasEmptyIndex[typeInfo.indexType]; Sequence => adrInfo.isDynamic _ Private.HasDynamicIndex[vectorInfo: typeInfo]; Definition, Any, Other => adrInfo.isAddress _ TRUE; <> ENDCASE => ERROR; adrInfo.isStatic _ NOT ( adrInfo.isAddress OR adrInfo.isDynamic OR adrInfo.isTransfer OR adrInfo.hasAddresses OR adrInfo.hasDynamics OR adrInfo.hasTransfers ); IF adrInfo.isStatic AND ~adrInfo.hasStatics THEN ERROR; END; <> HeaderWords: TYPE = Words[0..3]; HeaderInfo: TYPE = RECORD [ protocolHeaderSize: HeaderWords _ 0, useStandardSize: BOOLEAN _ FALSE] _ [0, TRUE]; NullHeader: HeaderWords = 0; NilHeader: HeaderWords = SIZE[BOOLEAN]; StringHeader: HeaderWords = SIZE[ RECORD[maxLength,length:CARDINAL] ]; RopeHeader: HeaderWords = SIZE[CARDINAL]; SequenceHeader: HeaderWords = SIZE[LONG CARDINAL]; ProtocolHeaderInfo: PACKED ARRAY ST.Types OF HeaderInfo = [ Transfer: [NullHeader], <> <> <> Pointer: [NilHeader], <> <> <> Ref: [NilHeader], <> String: [NilHeader+StringHeader], <> <> Text: [StringHeader], <> <> StringBody: [StringHeader], <> Rope: [NilHeader+RopeHeader], <> <> <> Atom: [NilHeader+RopeHeader], <> List: [SequenceHeader], <> <> Descriptor: [SequenceHeader], <> <> <> <> Sequence: [SequenceHeader], <> <> <> Zone: [] ]; <> MinFlatSize: PROCEDURE [typeInfo: ST.TypeInfo, zeroIfStandard: BOOLEAN] RETURNS [--minimumSize:-- Words] = INLINE BEGIN RETURN[ IF ProtocolHeaderInfo[typeInfo.type].useStandardSize THEN (IF zeroIfStandard THEN 0 ELSE Size[typeInfo.self]) ELSE ProtocolHeaderInfo[typeInfo.type].protocolHeaderSize ]; END; OverlayHeaderLength: PROCEDURE [paramInfo: ParamInfo] RETURNS [--length:-- Words] = BEGIN TransferIndexSize: INTEGER = SIZE[WORD]; CallbackBindingDetailsSize: INTEGER = 0;--SIZE[RpcLupine.CallbackBindingDetails]; RETURN[ SELECT paramInfo.paramRecordKind FROM argument => SELECT paramInfo.transferDeclaration FROM inInterface, inRoutine => TransferIndexSize + (IF paramInfo.adrInfo.hasTransfers THEN CallbackBindingDetailsSize ELSE 0), ENDCASE => ERROR, result => 0, ENDCASE => ERROR ]; END; MarshaledFlatSize: PROCEDURE [ type: ST.TypeHandle, passingMethod: ParamPassingMethod, paramKind: ParamRecordKind ] RETURNS [minFlatSize, maxFlatSize: Words] = BEGIN dynamic: BOOLEAN _ FALSE; stopAtAddresses: BOOLEAN = SELECT passingMethod FROM Var, Value => FALSE, Result => paramKind=argument, Handle, InterMds => TRUE, ENDCASE => ERROR; TraceSize: PROCEDURE [ type: ST.TypeHandle, include: {referentsOnly, bodyToo}, ptrDepth: INTEGER ] RETURNS [minSize, maxSize: Words_0] = BEGIN TraceArray: PROCEDURE [ arrayInfo: ST.TypeInfo, indexType, elementType: ST.TypeHandle, indexRange: {fixed, dynamic}, include: {referentsOnly, arrayToo} ] RETURNS [minSize, maxSize: Words] = BEGIN numElements: LONG INTEGER = Cardinality[indexType]; minSubElement, maxSubElement: Words; arraySize: Words = SELECT include FROM arrayToo => VectorSize[arrayInfo], referentsOnly => 0, ENDCASE => ERROR; [minSubElement, maxSubElement] _ TraceSize[elementType, referentsOnly, ptrDepth]; IF indexRange=dynamic THEN dynamic _ Private.HasDynamicIndex[vectorInfo: arrayInfo]; RETURN[ minSize: IF indexRange=dynamic THEN 0 ELSE (numElements*minSubElement)+arraySize, maxSize: (numElements*maxSubElement)+arraySize ]; END; -- TraceArray. typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; baseSize: Words = SELECT passingMethod FROM Handle, InterMds => IF include=referentsOnly THEN 0 ELSE Size[type], ENDCASE => MinFlatSize[ typeInfo: typeInfo, zeroIfStandard: include=referentsOnly ]; minExtra, maxExtra: Words _ 0; WITH info: typeInfo SELECT FROM Null, Definition, Basic, Transfer, Any, RelativePtr, Opaque, Zone, Other => NULL; Text, StringBody => dynamic _ TRUE; String, Rope, Atom => SELECT TRUE FROM stopAtAddresses => NULL; ~IsShortString[type] => dynamic _ TRUE; ENDCASE => BEGIN -- Small strings have bounded length: maxExtra_SIZE[ PACKED ARRAY [0..Private.MaxShortStringLength) OF CHARACTER ]; minExtra _ 0; END; Record => BEGIN CheckComponent: ST.ComponentProcedure = BEGIN min, max: Words; [min, max] _ TraceSize[componentType, referentsOnly, ptrDepth]; minExtra _ minExtra + min; maxExtra _ maxExtra + max; END; -- CheckComponent. [] _ ST.EnumerateRecord[recordType: type, proc: CheckComponent]; END; VariantPart => BEGIN CheckVariant: ST.VariantProcedure = BEGIN min, max: Words; [min, max] _ TraceSize[variantRecordType, referentsOnly, ptrDepth]; minExtra _ MAX[minExtra, min]; maxExtra _ MAX[maxExtra, max]; END; -- CheckVariant. [] _ ST.EnumerateVariants[variantPartType: type, proc: CheckVariant]; END; Pointer => BEGIN IF ptrDepth > MaxPointerDepth THEN RETURN; IF ~stopAtAddresses THEN { maxExtra_TraceSize[info.referentType, bodyToo, ptrDepth+1].maxSize; minExtra _ 0; } -- Pointer can be NIL => no extra. END; Ref => BEGIN IF ptrDepth > MaxPointerDepth THEN RETURN; IF ~stopAtAddresses THEN { maxExtra_TraceSize[info.referentType, bodyToo, ptrDepth+1].maxSize; minExtra _ 0; } -- Ref can be NIL => no extra. END; List => IF ~stopAtAddresses THEN dynamic _ TRUE; Array => [minExtra, maxExtra] _ TraceArray[ arrayInfo: info, indexType: info.indexType, elementType: info.elementType, indexRange: fixed, include: referentsOnly ]; Descriptor => SELECT TRUE FROM stopAtAddresses => NULL; ENDCASE => [minExtra, maxExtra] _ TraceArray[ arrayInfo: info, indexType: info.indexType, elementType: info.elementType, indexRange: dynamic, include: arrayToo ]; Sequence => [minExtra, maxExtra] _ TraceArray[ arrayInfo: info, indexType: info.indexType, elementType: info.elementType, indexRange: dynamic, include: arrayToo ]; ENDCASE => ERROR; RETURN[baseSize+minExtra, baseSize+maxExtra]; END; -- TraceSize. [minFlatSize, maxFlatSize] _ TraceSize[ type: type, include: bodyToo, ptrDepth: 0]; RETURN[minFlatSize, (IF dynamic THEN LAST[Words] ELSE maxFlatSize)]; END; <> GetAllocInfo: PROCEDURE [ type: ST.TypeHandle, passingMethod: ParamPassingMethod, paramKind: ParamRecordKind] RETURNS [allocInfo: AllocInfo] = BEGIN includeThisAlloc: BOOLEAN = SELECT passingMethod FROM Var, Result => paramKind=argument, Value => TRUE, Handle, InterMds => FALSE, ENDCASE => ERROR; TracePointers: PROCEDURE [ type: ST.TypeHandle, ptrDepth: INTEGER ] RETURNS [allocInfo: AllocInfo_NoAllocations] = BEGIN TraceArray: PROCEDURE [ arrayTypeInfo: ST.TypeInfo, indexType, elementType: ST.TypeHandle, indexRange: {fixed, dynamic} ] RETURNS [arrayInfo: AllocInfo] = BEGIN elementInfo: AllocInfo = TracePointers[elementType, ptrDepth]; dynamicIndex: BOOLEAN = SELECT indexRange FROM dynamic => Private.HasDynamicIndex[vectorInfo: arrayTypeInfo], fixed => Private.HasEmptyIndex[indexType], ENDCASE => ERROR; numElements: LONG INTEGER = IF dynamicIndex THEN 1 ELSE Cardinality[indexType]; FOR zone: AllocZone IN AllocZone DO arrayInfo[zone] _ AllocDetails[ number: SHORT[numElements*elementInfo[zone].number], isDynamic: elementInfo[zone].isDynamic AND numElements > 0 OR dynamicIndex AND elementInfo[zone].number > 0 ]; ENDLOOP; END; -- TraceArray. OneAlloc: ARRAY --isLongPointer:-- BOOLEAN OF AllocInfo = [ TRUE: AllocInfo[heap: [number: 1]], FALSE: AllocInfo[mds: [number: 1]] ]; typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; WITH info: typeInfo SELECT FROM Null, Definition, Basic, Transfer, Any, RelativePtr, Opaque, Zone, Other, Text, StringBody, Rope, Atom => NULL; String => IF includeThisAlloc THEN allocInfo _ OneAlloc[info.long]; Record => BEGIN CheckComponent: ST.ComponentProcedure = BEGIN allocInfo _ AddAllocInfo[ allocInfo, TracePointers[componentType, ptrDepth].allocInfo ]; END; -- CheckComponent. [] _ ST.EnumerateRecord[recordType: type, proc: CheckComponent]; END; VariantPart => BEGIN CheckVariant: ST.VariantProcedure = BEGIN variantInfo: AllocInfo _ TracePointers[variantRecordType, ptrDepth]; FOR zone: AllocZone IN AllocZone DO allocInfo[zone] _ AllocDetails[ number: MAX[allocInfo[zone].number, variantInfo[zone].number], isDynamic: allocInfo[zone].isDynamic OR variantInfo[zone].isDynamic ]; ENDLOOP; END; -- CheckVariant. [] _ ST.EnumerateVariants[variantPartType: type, proc: CheckVariant]; END; Pointer => BEGIN IF ptrDepth > MaxPointerDepth THEN RETURN; IF includeThisAlloc THEN BEGIN allocInfo _ AddAllocInfo[ OneAlloc[info.long], TracePointers[info.referentType, ptrDepth+1].allocInfo ]; END; END; Ref => BEGIN IF ptrDepth > MaxPointerDepth THEN RETURN; IF includeThisAlloc THEN allocInfo _ TracePointers[info.referentType, ptrDepth+1]; END; List => IF includeThisAlloc THEN BEGIN bodyInfo: AllocInfo = TracePointers[info.firstType, ptrDepth]; FOR zone: AllocZone IN AllocZone DO allocInfo[zone] _ AllocDetails[ number: bodyInfo[zone].number, -- Assume list has 1 element. isDynamic: bodyInfo[zone].number > 0 ]; -- Catch multiple elements. ENDLOOP; END; Array => allocInfo _ TraceArray[info, info.indexType, info.elementType, fixed]; Descriptor => IF includeThisAlloc THEN BEGIN allocInfo _ AddAllocInfo[ OneAlloc[info.long], TraceArray[info, info.indexType, info.elementType, dynamic] ]; END; Sequence => allocInfo _ TraceArray[info, info.indexType, info.elementType, dynamic]; ENDCASE => ERROR; END; -- TracePointers. RETURN[ TracePointers[type: type, ptrDepth: 0] ]; END; AddAllocInfo: PROCEDURE [a, b: AllocInfo] RETURNS [aPlusB: AllocInfo] = BEGIN FOR zone: AllocZone IN AllocZone DO aPlusB[zone] _ AllocDetails[ number: a[zone].number + b[zone].number, isDynamic: a[zone].isDynamic OR b[zone].isDynamic ]; ENDLOOP; END; <> NeedsMarshaling: PUBLIC Private.NeedsOperationProc = BEGIN RecordNeedsMarshaling: PROC [record: ST.TypeHandle] RETURNS [BOOLEAN] = INLINE BEGIN CheckComponent: ST.ComponentProcedure = {RETURN[ stop: NeedsMarshaling[componentType] ]}; RETURN[ ST.EnumerateRecord[record, CheckComponent].stopped ]; END; VariantNeedsMarshaling: PROC [variantPart: ST.TypeHandle] RETURNS [BOOLEAN] = INLINE BEGIN CheckVariant: ST.VariantProcedure = {RETURN[ stop: NeedsMarshaling[variantRecordType] ]}; RETURN[ ST.EnumerateVariants[variantPart, CheckVariant].stopped ]; END; typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; RETURN [ WITH typeInfo: typeInfo SELECT FROM Null, Basic, RelativePtr, Opaque => FALSE, Text, StringBody => TRUE, -- Dynamic length requires computing. Record => --WRONG: typeInfo.hasSequences OR-- RecordNeedsMarshaling[type], VariantPart => VariantNeedsMarshaling[type], Transfer, Pointer, Ref, List, String, Rope, Atom, Descriptor, Zone => typeInfo.passingMethod # handle, -- All these contain addresses. Array => NeedsMarshaling[typeInfo.elementType] OR Private.HasEmptyIndex[index: typeInfo.indexType], -- For error reporting. Sequence => NeedsMarshaling[typeInfo.elementType] OR typeInfo.kind = Computed, -- For error reporting. Definition, Any, Other => TRUE, -- So that an error will be issued. ENDCASE => ERROR ]; END; ContainsRefs: PUBLIC Private.NeedsOperationProc = BEGIN RecordContainsRefs: PROC [record: ST.TypeHandle] RETURNS [BOOLEAN] = --INLINE-- BEGIN CheckComponent: ST.ComponentProcedure = {RETURN[ stop: ContainsRefs[componentType] ]}; RETURN[ ST.EnumerateRecord[record, CheckComponent].stopped ]; END; VariantContainsRefs: PROC [variantPart: ST.TypeHandle] RETURNS [BOOLEAN] = --INLINE-- BEGIN CheckVariant: ST.VariantProcedure = {RETURN[ stop: ContainsRefs[variantRecordType] ]}; RETURN[ ST.EnumerateVariants[variantPart, CheckVariant].stopped ]; END; typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; RETURN [ WITH typeInfo: typeInfo SELECT FROM Ref, List, Rope, Atom, Transfer => typeInfo.passingMethod # handle, Null, Definition, Basic, Text, String, StringBody, Pointer, RelativePtr, Any, Zone, Opaque, Other => FALSE, Record => RecordContainsRefs[type], VariantPart => VariantContainsRefs[type], Array => ContainsRefs[typeInfo.elementType], Descriptor => ContainsRefs[typeInfo.elementType], Sequence => ContainsRefs[typeInfo.elementType], ENDCASE => ERROR ]; END; ContainsEmbeddedPtrs: PUBLIC Private.NeedsOperationProc = BEGIN ContainsPtrs: PROCEDURE [type: ST.TypeHandle, topLevel: BOOLEAN_FALSE] RETURNS [BOOLEAN] = BEGIN RecordContainsPtrs: PROC [record: ST.TypeHandle] RETURNS [BOOLEAN] = --INLINE-- BEGIN CheckComponent: ST.ComponentProcedure = {RETURN[ stop: ContainsPtrs[componentType] ]}; RETURN[ ST.EnumerateRecord[record, CheckComponent].stopped ]; END; VariantContainsPtrs: PROC [variantPart: ST.TypeHandle] RETURNS [BOOLEAN] = --INLINE-- BEGIN CheckVariant: ST.VariantProcedure = {RETURN[ stop: ContainsPtrs[variantRecordType] ]}; RETURN[ ST.EnumerateVariants[variantPart, CheckVariant].stopped ]; END; typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; RETURN [ WITH typeInfo: typeInfo SELECT FROM Null, Definition, Basic, StringBody, Text, RelativePtr, Any, Opaque, Other => FALSE, Transfer, Pointer, Ref, List, String, Rope, Atom, Zone => ~topLevel AND typeInfo.passingMethod # handle, Record => RecordContainsPtrs[type], VariantPart => VariantContainsPtrs[type], Array => ContainsPtrs[typeInfo.elementType], Descriptor => typeInfo.passingMethod # handle AND (~topLevel OR ContainsPtrs[typeInfo.elementType]), Sequence => ContainsPtrs[typeInfo.elementType], ENDCASE => ERROR ]; END; -- ContainsPtrs. RETURN[ ContainsPtrs[type: type, topLevel: TRUE] ]; END; ContainsStatics: PUBLIC Private.NeedsOperationProc = BEGIN RecordContainsStatics: PROC [recordType: ST.TypeHandle] RETURNS [BOOLEAN] = --INLINE-- BEGIN CheckField: ST.ComponentProcedure = {RETURN[ stop: ContainsStatics[componentType] ]}; RETURN[ ST.EnumerateRecord[recordType, CheckField].stopped ]; END; -- RecordContainsStatics. typeInfo: ST.TypeInfo = ST.GetTypeInfo[type]; RETURN[ WITH typeInfo: typeInfo SELECT FROM Null, Definition, Other => FALSE, Basic, RelativePtr, Zone, Opaque => TRUE, VariantPart => typeInfo.kind # Computed, -- So tag(s) get copied. Text, StringBody => FALSE, Transfer, String, Rope, Atom, Pointer, Ref, Any, List, Descriptor, Zone => typeInfo.passingMethod = handle, Array => ContainsStatics[typeInfo.elementType], Sequence => ContainsStatics[typeInfo.elementType], Record => RecordContainsStatics[type], ENDCASE => ERROR ]; END; ContainsSequences: PUBLIC Private.NeedsOperationProc = BEGIN RecordContainsSequences: PROC [record: ST.TypeHandle] RETURNS [BOOLEAN] = --INLINE-- BEGIN CheckComponent: ST.ComponentProcedure = {RETURN[ stop: ContainsSequences[componentType] ]}; RETURN[ ST.EnumerateRecord[record, CheckComponent].stopped ]; END; VariantContainsSequences: PROC [variantPart:ST.TypeHandle] RETURNS[BOOLEAN] = --INLINE-- BEGIN CheckVariant: ST.VariantProcedure = {RETURN[ stop: ContainsSequences[variantRecordType] ]}; RETURN[ ST.EnumerateVariants[variantPart, CheckVariant].stopped ]; END; typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; RETURN [ WITH typeInfo: typeInfo SELECT FROM Sequence => TRUE, Null, Definition, Basic, Transfer, Text, String, StringBody, Pointer, RelativePtr, Ref, List, Rope, Atom, Descriptor, Any, Zone, Opaque, Other => FALSE, Record => typeInfo.hasSequences, VariantPart => VariantContainsSequences[type], Array => ContainsSequences[typeInfo.elementType], ENDCASE => ERROR ]; END; <> Cardinality: PUBLIC PROCEDURE [index: ST.TypeHandle] RETURNS [LONG INTEGER] = --INLINE-- BEGIN WITH indexInfo: ST.GetTypeInfo[type: index] SELECT FROM Basic => RETURN[indexInfo.cardinality]; ENDCASE => ERROR; END; Size: PROCEDURE [type: ST.TypeHandle] RETURNS [--size:-- Words] = INLINE BEGIN RETURN[ST.Size[type: type]]; END; VectorSize: PUBLIC PROCEDURE [vectorInfo: ST.TypeInfo] RETURNS [--size:-- Words] = BEGIN RETURN[ WITH info: vectorInfo SELECT FROM Array => ST.Size[info.self], -- PACKED is handled automatically. Descriptor => ST.ComputeArraySize[ index: info.indexType, elements: info.elementType, packed: info.packed], Sequence => ST.ComputeArraySize[ index: info.indexType, elements: info.elementType, packed: info.packed], ENDCASE => ERROR ]; END; IsShortString: PUBLIC PROCEDURE [candidate: ST.TypeHandle] RETURNS [--yes:-- BOOLEAN] = BEGIN shortStringTypes: ARRAY [0..3) OF ST.FullTypeName _ [ [module: ModuleName[rpcPublic], name: "ShortSTRING"], [module: ModuleName[rpcPublic], name: "ShortROPE"], [module: ModuleName[rpcPublic], name: "ShortATOM"] ]; matchIndex: INTEGER = ST.SearchTypeDefinition[ rootDef: candidate, candidateDefs: DESCRIPTOR[shortStringTypes] ]; RETURN[ matchIndex IN [0..LENGTH[shortStringTypes]) ]; END; IsConversation: PROCEDURE [candidate: ST.TypeHandle] RETURNS [--yes:-- BOOLEAN] = BEGIN conversationTypes: ARRAY [0..1) OF ST.FullTypeName _ [ [module: ModuleName[rpcPublic], name: "Conversation"] ]; matchIndex: INTEGER = ST.SearchTypeDefinition[ rootDef: candidate, candidateDefs: DESCRIPTOR[conversationTypes] ]; RETURN[ matchIndex IN [0..LENGTH[conversationTypes]) ]; END; IsExplicitHandle: PUBLIC PROC [typeInfo: ST.TypeInfo] RETURNS [--yes:-- BOOLEAN] = BEGIN <> <> <> < changing the other.>> SELECT typeInfo.type FROM Null, Definition, Basic, Record, VariantPart, RelativePtr, Text, StringBody, Array, Sequence, Any, Opaque, Other => RETURN[FALSE]; String, Pointer, Descriptor, Transfer, Zone => RETURN[typeInfo.passingMethod = handle]; Ref, Rope, Atom, List => IF typeInfo.passingMethod = handle THEN BEGIN Private.Warning[code: HandleREF, type: typeInfo.self]; RETURN[TRUE]; END ELSE RETURN[FALSE]; ENDCASE => ERROR; END; DeterminePassingMethod: PROCEDURE [ typeInfo: ST.TypeInfo, paramKind: ParamRecordKind, options: Options, reportErrors: BOOLEAN_FALSE ] RETURNS[method: ParamPassingMethod] = BEGIN Error: PROCEDURE [ errorCode: ErrorCode_ImproperPassingMethod, default: ParamPassingMethod ] RETURNS [--default:-- ParamPassingMethod] = BEGIN IF reportErrors THEN Private.Warning[code: errorCode, type: typeInfo.self]; RETURN[default]; END; GetAddressMethod: PROCEDURE [hasRef: BOOLEAN_FALSE] RETURNS [method: ParamPassingMethod] = BEGIN method _ (SELECT typeInfo.passingMethod FROM var => Var, value => Value, result => Result, handle => Handle, standard => SELECT paramKind FROM argument => options.defaultParamPassing, result => SELECT options.defaultParamPassing FROM Var, Result => Value, ENDCASE => options.defaultParamPassing, ENDCASE => ERROR, ENDCASE => ERROR); IF hasRef AND method=Handle THEN method _ Error[HandleREF, Handle]; SELECT method FROM Var, Result => BEGIN IF typeInfo.readonly THEN method _ Error[ImproperReadonlyRESULT, Value]; IF paramKind=result THEN method _ Error[ImproperRESULTResult, Value]; END; ENDCASE => NULL; END; -- GetAddressMethod. RETURN[ IF options.defaultParamPassing = InterMds THEN InterMds ELSE SELECT typeInfo.type FROM Null, Definition, Basic, Record, VariantPart, RelativePtr, Text, StringBody, Array, Sequence, Any, Opaque, Other => SELECT typeInfo.passingMethod FROM standard, value => Value, ENDCASE => Error[default: Value], String, Pointer, Descriptor => GetAddressMethod[], Ref => GetAddressMethod[hasRef: TRUE], Rope, Atom, List => SELECT GetAddressMethod[hasRef: TRUE] FROM Value => Value, Handle => Handle, ENDCASE => Error[default: Value], Transfer => SELECT GetAddressMethod[hasRef: FALSE --For now.--] FROM Value => Value, Handle => Handle, ENDCASE => Error[default: Value], Zone => SELECT GetAddressMethod[] FROM Handle => Handle, ENDCASE => Error[default: Handle], ENDCASE => ERROR ]; END; END. -- LupineMarshalInfoImpl.