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

commits at source.squeak.org commits at source.squeak.org
Sun Aug 1 03:25:16 UTC 2021


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

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

Name: VMMaker.oscog-eem.3007
Author: eem
Time: 31 July 2021, 8:25:08.230439 pm
UUID: f4cf3c82-08f5-4cbb-b32a-14e7d8d60a1b
Ancestors: VMMaker.oscog-eem.3006

Spur: Fix a bad bug with computing accessor depths. Exported primitives in the StackInterpreter and suclasses had their accessor depths computed after inlining, which is too late.  Compute and cache accessor depths before inlining.  Fix a bad regression in primitiveAccessorDepthForExternalPrimitiveMethod:.  Now that this needs a shift to eliminate the primitive flags, it must use a signed shift.

Add VM parameter 76 to answer the minimumUnusedHeadroom on a stack page.  This is useful in checking that a FastCPrimitiveFlag primitive has not consumed too much stack.

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

Item was changed:
  Object subclass: #CCodeGenerator
+ 	instanceVariableNames: 'vmClass structClasses translationDict asArgumentTranslationDict inlineList constants variables variableDeclarations scopeStack methods macros apiMethods apiVariables kernelReturnTypes currentMethod headerFiles globalVariableUsage useSymbolicConstants generateDeadCode requiredSelectors previousCommentMarksInlining previousCommenter logger suppressAsmLabels asmLabelCounts pools selectorTranslations staticallyResolvedPolymorphicReceivers optionsDictionary breakSrcInlineSelectors breakDestInlineSelectors breakOnInline vmMaker accessorDepthCache beganInlining'
- 	instanceVariableNames: 'vmClass structClasses translationDict asArgumentTranslationDict inlineList constants variables variableDeclarations scopeStack methods macros apiMethods apiVariables kernelReturnTypes currentMethod headerFiles globalVariableUsage useSymbolicConstants generateDeadCode requiredSelectors previousCommentMarksInlining previousCommenter logger suppressAsmLabels asmLabelCounts pools selectorTranslations staticallyResolvedPolymorphicReceivers optionsDictionary breakSrcInlineSelectors breakDestInlineSelectors breakOnInline vmMaker'
  	classVariableNames: 'NoRegParmsInAssertVMs'
  	poolDictionaries: 'VMBasicConstants'
  	category: 'VMMaker-Translation to C'!
  
  !CCodeGenerator commentStamp: 'tpr 5/2/2003 14:30' prior: 0!
  This class oversees the translation of a subset of Smalltalk to C, allowing the comforts of Smalltalk during development and the efficiency and portability of C for the resulting interpreter.  
  See VMMaker for more useful info!

Item was changed:
  ----- Method: CCodeGenerator>>accessorDepthForMethod: (in category 'spur primitive compilation') -----
  accessorDepthForMethod: method
  	"Compute the depth the method traverses object structure, assuming it is a primitive.
  	 This is in support of Spur's lazy become.  A primitive may fail because it may encounter
  	 a forwarder.  The primitive failure code needs to know to what depth it must follow
  	  arguments to follow forwarders and, if any are found and followed, retry the primitive.
  	 This method determines that depth. It starts by collecting references to the stack and
  	 then follows these through assignments to variables and use of accessor methods
  	 such as fetchPointer:ofObject:. For example
  		| obj field  |
  		obj := self stackTop.
  		field := objectMemory fetchPointer: 1 ofObject: obj.
  		self storePointer: 1 ofObject: field withValue: (self stackValue: 1)
+ 	has depth 2, since field is accessed, and field is an element of obj.
- 	has depth 2, since field is accessed, and field is an element of obj."
  
