[Vm-dev] VM Maker: VMMaker.oscog-eem.2287.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Dec 7 21:22:42 UTC 2017


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2287.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.2287
Author: eem
Time: 7 December 2017, 1:22:10.777155 pm
UUID: 5da6c657-35ff-49b0-b61f-571cb1c4308d
Ancestors: VMMaker.oscog-eem.2286

Spur:
Rewrite determining the accessorDepth for the meta primitives (primitiveDoPrimitiveWithArgs and primitiveDoNamedPrimitiveWithArgs, 118 & 218). Have primitiveDoNamedPrimitiveWithArgs fetch the accessorDepth.  Discard the confused setting of newMethod to the prim index.  Introduce metaAccessorDepth and eliminate tempOop3.  This fixes a crash when stepping through something likely to fail such as [DoubleWordArray new: 64*1024*1024] repeat.

Write descriptions in the class comment for the variables of CoInterpreter and StackInterpreter and add a description for a new variable in InterpreterPrimitives.

Add the missing DoubleWordArray>>longAt:bigEndian: needed by the Bochs alien primitive failure code.

Fix a slip in printDecodeMethodHeaderOop:

=============== Diff against VMMaker.oscog-eem.2286 ===============

Item was changed:
  StackInterpreterPrimitives subclass: #CoInterpreter
  	instanceVariableNames: 'cogit cogMethodZone gcMode cogCodeSize desiredCogCodeSize heapBase lastCoggableInterpretedBlockMethod reenterInterpreter deferSmash deferredSmash primTraceLog primTraceLogIndex traceLog traceLogIndex traceSources cogCompiledCodeCompactionCalledFor statCodeCompactionCount statCodeCompactionUsecs lastUncoggableInterpretedBlockMethod flagInterpretedMethods maxLiteralCountForCompile minBackwardJumpCountForCompile'
  	classVariableNames: 'CSCallbackEnter CSCallbackLeave CSCheckEvents CSEnterCriticalSection CSExitCriticalSection CSOwnVM CSResume CSSignal CSSuspend CSSwitchIfNeccessary CSThreadBind CSThreadSchedulingLoop CSWait CSYield HasBeenReturnedFromMCPC HasBeenReturnedFromMCPCOop MFMethodFlagFrameIsMarkedFlag MinBackwardJumpCountForCompile PrimNumberHashMultiply PrimTraceLogSize ReturnToInterpreter RumpCStackSize TraceBlockActivation TraceBlockCreation TraceBufferSize TraceCodeCompaction TraceContextSwitch TraceDisownVM TraceFullGC TraceIncrementalGC TraceIsFromInterpreter TraceIsFromMachineCode TraceOwnVM TracePreemptDisowningThread TracePrimitiveFailure TracePrimitiveRetry TraceSources TraceStackOverflow TraceThreadSwitch TraceVMCallback TraceVMCallbackReturn'
  	poolDictionaries: 'CogMethodConstants VMStackFrameOffsets'
  	category: 'VMMaker-JIT'!
  
