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 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. LupineMarshalInfoImpl.mesa. Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by BZM on 9-Mar-82 18:19:55. Birrell, September 9, 1983 3:45 pm Bob Hagmann February 8, 1985 5:04:22 pm PST This module cooperates with LupineMarshal*Impl to export LupineMarshal. Types and constants from the internal LupineManagerPrivate interface. The ParamInfo routines pull together all the information needed for parameter marshaling and efficient one-packet-call stub generation. Implicit VARs and RESULTs in result record. GetFieldInfo and UpdateParamInfo cooperatively maintain this variable. IF adrInfo.isAddress OR adrInfo.isTransfer THEN BEGIN Don't send the addresses of top-level AC params, just the referents. minDataSize _ minDataSize + fieldInfo.minFlatSize - fieldInfo.size; maxDataSize _ maxDataSize + fieldInfo.maxFlatSize - fieldInfo.size; END ELSE BEGIN END; This enumerator is in this module because it cooperates intimately with MakeParamInfo in the handling of VAR and RESULT parameters. Address Information Routines. IsDynamic, IsStatic: BOOLEAN = TRUE; Will cause an error during marshaling. Size Information Routines. Callback transfers are statically numbered and therefore have no per-transfer overhead. One set of CallbackDispatcherDetails is used to marshal all the transfer parameters in a given routine. Pointers are marshaled by prefixing their referents with an isNIL tag. If true, nothing follows because the pointer is NIL. If false, then the referent follows. Refs are the same as pointers. Strings are like Text, but the full CARDINAL range can be used. NIL is mapped correctly. Text is marshaled by preceding the characters with the NAT (a subset of CARDINAL) maxLength and length. StringBody is the same as string proper, but there's no pointer. A rope is marshaled by preceding the rope's characters with the rope's NAT (subset of CARDINAL) length. NIL is mapped correctly. An atom's PName is marshaled like a rope. A list is preceded by its LONG CARDINAL number of nodes. NIL is equivalent to zero nodes. A descriptor's elements are preceded by the descriptor's LONG CARDINAL LENGTH (# of elements). LONG is used for future compatibility. NIL is equivalent to zero elements. Sequences are similar to descriptors, BUT THE LENGTH APPEARS IN FRONT OF THE CONTAINING RECORD, NOT BEFORE THE SEQUENCE PART. There's never NIL, although the (separate) record pointer might be. Zone pointers must always be handles. Explicit storage allocation information routines. Routines that determine whether marshaling is needed for various types. Information Utility Routines. IsExplicitHandle locates programer-declared HANDLETypes. It uses logic similar to DeterminePassingMethod, but cannot call it (the ideal) because the caller's context is awkwardly different. Changing one <=> changing the other. Κ#‚˜headšœ™Icodešœ Οmœ1™<—šœ™Jšœ™L™"L™+—J˜JšœG™GJ˜šΟk ˜ šœžœ˜J˜3Jšžœ ˜—šœžœ˜J˜0J˜"J˜+J˜3J˜:J˜,J˜—šœžœ˜J˜J˜3J˜—šœžœ˜J˜6J˜ J˜7J˜0J˜J˜——šœž˜šž˜J˜-Jšœžœ˜4—Jšžœ$˜+Jšžœ˜Jšœžœžœ%˜1J˜J˜JšœE™E˜Jšœžœ˜6J˜)Jšœžœ˜3J˜——J˜JšœC™CJšœC™C˜šΟn œžœž œ˜!Jšœ žœ ˜J˜!J˜J˜)Jšœžœ˜J˜)J˜J˜Jšžœ˜Jšž˜š Ÿœž œ žœ žœΟcœžœ˜GJšž˜šžœ˜šžœ˜šœCž˜GJšœžœ˜Jšœžœ˜!Jšžœžœ˜———Jšžœ  ˜—J˜+šž˜šœ žœ˜%Jšž˜J˜šžœ žœ˜*Jšžœ%˜)—Jšžœ˜—Jšœžœ=˜DJšžœ˜—šžœž˜Jšœ žœ!žœžœ˜:˜ šžœ!ž˜%Jšœ,žœžœ˜7——Jšžœžœ˜—J˜šœ žœ˜˜Jšœ &˜9Jšœ ˜&š œžœžœžœžœ˜DJšœ+™+—J˜J˜J˜!J˜J˜J˜)J˜J˜Jšœžœžœ˜.Jšœžœ˜Jšœžœžœ˜ Jšœžœ˜J˜J˜J˜J˜J˜J˜#Jšœžœ˜——šž˜˜4JšœF™F—J˜.šŸ œž œ˜Jšœ žœ#˜/J˜#Jšžœ˜ Jšž˜J˜J˜+˜(J˜J˜;—J˜%J˜'J˜$šžœžœ˜2JšžœC˜G—šžœžœžœ˜OJšžœ˜šžœž˜ šžœžœž˜šœžœ(˜šžœž˜ J˜%˜#Jšž˜šžœž˜(˜Jšž˜˜*JšžœD˜F—J˜@J˜,Jšžœ˜—Jšžœžœ˜—Jšžœ ˜—˜J˜<—Jšžœ7žœžœ˜DJšžœ "˜(——˜J˜.J˜ šœžœ˜0Jšžœ žœžœ˜6——˜Jšœžœ˜>—J˜9Jšžœ˜—Jšžœ  œ ˜Jšžœ˜J˜J˜—šŸ œžœž œ˜8Jšž˜Jšžœ˜Jšžœ˜J˜—šŸœžœž œ˜#J˜J˜Jšœžœžœ˜!Jšž˜JšœB™BJšœ@™@J˜3šžœ˜šžœž˜ šœ žœ˜ Jšž˜šžœ˜˜J˜J˜J˜J˜9——Jšžœ  ˜—JšœžœC˜JJšžœ˜——šžœž˜Jšœ!žœ˜?šžœž˜ J˜/˜Jšž˜šžœž˜(šœžœ˜˜J˜J˜J˜˜J˜6———Jšžœžœ˜—Jšžœ  ˜—J˜%Jšžœ˜——Jšžœ˜J˜——J˜Jšœ™˜šŸœž œ˜Jšœ žœ ˜J˜"J˜Jšžœ)˜0Jšž˜šœžœžœž˜*Jš œžœžœžœžœ˜H—šœ žœ˜Jšœžœ!˜;—Jšœ$™$šŸœžœžœžœ˜?Jšž˜Jšœžœ žœ˜/šŸ œžœ˜(Jšžœžœ˜(Jšž˜šžœ˜šžœž˜ Jšœžœ˜šžœž˜šœ žœ ˜Jšžœž˜Jšžœžœ˜—Jšœžœ˜Jšžœžœ˜—Jšž˜—Jšžœ ˜—Jšžœžœ žœžœ˜@Jšžœžœžœ˜CJšžœ ˜—JšŸ œžœžœžœ˜6šžœ žœž˜˜#J˜ —˜ Jšžœ žœžœžœ ˜?—˜ Jšžœ #˜*šœ žœ˜#J˜*—J˜ Jšœžœ5˜˜EJšžœ˜—˜Jšœžœ˜—˜ šžœž˜Jšœ*žœ˜B——˜ šžœž˜Jšœ*žœ˜B——˜ Jšž˜Jšžœžœžœ˜*Jšžœžœ/˜KJšžœ˜—˜Jšž˜Jšžœžœžœ˜*Jšžœžœ/˜GJšžœ˜—˜šžœ˜Jšžœž˜ Jšœžœ˜J˜)Jšžœ˜——˜Jšž˜šžœ-˜/Jšžœžœ ˜—˜ J˜B—šœ.žœ˜3Jšœ&™&—Jšžœžœ˜—šœžœ˜Jšœžœžœž˜?Jšœžœžœ˜F—Jšžœžœžœžœ˜7Jšžœ˜J˜——J˜Jšœ™˜Jšœ žœ˜ J˜šœ žœžœ˜J˜$Jšœžœžœžœ˜.J˜—J˜Jšœžœžœ˜'Jšœžœžœžœ˜FJšœžœžœ˜)Jšœžœžœžœ˜2J˜š œžœžœžœžœ˜;˜Jšœ=™=Jšœ?™?JšœB™B—˜Jšœ;™;Jšœ@™@Jšœ$™$—˜Jšœ™—˜!Jšœ?™?Jšœ™—˜Jšœ6™6Jšœ0™0—˜Jšœ@™@—˜Jšœ;™;Jšœ+™+Jšœ™—˜Jšœ)™)—˜Jšœ8™8Jšœ ™ —˜Jšœ8™8Jšœ7™7Jšœ™Jšœ#™#—˜Jšœ<™—šžœ˜šœ žœ˜Jšžœžœ'˜2—J˜1—Jšžœ ˜—Jšœ žœ žœ˜3šœžœž˜+Jšœžœžœžœ ˜Dšžœ˜J˜<——J˜šžœžœž˜˜"Jšœ)žœ˜.—Jšœžœ˜#˜šžœžœž˜Jšœžœ˜Jšœ"žœ˜'šžœ˜ Jšžœ %˜,šœ žœ˜Jšžœžœ#žœž œ˜>—J˜ Jšžœ˜———˜ Jšž˜šœžœ˜'Jšž˜J˜J˜?J˜6Jšžœ ˜—Jšœžœ9˜@Jšžœ˜—˜Jšž˜šœžœ˜#Jšž˜J˜J˜CJšœ žœžœ˜>Jšžœ ˜—Jšœžœ>˜EJšžœ˜—˜ Jšž˜Jšžœžœžœ˜*šžœžœ˜J˜CJšœ "˜3—Jšžœ˜—˜Jšž˜Jšžœžœžœ˜*šžœžœ˜J˜CJšœ ˜/—Jšžœ˜—Jšœžœžœ žœ˜0˜˜"J˜J˜9J˜,——˜ šžœžœž˜Jšœžœ˜šžœ˜ ˜"J˜J˜9J˜)————˜ ˜"J˜J˜9J˜)——Jšžœžœ˜—Jšžœ'˜-Jšžœ  ˜—˜'J˜+—Jš žœžœ žœžœžœ˜DJšžœ˜J˜——J˜Jšœ1™1˜šŸ œž œ˜Jšœžœ ˜J˜"J˜Jšžœ˜ Jšž˜šœžœžœž˜5J˜"Jšœ žœ˜Jšœžœ˜Jšžœžœ˜—šŸ œž œ˜Jšœžœ ˜Jšœ žœ˜Jšžœ'˜.Jšž˜šŸ œž œ˜Jšœžœ ˜Jšœžœ ˜&J˜Jšžœ˜ Jšž˜J˜>šœžœžœ ž˜.J˜>J˜*Jšžœžœ˜—šœ žœžœ˜Jšžœžœžœ˜3—šžœžœ ž˜#˜Jšœ žœ'˜7šœ'žœ˜:Jšžœžœ ˜3——Jšžœ˜—Jšžœ ˜—š œ žœ œžœžœ˜;Jšžœ žœ ˜IJšœ žœ žœ˜3—šžœžœž˜˜"J˜&Jšœ žœ˜%—˜ Jšžœžœ!˜9—˜ Jšž˜šœžœ˜'Jšž˜˜J˜>—Jšžœ ˜—Jšœžœ9˜@Jšžœ˜—˜Jšž˜šœžœ˜#Jšž˜J˜Dšžœžœ ž˜#˜Jšœžœ3˜>Jšœ%žœ˜F—Jšžœ˜—Jšžœ ˜—Jšœžœ>˜EJšžœ˜—˜ Jšž˜Jšžœžœžœ˜*šžœ˜šžœž˜ ˜J˜J˜9—Jšžœ˜——Jšžœ˜—˜Jšž˜Jšžœžœžœ˜*šžœ˜Jšžœ:˜>—Jšžœ˜—˜šžœ˜šžœžœ˜ J˜>šžœžœ ž˜#˜Jšœ  ˜=Jšœ) ˜D—Jšžœ˜—Jšžœ˜———˜J˜F—˜ šžœ˜šžœž˜ ˜J˜J˜>—Jšžœ˜———˜ J˜H—Jšžœžœ˜—Jšžœ ˜—Jšžœ+˜1Jšžœ˜J˜—šŸ œž œžœ˜GJšž˜šžœžœ ž˜#˜J˜+Jšœžœ˜4—Jšžœ˜—Jšžœ˜J˜——J˜JšœG™G˜šœžœ˜4Jšž˜š Ÿœžœ žœ žœžœ˜GJšžœž˜ šœžœ˜'Jšœžœ*˜1—Jšžœžœ3˜=Jšžœ˜—š Ÿœžœžœ žœžœ˜MJšžœž˜ šœžœ˜#Jšœžœ.˜5—Jšžœžœ8˜BJšžœ˜—Jšœ žœ žœ˜3šžœ˜šžœžœž˜#Jšœ$žœ˜*Jšœžœ %˜@Jšœ  #œ˜JJ˜,˜EJšœ" ˜A—˜Jšœ&ž˜(Jšœ2 ˜I—˜ Jšœ&ž˜(Jšœ ˜2—Jšœžœ #˜DJšžœžœ˜——Jšžœ˜J˜—šœžœ˜1Jšž˜š Ÿœžœ žœ žœžœ˜DJš  œž˜šœžœ˜'Jšœžœ'˜.—Jšžœžœ3˜=Jšžœ˜—š Ÿœžœžœ žœžœ˜JJš  œž˜šœžœ˜#Jšœžœ+˜2—Jšžœžœ8˜BJšžœ˜—Jšœ žœ žœ˜3šžœ˜šžœžœž˜#J˜C˜J˜/Jšœžœ˜"—J˜#J˜)J˜,J˜1J˜/Jšžœžœ˜——Jšžœ˜J˜—šœžœ˜9Jšž˜š Ÿ œž œžœžœžœ˜FJšžœžœ˜Jšž˜š Ÿœžœ žœ žœžœ˜DJš  œž˜šœžœ˜'Jšœžœ'˜.—Jšžœžœ3˜=Jšžœ˜—š Ÿœžœžœ žœžœ˜JJš  œž˜šœžœ˜#Jšœžœ+˜2—Jšžœžœ8˜BJšžœ˜—Jšœ žœ žœ˜3šžœ˜šžœžœž˜#˜7Jšœžœ˜—˜9Jšœ žœ!˜.—J˜#J˜)J˜,˜-Jšžœ žœ%˜6—J˜/Jšžœžœ˜——Jšžœ ˜—Jšžœ%žœ˜3Jšžœ˜J˜—šœžœ˜4Jšž˜š Ÿœžœžœ žœžœ˜KJš  œž˜šœ žœ˜#Jšœžœ*˜1—Jšžœžœ3˜=Jšžœ ˜—Jšœ žœ žœ˜-šžœ˜šžœžœž˜#Jšœžœ˜!Jšœ$žœ˜)Jšœ) ˜AJšœžœ˜˜0J˜J˜ —J˜/J˜2J˜&Jšžœžœ ˜——Jšžœ˜J˜—šœžœ˜6Jšž˜š Ÿœžœ žœ žœžœ˜IJš  œž˜šœžœ˜'Jšœžœ,˜3—Jšžœžœ3˜=Jšžœ˜—š Ÿœžœžœ žœžœ˜MJš  œž˜šœžœ˜#Jšœžœ0˜7—Jšžœžœ8˜BJšžœ˜—Jšœ žœ žœ˜3šžœ˜šžœžœž˜#Jšœ žœ˜˜"J˜/J˜Jšœ(žœ˜.—J˜ J˜.J˜1Jšžœžœ˜——Jšžœ˜J˜——J˜Jšœ™˜šŸ œžœž œ žœ žœžœžœ˜MJš  œž˜šžœ žœžœž˜7Jšœ žœ˜'Jšžœžœ˜—Jšžœ˜J˜—š Ÿœž œžœ žœ  œ ˜AJš žœžœžœžœžœ˜.J˜—šŸ œžœž œžœ ˜6Jšžœ  œ ˜Jšž˜šžœžœžœž˜*Jšœ žœ #˜Ašœžœ˜"J˜H—šœ žœ˜ J˜H—Jšžœžœ˜—Jšžœ˜J˜—šŸ œžœž œ žœ ˜:Jšžœ œžœ˜Jšž˜šœžœžœžœ˜5J˜5J˜3J˜5—šœ žœžœ˜.Jšœ#ž œ˜B—Jšžœ žœžœ˜6Jšžœ˜J˜—šŸœž œ žœ ˜4Jšžœ œžœ˜Jšž˜šœžœžœžœ˜6J˜8—šœ žœžœ˜.Jšœ#ž œ˜C—Jšžœ žœžœ˜7Jšžœ˜J˜—šŸœžœžœ žœ ˜5Jšžœ œžœ˜Jšž˜Jšœ8™8Jšœ0™0Jšœ;™;Jšœ=™=šžœž˜˜:J˜8Jšžœžœ˜—˜.Jšžœ"˜(—˜šžœ ˜"šžœž˜ J˜6Jšžœžœ˜ Jšž˜—Jšžœžœžœ˜——Jšžœžœ˜—Jšžœ˜J˜—šŸœž œ˜#Jšœ žœ ˜J˜J˜Jšœžœžœ˜Jšžœ˜%Jšž˜šŸœž œ˜J˜+J˜Jšžœ  œ˜+Jšž˜Jšžœžœ7˜KJšžœ ˜Jšžœ˜—šŸœž œ žœžœ˜3Jšžœ˜&Jšž˜˜šœžœž˜#J˜?šœ žœ ž˜!J˜(šœ žœž˜1J˜Jšžœ ˜'—Jšžœžœ˜—Jšžœžœ˜——Jšžœžœžœ#˜Cšžœž˜˜Jšž˜Jšžœžœ/˜HJšžœžœ-˜EJšžœ˜—Jšžœžœ˜—Jšžœ ˜—šžœ˜šžœ'˜)Jšžœ ˜ šžœžœž˜˜:J˜8šžœž˜"J˜Jšžœ˜!——˜J˜—˜Jšœžœ˜—˜šžœžœž˜*J˜!Jšžœ˜!——˜ šžœžœ  œž˜8J˜!Jšžœ˜!——˜šžœž˜J˜Jšžœ˜"——Jšžœžœ˜———Jšžœ˜J˜J˜——Jšžœ ˜J˜—…—yd¨