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

commits at source.squeak.org commits at source.squeak.org
Tue Nov 29 20:46:43 UTC 2016


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

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

Name: VMMaker.oscog-eem.2010
Author: eem
Time: 29 November 2016, 12:45:23.316587 pm
UUID: 5ead15e2-0452-433f-83d9-c14d1804fe5a
Ancestors: VMMaker.oscog-eem.2009

RegisterAllocatingCogit:
Count fixups for backward branches.

Implement saving the stack at a backward branch and reloading register state before taking the backward jump.  Reverse the sense of  reconcileWith: and rename it to reconcilePoppingWith: to match the backwards jump reconciliation code.

Extend CogRASSBytecodeFixup with the state of the optStatus for self and fix reInitialize.

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

Item was changed:
  CogSSBytecodeFixup subclass: #CogRASSBytecodeFixup
+ 	instanceVariableNames: 'cogit mergeSimStack isReceiverResultRegSelf'
- 	instanceVariableNames: 'cogit mergeSimStack'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'VMMaker-JIT'!
  
  !CogRASSBytecodeFixup commentStamp: 'eem 11/22/2016 08:44' prior: 0!
  A CogRASSBytecodeFixup extends CogSSBytecodeFixup with state to merge the stack at control-flow joins, preserving register contents.  By holding onto the entire stack state a CogRASSBytecodeFixup allows RegisterAllocatingCogit to merge individual stack entries, instead of merely spilling to the same height.
  
  Instance Variables
  	cogit:					<RegisterAllocatingCogit>
  	mergeSimStack:		<Array of: CogRegisterAllocatingSimStackEntry>
  
  cogit
  	- the JIT compiler
  
  mergeSimStack
  	- the state of the stack at the jump to this fixup!

Item was changed:
  ----- Method: CogRASSBytecodeFixup>>cogit: (in category 'initialize-release') -----
  cogit: aCogit
  	cogit := aCogit.
+ 	isReceiverResultRegSelf := false.
  	^self!

Item was added:
+ ----- Method: CogRASSBytecodeFixup>>isReceiverResultRegSelf (in category 'accessing') -----
+ isReceiverResultRegSelf
+ 
+ 	^ isReceiverResultRegSelf!

Item was added:
+ ----- Method: CogRASSBytecodeFixup>>isReceiverResultRegSelf: (in category 'accessing') -----
+ isReceiverResultRegSelf: anObject
+ 
+ 	^isReceiverResultRegSelf := anObject!

Item was added:
+ ----- Method: CogRASSBytecodeFixup>>reinitialize (in category 'accessing') -----
+ reinitialize
+ 	<inline: true>
+ 	super reinitialize.
+ 	mergeSimStack := nil.
+ 	isReceiverResultRegSelf := false!