+ !CoInterpreter commentStamp: 'eem 12/7/2017 11:19' prior: 0!
+ I am a variant of the StackInterpreter that can co-exist with the Cog JIT.  I interpret unjitted methods, either because they have been found for the first time or because they are judged to be too big to JIT.  See CogMethod class's comment for method interoperability.
+ 
+ cogCodeSize
+ 	- the current size of the machine code zone
+ 
+ cogCompiledCodeCompactionCalledFor
+ 	- a variable set when the machine code zone runs out of space, causing a machine code zone compaction at the next available opportunity
+ 
+ cogMethodZone
+ 	- the manager for the machine code zone (instance of CogMethodZone)
+ 
+ cogit
+ 	- the JIT (co-jit) (instance of SimpleStackBasedCogit, StackToRegisterMappoingCogit, etc)
+ 
+ deferSmash
+ 	- a flag causing deferral of smashes of the stackLimit around the call of functionSymbol (for assert checks)
+ 
+ deferredSmash
+ 	- a flag noting deferral of smashes of the stackLimit around the call of functionSymbol (for assert checks)
+ 
+ desiredCogCodeSize
+ 	- the desred size of the machine code zone, set at startup or via primitiveVMParameter to be written at snapshot time
+ 
+ flagInterpretedMethods
+ 	- true if methods that are interpreted shoudl have their flag bit set (used to identity methods that are interpreted because they're unjittable for some reason)
+ 
+ gcMode
+ 	- the variable holding the gcMode, used to inform the cogit of how to scan the machine code zone for oops on GC
+ 
+ heapBase
+ 	- the address in memory of the base of the objectMemory's heap, which is immediately above the machine code zone
+ 
+ lastCoggableInterpretedBlockMethod
+ 	- a variable used to invoke the cogit for a block mehtod being invoked repeatedly in the interpreter
+ 
+ lastUncoggableInterpretedBlockMethod
+ 	- a variable used to avoid invoking the cogit for an unjittable method encountered on block evaluation
+ 
+ maxLiteralCountForCompile
+ 	- the variable controlling which methods to jit.  methods with a literal count above this value will not be jitted (on the grounds that large methods are typically used for initialization, and take up a lot of space in the code zone)
+ 
+ minBackwardJumpCountForCompile
+ 	- the variable controlling when to attempt to jit a method being interpreted.  If as many backward jumps as this occur, the current method will be jitted
+ 
+ primTraceLog
+ 	- a small array implementing a crcular buffer logging the last N primitive invocations, GCs, code compactions, etc used for crash reporting
+ 
+ primTraceLogIndex
+ 	- the index into primTraceLog of the next entry
+ 
+ reenterInterpreter
+ 	- the jmpbuf used to jmp back into the interpreter when transitioning from machine code to the interpreter
+ 
+ statCodeCompactionCount
+ 	- the count of machine code zone compactions
+ 
+ statCodeCompactionUsecs
+ 	- the total microseconds spent in machine code zone compactions
+ 
+ traceLog
+ 	- a log of various events, used in debugging
+ 
+ traceLogIndex
+ 	- the index into traceLog of the next entry
+ 
+ traceSources
+ 	- the names associated with the codes of events in traceLog!
- !CoInterpreter commentStamp: '<historical>' prior: 0!
- I am a variant of the StackInterpreter that can co-exist with the Cog JIT.  I interpret unjitted methods, either because they have been found for the first time or because they are judged to be too big to JIT.  See CogMethod class's comment for method interoperability.!

Item was removed:
- ----- Method: CoInterpreter>>saneFunctionPointerForFailureOfPrimIndex: (in category 'primitive support') -----
- saneFunctionPointerForFailureOfPrimIndex: primIndex
- 	^instructionPointer >= objectMemory nilObject asUnsignedInteger
- 		ifTrue:
- 			[super saneFunctionPointerForFailureOfPrimIndex: primIndex]
- 		ifFalse:
- 			[self
- 				cCode:
- 					[primitiveFunctionPointer = (self functionPointerFor: primIndex
- 													inClass: objectMemory nilObject)]
- 				inSmalltalk:
- 					[(primitiveFunctionPointer isInteger
- 						ifTrue:
- 							[(cogit lookupAddress: primitiveFunctionPointer)
- 								endsWith: (self functionPointerFor: primIndex
- 												inClass: objectMemory nilObject)]
- 						ifFalse:
- 							[primitiveFunctionPointer = (self functionPointerFor: primIndex
- 															inClass: objectMemory nilObject)])]]!

Item was changed:
  ----- Method: CoInterpreterMT>>markAndTraceInterpreterOops: (in category 'object memory support') -----
  markAndTraceInterpreterOops: fullGCFlag
  	"Mark and trace all oops in the interpreter's state."
  	"Assume: All traced variables contain valid oops.
  	 N.B. Don't trace messageSelector and lkupClass; these are ephemeral, live
  	 only during message lookup and because createActualMessageTo will not
  	 cause a GC these cannot change during message lookup."
  	| oop |
  	<var: #vmThread type: #'CogVMThread *'>
  	"Must mark stack pages first to initialize the per-page trace
  	 flags for full garbage collect before any subsequent tracing."
  	self markAndTraceStackPages: fullGCFlag.
  	self markAndTraceTraceLog.
  	self markAndTracePrimTraceLog.
  	objectMemory markAndTrace: objectMemory specialObjectsOop. "also covers nilObj, trueObj, falseObj, and compact classes"
  	(objectMemory isImmediate: newMethod) ifFalse:
  		[objectMemory markAndTrace: newMethod].
  	self traceProfileState.
  	tempOop = 0 ifFalse: [objectMemory markAndTrace: tempOop].
  	tempOop2 = 0 ifFalse: [objectMemory markAndTrace: tempOop2].
- 	tempOop3 = 0 ifFalse: [objectMemory markAndTrace: tempOop3].
  
  	1 to: objectMemory remapBufferCount do:
  		[:i|
  		oop := objectMemory remapBuffer at: i.
  		(objectMemory isIntegerObject: oop) ifFalse:
  			[objectMemory markAndTrace: oop]].
  
  	"Callback support - trace suspended callback list - will be made per-thread soon"
  	1 to: jmpDepth do:
  		[:i|
  		oop := suspendedCallbacks at: i.
  		(objectMemory isIntegerObject: oop) ifFalse:
  			[objectMemory markAndTrace: oop].
  		oop := suspendedMethods at: i.
  		(objectMemory isIntegerObject: oop) ifFalse:
  			[objectMemory markAndTrace: oop]].
  
  	"Per-thread state; trace each thread's own newMethod and stack of awol processes."
  	1 to: cogThreadManager getNumThreads do:
  		[:i| | vmThread |
  		vmThread := cogThreadManager vmThreadAt: i.
  		vmThread state notNil ifTrue:
  			[vmThread newMethodOrNull notNil ifTrue:
  				[objectMemory markAndTrace: vmThread newMethodOrNull].
  			 0 to: vmThread awolProcIndex - 1 do:
  				[:j|
  				objectMemory markAndTrace: (vmThread awolProcesses at: j)]]]!

Item was added:
+ ----- Method: CogVMSimulator>>saneFunctionPointerForFailureOfPrimIndex: (in category 'primitive support') -----
+ saneFunctionPointerForFailureOfPrimIndex: primIndex
+ 	| basePrimitive |
+ 	(instructionPointer < objectMemory nilObject asUnsignedInteger
+ 	and: [primitiveFunctionPointer isInteger]) ifTrue:
+ 		[basePrimitive := self functionPointerFor: primIndex inClass: objectMemory nilObject.
+ 		 ^(cogit lookupAddress: primitiveFunctionPointer) endsWith: basePrimitive].
+ 
+ 	^super saneFunctionPointerForFailureOfPrimIndex: primIndex!

Item was added:
+ ----- Method: DoubleWordArray>>longAt:bigEndian: (in category '*VMMaker-JITSimulation') -----
+ longAt: byteIndex bigEndian: bigEndian
+ 	"Compatiblity with the ByteArray & Alien methods of the same name."
+ 	| wordIndex lowBits word hiWord |
+ 	wordIndex := byteIndex - 1 // 8 + 1.
+ 	lowBits := byteIndex - 1 bitAnd: 7.
+ 	word := (self at: wordIndex) bitShift: lowBits * -8.
+ 	lowBits > 4 ifTrue: "access straddles two words"
+ 		[hiWord := (self at: wordIndex + 1) bitShift: 8 - lowBits * 8.
+ 		 word := word + hiWord].
+ 	word := word bitAnd: 16rFFFFFFFF.
+ 	bigEndian ifTrue:
+ 		[word := ((word bitShift: -24) bitAnd: 16rFF)
+ 				 + ((word bitShift: -8) bitAnd: 16rFF00)
+  				 + ((word bitAnd: 16rFF00) bitShift: 8)
+ 				 + ((word bitAnd: 16rFF) bitShift: 24)].
+ 	(word bitShift: -24) > 127 ifTrue:
+ 		[word := word - 16r100000000].
+ 	^word!

Item was changed:
  VMClass subclass: #InterpreterPrimitives
  	instanceVariableNames: 'objectMemory messageSelector argumentCount newMethod primFailCode profileMethod profileProcess profileSemaphore nextProfileTick preemptionYields newFinalization sHEAFn'
  	classVariableNames: 'CrossedX EndOfRun MillisecondClockMask'
  	poolDictionaries: 'VMBasicConstants VMBytecodeConstants VMMethodCacheConstants VMObjectIndices VMSqueakClassIndices VMStackFrameOffsets'
  	category: 'VMMaker-Interpreter'!
  
+ !InterpreterPrimitives commentStamp: 'eem 12/7/2017 11:21' prior: 0!
- !InterpreterPrimitives commentStamp: 'eem 12/11/2012 17:11' prior: 0!
  InterpreterPrimitives implements most of the VM's core primitives.  It is the root of the interpreter hierarchy so as to share the core primitives amongst the varioius interpreters.
  
  Instance Variables
+ 	argumentCount:			<Integer>
+ 	messageSelector:			<Integer>
+ 	newMethod:				<Integer>
+ 	nextProfileTick:				<Integer>
+ 	objectMemory:				<ObjectMemory> (simulation only)
+ 	preemptionYields:			<Boolean>
+ 	primFailCode:				<Integer>
+ 	profileMethod:				<Integer>
+ 	profileProcess:				<Integer>
+ 	profileSemaphore:			<Integer>
+ 	secHasEnvironmentAccess <Integer>
- 	argumentCount:	<Integer>
- 	messageSelector:	<Integer>
- 	newMethod:		<Integer>
- 	nextProfileTick:		<Integer>
- 	objectMemory:		<ObjectMemory> (simulation only)
- 	preemptionYields:	<Boolean>
- 	primFailCode:		<Integer>
- 	profileMethod:		<Integer>
- 	profileProcess:		<Integer>
- 	profileSemaphore:	<Integer>
  
  argumentCount
  	- the number of arguments of the current message
  
  messageSelector
  	- the oop of the selector of the current message
  
  newMethod
  	- the oop of the result of looking up the current message
  
  nextProfileTick
  	- the millisecond clock value of the next profile tick (if profiling is in effect)
  
  objectMemory
  	- the memory manager and garbage collector that manages the heap
  
  preemptionYields
  	- a boolean controlling the process primitives.  If true (old, incorrect, blue-book semantics) a preempted process is sent to the back of its run-queue.  If false, a process preempted by a higher-priority process is put back at the head of its run queue, hence preserving cooperative scheduling within priorities.
  
  primFailCode
  	- primtiive success/failure flag, 0 for success, otherwise the reason code for failure
  
  profileMethod
  	- the oop of the method at the time nextProfileTick was reached
  
  profileProcess
  	- the oop of the activeProcess at the time nextProfileTick was reached
  
  profileSemaphore
  	- the oop of the semaphore to signal when nextProfileTick is reached
+ 
+ secHasEnvironmentAccess
+ 	- the function to call to check if access to the envronment should be granted to primitiveGetenv
  !

Item was changed:
  InterpreterPrimitives subclass: #StackInterpreter
(excessive size, no diff calculated)

Item was changed:
  ----- Method: StackInterpreter class>>initializePrimitiveTable (in category 'initialization') -----
(excessive size, no diff calculated)

Item was changed:
  ----- Method: StackInterpreter>>checkForAndFollowForwardedPrimitiveState (in category 'primitive support') -----
  checkForAndFollowForwardedPrimitiveState
  	"In Spur a primitive may fail due to encountering a forwarder. On failure,
  	 check the accessorDepth for the primitive and if non-negative scan the
  	 args to the depth, following any forwarders.  Answer if any are found so
+ 	 the prim can be retried.  The primitive index is derived from newMethod."
- 	 the prim can be retried.  The primitive index is derived from newMethod.
- 	 If the primitive is 118, then primitiveDoPrimitiveWithArgs sets newMethod
- 	 to a SmallInteger whose value is the primitive it is evaluating."
  	<option: #SpurObjectMemory>
  	| primIndex accessorDepth found scannedStackFrame |
  	self assert: self failed.
  	found := scannedStackFrame := false.
+ 	primIndex := self primitiveIndexOf: newMethod.
+ 	self assert: (argumentCount = (self argumentCountOf: newMethod) or: [self isMetaPrimitiveIndex: primIndex]).
+ 	"If the primitive is one of the meta primitives PrimNumberDoPrimitive or
+ 	 PrimNumberDoExternalCall, then metaAccessorDepth will have been set
+ 	 to nil at the start of the primitive, and to the accessor depth of the called
+ 	 primitive (or external call) immediately before dispatch.  Hence if primIndex
+ 	 is that of a meta primiitve then if metaAccessorDepth is -2, the accessor
+ 	 depth is that of the meta primitive, and if > -2, then metaAccessorDepth is
+ 	 the accessor depth of the primitive (or external call).  SImilarly, if the
+ 	 primitive is primitiveExternalCall then the accessor depth is that of
+ 	 primitiveExternalCall until primitiveFunctionPointer is assigned, at which
+ 	 point the accessor depth is taken from the slot in newMethod's first literal."
+ 	accessorDepth := ((self isMetaPrimitiveIndex: primIndex)
+ 						 and: [metaAccessorDepth > -2])
+ 							ifTrue: [metaAccessorDepth]
+ 							ifFalse:
+ 								[(primIndex = PrimNumberExternalCall
+ 								  and: [primitiveFunctionPointer ~~ #primitiveExternalCall])
+ 									ifTrue: [self primitiveAccessorDepthForExternalPrimitiveMethod: newMethod]
+ 									ifFalse: [primitiveAccessorDepthTable at: primIndex]].
+ 	self assert: (self saneFunctionPointerForFailureOfPrimIndex: primIndex).
- 	primIndex := (objectMemory isIntegerObject: newMethod)
- 					ifTrue: [objectMemory integerValueOf: newMethod]
- 					ifFalse:
- 						[self assert: argumentCount = (self argumentCountOf: newMethod).
- 						 self primitiveIndexOf: newMethod].
- 	accessorDepth := primitiveAccessorDepthTable at: primIndex.
- 	"For the method-executing primitives, failure could have been in those primitives or the
- 	 primitives of the methods they execute.  Find out which failed by seeing what is in effect."
- 	((primIndex = PrimNumberExternalCall and: [primitiveFunctionPointer ~~ #primitiveExternalCall])
- 	 or: [primIndex = PrimNumberDoExternalCall and: [primitiveFunctionPointer ~~ #primitiveDoNamedPrimitiveWithArgs]])
- 		ifTrue:
- 			[accessorDepth := self primitiveAccessorDepthForExternalPrimitiveMethod: newMethod]
- 		ifFalse:
- 			[self assert: (self saneFunctionPointerForFailureOfPrimIndex: primIndex)].
  	self assert: (accessorDepth between: -1 and: 4).
  	accessorDepth >= 0 ifTrue:
  		[0 to: argumentCount do:
  			[:index| | oop |
  			oop := self stackValue: index.
  			(objectMemory isNonImmediate: oop) ifTrue:
  				[(objectMemory isForwarded: oop) ifTrue:
  					[self assert: index < argumentCount. "receiver should have been caught at send time."
  					 found := true.
  					 oop := objectMemory followForwarded: oop.
  					 self stackValue: index put: oop.
  					 scannedStackFrame ifFalse:
  						[scannedStackFrame := true.
  						 self
  							followForwardedFrameContents: framePointer
  							stackPointer: stackPointer + (argumentCount + 1 * objectMemory wordSize) "don't repeat effort"]].
  				(accessorDepth > 0
  			 	 and: [(objectMemory hasPointerFields: oop)
  				 and: [objectMemory followForwardedObjectFields: oop toDepth: accessorDepth]]) ifTrue:
  					[found := true]]]].
  	^found!

Item was changed:
  ----- Method: StackInterpreter>>checkInterpreterIntegrity (in category 'object memory support') -----
  checkInterpreterIntegrity
  	"Perform an integrity/leak check using the heapMap.  Assume
  	 clearLeakMapAndMapAccessibleObjects has set a bit at each
  	 object's header.  Check that all oops in the interpreter's state
  	 points to a header.  Answer 0 if all checks pass."
  	| flags |
  	flags := 0.
+ 	(objectMemory checkOopIntegrity: objectMemory specialObjectsOop named: 'specialObjectsOop') ifFalse:
- 	(objectMemory checkOopIntegrity: objectMemory specialObjectsOop named: 'specialObjectsOop')ifFalse:
  		[flags := 1].
  	"No longer check messageSelector; it is ephemeral, not living beyond message lookup.
  	(objectMemory isNonImmediate: messageSelector) ifTrue:
+ 		[(objectMemory checkOopIntegrity: messageSelector named: 'messageSelector') ifFalse:
+ 			[flags := flags + N]]."
+ 	(objectMemory checkOopIntegrity: newMethod named: 'newMethod') ifFalse:
+ 		[flags := flags + 2].
- 		[(objectMemory checkOopIntegrity: messageSelector named: 'messageSelector')ifFalse:
- 			[ok := false]]."
- 	"Work around the primitiveDoPrimitiveWithArgs hack"
- 	(objectMemory hasSpurMemoryManagerAPI
- 	and: [objectMemory isIntegerObject: newMethod]) ifFalse:
- 		[(objectMemory checkOopIntegrity: newMethod named: 'newMethod')ifFalse:
- 			[flags := flags + 2]].
  	"No longer check lkupClass; it is ephemeral, not living beyond message lookup.
+ 	(objectMemory checkOopIntegrity: lkupClass named: 'lkupClass') ifFalse:
+ 		[flags := flags + N]."
+ 	(objectMemory checkOopIntegrity: profileProcess named: 'profileProcess') ifFalse:
- 	(objectMemory checkOopIntegrity: lkupClass named: 'lkupClass')ifFalse:
- 		[ok := false]."
- 	(objectMemory checkOopIntegrity: profileProcess named: 'profileProcess')ifFalse:
  		[flags := flags + 4].
+ 	(objectMemory checkOopIntegrity: profileMethod named: 'profileMethod') ifFalse:
- 	(objectMemory checkOopIntegrity: profileMethod named: 'profileMethod')ifFalse:
  		[flags := flags + 8].
+ 	(objectMemory checkOopIntegrity: profileSemaphore named: 'profileSemaphore') ifFalse:
- 	(objectMemory checkOopIntegrity: profileSemaphore named: 'profileSemaphore')ifFalse:
  		[flags := flags + 16].
  	tempOop = 0 ifFalse:
+ 		[(objectMemory checkOopIntegrity: tempOop named: 'tempOop') ifFalse:
- 		[(objectMemory checkOopIntegrity: tempOop named: 'tempOop')ifFalse:
  			[flags := flags + 32]].
  	tempOop2 = 0 ifFalse:
+ 		[(objectMemory checkOopIntegrity: tempOop2 named: 'tempOop2') ifFalse:
- 		[(objectMemory checkOopIntegrity: tempOop2 named: 'tempOop2')ifFalse:
  			[flags := flags + 64]].
- 	tempOop3 = 0 ifFalse:
- 		[(objectMemory checkOopIntegrity: tempOop3 named: 'tempOop3')ifFalse:
- 			[flags := flags + 128]].
  
  	"Callback support - check suspended callback list"
  	1 to: jmpDepth do:
  		[:i|
  		(objectMemory checkOopIntegrity: (suspendedCallbacks at: i) named: 'suspendedCallbacks' index: i) ifFalse:
+ 			[flags := flags + 128].
- 			[flags := flags + 256].
  		(objectMemory checkOopIntegrity: (suspendedMethods at: i) named: 'suspendedMethods' index: i) ifFalse:
+ 			[flags := flags + 256]].
- 			[flags := flags + 512]].
  
  	self checkLogIntegrity ifFalse:
+ 		[flags := flags + 512].
- 		[flags := flags + 1024].
  
  	^flags!

Item was changed:
  ----- Method: StackInterpreter>>initialize (in category 'initialization') -----
  initialize
  	"Here we can initialize the variables C initializes to zero.  #initialize methods do /not/ get translated."
  	checkAllocFiller := false. "must precede initializeObjectMemory:"
  	primFailCode := 0.
  	stackLimit := 0. "This is also the initialization flag for the stack system."
  	stackPage := overflowedPage := 0.
  	extraFramesToMoveOnOverflow := 0.
  	bytecodeSetSelector := 0.
  	highestRunnableProcessPriority := 0.
  	nextProfileTick := 0.
  	nextPollUsecs := 0.
  	nextWakeupUsecs := 0.
+ 	tempOop := tempOop2 := theUnknownShort := 0.
- 	tempOop := tempOop2 := tempOop3 := theUnknownShort := 0.
  	interruptPending := false.
  	inIOProcessEvents := 0.
  	fullScreenFlag := 0.
  	deferDisplayUpdates := false.
  	displayBits := displayWidth := displayHeight := displayDepth := 0.
  	pendingFinalizationSignals := statPendingFinalizationSignals := 0.
  	globalSessionID := 0.
  	jmpDepth := 0.
  	longRunningPrimitiveStartUsecs := longRunningPrimitiveStopUsecs := 0.
  	maxExtSemTabSizeSet := false.
  	debugCallbackInvokes := debugCallbackPath := debugCallbackReturns := 0.
  	statForceInterruptCheck := statStackOverflow := statCheckForEvents :=
  	statProcessSwitch := statIOProcessEvents := statStackPageDivorce :=
  	statIdleUsecs := 0!

Item was changed:
  ----- Method: StackInterpreter>>initializeInterpreter: (in category 'initialization') -----
  initializeInterpreter: bytesToShift
  	"Initialize Interpreter state before starting execution of a new image."
  	interpreterProxy := self sqGetInterpreterProxy.
  	self dummyReferToProxy.
  	objectMemory initializeObjectMemory: bytesToShift.
  	self checkAssumedCompactClasses.
  	self initializeExtraClassInstVarIndices.
  	method := newMethod := objectMemory nilObject.
  	self cCode: '' inSmalltalk:
  		[breakSelectorLength ifNil:
  			[breakSelectorLength := objectMemory minSmallInteger]].
  	methodDictLinearSearchLimit := 8.
  	self initialCleanup.
  	LowcodeVM ifTrue: [ self setupNativeStack ].
  	profileSemaphore := profileProcess := profileMethod := objectMemory nilObject.
  	interruptKeycode := 2094. "cmd-. as used for Mac but no other OS"
  	[globalSessionID = 0] whileTrue:
  		[globalSessionID := self
  								cCode: [(self time: #NULL) + self ioMSecs]
  								inSmalltalk: [(Random new next * SmallInteger maxVal) asInteger]].
+ 	metaAccessorDepth := -2.
+ 	super initializeInterpreter: bytesToShift!
- 	super initializeInterpreter: bytesToShift.!

Item was added:
+ ----- Method: StackInterpreter>>isMetaPrimitiveIndex: (in category 'primitive support') -----
+ isMetaPrimitiveIndex: primIndex
+ 	"This virtual machine provides two primitives that executes arbitrary primitives, one
+ 	 for indexed primitivces and one for named primitives.  These meta primitives are used
+ 	 in the debugger to execute primitives while simulating execution.  Spur needs to know
+ 	 the accessor depth for a primitive so that failures due to forwarders can be fixed up
+ 	 and retried.  This method identifies such meta primitives so that metaAccessorDepth
+ 	 can be substituted when appropriate."
+ 	<inline: true>
+ 	^primIndex = PrimNumberDoPrimitive
+ 	  or: [primIndex = PrimNumberDoExternalCall]!

Item was changed:
  ----- Method: StackInterpreter>>mapInterpreterOops (in category 'object memory support') -----
  mapInterpreterOops
  	"Map all oops in the interpreter's state to their new values 
  	 during garbage collection or a become: operation."
  	"Assume: All traced variables contain valid oops."
  	<inline: false>
  	self mapStackPages.
  	self mapMachineCode: self getGCMode.
  	self mapTraceLogs.
  	self mapVMRegisters.
  	self mapProfileState.
  	self remapCallbackState.
  	(tempOop ~= 0
  	 and: [objectMemory shouldRemapOop: tempOop]) ifTrue:
  		[tempOop := objectMemory remapObj: tempOop].
  	(tempOop2 ~= 0
  	 and: [objectMemory shouldRemapOop: tempOop2]) ifTrue:
+ 		[tempOop2 := objectMemory remapObj: tempOop2]!
- 		[tempOop2 := objectMemory remapObj: tempOop2].
- 	(tempOop3 ~= 0
- 	 and: [objectMemory shouldRemapOop: tempOop3]) ifTrue:
- 		[tempOop3 := objectMemory remapObj: tempOop3]!

Item was changed:
  ----- Method: StackInterpreter>>markAndTraceInterpreterOops: (in category 'object memory support') -----
  markAndTraceInterpreterOops: fullGCFlag
  	"Mark and trace all oops in the interpreter's state."
  	"Assume: All traced variables contain valid oops.
  	 N.B. Don't trace messageSelector and lkupClass; these are ephemeral, live
  	 only during message lookup and because createActualMessageTo will not
  	 cause a GC these cannot change during message lookup."
  	| oop |
  	"Must mark stack pages first to initialize the per-page trace
  	 flags for full garbage collect before any subsequent tracing."
  	self markAndTraceStackPages: fullGCFlag.
  	self markAndTraceTraceLog.
  	self markAndTracePrimTraceLog.
  	objectMemory markAndTrace: objectMemory specialObjectsOop. "also covers nilObj, trueObj, falseObj, and compact classes"
  	(objectMemory isImmediate: newMethod) ifFalse:
  		[objectMemory markAndTrace: newMethod].
  	self traceProfileState.
  	tempOop = 0 ifFalse: [objectMemory markAndTrace: tempOop].
  	tempOop2 = 0 ifFalse: [objectMemory markAndTrace: tempOop2].
- 	tempOop3 = 0 ifFalse: [objectMemory markAndTrace: tempOop3].
  
+ 	"V3 memory manager support"
+ 	1 to: objectMemory remapBufferCount do:
+ 		[:i | 
+ 		oop := objectMemory remapBuffer at: i.
+ 		(objectMemory isImmediate: oop) ifFalse: [objectMemory markAndTrace: oop]].
- 	1 to: objectMemory remapBufferCount do: [:i | 
- 			oop := objectMemory remapBuffer at: i.
- 			(objectMemory isIntegerObject: oop) ifFalse: [objectMemory markAndTrace: oop]].
  
+ 	"Old callback support - trace suspended callback list"
+ 	1 to: jmpDepth do:
+ 		[:i|
- 	"Callback support - trace suspended callback list"
- 	1 to: jmpDepth do:[:i|
  		oop := suspendedCallbacks at: i.
+ 		(objectMemory isImmediate: oop) ifFalse:[objectMemory markAndTrace: oop].
- 		(objectMemory isIntegerObject: oop) ifFalse:[objectMemory markAndTrace: oop].
  		oop := suspendedMethods at: i.
+ 		(objectMemory isImmediate: oop) ifFalse:[objectMemory markAndTrace: oop]]!
- 		(objectMemory isIntegerObject: oop) ifFalse:[objectMemory markAndTrace: oop].
- 	]!

Item was changed:
  ----- Method: StackInterpreter>>printDecodeMethodHeaderOop: (in category 'printing') -----
  printDecodeMethodHeaderOop: methodHeaderOop
  	self printOopShort: methodHeaderOop.
  	(self methodHeaderHasPrimitive: methodHeaderOop) ifTrue:
  		[self print: ' hasPrim'].
  	(self methodHeaderIndicatesLargeFrame: methodHeaderOop) ifTrue:
  		[self print: ' largeFrame'].
  	(SistaVM and: [self isOptimizedMethodHeader: methodHeaderOop]) ifTrue:
  		[self print: ' optimized'].
+ 	(MULTIPLEBYTECODESETS and: [(objectMemory integerValueOf: methodHeaderOop) < 0]) ifTrue:
- 	(MULTIPLEBYTECODESETS and: [objectMemory integerValueOf: methodHeaderOop]) < 0 ifTrue:
  		[self print: ' altSet'].
  	NewspeakVM ifTrue:
  		[| s |
  		s := (self accessModifierOfMethodHeader: methodHeaderOop) caseOf: {
  						[0] -> [' public'].
  						[1] -> [' private'].
  						[2] -> [' protected'].
  						[3] -> [' access undefined'] }.
  		 self print: s].
  	self print: ' nLits '; printNum: (objectMemory literalCountOfMethodHeader: methodHeaderOop);
  		print: ' nArgs '; printNum: (self argumentCountOfMethodHeader: methodHeaderOop);
  		print: ' nTemps '; printNum: (self temporaryCountOfMethodHeader: methodHeaderOop)!

Item was changed:
  ----- Method: StackInterpreter>>saneFunctionPointerForFailureOfPrimIndex: (in category 'primitive support') -----
  saneFunctionPointerForFailureOfPrimIndex: primIndex
+ 	| basePrimitive |
+ 	<var: 'basePrimitive' declareC: 'void (*basePrimitive)(void)'>
+ 	basePrimitive := self functionPointerFor: primIndex inClass: objectMemory nilObject.
+ 	^primitiveFunctionPointer = basePrimitive
+ 	  or: [(basePrimitive = #primitiveExternalCall and: [self isPrimitiveFunctionPointerAnIndex not]) 
+ 	  or: [(self isMetaPrimitiveIndex: primIndex) and: [metaAccessorDepth > -2]]]!
- 	^primitiveFunctionPointer = (self functionPointerFor: primIndex inClass: objectMemory nilObject)!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveDoNamedPrimitiveWithArgs (in category 'plugin primitives') -----
  primitiveDoNamedPrimitiveWithArgs
  	"Simulate an primitiveExternalCall invocation (e.g. for the Debugger).  Do not cache anything.
  	 e.g. ContextPart>>tryNamedPrimitiveIn: aCompiledMethod for: aReceiver withArgs: arguments"
  	| argumentArray arraySize methodArg methodHeader
  	  moduleName functionName moduleLength functionLength
  	  spec addr primRcvr isArray |
  	<var: #addr declareC: 'void (*addr)()'>
+ 	objectMemory hasSpurMemoryManagerAPI ifTrue: "See checkForAndFollowForwardedPrimitiveState"
+ 		[metaAccessorDepth := -2].
  	argumentArray := self stackTop.
  	methodArg := self stackValue: 2.
  	((objectMemory isArray: argumentArray)
  	 and: [objectMemory isOopCompiledMethod: methodArg]) ifFalse:
  		[^self primitiveFailFor: -2]. "invalid args"
  	arraySize := objectMemory numSlotsOf: argumentArray.
  	(self roomToPushNArgs: arraySize) ifFalse:
  		[^self primitiveFailFor: -2]. "invalid args"
  
  	methodHeader := objectMemory methodHeaderOf: methodArg.
  	(objectMemory literalCountOfMethodHeader: methodHeader) > 2 ifFalse:
  		[^self primitiveFailFor: -3]. "invalid methodArg state"
  	spec := objectMemory fetchPointer: 1 "first literal" ofObject: methodArg.
  	isArray := self isInstanceOfClassArray: spec.
  	(isArray
  	and: [(objectMemory numSlotsOf: spec) = 4
  	and: [(self primitiveIndexOfMethod: methodArg header: methodHeader) = PrimNumberExternalCall]]) ifFalse:
  		[^self primitiveFailFor: -3]. "invalid methodArg state"
  
  	(self argumentCountOfMethodHeader: methodHeader) = arraySize ifFalse:
  		[^self primitiveFailFor: -2]. "invalid args (Array args wrong size)"
  
  	"The function has not been loaded yet. Fetch module and function name."
  	moduleName := objectMemory fetchPointer: 0 ofObject: spec.
  	moduleName = objectMemory nilObject
  		ifTrue: [moduleLength := 0]
  		ifFalse: [self success: (objectMemory isBytes: moduleName).
  				moduleLength := objectMemory lengthOf: moduleName.
  				self cCode: '' inSmalltalk:
  					[ (#('FloatArrayPlugin' 'Matrix2x3Plugin') includes: (self stringOf: moduleName)) "??"
+ 						ifTrue: [moduleLength := 0  "Cause all of these to fail.  Why?? eem 12/7/2017 09:37"]]].
- 						ifTrue: [moduleLength := 0  "Cause all of these to fail"]]].
  	functionName := objectMemory fetchPointer: 1 ofObject: spec.
  	self success: (objectMemory isBytes: functionName).
  	functionLength := objectMemory lengthOf: functionName.
  	self successful ifFalse: [^self primitiveFailFor: -3]. "invalid methodArg state"
  
+ 	"Spur needs to know the primitive's accessorDepth."
+ 	objectMemory hasSpurMemoryManagerAPI
+ 		ifTrue:
+ 			[addr := self ioLoadExternalFunction: functionName + objectMemory baseHeaderSize
+ 						OfLength: functionLength
+ 						FromModule: moduleName + objectMemory baseHeaderSize
+ 						OfLength: moduleLength
+ 						AccessorDepthInto: (self addressOf: metaAccessorDepth
+ 												 put: [:val| metaAccessorDepth := val]).
+ 			 addr = 0 ifTrue:
+ 				[metaAccessorDepth := -2]]
+ 		ifFalse:
+ 			[addr := self ioLoadExternalFunction: functionName + objectMemory baseHeaderSize
+ 						OfLength: functionLength
+ 						FromModule: moduleName + objectMemory baseHeaderSize
+ 						OfLength: moduleLength].
- 	addr := self ioLoadExternalFunction: functionName + objectMemory baseHeaderSize
- 				OfLength: functionLength
- 				FromModule: moduleName + objectMemory baseHeaderSize
- 				OfLength: moduleLength.
  	addr = 0 ifTrue:
  		[^self primitiveFailFor: -1]. "could not find function; answer generic failure (see below)"
  
  	"Cannot fail this primitive from now on.  Can only fail the external primitive."
  	tempOop := objectMemory
  						eeInstantiateClassIndex: ClassArrayCompactIndex
  						format: objectMemory arrayFormat
+ 						numSlots: 4.
- 						numSlots: (objectMemory hasSpurMemoryManagerAPI
- 									ifTrue: [5]
- 									ifFalse: [4]).
  	objectMemory
  		storePointerUnchecked: 0 ofObject: tempOop withValue: (argumentArray := self popStack);
  		storePointerUnchecked: 1 ofObject: tempOop withValue: (primRcvr := self popStack);
  		storePointerUnchecked: 2 ofObject: tempOop withValue: self popStack; "the method"
  		storePointerUnchecked: 3 ofObject: tempOop withValue: self popStack. "the context receiver"
  	self push: primRcvr. "replace context receiver with actual receiver"
  	argumentCount := arraySize.
  	1 to: arraySize do:
  		[:index| self push: (objectMemory fetchPointer: index - 1 ofObject: argumentArray)].
+ 	self callExternalPrimitive: addr.
- 	objectMemory hasSpurMemoryManagerAPI
- 		ifTrue:
- 			[objectMemory storePointerUnchecked: 4 ofObject: tempOop withValue: newMethod.
- 			 newMethod := methodArg.
- 			 self callExternalPrimitive: addr. "On Spur, sets primitiveFunctionPointer"
- 			 self maybeRetryPrimitiveOnFailure.
- 			 newMethod := objectMemory fetchPointer: 4 ofObject: tempOop]
- 		ifFalse:
- 			[self callExternalPrimitive: addr].
  	self successful ifFalse: "If primitive failed, then restore state for failure code"
  		[self pop: arraySize + 1.
  		 self push: (objectMemory fetchPointer: 3 ofObject: tempOop).
  		 self push: (objectMemory fetchPointer: 2 ofObject: tempOop).
  		 self push: (objectMemory fetchPointer: 1 ofObject: tempOop).
  		 self push: (objectMemory fetchPointer: 0 ofObject: tempOop).
  		 argumentCount := 3.
  		 "Must reset primitiveFunctionPointer for checkForAndFollowForwardedPrimitiveState"
  		 objectMemory hasSpurMemoryManagerAPI ifTrue:
  			[primitiveFunctionPointer := #primitiveDoNamedPrimitiveWithArgs].
  		 "Hack.  A nil prim error code (primErrorCode = 1) is interpreted by the image
  		  as meaning this primitive is not implemented.  So to pass back nil as an error
  		  code we use -1 to indicate generic failure."
  		 primFailCode = 1 ifTrue:
  			[primFailCode := -1]]!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveDoPrimitiveWithArgs (in category 'control primitives') -----
  primitiveDoPrimitiveWithArgs
  	"Implement either ProtoObject>>tryPrimitive: primIndex withArgs: argArray
  	 or Context>>receiver: anObject tryPrimitive: primIndex withArgs: argArray.
  	 If this primitive fails, arrange that its error code is a negative integer, to
  	 distinguish between this failing and the primitive it invokes failing."
  	| argumentArray arraySize index primIdx savedNumArgs rcvr |
+ 	objectMemory hasSpurMemoryManagerAPI ifTrue: "See checkForAndFollowForwardedPrimitiveState"
+ 		[metaAccessorDepth := -2].
  	(argumentCount between: 2 and: 3) ifFalse:
  		[^self primitiveFailFor: PrimErrUnsupported negated].
  	argumentArray := self stackTop.
  	primIdx := self stackValue: 1.
  	((objectMemory isArray: argumentArray)
  	 and: [objectMemory isIntegerObject: primIdx]) ifFalse:
  		[^self primitiveFailFor: PrimErrBadArgument negated].
  	arraySize := objectMemory numSlotsOf: argumentArray.
  	(self roomToPushNArgs: arraySize) ifFalse:
  		[^self primitiveFailFor: PrimErrLimitExceeded negated].
  
  	primIdx := objectMemory integerValueOf: primIdx.
  	primitiveFunctionPointer := self functionPointerFor: primIdx inClass: nil.
  	primitiveFunctionPointer = 0 ifTrue:
  		[primitiveFunctionPointer := #primitiveDoPrimitiveWithArgs.
  		 ^self primitiveFailFor: PrimErrBadIndex negated].
  
  	"Pop primIndex and argArray, then push args in place..."
  	(savedNumArgs := argumentCount) = 3
  		ifTrue: "...and receiver if the three arg form"
  			[tempOop2 := self stackValue: 4. "actual receiver"
  			 rcvr := self stackValue: 3. "receiver for primitive"
  			 (objectMemory isOopForwarded: rcvr) ifTrue:
  				[rcvr := objectMemory followForwarded: rcvr].
  			 self pop: 4; push: rcvr] "use first arg as receiver"
  		ifFalse:
  			[self pop: 2].
  	argumentCount := arraySize.
  	index := 1.
+ 	[index <= arraySize] whileTrue:
- 	[index <= argumentCount] whileTrue:
  		[self push: (objectMemory fetchPointer: index - 1 ofObject: argumentArray).
  		 index := index + 1].
  
  	self isPrimitiveFunctionPointerAnIndex ifTrue:
  		[self externalQuickPrimitiveResponse.
  		 tempOop2 := 0.
  		^nil].
  	"We use tempOop instead of pushRemappableOop:/popRemappableOop here because in
  	 the Cogit primitiveEnterCriticalSection, primitiveSignal, primitiveResume et al longjmp back
  	 to either the interpreter or machine code, depending on the process activated.  So if we're
  	 executing one of these primitives, control won't actually return here and the matching
  	 popRemappableOop: wouldn't occur, potentially overflowing the remap buffer.
  	 Note that while recursion could occur (nil tryPrimitive: 118 withArgs: #(118 #(110 #())))
  	 it counts as shooting oneself in the foot."
  	tempOop := argumentArray. "prim might alloc/gc"
  
  	"Run the primitive (sets primFailCode)"
+ 	objectMemory hasSpurMemoryManagerAPI ifTrue: "See checkForAndFollowForwardedPrimitiveState"
+ 		[metaAccessorDepth := primitiveAccessorDepthTable at: primIdx].
+ 	self slowPrimitiveResponse.
- 	objectMemory hasSpurMemoryManagerAPI
- 		ifTrue:
- 			[tempOop3 := newMethod.
- 			 newMethod := objectMemory integerObjectOf: primIdx.
- 			 self slowPrimitiveResponse.
- 			 newMethod := tempOop3.
- 			 tempOop3 := 0]
- 		ifFalse:
- 			[self slowPrimitiveResponse].
  
  	self successful ifFalse: "If primitive failed, then restore state for failure code"
  		[self pop: arraySize.
  		 savedNumArgs = 3 ifTrue:
  			[rcvr := self stackTop.
  			 self stackTopPut: tempOop2.
  			 self push: rcvr].
  		 self pushInteger: primIdx.
  		 self push: tempOop.
  		 primitiveFunctionPointer := #primitiveDoPrimitiveWithArgs.
  		 argumentCount := savedNumArgs].
  	tempOop := tempOop2 := 0!




More information about the Vm-dev mailing list