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

commits at source.squeak.org commits at source.squeak.org
Fri Apr 4 23:04:06 UTC 2014


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

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

Name: VMMaker.oscog-eem.666
Author: eem
Time: 4 April 2014, 4:00:55.973 pm
UUID: 647ff48c-1974-41d1-9b8f-678688bc79d8
Ancestors: VMMaker.oscog-eem.665

Sista:
Fix several bugs in the primitiveSistaMethodPICAndCounterData
primitive.  Fix consistency between monomorphic and polymorphic
send tuples, always answering pc, class, method/selector.
Fix collecting data from PICs with MNU cases.  Remove a stray halt.
Make sure primitive fail points return. not continue on.

Eliminate dead conditional branch elimination so that the send and
branch data collection is not confused by branches for which no
counting code was produced.

Cogit: since the annotation arg is no longer used, refactor
targetMethodAndSendTableFor:annotation:into: to
targetMethodAndSendTableFor:into:.

Simulator:
Add missing asVoidPointer on methods.
Add instantiateClass:indexableSize: for the facade.
Provide a cog: entry point for in-image compiling a method.

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

Item was changed:
  ----- Method: CoInterpreterPrimitives>>primitiveResetCountersInMethod (in category 'method introspection primitives') -----
  primitiveResetCountersInMethod
  	<export: true>
  	<option: #SistaStackToRegisterMappingCogit>
  	| methodReceiver |
  	argumentCount ~= 0 ifTrue:
+ 		[^self primitiveFailFor: PrimErrBadNumArgs].
- 		[self primitiveFailFor: PrimErrBadNumArgs].
  	methodReceiver := self stackTop.
  	(self methodHasCogMethod: methodReceiver) ifTrue:
  		[cogit resetCountersIn: (self cogMethodOf: methodReceiver)]!

Item was changed:
  ----- Method: CoInterpreterPrimitives>>primitiveSistaMethodPICAndCounterData (in category 'method introspection primitives') -----
  primitiveSistaMethodPICAndCounterData
  	<export: true>
  	<option: #SistaStackToRegisterMappingCogit>
  	| methodReceiver data |
  	argumentCount ~= 0 ifTrue:
+ 		[^self primitiveFailFor: PrimErrBadNumArgs].
- 		[self primitiveFailFor: PrimErrBadNumArgs].
  	methodReceiver := self stackTop.
  	data := 0.
  	(self methodHasCogMethod: methodReceiver) ifTrue:
  		[data := self picDataFor: (self cogMethodOf: methodReceiver).
  		 data = -1 ifTrue:
+ 			[^self primitiveFailFor: PrimErrNoMemory]].
- 			[self primitiveFailFor: PrimErrNoMemory]].
  	data = 0 ifTrue:
  		[data := objectMemory instantiateClass: (objectMemory splObj: ClassArray) indexableSize: 0].
  	self pop: 1 thenPush: data!

Item was added:
+ ----- Method: CogMethodSurrogate>>asVoidPointer (in category 'coercing') -----
+ asVoidPointer
+ 	^self!

Item was added:
+ ----- Method: Cogit class>>cog: (in category 'in-image compilation') -----
+ cog: aCompiledMethod
+ 	^self cog: aCompiledMethod options: #()!

Item was added:
+ ----- Method: Cogit class>>cog:options: (in category 'in-image compilation') -----
+ cog: aCompiledMethod options: optionsArray
+ 	^self cog: aCompiledMethod selector: aCompiledMethod selector options: optionsArray!