+ 	The information is cached since it needs to be computed *before* inlining"
+ 	^accessorDepthCache
+ 		at: method smalltalkSelector
+ 		ifAbsentPut:
+ 			[beganInlining
+ 				ifTrue:
+ 					[((vmClass primitiveTable includes: method smalltalkSelector)
+ 					 or: [method export])
+ 						ifTrue: [-1]
+ 						ifFalse: [self error: 'it is too late to compute accessor depths!!']]
+ 				ifFalse:
+ 					 [((method definingClass includesSelector: method smalltalkSelector) ifTrue:
+ 							[(method definingClass >> method selector) pragmaAt: #accessorDepth:])
+ 						ifNil:
+ 							[((self
+ 									accessorChainsForMethod: method
+ 									interpreterClass: (vmClass ifNil: [StackInterpreter]))
+ 								inject: 0
+ 								into: [:length :chain| length max: (self accessorDepthForChain: chain)]) - 1]
+ 						ifNotNil: [:pragma| pragma arguments first]]]!
- 	^((method definingClass includesSelector: method selector) ifTrue:
- 			[(method definingClass >> method selector) pragmaAt: #accessorDepth:])
- 		ifNil:
- 			[((self
- 					accessorChainsForMethod: method
- 					interpreterClass: (vmClass ifNil: [StackInterpreter]))
- 				inject: 0
- 				into: [:length :chain| length max: (self accessorDepthForChain: chain)]) - 1]
- 		ifNotNil: [:pragma| pragma arguments first]!

Item was changed:
  ----- Method: CCodeGenerator>>doBasicInlining: (in category 'inlining') -----
  doBasicInlining: inlineFlagOrSymbol
  	"Inline the bodies of all methods that are suitable for inlining.
  	This method does only the basic inlining suitable for both the core VM and plugins - no bytecode inlining etc"
  
  	| pass progress |
+ 	beganInlining := true.
  	self collectInlineList: inlineFlagOrSymbol.
  	pass := 0.
  	progress := true.
  	[progress] whileTrue: [
  		"repeatedly attempt to inline methods until no further progress is made"
  		progress := false.
  		('Inlining pass ', (pass := pass + 1) printString, '...')
  			displayProgressAt: Sensor cursorPoint
  			from: 0 to: methods size
  			during: [:bar |
  				(self sortMethods: methods) withIndexDo: [:m :i |
  					bar value: i.
  					currentMethod := m.
  					(m tryToInlineMethodsIn: self)
  						ifTrue: [progress := true]]]].
  
  !

Item was changed:
  ----- Method: CCodeGenerator>>doInlining: (in category 'inlining') -----
  doInlining: inlineFlagOrSymbol
  	"Inline the bodies of all methods that are suitable for inlining."
  	"Modified slightly for the core VM translator, since the first level of inlining for the interpret loop must be performed in order that the instruction implementations can easily discover their addresses. Remember to inline the bytecode routines as well"
  
  	| removed |
+ 	beganInlining := true.
  	inlineFlagOrSymbol isSymbol ifTrue:
  		[self inlineDispatchesInMethodNamed: #interpret localizingVars: #().	
  		 self doBasicInlining: inlineFlagOrSymbol.
  		 self pruneUnreachableMethods.
  		 ^self].
  
  	inlineFlagOrSymbol ifFalse:
  		[self inlineDispatchesInMethodNamed: #interpret localizingVars: #().	
  		self pruneUnreachableMethods.
  		^self].
  
  	self doBasicInlining: inlineFlagOrSymbol.
  
  	vmClass ifNil: [^self].
  
  	'Inlining bytecodes'
  		displayProgressAt: Sensor cursorPoint
  		from: 1 to: 2
  		during: [:bar |
  			self inlineDispatchesInMethodNamed: #interpret
  				localizingVars: vmClass namesOfVariablesToLocalize.
  			bar value: 1.
  			removed := self removeMethodsReferingToGlobals: vmClass namesOfVariablesToLocalize
  							except: #interpret.
  			bar value: 2].
  
  	"only prune when generating the interpreter itself"
  	self pruneUnreachableMethods.
  
  	self reportShouldNotBeRemoved: removed  varList: vmClass namesOfVariablesToLocalize!

Item was changed:
  ----- Method: CCodeGenerator>>initialize (in category 'initialize-release') -----
  initialize
  	translationDict := Dictionary new.
  	inlineList := Array new.
  	constants := Dictionary new: 100.
  	variables := Set new: 100.
  	variableDeclarations := Dictionary new: 100.
  	methods := Dictionary new: 500.
  	kernelReturnTypes := self computeKernelReturnTypes.
  	macros := Dictionary new.
  	self initializeCTranslationDictionary.
  	headerFiles := OrderedCollection new.
  	globalVariableUsage := Dictionary new.
  	useSymbolicConstants := true.
  	generateDeadCode := true.
  	scopeStack := OrderedCollection new.
  	self getLogger.
  	pools := IdentitySet new.
  	selectorTranslations := IdentityDictionary new.
+ 	accessorDepthCache := IdentityDictionary new.
+ 	beganInlining := false.
  	suppressAsmLabels := false.
  	previousCommentMarksInlining := false.
  	previousCommenter := nil.
  	breakSrcInlineSelectors := IdentitySet new.
  	breakDestInlineSelectors := IdentitySet new!

Item was changed:
+ ----- Method: CoInterpreter>>minimumUnusedHeadroom (in category 'stack pages') -----
- ----- Method: CoInterpreter>>minimumUnusedHeadroom (in category 'debug support') -----
  minimumUnusedHeadroom
  	"Traverse all stack pages looking for non-zero bytes in the headroom part of each page.
  	 Answer the minimum size of unused headroom (zero bytes) in the pages.  This is for
  	 checking that there is enough headroom allocated in stack pages."
  	| minUnused page |
+ 	<inline: #never>
- 	<var: #page type: #'StackPage *'>
  	<var: #p type: #'char *'>
  	minUnused := (stackPages stackPageAt: 0) baseAddress - (stackPages stackPageAt: 0) lastAddress.
  	0 to: numStackPages - 1 do:
  		[:i| | p unused |
  		page := stackPages stackPageAt: i.
  		p := page lastAddress.
  		[p := p + objectMemory wordSize.
  		(self longAtPointer: p) = 0
  		 and: [p <= page baseAddress]] whileTrue.
  		unused := p - objectMemory wordSize - page lastAddress.
  		unused < minUnused ifTrue:
  			[minUnused := unused]].
  	^minUnused!

Item was changed:
  ----- Method: StackInterpreter>>primitiveAccessorDepthForExternalPrimitiveMethod: (in category 'primitive support') -----
  primitiveAccessorDepthForExternalPrimitiveMethod: methodObj
  	^(objectMemory integerValueOf:
  		(objectMemory
  			fetchPointer: 2
+ 			ofObject: (self literal: 0 ofMethod: methodObj))) >>> 8!
- 			ofObject: (self literal: 0 ofMethod: methodObj))) bitShift: -8!

Item was added:
+ ----- Method: StackInterpreterPrimitives>>minimumUnusedHeadroom (in category 'system control primitives') -----
+ minimumUnusedHeadroom
+ 	<inline: #always>
+ 	^-1!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveAllVMParameters: (in category 'system control primitives') -----
(excessive size, no diff calculated)

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveGetVMParameter: (in category 'system control primitives') -----
  primitiveGetVMParameter: arg 
  	"See primitiveVMParameter method comment.
  	 N.B. written as a returning case to avoid branch limits in the V3 bytecode set."
  	arg caseOf: {
  			[1]  ->	[^self positiveMachineIntegerFor: objectMemory oldSpaceSize].
  			[2]  ->	[^objectMemory integerObjectOf: objectMemory newSpaceSize].
  			[3]  ->	[^self positiveMachineIntegerFor: objectMemory totalMemorySize].
  			[6]  ->	[^objectMemory integerObjectOf: objectMemory tenuringThreshold].
  			[7]  ->	[^objectMemory integerObjectOf: objectMemory statFullGCs].
  			[8]  ->	[^objectMemory integerObjectOf: objectMemory statFullGCUsecs + 500 // 1000].
  			[9]  ->	[^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI
  														ifTrue: [objectMemory statScavenges]
  														ifFalse: [objectMemory statIncrGCs])].
  			[10] ->	[^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI
  														ifTrue: [objectMemory statScavengeGCUsecs]
  														ifFalse: [objectMemory statIncrGCUsecs]) + 500 // 1000].
  			[11] ->	[^objectMemory integerObjectOf: objectMemory statTenures].
  			[12] ->	[^objectMemory integerObjectOf: eventTraceMask].
  			[13] ->	[^self getVMTickerStartUSecs].
  			[14] ->	[^self getVMTickerCount].
  			[15] ->	[^self getVMTickeeCallCount].
  			[16] ->	[^self positive64BitIntegerFor: statIdleUsecs].
  			[17] ->	[^(SistaVM and: [self isCog])
  						ifTrue: [objectMemory floatObjectOf: self getCogCodeZoneThreshold]
  						ifFalse: [ConstZero]].
  			[18] ->	[^objectMemory hasSpurMemoryManagerAPI
  						ifTrue: [objectMemory integerObjectOf: objectMemory statCompactionUsecs + 500 // 1000]
  						ifFalse: [ConstZero]].
  			[19] ->	[^objectMemory hasSpurMemoryManagerAPI
  						ifTrue: [objectMemory integerObjectOf: objectMemory scavengeThresholdAsExtent]
  						ifFalse: [ConstZero]].
  			[20] ->	[^objectMemory positive64BitIntegerFor: self ioUTCStartMicroseconds].
  			[21] ->	[^objectMemory integerObjectOf: objectMemory rootTableCount].
  			[22] ->	[^objectMemory integerObjectOf: objectMemory statRootTableOverflows].
  			[23] ->	[^objectMemory integerObjectOf: extraVMMemory].
  			[24] ->	[^objectMemory integerObjectOf: objectMemory shrinkThreshold].
  			[25] ->	[^objectMemory integerObjectOf: objectMemory growHeadroom].
  			[26] ->	[^objectMemory integerObjectOf: self ioHeartbeatMilliseconds].
  			[27] ->	[^objectMemory integerObjectOf: objectMemory statMarkCount].
  			[28] ->	[^objectMemory integerObjectOf: objectMemory statSweepCount].
  			[29] ->	[^objectMemory integerObjectOf: objectMemory statMkFwdCount].
  			[30] ->	[^objectMemory integerObjectOf: objectMemory statCompMoveCount].
  			[31] ->	[^objectMemory integerObjectOf: objectMemory statGrowMemory].
  			[32] ->	[^objectMemory integerObjectOf: objectMemory statShrinkMemory].
  			[33] ->	[^objectMemory integerObjectOf: objectMemory statRootTableCount].
  			[34] ->	[^objectMemory hasSpurMemoryManagerAPI ifTrue:"was statAllocationCount"
  						[objectMemory positive64BitIntegerFor: objectMemory currentAllocatedBytes]].
  			[35] ->	[^objectMemory integerObjectOf: objectMemory statSurvivorCount].
  			[36] ->	[^objectMemory integerObjectOf: (self microsecondsToMilliseconds: objectMemory statGCEndUsecs)].
  			[37] ->	[^objectMemory integerObjectOf: objectMemory statSpecialMarkCount].
  			[38] ->	[^objectMemory integerObjectOf: objectMemory statIGCDeltaUsecs + 500 // 1000].
  			[39] ->	[^objectMemory integerObjectOf: statPendingFinalizationSignals].
  			[40] ->	[^objectMemory integerObjectOf: objectMemory wordSize].
  			[41] ->	[^objectMemory integerObjectOf: self imageFormatVersion].
  			[42] ->	[^objectMemory integerObjectOf: numStackPages].
  			[43] ->	[^objectMemory integerObjectOf: desiredNumStackPages].
  			[44] ->	[^objectMemory integerObjectOf: objectMemory edenBytes].
  			[45] ->	[^objectMemory integerObjectOf: desiredEdenBytes].
  			[46] ->	[^self getCogCodeSize].
  			[47] ->	[^self getDesiredCogCodeSize].
  			[48] ->	[^self getImageHeaderFlagsParameter].
  			[49] ->	[^objectMemory integerObjectOf: self ioGetMaxExtSemTableSize].
  			[52] ->	[^objectMemory integerObjectOf: objectMemory rootTableCapacity].
  			[53] ->	[^objectMemory hasSpurMemoryManagerAPI ifTrue:
  						[objectMemory integerObjectOf: objectMemory numSegments]].
  			[54] ->	[^objectMemory hasSpurMemoryManagerAPI ifTrue:
  						[objectMemory integerObjectOf: objectMemory freeSize]].
  			[55] ->	[^objectMemory hasSpurMemoryManagerAPI ifTrue:
  						[objectMemory floatObjectOf: objectMemory getHeapGrowthToSizeGCRatio]].
  			[56] ->	[^self positive64BitIntegerFor: statProcessSwitch].
  			[57] ->	[^self positive64BitIntegerFor: statIOProcessEvents].
  			[58] ->	[^self positive64BitIntegerFor: statForceInterruptCheck].
  			[59] ->	[^self positive64BitIntegerFor: statCheckForEvents].
  			[60] ->	[^self positive64BitIntegerFor: statStackOverflow].
  			[61] ->	[^self positive64BitIntegerFor: statStackPageDivorce].
  			[62] ->	[^self getCodeCompactionCount].
  			[63] ->	[^self getCodeCompactionMSecs].
  			[64] ->	[^self getCogMethodCount].
  			[65] ->	[^self getCogVMFeatureFlags].
  			[66] ->	[^objectMemory integerObjectOf: self stackPageByteSize].
  			[67] ->	[^objectMemory hasSpurMemoryManagerAPI ifTrue:
  						[self positiveMachineIntegerFor: objectMemory maxOldSpaceSize]].
  			[68] ->	[^objectMemory floatObjectOf: stackPages statAverageLivePagesWhenMapping].
  			[69] ->	[^objectMemory integerObjectOf: stackPages statMaxPageCountWhenMapping].
  			[70] ->	[^objectMemory integerObjectOf: self vmProxyMajorVersion].
  			[71] ->	[^objectMemory integerObjectOf: self vmProxyMinorVersion].
  			[72] ->	[^objectMemory integerObjectOf: objectMemory statMarkUsecs + 500 // 1000].
  			[73] ->	[^objectMemory integerObjectOf: objectMemory statSweepUsecs + 500 // 1000].
  			[74] ->	[^objectMemory hasSpurMemoryManagerAPI ifTrue:
  						[objectMemory integerObjectOf: objectMemory statMaxAllocSegmentTime + 500 // 1000]].
+ 			[75] ->	[^objectMemory booleanObjectOf: self primitiveDoMixedArithmetic].
+ 			[76] ->	[^objectMemory integerObjectOf: self minimumUnusedHeadroom] }
- 			[75] ->	[^objectMemory booleanObjectOf: self primitiveDoMixedArithmetic] }
  		otherwise: [^nil]!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveVMParameter (in category 'system control primitives') -----
  primitiveVMParameter
  	"Behaviour depends on argument count:
  		0 args:	return an Array of VM parameter values;
  		1 arg:	return the indicated VM parameter;
  		2 args:	set the VM indicated parameter.
  	VM parameters are numbered as follows:
  		1	end (v3)/size(Spur) of old-space (0-based, read-only)
  		2	end (v3)/size(Spur) of young/new-space (read-only)
  		3	end (v3)/size(Spur) of heap (read-only)
  		4	nil (was allocationCount (read-only))
  		5	nil (was allocations between GCs (read-write)
  		6	survivor count tenuring threshold (read-write)
  		7	full GCs since startup (read-only)
  		8	total milliseconds in full GCs since startup (read-only)
  		9	incremental GCs (SqueakV3) or scavenges (Spur) since startup (read-only)
  		10	total milliseconds in incremental GCs (SqueakV3) or scavenges (Spur) since startup (read-only)
  		11	tenures of surving objects since startup or reset (read-write)
  		12-20 were specific to ikp's JITTER VM, now 12 16 open for use
  		13	if started, the start time in utc microseconds of the high-priority ticker
  		14	if started, the number of checkHighPriorityTickees calls
  		15	if started, the number of tickee calls from checkHighPriorityTickees
  		16	total microseconds at idle since start-up (if non-zero)
  		17	fraction of the code zone to use (Sista only; used to control code zone use to preserve sendAndBranchData on counter tripped callback)
  		18	total milliseconds in compaction phase of full GC since start-up (Spur only)
  		19	scavenge threshold, the effective size of eden.  When eden fills to the threshold a scavenge is scheduled. Newer Spur VMs only.
  		20	utc microseconds at VM start-up (actually at time initialization, which precedes image load).
  		21	root/remembered table size (occupancy) (read-only)
  		22	root table overflows since startup (read-only)
  		23	bytes of extra memory to reserve for VM buffers, plugins, etc (stored in image file header).
  		24	memory threshold above which shrinking object memory (rw)
  		25	memory headroom when growing object memory (rw)
  		26	interruptChecksEveryNms - force an ioProcessEvents every N milliseconds (rw)
  		27	number of times mark loop iterated for current IGC/FGC (read-only) includes ALL marking
  		28	number of times sweep loop iterated for current IGC/FGC (read-only)
  		29	number of times make forward loop iterated for current IGC/FGC (read-only)
  		30	number of times compact move loop iterated for current IGC/FGC (read-only)
  		31	number of grow memory requests (read-only)
  		32	number of shrink memory requests (read-only)
  		33	number of root table entries used for current IGC/FGC (read-only)
  		34	Spur: bytes allocated in total since start-up or reset (read-write) (Used to be number of allocations done before current IGC/FGC (read-only))
  		35	number of survivor objects after current IGC/FGC (read-only)
  		36	millisecond clock when current IGC/FGC completed (read-only)
  		37	number of marked objects for Roots of the world, not including Root Table entries for current IGC/FGC (read-only)
  		38	milliseconds taken by current IGC (read-only)
  		39	Number of finalization signals for Weak Objects pending when current IGC/FGC completed (read-only)
  		40	BytesPerOop for this image
  		41	imageFormatVersion for the VM
  		42	number of stack pages in use
  		43	desired number of stack pages (stored in image file header, max 65535)
  		44	size of eden, in bytes
  		45	desired size of eden, in bytes (stored in image file header)
  		46	machine code zone size, in bytes (Cog only; otherwise nil)
  		47	desired machine code zone size (stored in image file header; Cog only; otherwise nil)
  		48	various header flags.  See getImageHeaderFlags.
  		49	max size the image promises to grow the external semaphore table to (0 sets to default, which is 256 as of writing)
  		50-51 nil; reserved for VM parameters that persist in the image (such as eden above)
  		52	root/remembered table capacity
  		53	number of segments (Spur only; otherwise nil)
  		54	total size of free old space (Spur only, otherwise nil)
  		55	ratio of growth and image size at or above which a GC will be performed post scavenge
  		56	number of process switches since startup (read-only)
  		57	number of ioProcessEvents calls since startup (read-only)
  		58	number of ForceInterruptCheck calls since startup (read-only)
  		59	number of check event calls since startup (read-only)
  		60	number of stack page overflows since startup (read-only)
  		61	number of stack page divorces since startup (read-only)
  		62	compiled code compactions since startup (read-only; Cog only; otherwise nil)
  		63	total milliseconds in compiled code compactions since startup (read-only; Cog only; otherwise nil)
  		64	the number of methods that currently have jitted machine-code
  		65	various VM feature flags; see getCogVMFeatureFlags
  		66	the byte size of a stack page
  		67	the max allowed size of old space (Spur only; nil otherwise; 0 implies no limit except that of the underlying platform)
  		68	the average number of live stack pages when scanned by GC (at scavenge/gc/become et al) (read-write)
  		69	the maximum number of live stack pages when scanned by GC (at scavenge/gc/become et al) (read-write)
  		70	the vmProxyMajorVersion (the interpreterProxy VM_MAJOR_VERSION)
  		71	the vmProxyMinorVersion (the interpreterProxy VM_MINOR_VERSION)
  		72 total milliseconds in full GCs Mark phase since startup (read-only)
  		73 total milliseconds in full GCs Sweep phase since startup (read-only, can be 0 depending on compactors)
  		74 maximum pause time due to segment allocation
  		75 whether the arithmetic primitives perform conversion in case of mixed SmallInteger/Float (true) or fail (false)
+ 		76 the minimum unused headroom in all stack pages; Cog VMs only
  		
  	Note: Thanks to Ian Piumarta for this primitive."
  
  	| paramsArraySize index |
+ 	paramsArraySize := 76.
- 	paramsArraySize := 75.
  	argumentCount = 0 ifTrue: [^self primitiveAllVMParameters: paramsArraySize].
  	argumentCount > 2 ifTrue: [^self primitiveFailFor: PrimErrBadNumArgs].
  	
  	"index read & checks"
  	index := self stackValue: (argumentCount = 1 ifTrue: [0] ifFalse: [1]).
  	(objectMemory isIntegerObject: index) ifFalse: [^self primitiveFailFor: PrimErrBadArgument].
  	index := objectMemory integerValueOf: index.
  	(index < 1 or: [index > paramsArraySize]) ifTrue: [^self primitiveFailFor: PrimErrBadIndex].
  	
  	argumentCount = 1 ifTrue:	 "read VM parameter; written this way to avoid branch limits in V3 bytecode set"
  		[| result |
  		 result := self primitiveGetVMParameter: index.
  		 ^self methodReturnValue: (result ifNil: [objectMemory nilObject])].
  
  	"write a VM parameter"
  	self primitiveSetVMParameter: index arg: self stackTop!

Item was changed:
  ----- Method: TMethod>>prepareMethodIn: (in category 'transformations') -----
  prepareMethodIn: aCodeGen
  	"Record sends of builtin operators, map sends of the special selector dispatchOn:in:
  	 with case statement nodes, and map sends of caseOf:[otherwise:] to switch statements.
  	 Declare limit variables for to:[by:]do: loops with limits that potentially have side-effects.
  	 As a hack also update the types of variables introduced to implement cascades correctly.
  	 This has to be done at the same time as this is done, so why not piggy back here?"
  	extraVariableNumber ifNotNil:
  		[declarations keysAndValuesDo:
  			[:varName :decl|
  			decl isBlock ifTrue:
  				[self assert: ((varName beginsWith: 'cascade') and: [varName last isDigit]).
  				 locals add: varName.
  				 self declarationAt: varName
  					put: (decl value: self value: aCodeGen), ' ', varName]]].
  	aCodeGen
  		pushScope: declarations
  		while:"N.B.  nodesWithParentsDo: is bottom-up, hence replacement is destructive and conserved."
  			[parseTree nodesWithParentsDo:
  				[:node :parent|
  				 node isSend ifTrue:
  					[aCodeGen ifStaticallyResolvedPolymorphicReceiverThenUpdateSelectorIn: node.
  					 (aCodeGen isBuiltinSelector: node selector)
  						ifTrue:
  							[node isBuiltinOperator: true.
  							"If a to:by:do:'s limit has side-effects, declare the limit variable, otherwise delete it from the args"
  							 node selector = #to:by:do: ifTrue:
  								[self ensureToByDoLoopLimitIsSafeAndEfficient: node in: aCodeGen]]
  						ifFalse:
+ 							[(StackInterpreter isStackAccessor: node selector)
+ 								ifTrue: "compute and cache the accessor depth early, before inlining destroys the accessor chains"
+ 									[self export ifTrue:
+ 										[aCodeGen accessorDepthForMethod: self]]
+ 								ifFalse:
+ 									[(CaseStatements includes: node selector) ifTrue:
+ 										[parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildCaseStmt: node in: aCodeGen})].
+ 									 (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue:
+ 										[parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildSwitchStmt: node parent: parent })].
+ 									 (#(printf: f:printf:) includes: node selector) ifTrue:
+ 										[self transformPrintf: node]]]]]]!
- 							[(CaseStatements includes: node selector) ifTrue:
- 								[parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildCaseStmt: node in: aCodeGen})].
- 							 (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue:
- 								[parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildSwitchStmt: node parent: parent })].
- 							 (#(printf: f:printf:) includes: node selector) ifTrue:
- 								[self transformPrintf: node]]]]]!



More information about the Vm-dev mailing list