Item was added:
+ ----- Method: CogRegisterAllocatingSimStackEntry>>reconcilePoppingWith: (in category 'compile abstract instructions') -----
+ reconcilePoppingWith: simStackEntry
+ 	"Make the state of a simStackEntry, a stack entry along the inlined special selector path,
+ 	 the same as the corresponding simStackEntry along the non-inlined path (the receiver)."
+ 	<var: #simStackEntry type: #'SimStackEntry *'>
+ 	simStackEntry type = SSConstant ifTrue:
+ 		[cogit AddCw: BytesPerWord R: SPReg.
+ 		 ^self].
+ 	simStackEntry registerOrNone ~= NoReg ifTrue:
+ 		[cogit PopR: simStackEntry registerOrNone.
+ 		 ^self].
+ 	self halt!

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>reconcileWith: (in category 'compile abstract instructions') -----
+ reconcileWith: targetEntry
+ 	"Make the state of the receiver, a stack entry at a backward jump,
+ 	 the same as the corresponding simStackEntry at the target of the jump"
+ 	<var: #targetEntry type: #'targetEntry *'>
+ 	targetEntry liveRegister = NoReg ifTrue:
+ 		[^self].
+ 	targetEntry type = SSConstant ifTrue:
+ 		[self assert: (type = SSConstant and: [constant = targetEntry constant]).
- reconcileWith: simStackEntry
- 	"Make the state of each simStackEntry, a stack entry along the non-inlined special selector path,
- 	 the same as the corresponding simStackEntry along the inlined path (the receiver)."
- 	<var: #simStackEntry type: #'SimStackEntry *'>
- 	type = SSConstant ifTrue:
- 		[cogit AddCw: BytesPerWord R: SPReg.
  		 ^self].
  	liveRegister ~= NoReg ifTrue:
+ 		[liveRegister ~= targetEntry liveRegister ifTrue:
+ 			[cogit MoveR: liveRegister R: targetEntry liveRegister].
- 		[simStackEntry popToReg: liveRegister.
  		 ^self].
+ 	type caseOf: {
+ 		[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: targetEntry liveRegister].
+ 		[SSSpill]		-> [cogit MoveMw: offset r: register R: targetEntry liveRegister].
+ 		[SSConstant]	-> [cogit genMoveConstant: constant R: targetEntry liveRegister].
+ 		[SSRegister]	-> [register ~= targetEntry liveRegister ifTrue:
+ 								[cogit MoveR: register R: targetEntry liveRegister]] }!
- 	type = SSRegister ifTrue:
- 		[simStackEntry popToReg: register.
- 		 ^self].
- 	self halt!

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>storeToReg: (in category 'compile abstract instructions') -----
  storeToReg: reg
  	liveRegister ~= NoReg
  		ifTrue:
+ 			[self deny: (type = SSRegister and: [register ~= liveRegister]).
- 			[self deny: spilled.
- 			 self deny: (type = SSRegister and: [register ~= liveRegister]).
  			 reg ~= liveRegister
  				ifTrue: [cogit MoveR: liveRegister R: reg]
  				ifFalse: [cogit Label]]
  		ifFalse:
  			[type caseOf: {
  				[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: reg].
  				[SSSpill]		-> [cogit MoveMw: offset r: register R: reg].
  				[SSConstant]	-> [cogit genMoveConstant: constant R: reg].
  				[SSRegister]	-> [reg ~= register
  											ifTrue: [cogit MoveR: register R: reg]
  											ifFalse: [cogit Label]] }].
  
  	(reg ~= TempReg and: [reg ~= liveRegister and: [type ~= SSRegister]]) ifTrue:
  		[liveRegister := reg.
  		 cogit copyLiveRegisterToCopiesOf: self]!

Item was changed:
  ----- Method: RegisterAllocatingCogit class>>declareCVarsIn: (in category 'C translation') -----
  declareCVarsIn: aCodeGen
  	aCodeGen
  		var: #scratchSimStack
+ 			type: #'SimStackEntry *';
- 			type: #'CogSimStackEntry *';
  		var: #scratchOptStatus
  			type: #CogSSOptStatus!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>genJumpBackTo: (in category 'bytecode generator support') -----
+ genJumpBackTo: targetBytecodePC
+ 	| nothingToFlush label |
+ 	<var: #label type: #'AbstractInstruction *'>
+ 	"If there's nothing to flush then the stack state at this point is the same as that after
+ 	 the check for interrups and we can avoid generating the register reload code twice."
+ 	(nothingToFlush := simStackPtr < 0 or: [self ssTop spilled]) ifTrue:
+ 		[label := self Label].
+ 	self reconcileRegisterStateForBackwardJoin: (self fixupAt: targetBytecodePC - initialPC).
+ 	self MoveAw: coInterpreter stackLimitAddress R: TempReg.
+ 	self CmpR: TempReg R: SPReg. "N.B. FLAGS := SPReg - TempReg"
+ 	self JumpAboveOrEqual: (self fixupAt: targetBytecodePC - initialPC).
+ 
+ 	self ssFlushTo: simStackPtr.
+ 	self CallRT: ceCheckForInterruptTrampoline.
+ 	self annotateBytecode: self Label.
+ 	nothingToFlush
+ 		ifTrue:
+ 			[self Jump: label]
+ 		ifFalse:
+ 			[self reconcileRegisterStateForBackwardJoin: (self fixupAt: targetBytecodePC - initialPC).
+ 			 self Jump: (self fixupAt: targetBytecodePC - initialPC)].
+ 	deadCode := true. "can't fall through"
+ 	^0!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>maybeCountFixup: (in category 'as yet unclassified') -----
  maybeCountFixup: descriptor
  	"Count needed fixups; descriptor is known to be a branch or a block creation."
  	<var: #descriptor type: #'BytecodeDescriptor *'>
  	<inline: true>
+ 	numFixups := numFixups + (descriptor isBranch
- 	numFixups := numFixups + ((descriptor isBranchTrue or: [descriptor isBranchFalse])
  									ifTrue:
+ 										[((descriptor isBranchTrue or: [descriptor isBranchFalse])
+ 										  and: [prevBCDescriptor generator == #genSpecialSelectorEqualsEquals
+ 												or: [prevBCDescriptor generator == #genSpecialSelectorComparison]])
+ 													ifTrue: [3]
+ 													ifFalse: [2]] "Forward branches only need one, but backward branches need two"
+ 									ifFalse:  [1]) "blocks"!
- 										[(prevBCDescriptor generator == #genSpecialSelectorEqualsEquals
- 										   or: [prevBCDescriptor generator == #genSpecialSelectorComparison])
- 											ifTrue: [3]
- 											ifFalse: [2]]
- 									ifFalse:  [1])!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>mergeWithFixupIfRequired: (in category 'simulation stack') -----
  mergeWithFixupIfRequired: fixup
  	"If this bytecode has a fixup, some kind of merge needs to be done. There are 4 cases:
  		1) the bytecode has no fixup (fixup isNotAFixup)
  			do nothing
  		2) the bytecode has a non merge fixup
  			the fixup has needsNonMergeFixup.
  			The code generating non merge fixup (currently only special selector code) is responsible
  				for the merge so no need to do it.
  			We set deadCode to false as the instruction can be reached from jumps.
  		3) the bytecode has a merge fixup, but execution flow *cannot* fall through to the merge point.
  			the fixup has needsMergeFixup and deadCode = true.
  			ignores the current simStack as it does not mean anything 
  			restores the simStack to the state the jumps to the merge point expects it to be.
  		4) the bytecode has a merge fixup and execution flow *can* fall through to the merge point.
  			the fixup has needsMergeFixup and deadCode = false.
  			flushes the stack to the stack pointer so the fall through execution path simStack is 
  				in the state the merge point expects it to be. 
  			restores the simStack to the state the jumps to the merge point expects it to be.
  			
  	In addition, if this is a backjump merge point, we patch the fixup to hold the current simStackPtr 
  	for later assertions."
  	
  	<var: #fixup type: #'BytecodeFixup *'>
  	"case 1"
  	fixup notAFixup ifTrue: [^ 0].
  
  	"case 2"
  	fixup isNonMergeFixup ifTrue: [deadCode := false. ^ 0 ].
  
  	"cases 3 and 4"
  	self assert: fixup isMergeFixup.
  	self traceMerge: fixup.
  	deadCode 
  		ifTrue: [simStackPtr := fixup simStackPtr] "case 3"
  		ifFalse: [self mergeCurrentSimStackWith: fixup mergeSimStack]. "case 4"
  	"cases 3 and 4"
  	deadCode := false.
+ 	fixup isBackwardBranchFixup ifTrue:
+ 		[self assert: fixup mergeSimStack isNil.
+ 		 self setMergeSimStackOf: fixup].
- 	fixup isBackwardBranchFixup ifTrue: [fixup simStackPtr: simStackPtr].
  	fixup targetInstruction: self Label.
  	self assert: simStackPtr = fixup simStackPtr.
  	self cCode: '' inSmalltalk:
  		[self assert: fixup simStackPtr = (self debugStackPointerFor: bytecodePC)].
  	self restoreSimStackAtMergePoint: fixup.
  	
  	^0!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>moveSimStackConstantsToRegisters (in category 'bytecode generator support') -----
  moveSimStackConstantsToRegisters
  	<inline: true>
+ 	<var: #desc type: #'SimStackEntry *'>
+ 	self flag: 'I think this should be done at the merge point if required.  e.g. self at: 1 put: (expr ifTrue: [a] ifFalse: [b]) does not need to assign'. 
  	(simSpillBase max: 0) to: simStackPtr do: 
+ 		[:i| | desc reg |
+ 		 desc := self simStackAt: i.
+ 		 (desc type = SSConstant and: [desc liveRegister = NoReg]) ifTrue:
+ 			[reg := self allocateRegNotConflictingWith: 0.
+ 			 reg ~= NoReg ifTrue:
+ 				[desc storeToReg: reg]]]!
- 		[:i|
- 			| desc |
- 			desc := self simStackAt: i.
- 			(desc type = SSConstant and: [desc liveRegister = NoReg])
- 				ifTrue: [ desc storeToReg: (self allocateRegNotConflictingWith: 0) ] ]!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>reconcileRegisterStateForBackwardJoin: (in category 'bytecode generator support') -----
+ reconcileRegisterStateForBackwardJoin: fixup 
+ 	<var: #fixup type: #'SSBytecodeFixup *'>
+ 	| fixupSimStack |
+ 	<var: #fixupSimStack type: #'SimStackEntry *'>
+ 	self assert: (optStatus ssEntry isSameEntryAs: simSelf). 
+ 	fixup isReceiverResultRegSelf ifTrue:
+ 		[optStatus isReceiverResultRegLive ifFalse:
+ 			[optStatus ssEntry storeToReg: ReceiverResultReg]].
+ 	fixupSimStack := fixup mergeSimStack.
+ 	simStackPtr to: 0 by: -1 do:
+ 		[:i|
+ 		 self assert: (self simStackAt: i) spilled.
+ 		 (self simStackAt: i) reconcileWith: (fixupSimStack at: i)]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>reconcileRegisterStateForJoinAfterSpecialSelectorSend (in category 'bytecode generator support') -----
  reconcileRegisterStateForJoinAfterSpecialSelectorSend
  	"When the control flow from the inlined special selector code (e.g. add or comparison)
  	 joins the control flow from the send, taken when the inlined code fails, we should decide
  	 whether to reload any registers known to contain useful values or mark them as dead."
  	 
  	"If ReceiverResultReg is live along the inlined path, and is used before the next full send,
  	 reload it on the uncommon path."
  	scratchOptStatus isReceiverResultRegLive ifTrue:
  		[(self existsInstVarRefBeforeSendOrReturn
  		  or: [self receiverRefOnScratchSimStack])
  			ifTrue:
  				[optStatus isReceiverResultRegLive: true.
  				 optStatus ssEntry storeToReg: ReceiverResultReg]
  			ifFalse: [optStatus isReceiverResultRegLive: false]].
  
  	"Restore the simStack to that in scratchSimStack,
  	 popping any spilled state back into allocated registers."
  	simSpillBase := scratchSpillBase.
  	simStackPtr to: 0 by: -1 do:
  		[:i|
  		 self assert: (i = simStackPtr
  						ifTrue: [(self simStackAt: i) type = SSRegister]
  						ifFalse: [(self simStackAt: i) spilled]).
  		 (self addressOf: (scratchSimStack at: i)) spilled ifTrue:
  			[self assert: ((scratchSimStack at: i) isSameEntryAs: (self simStackAt: i)).
  			 ^self].
+ 		 (self simStackAt: i) reconcilePoppingWith: (self addressOf: (scratchSimStack at: i)).
- 		 (self addressOf: (scratchSimStack at: i)) reconcileWith: (self simStackAt: i).
  		 simStack
  			at: i
  			put: (self
  					cCode: [scratchSimStack at: i]
  					inSmalltalk: [(scratchSimStack at: i) copy])]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>setMergeSimStackOf: (in category 'bytecode generator support') -----
  setMergeSimStackOf: fixup
  	<var: #fixup type: #'BytecodeFixup *'>
  	self assert: nextFixup <= numFixups.
  	self moveSimStackConstantsToRegisters.
  	self cCode: [fixup mergeSimStack: mergeSimStacksBase + (nextFixup * self simStackSlots * (self sizeof: CogSimStackEntry))].
+ 	fixup
+ 		simStackPtr: simStackPtr;
+ 		isReceiverResultRegSelf: optStatus isReceiverResultRegLive.
- 	fixup simStackPtr: simStackPtr.
  	nextFixup := nextFixup + 1.
  	self cCode: [self mem: fixup mergeSimStack cp: simStack y: self simStackSlots * (self sizeof: CogSimStackEntry)]
  		inSmalltalk: [fixup mergeSimStack: self copySimStack]!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>scanMethod (in category 'compile abstract instructions') -----
  scanMethod
  	"Scan the method (and all embedded blocks) to determine
  		- what the last bytecode is; extra bytes at the end of a method are used to encode things like source pointers or temp names
  		- if the method needs a frame or not
  		- what are the targets of any backward branches.
  		- how many blocks it creates
  	 Answer the block count or on error a negative error code"
  	| latestContinuation nExts descriptor pc numBlocks distance targetPC framelessStackDelta seenInstVarStore |
  	<var: #descriptor type: #'BytecodeDescriptor *'>
  	needsFrame := useTwoPaths := seenInstVarStore := false.
  	LowcodeVM ifTrue: [ hasNativeFrame := false ].
  	self maybeInitNumFixups.
  	self maybeInitNumCounters.
  	prevBCDescriptor := nil.
  	NewspeakVM ifTrue:
  		[numIRCs := 0].
  	(primitiveIndex > 0
  	 and: [coInterpreter isQuickPrimitiveIndex: primitiveIndex]) ifTrue:
  		[^0].
  	pc := latestContinuation := initialPC.
  	numBlocks := framelessStackDelta := nExts := extA := extB := 0.
  	[pc <= endPC] whileTrue:
  		[byte0 := (objectMemory fetchByte: pc ofObject: methodObj) + bytecodeSetOffset.
  		 descriptor := self generatorAt: byte0.
  		 descriptor isExtension ifTrue:
  			[descriptor opcode = Nop ifTrue: "unknown bytecode tag; see Cogit class>>#generatorTableFrom:"
  				[^EncounteredUnknownBytecode].
  			 self loadSubsequentBytesForDescriptor: descriptor at: pc.
  			 self perform: descriptor generator].
  		 (descriptor isReturn
  		  and: [pc >= latestContinuation]) ifTrue:
  			[endPC := pc].
  
  		  needsFrame ifFalse:
  			[(descriptor needsFrameFunction isNil
  			  or: [self perform: descriptor needsFrameFunction with: framelessStackDelta])
  					ifTrue:
  						["With immutability we win simply by avoiding a frame build if the receiver is young and not immutable."
  						 self cppIf: IMMUTABILITY
  							ifTrue: [descriptor is1ByteInstVarStore
  									ifTrue: [useTwoPaths := true]
  									ifFalse: [needsFrame := true. useTwoPaths := false]]
  							ifFalse: [needsFrame := true. useTwoPaths := false]]
  					ifFalse:
  						[framelessStackDelta := framelessStackDelta + descriptor stackDelta.
  						 "Without immutability we win if there are two or more stores and the receiver is new."
  						 self cppIf: IMMUTABILITY
  							ifTrue: []
  							ifFalse:
  								[descriptor is1ByteInstVarStore ifTrue:
  									[seenInstVarStore
  										ifTrue: [useTwoPaths := true]
  										ifFalse: [seenInstVarStore := true]]]]].
  
  		 descriptor isBranch ifTrue:
  			[distance := self spanFor: descriptor at: pc exts: nExts in: methodObj.
  			 targetPC := pc + descriptor numBytes + distance.
+ 			 self maybeCountFixup: descriptor.
  			 (self isBackwardBranch: descriptor at: pc exts: nExts in: methodObj)
  				ifTrue: [self initializeFixupAt: targetPC - initialPC]
  				ifFalse:
  					[latestContinuation := latestContinuation max: targetPC.
- 					 self maybeCountFixup: descriptor.
  					 self maybeCountCounter]].
  		 descriptor isBlockCreation ifTrue:
  			[numBlocks := numBlocks + 1.
  			 distance := self spanFor: descriptor at: pc exts: nExts in: methodObj.
  			 targetPC := pc + descriptor numBytes + distance.
  			 latestContinuation := latestContinuation max: targetPC.
  			 self maybeCountFixup: descriptor].
  
  		 NewspeakVM ifTrue:
  			[descriptor hasIRC ifTrue: [numIRCs := numIRCs + 1]].
  		 pc := pc + descriptor numBytes.
  		 nExts := descriptor isExtension ifTrue: [nExts + 1] ifFalse: [extA := extB := 0].
  		 prevBCDescriptor := descriptor].
  	^numBlocks!



More information about the Vm-dev mailing list