Item was changed:
  ----- Method: Cogit>>checkIfValidObjectRefAndTarget:pc:cogMethod: (in category 'garbage collection') -----
  checkIfValidObjectRefAndTarget: annotation pc: mcpc cogMethod: cogMethod
  	<var: #mcpc type: #'char *'>
  	| literal entryPoint |
  	annotation = IsObjectReference ifTrue:
  		[literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
  		 (self asserta: (objectRepresentation checkValidObjectReference: literal)) ifFalse:
  			[^1].
  		((objectRepresentation couldBeObject: literal)
  		 and: [objectMemory isReallyYoungObject: literal]) ifTrue:
  			[(self asserta: (self cCoerceSimple: cogMethod to: #'CogMethod *') cmRefersToYoung) ifFalse:
  				[^2]]].
  	(self isSendAnnotation: annotation) ifTrue:
  		[(self asserta: (self cCoerceSimple: cogMethod to: #'CogMethod *') cmType = CMMethod) ifFalse:
  			[^3].
  		 self offsetCacheTagAndCouldBeObjectAt: mcpc annotation: annotation into:
  			[:offset :cacheTag :tagCouldBeObject|
  			tagCouldBeObject
  				ifTrue:
  					[(objectRepresentation couldBeObject: cacheTag)
  						ifTrue:
  							[(self asserta: (objectRepresentation checkValidObjectReference: cacheTag)) ifFalse:
  								[^4]]
  						ifFalse:
  							[(self asserta: (objectRepresentation checkValidInlineCacheTag: cacheTag)) ifFalse:
  								[^5]].
  					((objectRepresentation couldBeObject: cacheTag)
  					 and: [objectMemory isReallyYoungObject: cacheTag]) ifTrue:
  						[(self asserta: (self cCoerceSimple: cogMethod to: #'CogMethod *') cmRefersToYoung) ifFalse:
  							[^6]]]
  				ifFalse:
  					[(self asserta: (objectRepresentation checkValidInlineCacheTag: cacheTag)) ifFalse:
  						[^7]]].
  		entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		entryPoint > methodZoneBase ifTrue:
  			["It's a linked send; find which kind."
+ 			 self targetMethodAndSendTableFor: entryPoint into:
- 			 self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  					[:targetMethod :sendTable|
  					 (self asserta: (targetMethod cmType = CMMethod
  								   or: [targetMethod cmType = CMClosedPIC
  								   or: [targetMethod cmType = CMOpenPIC]])) ifFalse:
  						[^8]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>incrementUsageOfTargetIfLinkedSend:mcpc:ignored: (in category 'compaction') -----
  incrementUsageOfTargetIfLinkedSend: annotation mcpc: mcpc ignored: superfluity
  	<var: #mcpc type: #'char *'>
  	| entryPoint |
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint > methodZoneBase ifTrue: "It's a linked send."
+ 			[self targetMethodAndSendTableFor: entryPoint into:
- 			[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  				[:targetMethod :sendTable|
  				 targetMethod cmUsageCount < (CMMaxUsageCount // 2) ifTrue:
  					[targetMethod cmUsageCount: targetMethod cmUsageCount + 1]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>markLiteralsAndUnlinkIfUnmarkedSend:pc:method: (in category 'garbage collection') -----
  markLiteralsAndUnlinkIfUnmarkedSend: annotation pc: mcpc method: cogMethod
  	"Mark and trace literals.  Unlink sends that have unmarked cache tags or targets."
  	<var: #mcpc type: #'char *'>
  	| literal |
  	annotation = IsObjectReference ifTrue:
  		[literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
  		 objectRepresentation markAndTraceLiteral: literal].
  	(self isSendAnnotation: annotation) ifTrue:
  		[self offsetCacheTagAndCouldBeObjectAt: mcpc annotation: annotation into:
  			[:entryPoint :cacheTag :tagCouldBeObj | | cacheTagMarked |
  			 cacheTagMarked := tagCouldBeObj and: [objectRepresentation cacheTagIsMarked: cacheTag].
  			 entryPoint > methodZoneBase
  				ifTrue: "It's a linked send."
+ 					[self targetMethodAndSendTableFor: entryPoint into:
- 					[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  						[:targetMethod :sendTable| | unlinkedRoutine |
  						 (cacheTagMarked not
  						  or: [self markAndTraceOrFreeCogMethod: targetMethod firstVisit: targetMethod asUnsignedInteger > mcpc asUnsignedInteger]) ifTrue:
  							["Either the cacheTag is unmarked (e.g. new class) or the target
  							  has been freed (because it is unmarked), so unlink the send."
  							 unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
  							 backEnd
  								rewriteInlineCacheAt: mcpc asInteger
  								tag: targetMethod selector
  								target: unlinkedRoutine.
  							 codeModified := true.
  							 objectRepresentation markAndTraceLiteral: targetMethod selector]]]
  				ifFalse:
  					[objectRepresentation markAndTraceLiteral: cacheTag.  "cacheTag is selector"
  					 self cppIf: NewspeakVM ifTrue:
  						[entryPoint = ceImplicitReceiverTrampoline ifTrue:
  							[| classpc mixinpc class mixin |
  							 objectRepresentation markAndTraceLiteral: cacheTag.  "cacheTag is selector"
  							 classpc := mcpc asInteger + backEnd jumpShortByteSize.
  							 mixinpc := mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop.
  							 class := backEnd unalignedLongAt: classpc.
  							 class ~= 0
  								ifTrue:
  									[self assert: (objectMemory addressCouldBeObj: class).
  									 (objectRepresentation cacheTagIsMarked: class)
  										ifTrue:
  											[(mixin := backEnd unalignedLongAt: mixinpc) ~= 0 ifTrue:
  												[objectRepresentation markAndTraceLiteral: mixin]]
  										ifFalse:
  											[backEnd
  												unalignedLongAt: classpc put: 0;
  												unalignedLongAt: mixinpc put: 0.
  											 codeModified := true]]
  								ifFalse:
  									[self assert: (backEnd unalignedLongAt: mixinpc) = 0]]]]]].
  	^0 "keep scanning"!

Item was removed:
- ----- Method: Cogit>>targetMethodAndSendTableFor:annotation:into: (in category 'in-line cacheing') -----
- targetMethodAndSendTableFor: entryPoint annotation: annotation into: binaryBlock
- 	"Evaluate binaryBlock with the targetMethod and relevant send table for a linked-send
- 	 to entryPoint.  Do so based on the alignment of entryPoint.  N.B.  For Newspeak sends
- 	 we don't need to distinguish between ceImplicitReceiver and the other sends since
- 	 ceImplicitReceiver will never appear to be linked, so only three cases here."
- 	<inline: true>
- 	| targetMethod sendTable |
- 	<var: #targetMethod type: #'CogMethod *'>
- 	<var: #sendTable type: #'sqInt *'>
- 	self cppIf: NewspeakVM
- 		ifTrue:
- 			[self assert: annotation = IsSendCall.
- 			 (entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
- 				ifTrue:
- 					[targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
- 					 sendTable := sendTrampolines]
- 				ifFalse:
- 					[(entryPoint bitAnd: entryPointMask) = dynSuperEntryAlignment
- 						ifTrue:
- 							[targetMethod := self cCoerceSimple: entryPoint - cmDynSuperEntryOffset to: #'CogMethod *'.
- 							 sendTable := dynamicSuperSendTrampolines]
- 						ifFalse:
- 							[targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
- 							 sendTable := superSendTrampolines]]]
- 		ifFalse:
- 			[(entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
- 				ifTrue:
- 					[targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
- 					 sendTable := sendTrampolines]
- 				ifFalse:
- 					[targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
- 					 sendTable := superSendTrampolines]].
- 	binaryBlock
- 		value: targetMethod
- 		value: sendTable!

Item was added:
+ ----- Method: Cogit>>targetMethodAndSendTableFor:into: (in category 'in-line cacheing') -----
+ targetMethodAndSendTableFor: entryPoint into: binaryBlock
+ 	"Evaluate binaryBlock with the targetMethod and relevant send table for a linked-send
+ 	 to entryPoint.  Do so based on the alignment of entryPoint.  N.B.  For Newspeak sends
+ 	 we don't need to distinguish between ceImplicitReceiver and the other sends since
+ 	 ceImplicitReceiver will never appear to be linked, so only three cases here."
+ 	<inline: true>
+ 	| targetMethod sendTable |
+ 	<var: #targetMethod type: #'CogMethod *'>
+ 	<var: #sendTable type: #'sqInt *'>
+ 	self cppIf: NewspeakVM
+ 		ifTrue:
+ 			[(entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
+ 				ifTrue:
+ 					[targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
+ 					 sendTable := sendTrampolines]
+ 				ifFalse:
+ 					[(entryPoint bitAnd: entryPointMask) = dynSuperEntryAlignment
+ 						ifTrue:
+ 							[targetMethod := self cCoerceSimple: entryPoint - cmDynSuperEntryOffset to: #'CogMethod *'.
+ 							 sendTable := dynamicSuperSendTrampolines]
+ 						ifFalse:
+ 							[targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
+ 							 sendTable := superSendTrampolines]]]
+ 		ifFalse:
+ 			[(entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
+ 				ifTrue:
+ 					[targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
+ 					 sendTable := sendTrampolines]
+ 				ifFalse:
+ 					[targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
+ 					 sendTable := superSendTrampolines]].
+ 	binaryBlock
+ 		value: targetMethod
+ 		value: sendTable!

Item was changed:
  ----- Method: Cogit>>unlinkIfFreeOrLinkedSend:pc:of: (in category 'in-line cacheing') -----
  unlinkIfFreeOrLinkedSend: annotation pc: mcpc of: theSelector
  	<var: #mcpc type: #'char *'>
  	| entryPoint |
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint > methodZoneBase
  			ifTrue: "It's a linked send."
+ 				[self targetMethodAndSendTableFor: entryPoint into:
- 				[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  					[:targetMethod :sendTable| | unlinkedRoutine |
  					 (targetMethod cmType = CMFree
  					  or: [targetMethod selector = theSelector]) ifTrue:
  						[unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
  						 backEnd
  							rewriteInlineCacheAt: mcpc asInteger
  							tag: targetMethod selector
  							target: unlinkedRoutine.
  						 codeModified := true]]]
  			ifFalse:
  				[self cppIf: NewspeakVM ifTrue:
  					[(entryPoint = ceImplicitReceiverTrampoline
  					 and: [(backEnd inlineCacheTagAt: mcpc asInteger) = theSelector]) ifTrue:
  					 	[backEnd
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize put: 0;
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop put: 0]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>unlinkIfLinkedSend:pc:ignored: (in category 'in-line cacheing') -----
  unlinkIfLinkedSend: annotation pc: mcpc ignored: superfluity
  	<var: #mcpc type: #'char *'>
  	| entryPoint |
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint > methodZoneBase
  			ifTrue: "It's a linked send."
+ 				[self targetMethodAndSendTableFor: entryPoint into:
- 				[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  					[:targetMethod :sendTable| | unlinkedRoutine |
  					 unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
  					 backEnd
  						rewriteInlineCacheAt: mcpc asInteger
  						tag: targetMethod selector
  						target: unlinkedRoutine]]
  			ifFalse:
  				[self cppIf: NewspeakVM ifTrue:
  					[entryPoint = ceImplicitReceiverTrampoline ifTrue:
  						[backEnd
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize put: 0;
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop put: 0]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>unlinkIfLinkedSend:pc:of: (in category 'in-line cacheing') -----
  unlinkIfLinkedSend: annotation pc: mcpc of: theSelector
  	<var: #mcpc type: #'char *'>
  	| entryPoint |
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint > methodZoneBase
  			ifTrue: "It's a linked send."
+ 				[self targetMethodAndSendTableFor: entryPoint into:
- 				[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  					[:targetMethod :sendTable| | unlinkedRoutine |
  					 targetMethod selector = theSelector ifTrue:
  						[unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
  						 backEnd
  							rewriteInlineCacheAt: mcpc asInteger
  							tag: targetMethod selector
  							target: unlinkedRoutine.
  						 codeModified := true]]]
  			ifFalse:
  				[self cppIf: NewspeakVM ifTrue:
  					[(entryPoint = ceImplicitReceiverTrampoline
  					  and: [(backEnd inlineCacheTagAt: mcpc asInteger) = theSelector]) ifTrue:
  						[backEnd
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize put: 0;
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop put: 0]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>unlinkIfLinkedSend:pc:to: (in category 'in-line cacheing') -----
  unlinkIfLinkedSend: annotation pc: mcpc to: theCogMethod
  	<var: #mcpc type: #'char *'>
  	| entryPoint |
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint > methodZoneBase
  			ifTrue: "It's a linked send."
+ 				[self targetMethodAndSendTableFor: entryPoint into:
- 				[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  					[:targetMethod :sendTable| | unlinkedRoutine |
  					 targetMethod asInteger = theCogMethod ifTrue:
  						[unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
  						 backEnd
  							rewriteInlineCacheAt: mcpc asInteger
  							tag: targetMethod selector
  							target: unlinkedRoutine.
  						 codeModified := true]]]
  			ifFalse: "Can't tell the target with PushReciver/SendImplicit so flush anyway."
  				[self cppIf: NewspeakVM ifTrue:
  					[entryPoint = ceImplicitReceiverTrampoline ifTrue:
  						[backEnd
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize put: 0;
  							unalignedLongAt: mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop put: 0]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>unlinkIfLinkedSendToFree:pc:ignored: (in category 'in-line cacheing') -----
  unlinkIfLinkedSendToFree: annotation pc: mcpc ignored: superfluity
  	<var: #mcpc type: #'char *'>
  	| entryPoint |
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint > methodZoneBase ifTrue: "It's a linked send."
+ 			[self targetMethodAndSendTableFor: entryPoint into:
- 			[self targetMethodAndSendTableFor: entryPoint annotation: annotation into:
  				[:targetMethod :sendTable| | unlinkedRoutine |
  				 targetMethod cmType = CMFree ifTrue:
  					[unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
  					 backEnd
  						rewriteInlineCacheAt: mcpc asInteger
  						tag: targetMethod selector
  						target: unlinkedRoutine.
  					 codeModified := true]]]].
  	^0 "keep scanning"!

Item was added:
+ ----- Method: CurrentImageCoInterpreterFacade>>instantiateClass:indexableSize: (in category 'instantiation') -----
+ instantiateClass: classPointer indexableSize: size
+ 	(self objectForOop: classPointer) caseOf:
+ 		{[Array]	->	[^self oopForObject: (Array new: size)]}!

Item was changed:
  StackToRegisterMappingCogit subclass: #SistaStackToRegisterMappingCogit
  	instanceVariableNames: 'picDataIndex picData numCounters counters counterIndex initialCounterValue counterMethodCache prevMapAbsPCMcpc'
  	classVariableNames: 'CounterBytes MaxCounterValue'
  	poolDictionaries: ''
  	category: 'VMMaker-JIT'!
+ 
+ !SistaStackToRegisterMappingCogit commentStamp: 'eem 4/4/2014 12:39' prior: 0!
+ A SistaStackToRegisterMappingCogit is a refinement of StackToRegisterMappingCogit that generates code suitable for dynamic optimization by Sista, the Speculative Inlining Smalltalk Architecture, a project by Clément Bera and Eliot Miranda.  Sista is an optimizer that exists in the Smalltalk image, /not/ in the VM,  and optimizes by substituting normal bytecoded methods by optimized bytecoded methods that may use special bytecodes for which the Cogit can generate faster code.  These bytecodes eliminate overheads such as bounds checks or polymorphic code (indexing Array, ByteArray, String etc).  But the bulk of the optimization performed is in inlining blocks and sends for the common path.
+ 
+ The basic scheme is that SistaStackToRegisterMappingCogit generates code containing performance counters.  When these counters trip, a callback into the image is performed, at which point Sista analyses some portion of the stack, looking at performance data for the methods on the stack, and optimises based on teh stack and performance data.  Execution then resumes in the optimized code.
+ 
+ SistaStackToRegisterMappingCogit adds counters to conditional branches.  Each branch has an executed and a taken count, implemented at the two 16-bit halves of a single 32-bit word.  Each counter pair is initialized with initialCounterValue.  On entry to the branch the executed count is decremented and if the count goes below zero the ceMustBeBooleanAdd[True|False] trampoline called.  The trampoline distinguishes between true mustBeBoolean and counter trips because in the former the register temporarily holding the counter value will contain zero.  Then the condition is tested, and if the branch is taken the taken count is decremented.  The two counter values allow an optimizer to collect basic block execution paths and to know what are the "hot" paths through execution that are worth agressively optimizing.  Since conditional branches are about 1/6 as frequent as sends, and since they can be used to determine the hot path throguh code, they are a better choice to count than, for example, method or block entry.
+ 
+ SistaStackToRegisterMappingCogit implements picDataFor:into: that fills an Array with the state of the counters in a method and the state of each linked send in a method.  This is used to implement a primitive used by the optimizer to answer the branch and send data for a method as an Array.
+ 
+ Instance Variables
+ 	counterIndex:			<Integer>
+ 	counterMethodCache:	<CogMethod>
+ 	counters:				<Array of AbstractInstruction>
+ 	initialCounterValue:		<Integer>
+ 	numCounters:			<Integer>
+ 	picData:				<Integer Oop>
+ 	picDataIndex:			<Integer>
+ 	prevMapAbsPCMcpc:	<Integer>
+ 
+ counterIndex
+ 	- xxxxx
+ 
+ counterMethodCache
+ 	- xxxxx
+ 
+ counters
+ 	- xxxxx
+ 
+ initialCounterValue
+ 	- xxxxx
+ 
+ numCounters
+ 	- xxxxx
+ 
+ picData
+ 	- xxxxx
+ 
+ picDataIndex
+ 	- xxxxx
+ 
+ prevMapAbsPCMcpc
+ 	- xxxxx
+ !

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>genJumpIf:to: (in category 'bytecode generators') -----
  genJumpIf: boolean to: targetBytecodePC
  	"The heart of performance counting in Sista.  Conditional branches are 6 times less
  	 frequent than sends and can provide basic block frequencies (send counters can't).
  	 Each conditional has a 32-bit counter split into an upper 16 bits counting executions
  	 and a lower half counting untaken executions of the branch.  Executing the branch
  	 decrements the upper half, tripping if the count goes negative.  Not taking the branch
+ 	 decrements the lower half.  N.B. We *do not* eliminate dead branches (true ifTrue:/true ifFalse:)
+ 	 so that scanning for send and branch data is simplified and that branch data is correct."
- 	 decrements the lower half."
  	<inline: false>
+ 	| desc ok counter countTripped retry |
- 	| desc fixup ok counter countTripped retry |
  	<var: #desc type: #'CogSimStackEntry *'>
- 	<var: #fixup type: #'BytecodeFixup *'>
  	<var: #ok type: #'AbstractInstruction *'>
  	<var: #retry type: #'AbstractInstruction *'>
  	<var: #counter type: #'AbstractInstruction *'>
  	<var: #countTripped type: #'AbstractInstruction *'>
  	self ssFlushTo: simStackPtr - 1.
  	desc := self ssTop.
  	self ssPop: 1.
- 	(desc type == SSConstant
- 	 and: [desc constant = objectMemory trueObject or: [desc constant = objectMemory falseObject]]) ifTrue:
- 		["Must arrange there's a fixup at the target whether it is jumped to or
- 		  not so that the simStackPtr can be kept correct."
- 		 fixup := self ensureFixupAt: targetBytecodePC - initialPC.
- 		 "Must enter any annotatedConstants into the map"
- 		 self annotateBytecodeIfAnnotated: desc.
- 		 "Must annotate the bytecode for correct pc mapping."
- 		 self annotateBytecode: (desc constant = boolean
- 									ifTrue: [self Jump: fixup]
- 									ifFalse: [self prevInstIsPCAnnotated
- 												ifTrue: [self Nop]
- 												ifFalse: [self Label]]).
- 		 ^0].
  	desc popToReg: TempReg.
  
  	self ssAllocateRequiredReg: SendNumArgsReg. "Use this as the count reg."
  	counter := self addressOf: (counters at: counterIndex).
  	counterIndex := counterIndex + 1.
  	self flag: 'will need to use MoveAw32:R: if 64 bits'.
  	self assert: BytesPerWord = CounterBytes.
  	retry := counter addDependent: (self annotateAbsolutePCRef:
  				(self MoveAw: counter asUnsignedInteger R: SendNumArgsReg)).
  	self SubCq: 16r10000 R: SendNumArgsReg. "Count executed"
  	"Don't write back if we trip; avoids wrapping count back to initial value, and if we trip we don't execute."
  	countTripped := self JumpCarry: 0.
  	counter addDependent: (self annotateAbsolutePCRef:
  		(self MoveR: SendNumArgsReg Aw: counter asUnsignedInteger)). "write back"
  
  	"Cunning trick by LPD.  If true and false are contiguous subtract the smaller.
  	 Correct result is either 0 or the distance between them.  If result is not 0 or
  	 their distance send mustBeBoolean."
  	self assert: (objectMemory objectAfter: objectMemory falseObject) = objectMemory trueObject.
  	self annotate: (self SubCw: boolean R: TempReg) objRef: boolean.
  	self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
  
  	self SubCq: 1 R: SendNumArgsReg. "Count untaken"
  	counter addDependent: (self annotateAbsolutePCRef:
  		(self MoveR: SendNumArgsReg Aw: counter asUnsignedInteger)). "write back"
  
  	self CmpCq: (boolean == objectMemory falseObject
  					ifTrue: [objectMemory trueObject - objectMemory falseObject]
  					ifFalse: [objectMemory falseObject - objectMemory trueObject])
  		R: TempReg.
  	ok := self JumpZero: 0.
  	self MoveCq: 0 R: SendNumArgsReg. "if SendNumArgsReg is 0 this is a mustBeBoolean, not a counter trip."
  	countTripped jmpTarget:
  		(self CallRT: (boolean == objectMemory falseObject
  						ifTrue: [ceSendMustBeBooleanAddFalseTrampoline]
  						ifFalse: [ceSendMustBeBooleanAddTrueTrampoline])).
  	"Now we have to jump back to the retry point.  This is always the point at which the boolean is tested.
  	 The register to be tested must be reloaded with the return value of the trampoline; this is for the case
  	 where the trampoline returns immediately without sending back.."
  	backEnd cResultRegister ~= TempReg ifTrue:
  		[self MoveR: backEnd cResultRegister R: TempReg].
  	self Jump: retry.
  	ok jmpTarget: (self annotateBytecode: self Label).
  	^0!

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>mapFor:bcpc:performUntil:arg: (in category 'method map') -----
  mapFor: cogMethod bcpc: startbcpc performUntil: functionSymbol arg: arg
  	"Machine-code <-> bytecode pc mapping support.  Evaluate functionSymbol
  	 for each mcpc, bcpc pair in the map until the function returns non-zero,
  	 answering that result, or 0 if it fails to.  This works only for frameful methods."
  	<var: #cogMethod type: #'CogBlockMethod *'>
  	<var: #functionSymbol declareC: 'sqInt (*functionSymbol)(BytecodeDescriptor * desc, char *mcpc, sqInt bcpc, void *arg)'>
  	<var: #arg type: #'void *'>
  	| isInBlock mcpc bcpc endbcpc map mapByte homeMethod aMethodObj result
  	  latestContinuation byte descriptor bsOffset nExts |
  	<var: #descriptor type: #'BytecodeDescriptor *'>
  	<var: #homeMethod type: #'CogMethod *'>
  	self assert: cogMethod stackCheckOffset > 0.
  	"In both CMMethod and CMBlock cases find the start of the map and
  	 skip forward to the bytecode pc map entry for the stack check."
  	cogMethod cmType = CMMethod
  		ifTrue:
  			[isInBlock := false.
  			 homeMethod := self cCoerceSimple: cogMethod to: #'CogMethod *'.
  			 self assert: startbcpc = (coInterpreter startPCOfMethodHeader: homeMethod methodHeader).
  			 map := self mapStartFor: homeMethod.
  			 self assert: ((objectMemory byteAt: map) >> AnnotationShift = IsAbsPCReference
  						 or: [(objectMemory byteAt: map) >> AnnotationShift = IsRelativeCall
  						 or: [(objectMemory byteAt: map) >> AnnotationShift = IsDisplacementX2N]]).
  			 latestContinuation := startbcpc.
  			 aMethodObj := homeMethod methodObject.
  			 endbcpc := (objectMemory byteLengthOf: aMethodObj) - 1.
  			 bsOffset := self bytecodeSetOffsetForHeader: homeMethod methodHeader]
  		ifFalse:
  			[isInBlock := true.
  			 homeMethod := cogMethod cmHomeMethod.
  			 map := self findMapLocationForMcpc: cogMethod asUnsignedInteger + (self sizeof: CogBlockMethod)
  						inMethod: homeMethod.
  			 self assert: map ~= 0.
  			 self assert: ((objectMemory byteAt: map) >> AnnotationShift = HasBytecodePC "fiducial"
  						 or: [(objectMemory byteAt: map) >> AnnotationShift = IsDisplacementX2N]).
  			 [(objectMemory byteAt: map) >> AnnotationShift ~= HasBytecodePC] whileTrue:
  				[map := map - 1].
  			 map := map - 1. "skip fiducial; i.e. the map entry for the pc immediately following the method header."
  			 aMethodObj := homeMethod methodObject.
  			 bcpc := startbcpc - (self blockCreationBytecodeSizeForHeader: homeMethod methodHeader).
  			 bsOffset := self bytecodeSetOffsetForHeader: homeMethod methodHeader.
  			 byte := (objectMemory fetchByte: bcpc ofObject: aMethodObj) + bsOffset.
  			 descriptor := self generatorAt: byte.
  			 endbcpc := self nextBytecodePCFor: descriptor at: bcpc exts: -1 in: aMethodObj].
  	bcpc := startbcpc.
  	mcpc := cogMethod asUnsignedInteger + cogMethod stackCheckOffset.
  	nExts := 0.
  	"as a hack for collecting counters, remember the prev mcpc in a static variable."
  	prevMapAbsPCMcpc := 0.
  	"The stack check maps to the start of the first bytecode,
  	 the first bytecode being effectively after frame build."
  	result := self perform: functionSymbol
  					with: nil
  					with: (self cCoerceSimple: mcpc to: #'char *')
  					with: startbcpc
  					with: arg.
  	result ~= 0 ifTrue:
  		[^result].
  	"Now skip up through the bytecode pc map entry for the stack check." 
  	[(objectMemory byteAt: map) >> AnnotationShift ~= HasBytecodePC] whileTrue:
  		[map := map - 1].
  	map := map - 1.
  	[(mapByte := objectMemory byteAt: map) ~= MapEnd] whileTrue: "defensive; we exit on bcpc"
  		[mapByte >= FirstAnnotation
  			ifTrue:
  				[| annotation nextBcpc |
  				annotation := mapByte >> AnnotationShift.
  				mcpc := mcpc + (mapByte bitAnd: DisplacementMask).
  				(self isPCMappedAnnotation: annotation alternateInstructionSet: bsOffset > 0) ifTrue:
  					[[byte := (objectMemory fetchByte: bcpc ofObject: aMethodObj) + bsOffset.
  					  descriptor := self generatorAt: byte.
  					  isInBlock
  						ifTrue: [bcpc >= endbcpc ifTrue: [^0]]
  						ifFalse:
  							[(descriptor isReturn and: [bcpc >= latestContinuation]) ifTrue: [^0].
  							 (descriptor isBranch or: [descriptor isBlockCreation]) ifTrue:
  								[| targetPC |
  								 targetPC := self latestContinuationPCFor: descriptor at: bcpc exts: nExts in: aMethodObj.
  								 latestContinuation := latestContinuation max: targetPC]].
  					  nextBcpc := self nextBytecodePCFor: descriptor at: bcpc exts: nExts in: aMethodObj.
  					  descriptor isMapped
  					  or: [isInBlock and: [descriptor isMappedInBlock]]] whileFalse:
  						[bcpc := nextBcpc.
  						 nExts := descriptor isExtension ifTrue: [nExts + 1] ifFalse: [0]].
  					"All subsequent bytecodes except backward branches map to the
  					 following bytecode. Backward branches map to themselves other-
  					 wise mapping could cause premature breaking out of loops." 
  					result := self perform: functionSymbol
  									with: descriptor
  									with: (self cCoerceSimple: mcpc to: #'char *')
  									with: ((descriptor isBranch
  										   and: [self isBackwardBranch: descriptor at: bcpc exts: nExts in: aMethodObj])
  											ifTrue: [bcpc]
  											ifFalse: [bcpc + descriptor numBytes])
  									with: arg.
  					 result ~= 0 ifTrue:
  						[^result].
  					 bcpc := nextBcpc.
  					 nExts := descriptor isExtension ifTrue: [nExts + 1] ifFalse: [0]].
  				annotation = IsAbsPCReference ifTrue:
+ 					[self assert: mcpc ~= 0.
+ 					 prevMapAbsPCMcpc := mcpc]]
- 					[prevMapAbsPCMcpc := mcpc]]
  			ifFalse:
  				[mcpc := mcpc + (mapByte >= DisplacementX2N
  									ifTrue: [mapByte - DisplacementX2N << AnnotationShift]
  									ifFalse: [mapByte])].
  		 map := map - 1].
  	^0!

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>picDataFor:Mcpc:Bcpc:Method: (in category 'method introspection') -----
  picDataFor: descriptor Mcpc: mcpc Bcpc: bcpc Method: cogMethodArg
  	<var: #descriptor type: #'BytecodeDescriptor *'>
  	<var: #mcpc type: #'char *'>
  	<var: #cogMethodArg type: #'void *'>
+ 	| entryPoint tuple |
- 	| entryPoint offset targetMethod tuple |
- 	<var: #targetMethod type: #'CogMethod *'>
  	descriptor isNil ifTrue:
  		[^0].
  	descriptor isBranch ifFalse: "infer it's a send"
  		[self assert: (backEnd isCallPreceedingReturnPC: mcpc asUnsignedInteger).
  		 entryPoint := backEnd callTargetFromReturnAddress: mcpc asUnsignedInteger.
  		 entryPoint <= methodZoneBase ifTrue: "send is not linked"
  			[^0].
+ 		 self targetMethodAndSendTableFor: entryPoint into: "It's a linked send; find which kind."
+ 			[:targetMethod :sendTable|
+ 			 tuple := self picDataForSendTo: targetMethod at: mcpc bcpc: bcpc + 1 - descriptor numBytes].
- 		"It's a linked send; find which kind."
- 		offset := (entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
- 						ifTrue: [cmEntryOffset]
- 						ifFalse: [cmNoCheckEntryOffset].
- 		 targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
- 		 tuple := self picDataForSendTo: targetMethod at: mcpc bcpc: bcpc.
  		 tuple = 0 ifTrue: [^PrimErrNoMemory].
  		 objectMemory storePointer: picDataIndex ofObject: picData withValue: tuple.
  		 picDataIndex := picDataIndex + 1.
  		 ^0].
  	"it's a branch; conditional?"
  	(descriptor isBranchTrue or: [descriptor isBranchFalse]) ifTrue:
  		[tuple := self picDataForConditionalBranch: prevMapAbsPCMcpc at: bcpc.
  		 tuple = 0 ifTrue: [^PrimErrNoMemory].
  		 objectMemory storePointer: picDataIndex ofObject: picData withValue: tuple.
  		 picDataIndex := picDataIndex + 1.
  		 ^0].
  	^0!

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>picDataFor:into: (in category 'method introspection') -----
  picDataFor: cogMethod into: arrayObj
+ 	"Collect the branch and send data for cogMethod, storing it into arrayObj."
- 	"Answer the zero-relative bytecode pc matching the machine code pc argument in
- 	 cogMethod, given the start of the bytecodes for cogMethod's block or method object."
  	<api>
  	<var: #cogMethod type: #'CogMethod *'>
  	| errCode |
  	cogMethod stackCheckOffset = 0 ifTrue:
  		[^0].
  	picDataIndex := 0.
  	picData := arrayObj.
  	errCode := self
  					mapFor: (self cCoerceSimple: cogMethod to: #'CogBlockMethod *')
  					bcpc: (coInterpreter startPCOfMethod: cogMethod methodObject)
  					performUntil: #picDataFor:Mcpc:Bcpc:Method:
  					arg: cogMethod asVoidPointer.
  	errCode ~= 0 ifTrue:
  		[self assert: errCode = PrimErrNoMemory.
  		 ^-1].
+ 	cogMethod blockEntryOffset ~= 0 ifTrue:
+ 		[errCode := self blockDispatchTargetsFor: cogMethod
+ 						perform: #picDataForBlockEntry:Method:
+ 						arg: cogMethod asVoidPointer.
+ 		 errCode ~= 0 ifTrue:
+ 			[self assert: errCode = PrimErrNoMemory.
+ 			 ^-1]].
  	^picDataIndex!

Item was added:
+ ----- Method: SistaStackToRegisterMappingCogit>>picDataForBlockEntry:Method: (in category 'method introspection') -----
+ picDataForBlockEntry: blockEntryMcpc Method: cogMethod
+ 	"Collect the branch and send data for the block method starting at blockEntryMcpc, storing it into picData."
+ 	| cogBlockMethod |
+ 	<var: #cogBlockMethod type: #'CogBlockMethod *'>
+ 	cogBlockMethod := self cCoerceSimple: blockEntryMcpc - (self sizeof: CogBlockMethod)
+ 							  to: #'CogBlockMethod *'.
+ 	cogBlockMethod stackCheckOffset = 0 ifTrue:
+ 		[^0].
+ 	^self
+ 		mapFor: cogBlockMethod
+ 		bcpc: cogBlockMethod startpc
+ 		performUntil: #picDataFor:Mcpc:Bcpc:Method:
+ 		arg: cogMethod!

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>picDataForSendTo:at:bcpc: (in category 'method introspection') -----
  picDataForSendTo: cogMethod at: sendMcpc bcpc: sendBcpc
+ 	"Answer a tuple with the send data for a linked send to cogMethod.
+ 	 If the target is a CogMethod (monomorphic send) answer
+ 		{ bytecode pc, inline cache class, target method }
+ 	 If the target is an open PIC (megamorphic send) answer
+ 		{ bytecode pc, nil, send selector }
+ 	If the target is a closed PIC (polymorphic send) answer
+ 		{ bytecode pc, first class, target method, second class, second target method, ... }"
  	<var: #cogMethod type: #'CogMethod *'>
  	<var: #sendMcpc type: #'char *'>
  	| tuple |
  	cogMethod cmType = CMMethod ifTrue:
  		[tuple := objectMemory
  					eeInstantiateClass: (objectMemory splObj: ClassArray)
  					indexableSize: 3.
  		tuple = 0 ifTrue:
  			[^0].
  		objectMemory
  			storePointerUnchecked: 0 ofObject: tuple withValue: (objectMemory integerObjectOf: sendBcpc);
+ 			storePointer: 1
- 			storePointer: 1 ofObject: tuple withValue: cogMethod methodObject;
- 			storePointer: 2
  				ofObject: tuple
+ 					withValue: (objectRepresentation classForInlineCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger));
+ 			storePointer: 2 ofObject: tuple withValue: cogMethod methodObject.
- 					withValue: (objectRepresentation classForInlineCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger)).
  		^tuple].
  	cogMethod cmType = CMClosedPIC ifTrue:
  		[tuple := objectMemory
  					eeInstantiateClass: (objectMemory splObj: ClassArray)
  					indexableSize: 2 * cogMethod cPICNumCases + 1.
  		tuple = 0 ifTrue:
  			[^0].
  		objectMemory storePointerUnchecked: 0 ofObject: tuple withValue: (objectMemory integerObjectOf: sendBcpc).
  		self populate: tuple withPICInfoFor: cogMethod firstCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger).
  		^tuple].
  	cogMethod cmType = CMOpenPIC ifTrue:
  		[tuple := objectMemory
  					eeInstantiateClass: (objectMemory splObj: ClassArray)
+ 					indexableSize: 3.
- 					indexableSize: 2.
  		tuple = 0 ifTrue:
  			[^0].
+ 		objectMemory
+ 			storePointerUnchecked: 0 ofObject: tuple withValue: (objectMemory integerObjectOf: sendBcpc);
+ 			storePointerUnchecked: 1 ofObject: tuple withValue: objectMemory nilObject;
+ 			storePointer: 2 ofObject: tuple withValue: cogMethod selector.
- 		coInterpreter
- 			storeInteger: 0 ofObject: tuple withValue: sendBcpc;
- 			storePointerUnchecked: 1 ofObject: tuple withValue: objectMemory nilObject.
  		^tuple].
  	self error: 'invalid method type'.
  	^0 "to get Slang to type this method as answering sqInt"!

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>populate:withPICInfoFor:firstCacheTag: (in category 'method introspection') -----
  populate: tuple withPICInfoFor: cPIC firstCacheTag: firstCacheTag
  	"Populate tuple (which must be large enough) with the ClosedPIC's target method class pairs.
  	 The first entry in tuple contains the bytecode pc for the send, so skip the tuple's first field."
  	<var: #cPIC type: #'CogMethod *'>
+ 	| pc cacheTag classOop entryPoint targetMethod value |
- 	| pc cacheTag classOop entryPoint targetMethod |
  	<var: #targetMethod type: #'CogMethod *'>
- 	self halt.
  	pc := cPIC asInteger + firstCPICCaseOffset.
  	1 to: cPIC cPICNumCases do:
  		[:i|
  		cacheTag := i = 1
  						ifTrue: [firstCacheTag]
  						ifFalse: [backEnd literalBeforeFollowingAddress: pc
  																		- backEnd jumpLongConditionalByteSize
  																		- backEnd loadLiteralByteSize].
  		classOop := objectRepresentation classForInlineCacheTag: cacheTag.
  		objectMemory storePointer: i * 2 - 1 ofObject: tuple withValue: classOop.
  		entryPoint := backEnd jumpLongTargetBeforeFollowingAddress: pc.
+ 		"Find target from jump.  A jump to the MNU entry-point should collect #doesNotUnderstand:"
- 		"Find target from jump.  Ignore jumps to the interpret and MNU calls within this PIC"
  		(entryPoint asUnsignedInteger < cPIC asUnsignedInteger
  		 or: [entryPoint asUnsignedInteger > (cPIC asUnsignedInteger + cPIC blockSize) asUnsignedInteger])
  			ifTrue:
  				[targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
  				 self assert: targetMethod cmType = CMMethod.
+ 				 value := targetMethod methodObject]
+ 			ifFalse:
+ 				[value := objectMemory splObj: SelectorDoesNotUnderstand].
+ 		objectMemory storePointer: i * 2 ofObject: tuple withValue: value.
- 				 objectMemory storePointer: i * 2 ofObject: tuple withValue: targetMethod methodObject].
  		pc := pc + cPICCaseSize]!



More information about the Vm-dev mailing list