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

commits at source.squeak.org commits at source.squeak.org
Fri Sep 6 19:55:54 UTC 2019


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

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

Name: VMMaker.oscog-eem.2555
Author: eem
Time: 6 September 2019, 12:55:40.085336 pm
UUID: 4c3d555e-9970-4e10-9620-8011a7a63e4b
Ancestors: VMMaker.oscog-nice.2554

Implement discarding methods with machine code primitives on toggling primitiveDoMixedArithmetic.

Next up, adding primitiveDoMixedArithmetic as a flag saved in the image header.

=============== Diff against VMMaker.oscog-nice.2554 ===============

Item was added:
+ ----- Method: CoInterpreter>>divorceAMachineCodeFrameWithMachineCodePrimitiveMethodIn: (in category 'frame access') -----
+ divorceAMachineCodeFrameWithMachineCodePrimitiveMethodIn: aStackPage
+ 	"Divorce at most one frame in the current page (since the divorce may cause the page to be split)
+ 	 and answer whether a frame was divorced."
+ 	<var: #aStackPage type: #'StackPage *'>
+ 	| theFP calleeFP theSP theContext |
+ 	<var: #aStackPage type: #'StackPage *'>
+ 	<var: #theFP type: #'char *'>
+ 	<var: #calleeFP type: #'char *'>
+ 	<var: #theSP type: #'char *'>
+ 
+ 	theFP := aStackPage headFP.
+ 	theSP := aStackPage headSP.
+ 	theSP := theSP + objectMemory wordSize. "theSP points at hottest item on frame's stack"
+ 
+ 	[((self isMachineCodeFrame: theFP)
+ 	  and: [cogit cogMethodHasMachineCodePrim: (self mframeHomeMethod: theFP)]) ifTrue:
+ 		[theContext := self ensureFrameIsMarried: theFP SP: theSP.
+ 		 self externalDivorceFrame: theFP andContext: theContext.
+ 		 ^true].
+ 	 calleeFP := theFP.
+ 	 theFP := self frameCallerFP: theFP.
+ 	 theFP ~= 0] whileTrue:
+ 		["theSP points at stacked hottest item on frame's stack"
+ 		 theSP := self frameCallerSP: calleeFP].
+ 
+ 	^false!

Item was added:
+ ----- Method: CoInterpreter>>divorceMachineCodeFramesWithMachineCodePrimitiveMethod (in category 'frame access') -----
+ divorceMachineCodeFramesWithMachineCodePrimitiveMethod
+ 	| divorcedSome |
+ 	[stackPage ~= 0 ifTrue: "This is needed for the assert in externalDivorceFrame:andContext:"
+ 		[stackPages markStackPageMostRecentlyUsed: stackPage].
+ 	 "Slang can't currently cope with the lack of the variable here.
+ 	  Something to do with the preceding statement.  Take it out
+ 	  and the code is good.  leave it in and we get do { ... } while(l1:)"
+ 	 divorcedSome := self divorceSomeFramesWithMachineCodePrimitiveMethod.
+ 	 divorcedSome] whileTrue!

Item was added:
+ ----- Method: CoInterpreter>>divorceSomeFramesWithMachineCodePrimitiveMethod (in category 'frame access') -----
+ divorceSomeFramesWithMachineCodePrimitiveMethod
+ 	"Divorce at most one frame (since the divorce may cause the containing
+ 	 page to be split) and answer whether a frame was divorced."
+ 	<var: #cogMethod type: #'CogMethod *'>
+ 	| divorcedSome |
+ 	<var: #aPage type: #'StackPage *'>
+ 	divorcedSome := false.
+ 	0 to: numStackPages - 1 do:
+ 		[:i| | aPage |
+ 		aPage := stackPages stackPageAt: i.
+ 		(stackPages isFree: aPage) ifFalse:
+ 			["this to avoid assert in externalDivorceFrame:andContext:"
+ 			 stackPages markStackPageMostRecentlyUsed: stackPage.
+ 			 (self divorceAMachineCodeFrameWithMachineCodePrimitiveMethodIn: aPage) ifTrue:
+ 				[divorcedSome := true]]].
+ 	^divorcedSome!

