Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2892.mcz ==================== Summary ==================== Name: VMMaker.oscog-eem.2892 Author: eem Time: 20 November 2020, 11:51:23.884407 am UUID: c01b9cfa-a988-4deb-952c-2decf8ea1a0c Ancestors: VMMaker.oscog-eem.2891 Implement a better fix for the VMMaker.oscog-eem.2824/http://forum.world.st/corruption-of-PC-in-context-objects-or-not-tt5121662.html case. Instead of changing to the interpreter, mark the cog method containing instructionPointer and relocate instructionPointer in markActiveMethodsAndReferents/updateStackZoneReferencesToCompiledCodePreCompaction. Rename PrimCallMayCallBack to PrimCallMayEndureCodeCompaction. Get rid of some <doNotGenerate>'s from initialize methods. =============== Diff against VMMaker.oscog-eem.2891 =============== Item was changed: ----- Method: CoInterpreter class>>initializeMiscConstants (in category 'initialization') ----- initializeMiscConstants super initializeMiscConstants. COGVM := true. MinBackwardJumpCountForCompile := 40. MaxNumArgs := 15. PrimCallNeedsNewMethod := 1. PrimCallNeedsPrimitiveFunction := 2. + PrimCallMayEndureCodeCompaction := 4. - PrimCallMayCallBack := 4. PrimCallOnSmalltalkStack := 8. PrimCallCollectsProfileSamples := 16. "CheckAllocationFillerAfterPrimCall := 32. this has never been successfully used in all the years we've had it; nuking it" PrimCallDoNotJIT := 64. PrimTraceLogSize := 256. "Room for 256 selectors. Must be 256 because we use a byte to hold the index" TraceBufferSize := 256 * 3. "Room for 256 events" TraceContextSwitch := self objectMemoryClass basicNew integerObjectOf: 1. TraceBlockActivation := self objectMemoryClass basicNew integerObjectOf: 2. TraceBlockCreation := self objectMemoryClass basicNew integerObjectOf: 3. TraceIncrementalGC := self objectMemoryClass basicNew integerObjectOf: 4. TraceFullGC := self objectMemoryClass basicNew integerObjectOf: 5. TraceCodeCompaction := self objectMemoryClass basicNew integerObjectOf: 6. TraceOwnVM := self objectMemoryClass basicNew integerObjectOf: 7. TraceDisownVM := self objectMemoryClass basicNew integerObjectOf: 8. TraceThreadSwitch := self objectMemoryClass basicNew integerObjectOf: 9. TracePreemptDisowningThread := self objectMemoryClass basicNew integerObjectOf: 10. TraceVMCallback := self objectMemoryClass basicNew integerObjectOf: 11. TraceVMCallbackReturn := self objectMemoryClass basicNew integerObjectOf: 12. TraceStackOverflow := self objectMemoryClass basicNew integerObjectOf: 13. TracePrimitiveFailure := self objectMemoryClass basicNew integerObjectOf: 14. TracePrimitiveRetry := self objectMemoryClass basicNew integerObjectOf: 15. TraceIsFromMachineCode := 1. TraceIsFromInterpreter := 2. CSCallbackEnter := 3. CSCallbackLeave := 4. CSEnterCriticalSection := 5. CSExitCriticalSection := 6. CSResume := 7. CSSignal := 8. CSSuspend := 9. CSWait := 10. CSYield := 11. CSCheckEvents := 12. CSThreadSchedulingLoop := 13. CSOwnVM := 14. CSThreadBind := 15. CSSwitchIfNeccessary := 16. TraceSources := CArrayAccessor on: #('?' 'm' 'i' 'callbackEnter' 'callbackLeave' 'enterCritical' 'exitCritical' 'resume' 'signal' 'suspend' 'wait' 'yield' 'eventcheck' 'threadsched' 'ownVM' 'bindToThread' 'switchIfNecessary'). "this is simulation only" RumpCStackSize := 4096! Item was added: + ----- Method: CoInterpreter>>isCodeCompactingPrimitiveIndex: (in category 'primitive support') ----- + isCodeCompactingPrimitiveIndex: primIndex + "If instVarAt:, slotAt: or shallowCopy operate on a Context then they compute a + bytecode pc and hence may provoke a code compaction. Hence primtiive invocation + from these primitives must use a static return address (cePrimReturnEnterCogCode:)." + <inline: true> + self cCode: [] inSmalltalk: [#primitiveClone. #primitiveInstVarAt. #primitiveSlotAt]. "For senders..." + ^primIndex = PrimNumberInstVarAt + or: [primIndex = PrimNumberShallowCopy + or: [primIndex = PrimNumberSlotAt]]! Item was changed: ----- Method: CoInterpreter>>markActiveMethodsAndReferents (in category 'cog jit support') ----- markActiveMethodsAndReferents <api> + "If instructionPointer is referring to machine code, as it will be if a primitive is in progress + (see isCodeCompactingPrimitiveIndex:) it may refer to a method, and if so that method + must be retained." + instructionPointer ~= 0 ifTrue: + [(cogit cogMethodContaining: instructionPointer) ifNotNil: + [:primCogMethod| + cogit markMethodAndReferents: primCogMethod]]. + - | thePage | - <var: #thePage type: #'StackPage *'> 0 to: numStackPages - 1 do: + [:i| | thePage | - [:i| thePage := stackPages stackPageAt: i. (stackPages isFree: thePage) ifFalse: [self markCogMethodsAndReferentsOnPage: thePage]]! Item was changed: ----- Method: CoInterpreter>>markCogMethodsAndReferentsOnPage: (in category 'frame access') ----- markCogMethodsAndReferentsOnPage: thePage <var: #thePage type: #'StackPage *'> | theFP callerFP | - <var: #theFP type: #'char *'> - <var: #callerFP type: #'char *'> <inline: false> self assert: (stackPages isFree: thePage) not. self assert: (self ifCurrentStackPageHasValidHeadPointers: thePage). theFP := thePage headFP. - "Skip the instruction pointer on top of stack of inactive pages." [(self isMachineCodeFrame: theFP) ifTrue: [cogit markMethodAndReferents: (self mframeCogMethod: theFP)]. (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue: [theFP := callerFP]! Item was changed: ----- Method: CoInterpreter>>primitivePropertyFlagsForSpur: (in category 'cog jit support') ----- primitivePropertyFlagsForSpur: primIndex <inline: true> "Answer any special requirements of the given primitive. Spur always needs to set primitiveFunctionPointer and newMethod so primitives can retry on failure due to forwarders." | baseFlags | self cCode: [] inSmalltalk: [#(mcprimHashMultiply: primitiveExternalCall primitiveCalloutToFFI)]. "For senders..." primIndex = PrimNumberHashMultiply ifTrue: [^PrimCallOnSmalltalkStack]. baseFlags := PrimCallNeedsPrimitiveFunction + PrimCallNeedsNewMethod. profileSemaphore ~= objectMemory nilObject ifTrue: [baseFlags := baseFlags bitOr: PrimCallCollectsProfileSamples]. + ((self isCalloutPrimitiveIndex: primIndex) "For callbacks" + or: [self isCodeCompactingPrimitiveIndex: primIndex]) ifTrue: "For code reclamations" + [baseFlags := baseFlags bitOr: PrimCallMayEndureCodeCompaction]. - (self isCalloutPrimitiveIndex: primIndex) ifTrue: "For callbacks" - [baseFlags := baseFlags bitOr: PrimCallMayCallBack]. ^baseFlags! Item was changed: ----- Method: CoInterpreter>>primitivePropertyFlagsForV3: (in category 'cog jit support') ----- primitivePropertyFlagsForV3: primIndex <inline: true> "Answer any special requirements of the given primitive" | baseFlags | baseFlags := profileSemaphore ~= objectMemory nilObject ifTrue: [PrimCallNeedsNewMethod + PrimCallCollectsProfileSamples] ifFalse: [0]. longRunningPrimitiveCheckSemaphore ifNotNil: [baseFlags := baseFlags bitOr: PrimCallNeedsNewMethod]. (self isCalloutPrimitiveIndex: primIndex) ifTrue: "For callbacks" + [baseFlags := baseFlags bitOr: PrimCallNeedsNewMethod + PrimCallNeedsPrimitiveFunction + PrimCallMayEndureCodeCompaction]. - [baseFlags := baseFlags bitOr: PrimCallNeedsNewMethod + PrimCallNeedsPrimitiveFunction + PrimCallMayCallBack]. (self isCodeCompactingPrimitiveIndex: primIndex) ifTrue: + [baseFlags := baseFlags bitOr: PrimCallNeedsNewMethod + PrimCallMayEndureCodeCompaction]. - [baseFlags := baseFlags bitOr: PrimCallNeedsNewMethod]. ^baseFlags! Item was changed: ----- Method: CoInterpreter>>updateStackZoneReferencesToCompiledCodePreCompaction (in category 'code compaction') ----- updateStackZoneReferencesToCompiledCodePreCompaction <api> + "Go through all frames in the stack zone and mark their methods + so that compaction does not free any methods that are in use." + <var: 'primCogMethod' type: #'CogMethod *'> + + "If instructionPointer is referring to machine code, as it will be if a primitive is in progress + (see isCodeCompactingPrimitiveIndex:) it must be updated if it is referring to a moved + method." + instructionPointer ~= 0 ifTrue: + [(cogit cogMethodContaining: instructionPointer) ifNotNil: + [:primCogMethod| + instructionPointer := instructionPointer + primCogMethod objectHeader]]. + - <var: #thePage type: #'StackPage *'> - <var: #theFP type: #'char *'> - <var: #callerFP type: #'char *'> - <var: #theIPPtr type: #'char *'> - <var: #theIP type: #usqInt> - <var: #theMethod type: #'CogMethod *'> 0 to: numStackPages - 1 do: + [:i| | thePage | - [:i| | thePage theFP callerFP theIPPtr theIP theMethodField theFlags theMethod | thePage := stackPages stackPageAt: i. (stackPages isFree: thePage) ifFalse: + [self updateStackZoneReferencesToCompiledCodePreCompactionOnPage: thePage]]! - [theIPPtr := thePage headSP. - theFP := thePage headFP. - [(self isMachineCodeFrame: theFP) ifTrue: - [theMethodField := self frameMethodField: theFP. - theFlags := theMethodField bitAnd: MFMethodFlagsMask. - theMethod := self cCoerceSimple: theMethodField - theFlags to: #'CogMethod *'. - theMethod cmType = CMBlock ifTrue: - [theMethod := (self cCoerceSimple: theMethodField - theFlags to: #'CogBlockMethod *') cmHomeMethod]. - theIP := (stackPages longAt: theIPPtr) asUnsignedInteger. - (theIP ~= cogit ceCannotResumePC - and: [self asserta: (theIP >= theMethod asUnsignedInteger - and: [theIP < (theMethod asUnsignedInteger + theMethod blockSize)])]) ifTrue: - [stackPages - longAt: theIPPtr - put: theIP + theMethod objectHeader]. - stackPages - longAt: theFP + FoxMethod - put: theMethodField + theMethod objectHeader]. - (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue: - [theIPPtr := theFP + FoxCallerSavedIP. - theFP := callerFP]]]! Item was added: + ----- Method: CoInterpreter>>updateStackZoneReferencesToCompiledCodePreCompactionOnPage: (in category 'frame access') ----- + updateStackZoneReferencesToCompiledCodePreCompactionOnPage: thePage + <var: #thePage type: #'StackPage *'> + <inline: true> + | theFP callerFP theIPPtr theIP theMethodField theFlags theMethod | + theIPPtr := thePage headSP. + theFP := thePage headFP. + [(self isMachineCodeFrame: theFP) ifTrue: + [theMethodField := self frameMethodField: theFP. + theFlags := theMethodField bitAnd: MFMethodFlagsMask. + theMethod := self cCoerceSimple: theMethodField - theFlags to: #'CogMethod *'. + theMethod cmType = CMBlock ifTrue: + [theMethod := (self cCoerceSimple: theMethodField - theFlags to: #'CogBlockMethod *') cmHomeMethod]. + theIP := (stackPages longAt: theIPPtr) asUnsignedInteger. + (theIP ~= cogit ceCannotResumePC + and: [self asserta: (theIP >= theMethod asUnsignedInteger + and: [theIP < (theMethod asUnsignedInteger + theMethod blockSize)])]) ifTrue: + [stackPages + longAt: theIPPtr + put: theIP + theMethod objectHeader]. + stackPages + longAt: theFP + FoxMethod + put: theMethodField + theMethod objectHeader]. + (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue: + [theIPPtr := theFP + FoxCallerSavedIP. + theFP := callerFP]! Item was removed: - ----- Method: CoInterpreterPrimitives>>cloneContext: (in category 'primitive support') ----- - cloneContext: aContext - "Copy a Context. There are complications here. - Fields of married contexts must be mapped to image-level values. - In mapping a machine code pc, a code compaction may occur. - In this case return through machine code is impossible without - updating a C call stack return address, since the machine code - method that invoked this primitive could have moved. So if this - happens, map to an interpreter frame and return to the interpreter." - | cloned couldBeCogMethod | - self assert: ((objectMemory isCompiledMethod: newMethod) - and: [(self primitiveIndexOf: newMethod) > 0]). - - couldBeCogMethod := objectMemory rawHeaderOf: newMethod. - cloned := super cloneContext: aContext. - - "If the header has changed in any way then it is most likely that machine code - has been moved or reclaimed for this method and so normal return is impossible." - couldBeCogMethod ~= (objectMemory rawHeaderOf: newMethod) ifTrue: - [self convertToInterpreterFrame: 0. - self push: cloned. - cogit ceInvokeInterpret - "NOTREACHED"]. - - ^cloned! Item was removed: - ----- Method: CoInterpreterPrimitives>>primitiveInstVarAt (in category 'object access primitives') ----- - primitiveInstVarAt - "Override to deal with potential code compaction on accessing context pcs" - | index rcvr hdr fmt totalLength fixedFields value | - self assert: ((objectMemory isCompiledMethod: newMethod) - and: [(self primitiveIndexOf: newMethod) > 0]). - - index := self stackTop. - rcvr := self stackValue: 1. - ((objectMemory isNonIntegerObject: index) - or: [argumentCount > 1 "e.g. object:instVarAt:" - and: [objectMemory isOopForwarded: rcvr]]) ifTrue: - [^self primitiveFailFor: PrimErrBadArgument]. - (objectMemory isImmediate: rcvr) ifTrue: [^self primitiveFailFor: PrimErrInappropriate]. - index := objectMemory integerValueOf: index. - hdr := objectMemory baseHeader: rcvr. - fmt := objectMemory formatOfHeader: hdr. - totalLength := objectMemory lengthOf: rcvr baseHeader: hdr format: fmt. - fixedFields := objectMemory fixedFieldsOf: rcvr format: fmt length: totalLength. - (index >= 1 and: [index <= fixedFields]) ifFalse: - [^self primitiveFailFor: PrimErrBadIndex]. - (fmt = objectMemory indexablePointersFormat - and: [objectMemory isContextHeader: hdr]) - ifTrue: - [| couldBeCogMethod | - self externalWriteBackHeadFramePointers. - "Note newMethod's header to check for potential code compaction - in mapping the context's pc from machine code to bytecode." - index = InstructionPointerIndex ifTrue: - [couldBeCogMethod := objectMemory rawHeaderOf: newMethod]. - value := self externalInstVar: index - 1 ofContext: rcvr. - "If the header has changed in any way then it is most likely that machine code - has been moved or reclaimed for this method and so normal return is impossible." - (index = InstructionPointerIndex - and: [couldBeCogMethod ~= (objectMemory rawHeaderOf: newMethod)]) ifTrue: - [self pop: argumentCount + 1. - self convertToInterpreterFrame: 0. - self push: value. - cogit ceInvokeInterpret - "NOTREACHED"]] - ifFalse: [value := self subscript: rcvr with: index format: fmt]. - self pop: argumentCount + 1 thenPush: value! Item was removed: - ----- Method: CoInterpreterPrimitives>>primitiveSlotAt (in category 'object access primitives') ----- - primitiveSlotAt - "Answer a slot in an object. This numbers all slots from 1, ignoring the distinction between - named and indexed inst vars. In objects with both named and indexed inst vars, the named - inst vars precede the indexed ones. In non-object indexed objects (objects that contain - bits, not object references) this primitive answers the raw integral value at each slot. - e.g. for Strings it answers the character code, not the Character object at each slot." - - "Override to deal with potential code compaction on accessing context pcs" - | index rcvr fmt numSlots | - self assert: ((objectMemory isCompiledMethod: newMethod) - and: [(self primitiveIndexOf: newMethod) > 0]). - - index := self stackTop. - rcvr := self stackValue: 1. - (objectMemory isIntegerObject: index) ifFalse: - [^self primitiveFailFor: PrimErrBadArgument]. - (objectMemory isImmediate: rcvr) ifTrue: - [^self primitiveFailFor: PrimErrBadReceiver]. - fmt := objectMemory formatOf: rcvr. - index := (objectMemory integerValueOf: index) - 1. - - fmt <= objectMemory lastPointerFormat ifTrue: - [numSlots := objectMemory numSlotsOf: rcvr. - (self asUnsigned: index) < numSlots ifTrue: - [| value numLiveSlots | - (objectMemory isContextNonImm: rcvr) - ifTrue: - [self externalWriteBackHeadFramePointers. - numLiveSlots := (self stackPointerForMaybeMarriedContext: rcvr) + CtxtTempFrameStart. - (self asUnsigned: index) < numLiveSlots - ifTrue: - [| couldBeCogMethod | - "Note newMethod's header to check for potential code compaction - in mapping the context's pc from machine code to bytecode." - index = InstructionPointerIndex ifTrue: - [couldBeCogMethod := objectMemory rawHeaderOf: newMethod]. - value := self externalInstVar: index ofContext: rcvr. - "If the header has changed in any way then it is most likely that machine code - has been moved or reclaimed for this method and so normal return is impossible." - (index = InstructionPointerIndex - and: [couldBeCogMethod ~= (objectMemory rawHeaderOf: newMethod)]) ifTrue: - [self pop: argumentCount + 1. - self convertToInterpreterFrame: 0. - self push: value. - cogit ceInvokeInterpret - "NOTREACHED"]] - ifFalse: [value := objectMemory nilObject]] - ifFalse: - [value := objectMemory fetchPointer: index ofObject: rcvr]. - self pop: argumentCount + 1 thenPush: value. - ^0]. - ^self primitiveFailFor: PrimErrBadIndex]. - - fmt >= objectMemory firstByteFormat ifTrue: - [fmt >= objectMemory firstCompiledMethodFormat ifTrue: - [^self primitiveFailFor: PrimErrUnsupported]. - numSlots := objectMemory numBytesOfBytes: rcvr. - (self asUnsigned: index) < numSlots ifTrue: - [self pop: argumentCount + 1 thenPushInteger: (objectMemory fetchByte: index ofObject: rcvr). - ^0]. - ^self primitiveFailFor: PrimErrBadIndex]. - - (objectMemory hasSpurMemoryManagerAPI - and: [fmt >= objectMemory firstShortFormat]) ifTrue: - [numSlots := objectMemory num16BitUnitsOf: rcvr. - (self asUnsigned: index) < numSlots ifTrue: - [self pop: argumentCount + 1 thenPushInteger: (objectMemory fetchUnsignedShort16: index ofObject: rcvr). - ^0]. - ^self primitiveFailFor: PrimErrBadIndex]. - - fmt = objectMemory sixtyFourBitIndexableFormat ifTrue: - [numSlots := objectMemory num64BitUnitsOf: rcvr. - (self asUnsigned: index) < numSlots ifTrue: - [self pop: argumentCount + 1 - thenPush: (self positive64BitIntegerFor: (objectMemory fetchLong64: index ofObject: rcvr)). - ^0]. - ^self primitiveFailFor: PrimErrBadIndex]. - - fmt >= objectMemory firstLongFormat ifTrue: - [numSlots := objectMemory num32BitUnitsOf: rcvr. - (self asUnsigned: index) < numSlots ifTrue: - [self pop: argumentCount + 1 - thenPush: (self positive32BitIntegerFor: (objectMemory fetchLong32: index ofObject: rcvr)). - ^0]. - ^self primitiveFailFor: PrimErrBadIndex]. - - ^self primitiveFailFor: PrimErrBadReceiver! Item was removed: - ----- Method: CogARMCompiler>>initialize (in category 'generate machine code') ----- - initialize - "This method intializes the Smalltalk instance. The C instance is merely a struct and doesn't need initialization." - <doNotGenerate> - operands := CArrayAccessor on: (Array new: NumOperands). - machineCode := CArrayAccessor on: (WordArray new: self machineCodeWords)! Item was changed: ----- Method: CogAbstractInstruction>>initialize (in category 'initialization') ----- initialize "This method intializes the Smalltalk instance. The C instance is merely a struct and doesn't need initialization." - <doNotGenerate> operands := CArrayAccessor on: (Array new: NumOperands). + machineCode := CArrayAccessor on: (self codeGranularity = 4 + ifTrue: [WordArray new: self machineCodeWords] + ifFalse: [ByteArray new: self machineCodeBytes])! - machineCode := CArrayAccessor on: (ByteArray new: self machineCodeBytes)! Item was removed: - ----- Method: CogMIPSELCompiler>>initialize (in category 'generate machine code') ----- - initialize - "This method intializes the Smalltalk instance. The C instance is merely a struct and doesn't need initialization." - <doNotGenerate> - operands := CArrayAccessor on: (Array new: NumOperands). - machineCode := CArrayAccessor on: (Array new: self machineCodeWords)! Item was changed: SharedPool subclass: #CogMethodConstants instanceVariableNames: '' + classVariableNames: 'CMBlock CMClosedPIC CMFree CMMaxUsageCount CMMethod CMOpenPIC CompletePrimitive EncounteredUnknownBytecode InsufficientCodeSpace MaxLiteralCountForCompile MaxMethodSize MaxNegativeErrorCode MaxNumArgs MaxStackCheckOffset MethodTooBig NotFullyInitialized PrimCallCollectsProfileSamples PrimCallDoNotJIT PrimCallMayEndureCodeCompaction PrimCallNeedsNewMethod PrimCallNeedsPrimitiveFunction PrimCallOnSmalltalkStack ShouldNotJIT UnfailingPrimitive UnimplementedPrimitive YoungSelectorInPIC' - classVariableNames: 'CMBlock CMClosedPIC CMFree CMMaxUsageCount CMMethod CMOpenPIC CompletePrimitive EncounteredUnknownBytecode InsufficientCodeSpace MaxLiteralCountForCompile MaxMethodSize MaxNegativeErrorCode MaxNumArgs MaxStackCheckOffset MethodTooBig NotFullyInitialized PrimCallCollectsProfileSamples PrimCallDoNotJIT PrimCallMayCallBack PrimCallNeedsNewMethod PrimCallNeedsPrimitiveFunction PrimCallOnSmalltalkStack ShouldNotJIT UnfailingPrimitive UnimplementedPrimitive YoungSelectorInPIC' poolDictionaries: '' category: 'VMMaker-JIT'! Item was added: + ----- Method: CogMethodZone>>cogMethodContaining: (in category 'jit - api') ----- + cogMethodContaining: mcpc + "Answer the method containing mcpc for the purposes of code zone compaction, + where mcpc is actually the value of instructionPointer at the time of a compaction." + <var: 'mcpc' type: #usqInt> + <api> + | cogMethod prevMethod | + mcpc > limitAddress ifTrue: + [^nil]. + mcpc < baseAddress ifTrue: + [cogit assertMcpcIsPrimReturn: mcpc. + ^nil]. + self assert: mcpc < self limitZony. + cogMethod := coInterpreter cCoerceSimple: baseAddress to: #'CogMethod *'. + [cogMethod < mcpc] whileTrue: + [prevMethod := cogMethod. + cogMethod := self methodAfter: cogMethod]. + + "Since mcpc is actually instructionPointer we expect that it is either at the stack check + (normal code zone reclamation invoked through checkForEventsMayContextSwitch:) + or is in a primitive, immediately following the call of the C primitive routine." + self assert: (prevMethod notNil + and: [mcpc = prevMethod asUnsignedInteger + prevMethod stackCheckOffset + or: [(coInterpreter + primitiveIndexOfMethod: prevMethod methodObject + header: prevMethod methodHeader) > 0 + and: [cogit backEnd isCallPrecedingReturnPC: mcpc]]]). + ^prevMethod! Item was added: + ----- Method: Cogit>>assertMcpcIsPrimReturn: (in category 'debugging') ----- + assertMcpcIsPrimReturn: mcpc + <inline: #always> + ^self assert: (mcpc = cePrimReturnEnterCogCode + or: [mcpc = cePrimReturnEnterCogCodeProfiling])! Item was added: + ----- Method: Cogit>>cogMethodContaining: (in category 'jit - api') ----- + cogMethodContaining: mcpc + <doNotGenerate> + ^methodZone cogMethodContaining: mcpc! Item was changed: ----- Method: SimpleStackBasedCogit>>compileInterpreterPrimitive:flags: (in category 'primitive generators') ----- compileInterpreterPrimitive: primitiveRoutine flags: flags "Compile a call to an interpreter primitive. Call the C routine with the usual stack-switching dance, test the primFailCode and then either return on success or continue to the method body." <var: #primitiveRoutine declareC: 'void (*primitiveRoutine)(void)'> | jmp jmpSamplePrim continuePostSamplePrim jmpSampleNonPrim continuePostSampleNonPrim | <var: #jmp type: #'AbstractInstruction *'> <var: #jmpSamplePrim type: #'AbstractInstruction *'> <var: #jmpSampleNonPrim type: #'AbstractInstruction *'> <var: #continuePostSamplePrim type: #'AbstractInstruction *'> <var: #continuePostSampleNonPrim type: #'AbstractInstruction *'> "Save processor fp, sp and return pc in the interpreter's frame stack and instruction pointers" self genExternalizePointersForPrimitiveCall. "Switch to the C stack." self genLoadCStackPointersForPrimCall. (flags anyMask: PrimCallCollectsProfileSamples) ifTrue: ["Test nextProfileTick for being non-zero and call checkProfileTick if so" objectMemory wordSize = 4 ifTrue: [self MoveAw: coInterpreter nextProfileTickAddress R: TempReg. self MoveAw: coInterpreter nextProfileTickAddress + objectMemory wordSize R: ClassReg. self OrR: TempReg R: ClassReg] ifFalse: [self MoveAw: coInterpreter nextProfileTickAddress R: TempReg. self CmpCq: 0 R: TempReg]. "If set, jump to record sample call." jmpSampleNonPrim := self JumpNonZero: 0. continuePostSampleNonPrim := self Label]. "Old full prim trace is in VMMaker-eem.550 and prior" self recordPrimTrace ifTrue: [self genFastPrimTraceUsing: ClassReg and: SendNumArgsReg]. "Clear the primFailCode and set argumentCount" self MoveCq: 0 R: TempReg. self MoveR: TempReg Aw: coInterpreter primFailCodeAddress. methodOrBlockNumArgs ~= 0 ifTrue: [self MoveCq: methodOrBlockNumArgs R: TempReg]. self MoveR: TempReg Aw: coInterpreter argumentCountAddress. "If required, set primitiveFunctionPointer and newMethod" (flags anyMask: PrimCallNeedsPrimitiveFunction) ifTrue: [self MoveCw: primitiveRoutine asInteger R: TempReg. primSetFunctionLabel := self MoveR: TempReg Aw: coInterpreter primitiveFunctionPointerAddress]. + (flags anyMask: PrimCallNeedsNewMethod+PrimCallMayEndureCodeCompaction) ifTrue: - (flags anyMask: PrimCallNeedsNewMethod+PrimCallMayCallBack) ifTrue: ["The ceActivateFailingPrimitiveMethod: machinery can't handle framelessness." + (flags anyMask: PrimCallMayEndureCodeCompaction) ifTrue: - (flags anyMask: PrimCallMayCallBack) ifTrue: [needsFrame := true]. methodLabel addDependent: (self annotateAbsolutePCRef: (self MoveCw: methodLabel asInteger R: ClassReg)). self MoveMw: (self offset: CogMethod of: #methodObject) r: ClassReg R: TempReg. self MoveR: TempReg Aw: coInterpreter newMethodAddress]. "Invoke the primitive" self PrefetchAw: coInterpreter primFailCodeAddress. + (flags anyMask: PrimCallMayEndureCodeCompaction) - (flags anyMask: PrimCallMayCallBack) ifTrue: "Sideways call the C primitive routine so that we return through cePrimReturnEnterCogCode." ["On Spur ceActivateFailingPrimitiveMethod: would like to retry if forwarders are found. So insist on PrimCallNeedsPrimitiveFunction being set too." self assert: (flags anyMask: PrimCallNeedsPrimitiveFunction). backEnd genMarshallNArgs: 0 arg: nil arg: nil arg: nil arg: nil; genSubstituteReturnAddress: ((flags anyMask: PrimCallCollectsProfileSamples) ifTrue: [cePrimReturnEnterCogCodeProfiling] ifFalse: [cePrimReturnEnterCogCode]). primInvokeInstruction := self JumpFullRT: primitiveRoutine asInteger. jmp := jmpSamplePrim := continuePostSamplePrim := nil] ifFalse: ["Call the C primitive routine." backEnd genMarshallNArgs: 0 arg: 0 arg: 0 arg: 0 arg: 0. primInvokeInstruction := self CallFullRT: primitiveRoutine asInteger. backEnd genRemoveNArgsFromStack: 0. (flags anyMask: PrimCallCollectsProfileSamples) ifTrue: [self assert: (flags anyMask: PrimCallNeedsNewMethod). "Test nextProfileTick for being non-zero and call checkProfileTick if so" objectMemory wordSize = 4 ifTrue: [self MoveAw: coInterpreter nextProfileTickAddress R: TempReg. self MoveAw: coInterpreter nextProfileTickAddress + objectMemory wordSize R: ClassReg. self OrR: TempReg R: ClassReg] ifFalse: [self MoveAw: coInterpreter nextProfileTickAddress R: TempReg. self CmpCq: 0 R: TempReg]. "If set, jump to record sample call." jmpSamplePrim := self JumpNonZero: 0. continuePostSamplePrim := self Label]. objectRepresentation maybeCompileRetryOnPrimitiveFail: primitiveIndex. "Switch back to the Smalltalk stack. Stack better be in either of these two states: success: stackPointer -> result (was receiver) arg1 ... argN return pc failure: receiver arg1 ... stackPointer -> argN return pc In either case we can push the instructionPointer or load it into the LinkRegister to reestablish the return pc" self MoveAw: coInterpreter instructionPointerAddress R: (backEnd hasLinkRegister ifTrue: [LinkReg] ifFalse: [ClassReg]). backEnd genLoadStackPointers. "Test primitive failure" self MoveAw: coInterpreter primFailCodeAddress R: TempReg. backEnd hasLinkRegister ifFalse: [self PushR: ClassReg]. "Restore return pc on CISCs" self flag: 'ask concrete code gen if move sets condition codes?'. self CmpCq: 0 R: TempReg. jmp := self JumpNonZero: 0. "Fetch result from stack" self MoveMw: (backEnd hasLinkRegister ifTrue: [0] ifFalse: [objectMemory wordSize]) r: SPReg R: ReceiverResultReg. self RetN: objectMemory wordSize]. "return to caller, popping receiver" (flags anyMask: PrimCallCollectsProfileSamples) ifTrue: ["The sample is collected by cePrimReturnEnterCogCode for external calls" jmpSamplePrim ifNotNil: ["Call ceCheckProfileTick: to record sample and then continue." jmpSamplePrim jmpTarget: self Label. self assert: (flags anyMask: PrimCallNeedsNewMethod). self CallFullRT: (self cCode: [#ceCheckProfileTick asUnsignedIntegerPtr] inSmalltalk: [self simulatedTrampolineFor: #ceCheckProfileTick]). "reenter the post-primitive call flow" self Jump: continuePostSamplePrim]. "Null newMethod and call ceCheckProfileTick: to record sample and then continue. ceCheckProfileTick will map null/0 to coInterpreter nilObject" jmpSampleNonPrim jmpTarget: self Label. self MoveCq: 0 R: TempReg. self MoveR: TempReg Aw: coInterpreter newMethodAddress. self CallFullRT: (self cCode: [#ceCheckProfileTick asUnsignedIntegerPtr] inSmalltalk: [self simulatedTrampolineFor: #ceCheckProfileTick]). "reenter the post-primitive call flow" self Jump: continuePostSampleNonPrim]. jmp ifNotNil: ["Jump to restore of receiver reg and proceed to frame build for failure." jmp jmpTarget: self Label. "Restore receiver reg from stack. If on RISCs ret pc is in LinkReg, if on CISCs ret pc is on stack." self MoveMw: objectMemory wordSize * (methodOrBlockNumArgs + (backEnd hasLinkRegister ifTrue: [0] ifFalse: [1])) r: SPReg R: ReceiverResultReg]. ^0! Item was changed: ----- Method: SimpleStackBasedCogit>>rewritePrimInvocationIn:to: (in category 'external primitive support') ----- rewritePrimInvocationIn: cogMethod to: primFunctionPointer <api> <var: #cogMethod type: #'CogMethod *'> <var: #primFunctionPointer declareC: #'void (*primFunctionPointer)(void)'> | primIndex flags address extent | self cCode: [] inSmalltalk: [primFunctionPointer isInteger ifFalse: [^self rewritePrimInvocationIn: cogMethod to: (self simulatedTrampolineFor: primFunctionPointer)]]. self assert: cogMethod cmType = CMMethod. primIndex := coInterpreter primitiveIndexOfMethod: cogMethod methodObject header: cogMethod methodHeader. flags := coInterpreter primitivePropertyFlags: primIndex. (flags anyMask: PrimCallNeedsPrimitiveFunction) ifTrue: [backEnd storeLiteral: primFunctionPointer asUnsignedInteger beforeFollowingAddress: cogMethod asUnsignedInteger + (externalSetPrimOffsets at: cogMethod cmNumArgs)]. "See compileInterpreterPrimitive:" + (flags anyMask: PrimCallMayEndureCodeCompaction) - (flags anyMask: PrimCallMayCallBack) ifTrue: [address := cogMethod asUnsignedInteger + (externalPrimJumpOffsets at: cogMethod cmNumArgs). extent := backEnd rewriteJumpFullAt: address target: primFunctionPointer asUnsignedInteger] ifFalse: [address := cogMethod asUnsignedInteger + (externalPrimCallOffsets at: cogMethod cmNumArgs). extent := backEnd rewriteCallFullAt: address target: primFunctionPointer asUnsignedInteger]. extent > 0 ifTrue: [backEnd flushICacheFrom: cogMethod asUnsignedInteger + cmNoCheckEntryOffset to: address asUnsignedInteger + extent]! Item was removed: - ----- Method: StackInterpreter>>isCodeCompactingPrimitiveIndex: (in category 'primitive support') ----- - isCodeCompactingPrimitiveIndex: primIndex - "If instVarAt:, slotAt: or shallowCopy operate on a Context then they compute a - bytecode pc and hence may provoke a code compaction. If so, they *cannot* - return through the potentially moved method and so continue in the interpreter." - <inline: true> - self cCode: [] inSmalltalk: [#primitiveClone primitiveInstVarAt primitiveSlotAt]. "For senders..." - ^primIndex = PrimNumberInstVarAt - or: [primIndex = PrimNumberShallowCopy - or: [primIndex = PrimNumberSlotAt]]! |
Free forum by Nabble | Edit this page |