Item was added:
+ ----- Method: CoInterpreter>>ensureAllContextsWithMethodMachineCodePrimitiveMethodHaveBytecodePCs (in category 'frame access') -----
+ ensureAllContextsWithMethodMachineCodePrimitiveMethodHaveBytecodePCs
+ 	"Map all native pcs to bytecoded pcs in all contexts that have a method with a cog method with a machine code primitive.
+ 	 Used to implement flushMethodsWithMachineCodePrimitivesAndContinueAnswering:/vmParameterAt: 75 put: aBool."
+ 	<inline: true>
+ 	objectMemory allObjectsDo:
+ 		[:oop| | methodHeader |
+ 		 (objectMemory isContextNonImm: oop) ifTrue:
+ 			[methodHeader := self rawHeaderOf: (objectMemory fetchPointer: MethodIndex ofObject: oop).
+ 			 ((self isCogMethodReference: methodHeader)
+ 			  and: [cogit cogMethodHasMachineCodePrim: (self cCoerceSimple: methodHeader to: #'CogMethod *')]) ifTrue:
+ 				[self widowOrForceToBytecodePC: oop]]]!

Item was added:
+ ----- Method: CoInterpreter>>flushMethodsWithMachineCodePrimitivesAndContinueAnswering: (in category 'primitive support') -----
+ flushMethodsWithMachineCodePrimitivesAndContinueAnswering: result
+ 	"Arrange that any and all cog methods with machine code primitives can be and are discarded.
+ 	 Hence scan contexts and map their PCs to bytecode PCs if required, and scan frames, divorcing
+ 	 the frames of activationsif required.  The continue execution answering result.  THIS MUST BE
+ 	 INVOKED IN THE CONTEXT OF A PRIMITIVE.  It exists to support vmParameterAt:put:."
+ 	| activeContext theFrame thePage |
+ 	<var: #theFrame type: #'char *'>
+ 	<var: #thePage type: #'StackPage *'>
+ 	activeContext := self ensureFrameIsMarried: framePointer SP: stackPointer.
+ 	self ensurePushedInstructionPointer.
+ 	self externalWriteBackHeadFramePointers.
+ 	self divorceMachineCodeFramesWithMachineCodePrimitiveMethod.
+ 	self ensureAllContextsWithMethodMachineCodePrimitiveMethodHaveBytecodePCs.
+ 	cogit unlinkSendsToMachineCodePrimitiveMethodsAndFreeIf: true.
+ 
+ 	"If flushing led to divorce continue in the interpreter."
+ 	(self isStillMarriedContext: activeContext) ifFalse:
+ 		[self zeroStackPage. "to avoid assert in marryContextInNewStackPageAndInitializeInterpreterRegisters:"
+ 		 self marryContextInNewStackPageAndInitializeInterpreterRegisters: activeContext.
+ 		"pop bogus machine-code instructionPointer, arguments and receiver"
+ 		 self pop: argumentCount + 2 thenPush: result.
+ 		 self siglong: reenterInterpreter jmp: ReturnToInterpreter.
+ 		 "NOTREACHED"].
+ 	"If not, work out where we are and continue"
+ 	theFrame := self frameOfMarriedContext: activeContext.
+ 	thePage := stackPages stackPageFor: theFrame.
+ 	self assert: thePage headFP = theFrame.
+ 	self setStackPageAndLimit: thePage.
+ 	self setStackPointersFromPage: thePage.
+ 	instructionPointer := self popStack.
+ 	 self pop: argumentCount + 1 thenPush: result!

Item was changed:
  ----- Method: Cogit>>setHasYoungReferent: (in category 'accessing') -----
  setHasYoungReferent: boolean
  	"Written this way to allow reak-pointing in the simulator."
  	<cmacro: '(b) (hasYoungReferent = (b))'>
+ 	"boolean ifTrue:
+ 		[self halt]."
- 	boolean ifTrue:
- 		[self halt].
  	"(hasYoungReferent == false and: [boolean == true]) ifTrue:
  		[self halt]."
  	hasYoungReferent := boolean!

Item was added:
+ ----- Method: Cogit>>unlinkIfLinkedSend:pc:toMachineCodePrim: (in category 'in-line cacheing') -----
+ unlinkIfLinkedSend: annotation pc: mcpc toMachineCodePrim: ignored
+ 	<var: #mcpc type: #'char *'>
+ 	<var: #nsSendCache type: #'NSSendCache *'>
+ 	| entryPoint |
+ 
+ 	NewspeakVM ifTrue:
+ 		[| nsSendCache |
+ 		 annotation = IsNSSendCall ifTrue:
+ 			[nsSendCache := self nsSendCacheFromReturnAddress: mcpc asInteger.
+ 			(entryPoint := nsSendCache target) ~= 0 ifTrue:
+ 				[ | targetMethod |
+ 				targetMethod := entryPoint - cmNoCheckEntryOffset.
+ 				(self cogMethodHasMachineCodePrim: targetMethod) ifTrue:
+ 					[self voidNSSendCache: nsSendCache]].
+ 			^0 "keep scanning"]].
+ 
+ 	(self isPureSendAnnotation: annotation) ifTrue:
+ 		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
+ 		 entryPoint > methodZoneBase ifTrue: "It's a linked send."
+ 			[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
+ 				[:targetMethod :sendTable| 
+ 				 (self cogMethodHasMachineCodePrim: targetMethod) ifTrue:
+ 					[self unlinkSendAt: mcpc targetMethod: targetMethod sendTable: sendTable]]]].
+ 
+ 	^0 "keep scanning"!

Item was added:
+ ----- Method: Cogit>>unlinkSendsToMachineCodePrimitiveMethodsAndFreeIf: (in category 'jit - api') -----
+ unlinkSendsToMachineCodePrimitiveMethodsAndFreeIf: freeIfTrue
+ 	<api>
+ 	"Unlink all sends in cog methods to methods with a machine code
+ 	 primitive, and free machine code primitive methods if freeIfTrue.
+ 	 To avoid having to scan PICs, free any and all PICs"
+ 	| cogMethod freedSomething |
+ 	<var: #cogMethod type: #'CogMethod *'>
+ 	methodZoneBase ifNil: [^self].
+ 	codeModified := freedSomething := false.
+ 	cogMethod := self cCoerceSimple: methodZoneBase to: #'CogMethod *'.
+ 	[cogMethod < methodZone limitZony] whileTrue:
+ 		[cogMethod cmType = CMMethod
+ 			ifTrue:
+ 				[(freeIfTrue
+ 				  and: [self cogMethodHasMachineCodePrim: cogMethod])
+ 					ifTrue:
+ 						[methodZone freeMethod: cogMethod.
+ 						 freedSomething := true]
+ 					ifFalse:
+ 						[self mapFor: cogMethod
+ 							 performUntil: #unlinkIfLinkedSend:pc:toMachineCodePrim:
+ 							 arg: 0]]
+ 			ifFalse:
+ 				[cogMethod cmType = CMClosedPIC ifTrue:
+ 					[methodZone freeMethod: cogMethod.
+ 					 freedSomething := true]].
+ 		cogMethod := methodZone methodAfter: cogMethod].
+ 	freedSomething
+ 		ifTrue: [self unlinkSendsToFree]
+ 		ifFalse:
+ 			[codeModified ifTrue: "After possibly updating inline caches we need to flush the icache."
+ 				[processor flushICacheFrom: methodZoneBase asUnsignedInteger to: methodZone limitZony asUnsignedInteger]]!

Item was added:
+ ----- Method: SimpleStackBasedCogit>>cogMethodHasMachineCodePrim: (in category 'in-line cacheing') -----
+ cogMethodHasMachineCodePrim: aCogMethod
+ 	<api>
+ 	<var: 'aCogMethod' type: #'CogMethod *'>
+ 	<inline: true>
+ 	| primIndex |
+ 	primIndex := coInterpreter primitiveIndexOfMethod: aCogMethod methodObject header: aCogMethod objectHeader.
+ 	^(primIndex between: 1 and: MaxCompiledPrimitiveIndex)
+ 	  and: [(primitiveGeneratorTable at: primIndex) primitiveGenerator notNil]!

Item was changed:
  ----- Method: StackInterpreter class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCCodeGenerator
  	| vmClass |
  	self class == thisContext methodClass ifFalse: [^self]. "Don't duplicate decls in subclasses"
  	vmClass := aCCodeGenerator vmClass. "Generate primitiveTable etc based on vmClass, not just StackInterpreter"
  	aCCodeGenerator
  		addHeaderFile:'<stddef.h> /* for e.g. alloca */';
  		addHeaderFile:'<setjmp.h>';
  		addHeaderFile:'<wchar.h> /* for wint_t */';
  		addHeaderFile:'"vmCallback.h"';
  		addHeaderFile:'"sqMemoryFence.h"';
  		addHeaderFile:'"dispdbg.h"'.
  	LowcodeVM ifTrue: [ aCCodeGenerator addHeaderFile:'"sqLowcodeFFI.h"'].
  
  	vmClass declareInterpreterVersionIn: aCCodeGenerator defaultName: 'Stack'.
  	aCCodeGenerator
  		var: #interpreterProxy  type: #'struct VirtualMachine*'.
  	aCCodeGenerator
  		declareVar: #sendTrace type: 'volatile int';
  		declareVar: #byteCount type: #usqInt.
  	"These need to be pointers or unsigned."
  	self declareC: #(instructionPointer method newMethod)
  		as: #usqInt
  		in: aCCodeGenerator.
  	"These are all pointers; char * because Slang has no support for C pointer arithmetic."
  	self declareC: #(localIP localSP localFP stackPointer framePointer stackLimit breakSelector)
  		as: #'char *'
  		in: aCCodeGenerator.
  	aCCodeGenerator
  		var: #breakSelectorLength
  		declareC: 'sqInt breakSelectorLength = MinSmallInteger'.
  	self declareC: #(stackPage overflowedPage)
  		as: #'StackPage *'
  		in: aCCodeGenerator.
  	aCCodeGenerator removeVariable: 'stackPages'.  "this is an implicit receiver in the translated code."
  	"This defines bytecodeSetSelector as 0 if MULTIPLEBYTECODESETS
  	 is not defined, for the benefit of the interpreter on slow machines."
  	aCCodeGenerator addConstantForBinding: (self bindingOf: #MULTIPLEBYTECODESETS).
  	MULTIPLEBYTECODESETS == false ifTrue:
  		[aCCodeGenerator
  			removeVariable: 'bytecodeSetSelector'].
  	BytecodeSetHasExtensions == false ifTrue:
  		[aCCodeGenerator
  			removeVariable: 'extA';
  			removeVariable: 'extB'].
  	aCCodeGenerator
  		var: #methodCache
  		declareC: 'sqIntptr_t methodCache[MethodCacheSize + 1 /* ', (MethodCacheSize + 1) printString, ' */]'.
  	NewspeakVM
  		ifTrue:
  			[aCCodeGenerator
  				var: #nsMethodCache
  				declareC: 'sqIntptr_t nsMethodCache[NSMethodCacheSize + 1 /* ', (NSMethodCacheSize + 1) printString, ' */]']
  		ifFalse:
  			[aCCodeGenerator
  				removeVariable: #nsMethodCache;
  				removeVariable: 'localAbsentReceiver';
  				removeVariable: 'localAbsentReceiverOrZero'].
  	AtCacheTotalSize isInteger ifTrue:
  		[aCCodeGenerator
  			var: #atCache
  			declareC: 'sqInt atCache[AtCacheTotalSize + 1 /* ', (AtCacheTotalSize + 1) printString, ' */]'].
  	aCCodeGenerator
  		var: #primitiveTable
  		declareC: 'void (*primitiveTable[MaxPrimitiveIndex + 2 /* ', (MaxPrimitiveIndex + 2) printString, ' */])(void) = ', vmClass primitiveTableString.
  	vmClass primitiveTable do:
  		[:symbolOrNot|
  		(symbolOrNot isSymbol
  		 and: [symbolOrNot ~~ #primitiveFail]) ifTrue:
  			[(aCCodeGenerator methodNamed: symbolOrNot) ifNotNil:
  				[:tMethod| tMethod returnType: #void]]].
  	vmClass objectMemoryClass hasSpurMemoryManagerAPI
  		ifTrue:
  			[aCCodeGenerator
  				var: #primitiveAccessorDepthTable
  				type: 'signed char'
  				sizeString: 'MaxPrimitiveIndex + 2 /* ', (MaxPrimitiveIndex + 2) printString, ' */'
  				array: vmClass primitiveAccessorDepthTable]
  		ifFalse:
  			[aCCodeGenerator removeVariable: #primitiveAccessorDepthTable].
  	aCCodeGenerator
  		var: #displayBits type: #'void *'.
  	self declareC: #(displayWidth displayHeight displayDepth) as: #int in: aCCodeGenerator.
  	aCCodeGenerator
  		var: #primitiveFunctionPointer
  			declareC: 'void (*primitiveFunctionPointer)()';
  		var: #externalPrimitiveTable
  			declareC: 'void (*externalPrimitiveTable[MaxExternalPrimitiveTableSize + 1 /* ', (MaxExternalPrimitiveTableSize + 1) printString, ' */])(void)';
  		var: #interruptCheckChain
  			declareC: 'void (*interruptCheckChain)(void) = 0';
  		var: #showSurfaceFn
  			declareC: 'int (*showSurfaceFn)(sqIntptr_t, int, int, int, int)';
  		var: #jmpBuf
  			declareC: 'jmp_buf jmpBuf[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]';
  		var: #suspendedCallbacks
  			declareC: 'usqInt suspendedCallbacks[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]';
  		var: #suspendedMethods
  			declareC: 'usqInt suspendedMethods[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]'.
  
  	self declareCAsUSqLong: #(nextPollUsecs nextWakeupUsecs longRunningPrimitiveGCUsecs
  								longRunningPrimitiveStartUsecs longRunningPrimitiveStopUsecs
  								"these are high-frequency enough that they're overflowing quite quickly on modern hardware"
  								statProcessSwitch statIOProcessEvents statForceInterruptCheck
  								statCheckForEvents statStackOverflow statStackPageDivorce
  								statIdleUsecs)
  		in: aCCodeGenerator.
  	aCCodeGenerator var: #nextProfileTick type: #sqLong.
  	aCCodeGenerator
  		var: #reenterInterpreter
  		declareC: 'jmp_buf reenterInterpreter; /* private export */'.
  	LowcodeVM
  		ifTrue:
  			[aCCodeGenerator
  				var: #lowcodeCalloutState type: #'sqLowcodeCalloutState*'.
  			 self declareC: #(nativeSP nativeStackPointer shadowCallStackPointer)
  				as: #'char *'
  				in: aCCodeGenerator]
  		ifFalse:
  			[#(lowcodeCalloutState nativeSP nativeStackPointer shadowCallStackPointer) do:
  				[:var| aCCodeGenerator removeVariable: var]].
  		
  	aCCodeGenerator
  		var: #primitiveDoMixedArithmetic
+ 		declareC: 'char primitiveDoMixedArithmetic = 1'.!
- 		declareC: 'sqInt primitiveDoMixedArithmetic = 1'.!

Item was changed:
  ----- Method: StackInterpreter class>>mustBeGlobal: (in category 'translation') -----
  mustBeGlobal: var
+ 	"Answer if a variable must be global and exported.  Used for inst vars that are accessed from VM support code,
+ 	 and for variables that are initialized to some value (e.g. primitiveDoMixedArithmetic)."
- 	"Answer if a variable must be global and exported.  Used for inst vars that are accessed from VM support code."
  
  	^(super mustBeGlobal: var)
  	   or: [(self objectMemoryClass mustBeGlobal: var)
  	   or: [(#('interpreterProxy' 'interpreterVersion' 'inIOProcessEvents' 'sendWheelEvents'
  			'deferDisplayUpdates' 'extraVMMemory'
  			'showSurfaceFn' 'displayBits' 'displayWidth' 'displayHeight' 'displayDepth'
  			'desiredNumStackPages' 'desiredEdenBytes'
+ 			'primitiveDoMixedArithmetic'
  			'breakLookupClassTag' 'breakSelector' 'breakSelectorLength' 'sendTrace' 'checkAllocFiller' 'checkedPluginName'
  			'reenterInterpreter' 'suppressHeartbeatFlag' 'ffiExceptionResponse'
  			'debugCallbackInvokes' 'debugCallbackPath' 'debugCallbackReturns') includes: var)
  	   or: [ "This allows slow machines to define bytecodeSetSelector as 0
  			to avoid the interpretation overhead."
  			MULTIPLEBYTECODESETS not and: [var = 'bytecodeSetSelector']]]]!

Item was changed:
  ----- Method: StackInterpreter>>canContextSwitchIfActivating:header: (in category 'message sending') -----
  canContextSwitchIfActivating: theMethod header: methodHeader
  	"Context switch should not be allowed on every method activation.  In particular
  	 the implementation of ensure: and ifCurtailed: depends on there being no
  	 suspension point on failing primitive 198 (primitiveMarkUnwindMethod).
  	 slowPrimitiveResponse states
  		``N.B.  This means there is no suspension point on primitive failure
  		    which methods such as ensure: and ifCurtailed: rely on.''
  	 Rather than prevent context switch on all primitives but the ones we really need
  	 to be suspension points (primitiveSignal et al) we choose to allow context switch
  	 for all but primitiveMarkUnwindMethod."
  	| primitiveIndex |
  	<api>
  	<inline: true>
  	primitiveIndex := self primitiveIndexOfMethod: theMethod header: methodHeader.
  	^self cppIf: true
  		ifTrue:
  			[primitiveIndex ~= 198] "primitiveMarkUnwindMethod"
  		ifFalse:
  			[primitiveIndex = 0
  			  or: [(primitiveIndex between: 85 and: 88) "primitiveSignal primitiveWait primitiveResume primitiveSuspend"
+ 			  or: [primitiveIndex = 167 "primitiveYield"
+ 			  or: [primitiveIndex between: 185 and: 186 "primitiveExitCriticalSection primitiveEnterCriticalSection"]]]]!
- 			  or: [primitiveIndex = 167]]] "primitiveYield"!

Item was added:
+ ----- Method: StackInterpreter>>flushMethodsWithMachineCodePrimitivesAndContinueAnswering: (in category 'primitive support') -----
+ flushMethodsWithMachineCodePrimitivesAndContinueAnswering: result
+ 	"In the StackInterpreter this is simply a no op"!

Item was changed:
  ----- Method: StackInterpreter>>primitiveDoMixedArithmetic (in category 'primitive support') -----
  primitiveDoMixedArithmetic
  	"If primitiveDoMixedArithmetic is true, then primitive can handle the conversions:
  	SmallInteger arithmeticOp: Float (Small or Boxed)
  	SmallInteger compareOp: Float (Small or Boxed)
+ 	Else, the primitive fail in case of mixed arithmetic, and conversion should be performed in the image."
- 	Else, the primitive fail in case of mixed arithmetic, and conversion should be performed at image side"
  	<api>
+ 	<cmacro: '() primitiveDoMixedArithmetic'>
- 	<cmacro: '() GIV(primitiveDoMixedArithmetic)'>
  	^primitiveDoMixedArithmetic!

Item was removed:
- ----- Method: StackInterpreter>>setPrimitiveDoMixedArithmetic: (in category 'primitive support') -----
- setPrimitiveDoMixedArithmetic: aBool
- 	"See #primitiveDoMixedArithmetic method"
- 	primitiveDoMixedArithmetic = aBool ifFalse: [self flushMethodCache].
- 	primitiveDoMixedArithmetic := aBool!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveSetVMParameter:arg: (in category 'system control primitives') -----
  primitiveSetVMParameter: index arg: argOop
  	"See primitiveVMParameter method comment"
  	| arg result |
  
  	"argOop read & checks; in most cases this is an integer parameter.  In some it is either an integer or a Float"
  	index = 75
  		ifTrue:
  			[ arg := objectMemory booleanValueOf: argOop.
  			self failed ifTrue: [^self primitiveFailFor: PrimErrBadArgument]]
  		ifFalse: [(index = 17 or: [index = 55 or: [index = 68]])
  			ifTrue:
  				[((objectMemory isFloatInstance: argOop)
  			 	 or: [objectMemory isIntegerObject: argOop]) ifFalse:
  					[^self primitiveFailFor: PrimErrBadArgument]]
  			ifFalse: [(objectMemory isIntegerObject: argOop) ifFalse:
  					[^self primitiveFailFor: PrimErrBadArgument].
  				 arg := objectMemory integerValueOf: argOop]].
  
  	"assume failure, then set success for handled indices"
  	self primitiveFailFor: PrimErrBadArgument.
  	index caseOf: {
  		[5] ->	[objectMemory hasSpurMemoryManagerAPI ifFalse:
  					["Was:
  							result := allocationsBetweenGCs.
  							allocationsBetweenGCs := arg."
  						"Ignore for now, because old images won't start up otherwise.
  						 See 45 for eden size setting."
  					 result := objectMemory nilObject.
  					 self initPrimCall]].
  		[6] ->	[result := objectMemory integerObjectOf: objectMemory tenuringThreshold.
  				 primFailCode := objectMemory tenuringThreshold: arg].
  		[11] ->	[arg >= 0 ifTrue:
  					[result := objectMemory integerObjectOf: objectMemory statTenures.
  					 objectMemory statTenures: arg.
  					 self initPrimCall]].
  		[17] ->	[(SistaVM and: [self isCog]) ifTrue:
  					[result := objectMemory floatObjectOf: self getCogCodeZoneThreshold.
  					 primFailCode := self setCogCodeZoneThreshold: (self noInlineLoadFloatOrIntFrom: argOop)]].
  		[23] ->	[result := objectMemory integerObjectOf: extraVMMemory.
  				 extraVMMemory := arg.
  				 self initPrimCall].
  		[24] ->	[arg > 0 ifTrue:
  					[result := objectMemory integerObjectOf: objectMemory shrinkThreshold.
  					 objectMemory shrinkThreshold: arg.
  					 self initPrimCall]].
  		[25] ->	[arg > 0 ifTrue:
  					[result := objectMemory integerObjectOf: objectMemory growHeadroom.
  					 objectMemory growHeadroom: arg.
  					 self initPrimCall]].
  		[26] ->	[arg >= 0 ifTrue: "0 turns off the heartbeat"
  					[result := objectMemory integerObjectOf: self ioHeartbeatMilliseconds.
  					 self ioSetHeartbeatMilliseconds: arg.
  					 self initPrimCall]].
  		[34] ->	[(objectMemory hasSpurMemoryManagerAPI "was statAllocationCount; now statAllocatedBytes"
  				  and: [arg >= 0]) ifTrue:
  					[result := objectMemory positive64BitIntegerFor: objectMemory currentAllocatedBytes.
  					 objectMemory setCurrentAllocatedBytesTo: arg.
  					 self initPrimCall]].
  		[43] ->	[(arg between: 0 and: 65535) ifTrue:
  					[result := objectMemory integerObjectOf: desiredNumStackPages.
  					 desiredNumStackPages := arg.
  					 self initPrimCall]].
  		[45] ->	[arg >= 0 ifTrue:
  					[result := objectMemory integerObjectOf: desiredEdenBytes.
  					 desiredEdenBytes := arg.
  					 self initPrimCall]].
  		[47] ->	[(self isCog
  				  and: [arg between: 0 and: self maxCogCodeSize]) ifTrue:
  					[result := objectMemory integerObjectOf: self getDesiredCogCodeSize.
  					 self setDesiredCogCodeSize: arg.
  					 self initPrimCall]].
  		[48] ->	[arg >= 0 ifTrue:
  					[result := objectMemory integerObjectOf: self getCogVMFlags.
  					 self initPrimCall. "i.e. setCogVMFlags: can fail"
  					 self setCogVMFlags: arg]].
  		[49] ->	[(arg between: 0 and: 65535) ifTrue:
  					[result := objectMemory integerObjectOf: self ioGetMaxExtSemTableSize.
  					 self initPrimCall. "i.e. ioSetMaxExtSemTableSize: is allowed to fail"
  					 self setMaxExtSemSizeTo: arg]].
  		[55] ->	[objectMemory hasSpurMemoryManagerAPI ifTrue:
  					[result := objectMemory floatObjectOf: objectMemory getHeapGrowthToSizeGCRatio.
  					 primFailCode := objectMemory setHeapGrowthToSizeGCRatio: (self noInlineLoadFloatOrIntFrom: argOop)]].
  		[67] ->	[(arg >= 0
  				  and: [objectMemory hasSpurMemoryManagerAPI]) ifTrue:
  					[result := objectMemory integerObjectOf: objectMemory maxOldSpaceSize.
  					 primFailCode := objectMemory setMaxOldSpaceSize: arg]].
  		[68] ->	[result := objectMemory floatObjectOf: stackPages statAverageLivePagesWhenMapping.
  				 self initPrimCall. "i.e. statAverageLivePagesWhenMapping: is allowed to fail"
  				 stackPages statAverageLivePagesWhenMapping: (self noInlineLoadFloatOrIntFrom: argOop)].
  		[69] ->	[arg >= 0 ifTrue:
  					[result := objectMemory integerObjectOf: stackPages statMaxPageCountWhenMapping.
  					 stackPages statMaxPageCountWhenMapping: arg.
  					 self initPrimCall]].
  		[74] ->	[(arg >= 0
  				  and: [objectMemory hasSpurMemoryManagerAPI]) ifTrue:
  					[result := objectMemory integerObjectOf: objectMemory statMaxAllocSegmentTime + 500 // 1000.
  					 stackPages statMaxAllocSegmentTime: arg. "usually 0"
  					 self initPrimCall]].
+ 		[75] ->	[| mustFlush |
+ 				 result := objectMemory booleanObjectOf: self primitiveDoMixedArithmetic.
+ 				 self initPrimCall.
+ 				 mustFlush := primitiveDoMixedArithmetic ~= arg.
+ 				 primitiveDoMixedArithmetic := arg.
+ 				 mustFlush ifTrue:
+ 					[self flushMethodCache.
+ 					 self flushMethodsWithMachineCodePrimitivesAndContinueAnswering: result
+ 					 "NOT REACHED (in CoInterpreter)"]] }
- 		[75] ->	[result := objectMemory booleanObjectOf: self primitiveDoMixedArithmetic.
- 				self setPrimitiveDoMixedArithmetic: arg.
- 				self initPrimCall] }
  		otherwise: [].
  
  	self successful
  		ifTrue: [self methodReturnValue: result]  "return old value"
  		ifFalse: [self primitiveFailFor: PrimErrInappropriate] "attempting to write a read-only or non-existent parameter"!



More information about the Vm-dev mailing list