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

commits at source.squeak.org commits at source.squeak.org
Sat Dec 3 01:02:34 UTC 2016


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

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

Name: VMMaker.oscog-eem.2022
Author: eem
Time: 2 December 2016, 5:01:48.877113 pm
UUID: 0f8040b3-62e2-4f22-af99-5ba2cfb4974f
Ancestors: VMMaker.oscog-eem.2021

RegisterAllocatingCogit:
Abstract away voiding the optStatus into voidReceiverOptStatus so that RegisterAllocatingCogit can override to clear the liveRegister on simSelf.

Add voidReceiverResultRegContainsSelf that scans the stack for occurrences of simSelf in a register on stack and to either flush (StackToRegisterMappingCogit) or void liveRegister (RegisterAllocatingCogit).  Except that I suspect RegisterAllocatingCogit may have to flush in certain curcumstances too.

Add asserts to check that optStatus and simSelf are in sync w.r.t. ReceiverResultReg.

Fix a bad slip in existsInstVarRefBeforeSendOrReturn.

Nuke an obsolete NewspeakV3 bytecode.

Very close to working properly.  System no longer crashes in JIT or assert failure but runs, albeit looping on an MNU.

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

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>popToReg: (in category 'compile abstract instructions') -----
  popToReg: reg
  	<var: #inst type: #'AbstractInstruction *'>
  	liveRegister ~= NoReg
  		ifTrue: 
+ 			[self deny: (type = SSRegister and: [register ~= liveRegister and: [cogit needsFrame]]).
+ 			 spilled ifTrue: "This is rare, and in some cases it isn't even needed (e.g. frameful return) but we can't tell as yet."
+ 				[cogit AddCq: objectRepresentation wordSize R: SPReg].
- 			[self deny: spilled.
- 			 self deny: (type = SSRegister and: [register ~= liveRegister]).
  			 reg ~= liveRegister
  				ifTrue: [cogit MoveR: liveRegister R: reg]
  				ifFalse: [cogit Label]]
  		ifFalse: 
  			[spilled
  				ifTrue:
  					[cogit PopR: reg]
  				ifFalse:
  					[type caseOf: {
  						[SSBaseOffset]	-> [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>>captureUnspilledSpillsForSpecialSelectorSend: (in category 'bytecode generator support') -----
  captureUnspilledSpillsForSpecialSelectorSend: liveRegisterMask
  	"Since we're allocating values in registers we would like to keep those registers live on the inlined path
  	 and reload registers along the non-inlined send path.  But any values that would need to be spilled
  	 along the non-inlined path must be captured before the split so that both paths can join.  If we don't
  	 capture the values on the non-inlined path we could access stale values.  So for all stack entries that
  	 would be spilled along the non-inlined path, assign them to registers, or spill if none are available."
  	| i liveRegs reg |
  	liveRegs := liveRegisterMask.
+ 	self assert: (simSelf liveRegister = ReceiverResultReg) = optStatus isReceiverResultRegLive.
  	optStatus isReceiverResultRegLive ifTrue:
  		[liveRegs := liveRegs + (self registerMaskFor: ReceiverResultReg)].
  	reg := TempReg. "Anything but NoReg"
  	i := simStackPtr + 1. "We must spill a contiguous range at the hot top of stack, so we assign coldest first :-("
  	[reg ~= NoReg and: [i > simSpillBase and: [i > 0]]] whileTrue:
  		[i := i - 1.
  		 ((self simStackAt: i) spilled not
  		  and: [(self simStackAt: i) type = SSBaseOffset]) ifTrue:
  			[reg := self allocateRegNotConflictingWith: liveRegs.
  			 reg ~= NoReg ifTrue:
  				[(self simStackAt: i) storeToReg: reg.
  				 liveRegs := liveRegs bitOr: (self registerMaskFor: reg)]]].
  	reg = NoReg ifTrue:
  		[self ssFlushTo: i]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>ensureReceiverResultRegContainsSelf (in category 'bytecode generator support') -----
  ensureReceiverResultRegContainsSelf
  	super ensureReceiverResultRegContainsSelf.
+ 	methodOrBlockNumTemps to: simStackPtr do:
- 	0 to: simStackPtr do:
  		[:i|
  		(simSelf isSameEntryAs: (self simStackAt: i))
  			ifTrue: [(self simStackAt: i) liveRegister: ReceiverResultReg]
  			ifFalse:
  				[(self simStackAt: i) liveRegister = ReceiverResultReg ifTrue:
  					[(self simStackAt: i) liveRegister: NoReg]]].
  	simSelf liveRegister: ReceiverResultReg!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>existsInstVarRefBeforeSendOrReturn (in category 'bytecode generator support') -----
  existsInstVarRefBeforeSendOrReturn
  	"Answer if the current bytecode is followed by an inst var ref before the next full send."
+ 	| pc nExts byte descriptor |
- 	| pc nExts descriptor |
  	pc := bytecodePC.
  	nExts := 0.
  	[pc <= endPC] whileTrue:
+ 		[byte := (objectMemory fetchByte: pc ofObject: methodObj) + bytecodeSetOffset.
+ 		 descriptor := self generatorAt: byte.
- 		[descriptor := self generatorAt: pc.
  		 (descriptor isMapped
  		  or: [descriptor isBranchTrue
  		  or: [descriptor isBranchFalse
  		  or: [descriptor spanFunction notNil]]]) ifTrue:
  			[^false].
  		 descriptor isInstVarRef ifTrue:
  			[^true].
  		 nExts := descriptor isExtension ifTrue: [nExts + 1] ifFalse: [0].
  		 pc := self nextBytecodePCFor: descriptor at: pc exts: nExts in: methodObj].
  	^false!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>moveVolatileSimStackEntriesToRegisters (in category 'bytecode generator support') -----
  moveVolatileSimStackEntriesToRegisters
  	"When jumping forward to a merge point the stack mst be reconcilable with the state that falls through to the merge point.
  	 We cannot easily arrange that later we add code to the branch, e.g. to spill values.  Instead, any volatile contents must be
  	 moved to registers.  [In fact, that's not exactly true, consider these two code sequences:
  							self at: (expr ifTrue: [1] ifFalse: [2]) put: a
  							self at: 1 put: (expr ifTrue: [a] ifFalse: [b])
  						 The first one needs 1 saving to a register to reconcile with 2.
  						 The second one has 1 on both paths, but we're not clever enough to spot this case yet.]
+ 	 Volatile contents are anything not spilled to the stack, because as yet we can only merge registers."
- 	 Volatile contents are constants and base-offset references other than temporaries and spills (regsier ~= FPReg)"
  	<inline: true>
  	<var: #desc type: #'SimStackEntry *'>
  	(simSpillBase max: 0) to: simStackPtr do: 
  		[:i| | desc reg |
  		 desc := self simStackAt: i.
+ 		 desc spilled
+ 			ifTrue: [simSpillBase := i]
+ 			ifFalse:
+ 				[desc registerOrNone = NoReg ifTrue:
+ 					[reg := self allocateRegNotConflictingWith: 0.
+ 					 reg = NoReg
+ 						ifTrue: [self halt] "have to spill"
+ 						ifFalse: [desc storeToReg: reg]]]]!
- 		 ((desc type = SSConstant or: [desc type = SSBaseOffset and: [desc register ~= FPReg]])
- 		  and: [desc liveRegister = NoReg]) ifTrue:
- 			[reg := self allocateRegNotConflictingWith: 0.
- 			 reg = NoReg
- 				ifTrue: [self halt] "have to spill"
- 				ifFalse: [desc storeToReg: reg]]]!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>needsFrame (in category 'accessing') -----
+ needsFrame
+ 	"for asserts"
+ 	<cmacro: '() needsFrame'>
+ 	^needsFrame!

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: [self voidReceiverOptStatus]].
- 			ifFalse:
- 				[optStatus isReceiverResultRegLive: false.
- 				 optStatus ssEntry liveRegister: NoReg]].
  
  	"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 simStackAt: i) reconcilePoppingWith: (self simStack: scratchSimStack at: i).
  		 simStack
  			at: i
  			put: (self
  					cCode: [scratchSimStack at: i]
  					inSmalltalk: [(scratchSimStack at: i) copy])]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>restoreSimStackAtMergePoint: (in category 'simulation stack') -----
  restoreSimStackAtMergePoint: fixup
  	<inline: true>
  	"All the execution paths reaching a merge point expect everything to be spilled
  	 on stack and the optStatus is unknown.  If the merge point follows a return, it
  	 isn't a merge, but a skip past a return.  If it is a real merge point then throw
  	 away all simStack and optStatus optimization state."
+ 	simSelf liveRegister: ((optStatus isReceiverResultRegLive: fixup isReceiverResultRegSelf)
+ 							ifTrue: [ReceiverResultReg]
+ 							ifFalse: [NoReg]).
- 	(optStatus isReceiverResultRegLive: fixup isReceiverResultRegSelf) ifFalse:
- 		[simSelf liveRegister: NoReg].
  	fixup mergeSimStack ifNotNil:
  		[simSpillBase := methodOrBlockNumTemps.
  		 0 to: simStackPtr do:
  			[:i|
  			self cCode: [simStack at: i put: (fixup mergeSimStack at: i)]
  				inSmalltalk: [(simStack at: i) copyFrom: (fixup mergeSimStack at: i)]]].
  	^0!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>simSelfOnStackInReceiverResultReg (in category 'bytecode generator support') -----
+ simSelfOnStackInReceiverResultReg
+ 	"For assert checking only."
+ 	methodOrBlockNumArgs to: simStackPtr do:
+ 		[:i|
+ 		 ((simSelf isSameEntryAs: (self simStackAt: i))
+ 		  and: [(self simStackAt: i) registerOrNone = ReceiverResultReg]) ifTrue:
+ 			[^true]].
+ 	^false!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>voidReceiverOptStatus (in category 'bytecode generator support') -----
+ voidReceiverOptStatus
+ 	"Used to mark ReceiverResultReg as dead or not containing simSelf.
+ 	 Used when the simStack has already been flushed, e.g. for sends."
+ 	<inline: true>
+ 	super voidReceiverOptStatus.
+ 	simSelf liveRegister: NoReg!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>voidReceiverResultRegContainsSelf (in category 'bytecode generator support') -----
+ voidReceiverResultRegContainsSelf
+ 	"Used when ReceiverResultReg is allocated for other than simSelf, and
+ 	 there may be references to ReceiverResultReg which need to be spilled."
+ 	self assert: (simSelf liveRegister = ReceiverResultReg) = optStatus isReceiverResultRegLive.
+ 	optStatus isReceiverResultRegLive ifFalse:
+ 		[self deny: self simSelfOnStackInReceiverResultReg.
+ 		 ^self].
+ 	optStatus isReceiverResultRegLive: false.
+ 	methodOrBlockNumTemps to: simStackPtr do:
+ 		[:i|
+ 		(simSelf isSameEntryAs: (self simStackAt: i)) ifTrue:
+ 			[(self simStackAt: i) liveRegister: NoReg]].
+ 	simSelf liveRegister: NoReg!

Item was removed:
- ----- Method: SimpleStackBasedCogit>>genPushEnclosingObjectBytecode (in category 'bytecode generators') -----
- genPushEnclosingObjectBytecode
- 	"Uncached push enclosing object"
- 	| levelOop |
- 	levelOop := self getLiteral: byte1.
- 	self assert: (objectMemory isIntegerObject: levelOop).
- 	^self genPushEnclosingObjectAt: (objectMemory integerValueOf: levelOop)!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>allocateRegForStackTopThreeEntriesInto:thirdIsReceiver: (in category 'simulation stack') -----
  allocateRegForStackTopThreeEntriesInto: trinaryBlock thirdIsReceiver: thirdIsReceiver
  	"Answers registers for the 3 top values on stack. If the values are already in registers, answers
  	these registers, else allocate registers not conflicting with each others.
  	If thirdIsReceiver is true, allocate ReceiverResultReg for stackTop - 2 (for ceStoreCheck)."
  	<inline: true>
  	| topRegistersMask rTop rNext rThird |
  	
  	topRegistersMask := 0.
  	rTop := rNext := rThird := NoReg.
  	
  	(self ssTop registerOrNone ~= NoReg and: [ thirdIsReceiver not or: [ self ssTop registerOrNone ~= ReceiverResultReg ] ]) ifTrue: 
  		[ topRegistersMask := self registerMaskFor: (rTop := self ssTop registerOrNone)].
  	((self ssValue: 1) registerOrNone ~= NoReg and: [ thirdIsReceiver not or: [ (self ssValue: 1) registerOrNone ~= ReceiverResultReg ] ]) ifTrue: 
  		[ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) registerOrNone))].
  	((self ssValue: 2) registerOrNone ~= NoReg and: [thirdIsReceiver not or: [ (self ssValue: 2) registerOrNone = ReceiverResultReg ] ]) ifTrue: 
  		[ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rThird := (self ssValue: 2) registerOrNone))].
  	
  	rThird = NoReg ifTrue:
  		[ thirdIsReceiver 
  			ifTrue:
  				[ rThird := ReceiverResultReg.  "Free ReceiverResultReg if it was not free"
  				self ssAllocateRequiredReg: ReceiverResultReg.
+ 				self voidReceiverResultRegContainsSelf ]
- 				optStatus isReceiverResultRegLive: false ]
  			ifFalse: [ rThird := self allocateRegNotConflictingWith: topRegistersMask ].
  		topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rThird) ].
  	
  	rTop = NoReg ifTrue:
  		[ rTop := self allocateRegNotConflictingWith: topRegistersMask.
  		  topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rTop) ].
  	
  	rNext = NoReg ifTrue:
  		[ rNext := self allocateRegNotConflictingWith: topRegistersMask ].
  
  	self deny: (rTop = NoReg or: [rNext = NoReg or: [rThird = NoReg]]).
  
  	^ trinaryBlock value: rTop value: rNext value: rThird!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>allocateRegNotConflictingWith: (in category 'simulation stack') -----
  allocateRegNotConflictingWith: regMask
  	| reg |
  	"if there's a free register, use it"
  	reg := backEnd availableRegisterOrNoneFor: (self liveRegisters bitOr: regMask).
  	reg = NoReg ifTrue: "No free register, choose one that does not conflict with regMask"
  		[reg := self freeAnyRegNotConflictingWith: regMask].
  	reg = ReceiverResultReg ifTrue: "If we've allocated RcvrResultReg, it's not live anymore"
+ 		[self voidReceiverResultRegContainsSelf].
- 		[optStatus isReceiverResultRegLive: false].
  	^ reg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genExtPushFullClosureBytecode (in category 'bytecode generators') -----
  genExtPushFullClosureBytecode
  	"Full Block creation compilation. The block's actual code will be compiled separatedly."
  	"*	255		11111111	xxxxxxxx	siyyyyyy	push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1"
  	| numCopied ignoreContext receiverIsOnStack compiledBlock reg |
  	self assert: needsFrame.
  	compiledBlock := self getLiteral: byte1 + (extA << 8).
  	extA := 0.
  	numCopied := byte2 bitAnd: 1<< 6 - 1.
  	receiverIsOnStack := byte2 anyMask: 1 << 7.
  	ignoreContext := byte2 anyMask: 1 << 6.
+ 	self voidReceiverResultRegContainsSelf.
- 	optStatus isReceiverResultRegLive: false.
  	self ssAllocateCallReg: ReceiverResultReg
  		and: SendNumArgsReg
  		and: ClassReg.
  	objectRepresentation
  		genCreateFullClosure: compiledBlock
  		numArgs: (coInterpreter argumentCountOf: compiledBlock)
  		numCopied: numCopied
  		ignoreContext: ignoreContext
  		contextNumArgs: methodOrBlockNumArgs
  		large: (coInterpreter methodNeedsLargeContext: methodObj)
  		inBlock: inBlock.
  	"Closure in ReceiverResultReg"
  	1 to: numCopied do:
  		[:i| 
  		reg := self ssStorePop: true toPreferredReg: TempReg.
  		 objectRepresentation
  			genStoreSourceReg: reg
  			slotIndex: FullClosureFirstCopiedValueIndex + numCopied - i
  			intoNewObjectInDestReg: ReceiverResultReg].
  	receiverIsOnStack
  		ifTrue: [reg := self ssStorePop: true toPreferredReg: TempReg]
  		ifFalse: [(self addressOf: simSelf) storeToReg: (reg := TempReg)].
  	objectRepresentation
  			genStoreSourceReg: reg
  			slotIndex: FullClosureReceiverIndex
  			intoNewObjectInDestReg: ReceiverResultReg.
  	self ssPushRegister: ReceiverResultReg.
  	^0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genInlineClosure:numArgs:numCopied: (in category 'bytecode generator support') -----
  genInlineClosure: startpc numArgs: numArgs numCopied: numCopied
  	<inline: true>
  	self assert: objectRepresentation getActiveContextAllocatesInMachineCode.
+ 	 self voidReceiverResultRegContainsSelf.
- 	 optStatus isReceiverResultRegLive: false.
  	 self ssAllocateCallReg: ReceiverResultReg
  		and: SendNumArgsReg
  		and: ClassReg.
  	 objectRepresentation
  		genNoPopCreateClosureAt: startpc + 1 "1 relative"
  		numArgs: numArgs
  		numCopied: numCopied
  		contextNumArgs: methodOrBlockNumArgs
  		large: (coInterpreter methodNeedsLargeContext: methodObj)
  		inBlock: inBlock.
  	 1 to: numCopied do:
  		[:i| | reg |
  		 reg := self ssStorePop: true toPreferredReg: TempReg.
  		 objectRepresentation
  			genStoreSourceReg: reg
  			slotIndex: ClosureFirstCopiedValueIndex + numCopied - i
  			intoNewObjectInDestReg: ReceiverResultReg].
  	 self ssPushRegister: ReceiverResultReg
  !

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genLoadLiteralVariable:in: (in category 'bytecode generator support') -----
  genLoadLiteralVariable: litVarIndex in: destReg
  	<inline: true>
  	| association |
  	association := self getLiteral: litVarIndex.
+ 	destReg = ReceiverResultReg ifTrue: [self voidReceiverResultRegContainsSelf].
- 	destReg = ReceiverResultReg ifTrue: [ optStatus isReceiverResultRegLive: false ].
  	self ssAllocateRequiredReg: destReg.
  	self genMoveConstant: association R: destReg.
  	objectRepresentation genEnsureObjInRegNotForwarded: destReg scratchReg: TempReg.!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genLoadTemp:in: (in category 'bytecode generator support') -----
  genLoadTemp: objectIndex in: destReg
+ 	destReg = ReceiverResultReg ifTrue: [self voidReceiverResultRegContainsSelf].
- 	destReg = ReceiverResultReg ifTrue: [ optStatus isReceiverResultRegLive: false ].
  	self ssAllocateRequiredReg: destReg. 
  	self MoveMw: (self frameOffsetOfTemporary: objectIndex) r: FPReg R: destReg.!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genMarshalledSend:numArgs:sendTable: (in category 'bytecode generator support') -----
  genMarshalledSend: selectorIndex numArgs: numArgs sendTable: sendTable
  	<inline: false>
  	<var: #sendTable type: #'sqInt *'>
  	| annotation |
  	self assert: needsFrame.
  	annotation := self annotationForSendTable: sendTable.
  	"Deal with stale super sends; see SpurMemoryManager's class comment."
  	(self annotationIsForUncheckedEntryPoint: annotation) ifTrue:
  		[objectRepresentation genEnsureOopInRegNotForwarded: ReceiverResultReg scratchReg: TempReg].
  	"0 through (NumSendTrampolines - 2) numArgs sends have the arg count implciti in the trampoline.
  	 The last send trampoline (NumSendTrampolines - 1) passes numArgs in SendNumArgsReg."
  	numArgs >= (NumSendTrampolines - 1) ifTrue:
  		[self MoveCq: numArgs R: SendNumArgsReg].
  	(BytecodeSetHasDirectedSuperSend
  	 and: [annotation = IsDirectedSuperSend]) ifTrue:
  		[self genMoveConstant: tempOop R: TempReg].
  	self genLoadInlineCacheWithSelector: selectorIndex.
  	(self Call: (sendTable at: (numArgs min: NumSendTrampolines - 1))) annotation: annotation.
+ 	self voidReceiverOptStatus.
- 	optStatus isReceiverResultRegLive: false.
  	^self ssPushRegister: ReceiverResultReg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genNSSend:numArgs:depth:sendTable: (in category 'bytecode generators') -----
  genNSSend: selectorIndex numArgs: numArgs depth: depth sendTable: sendTable
  	<var: #sendTable type: #'sqInt *'>
  	| selector nsSendCache |
  	self assert: (selectorIndex between: 0 and: (objectMemory literalCountOf: methodObj) - 1).
  	selector := self getLiteral: selectorIndex.
  	self assert: (objectMemory addressCouldBeOop: selector).	
  	(objectMemory isYoung: selector) ifTrue:
  		[hasYoungReferent := true].
  
  	nsSendCache := theIRCs + (NumOopsPerNSC * objectMemory bytesPerOop * indexOfIRC).
  	indexOfIRC := indexOfIRC + 1.
  	self assert: (objectMemory isInOldSpace: nsSendCache).
  	self initializeNSSendCache: nsSendCache selector: selector numArgs: numArgs depth: depth.
  
  	self ssAllocateCallReg: SendNumArgsReg.
  
  	"This may leave the method receiver on the stack, which might not be the implicit receiver.
  	 But the lookup trampoline will establish an on-stack receiver once it locates it."
  	self marshallAbsentReceiverSendArguments: numArgs.
  
  	"Load the cache last so it is a fixed distance from the call."
  	self MoveUniqueCw: nsSendCache R: SendNumArgsReg.
  	self CallNewspeakSend: (sendTable at: (numArgs min: NumSendTrampolines - 1)).
  
+ 	self voidReceiverOptStatus.
- 	optStatus isReceiverResultRegLive: false.
  	self ssPushRegister: ReceiverResultReg.
  	^0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genOutlineClosure:numArgs:numCopied: (in category 'bytecode generator support') -----
  genOutlineClosure: startpc numArgs: numArgs numCopied: numCopied
  	<inline: true>
  	numCopied > 0 ifTrue:
  		[self ssFlushTo: simStackPtr].
+ 	self voidReceiverResultRegContainsSelf.
- 	optStatus isReceiverResultRegLive: false.
  	objectRepresentation getActiveContextAllocatesInMachineCode
  		ifTrue: [self ssAllocateCallReg: ReceiverResultReg
  					and: SendNumArgsReg
  					and: ClassReg]
  		ifFalse: [self ssAllocateCallReg: SendNumArgsReg
  					and: ReceiverResultReg].
  	objectRepresentation
  		genCreateClosureAt: startpc + 1 "1 relative"
  		numArgs: numArgs
  		numCopied: numCopied
  		contextNumArgs: methodOrBlockNumArgs
  		large: (coInterpreter methodNeedsLargeContext: methodObj)
  		inBlock: inBlock.
  	numCopied > 0 ifTrue:
  		[self ssPop: numCopied].
  	self ssPushRegister: ReceiverResultReg
  !

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPushActiveContextBytecode (in category 'bytecode generators') -----
  genPushActiveContextBytecode
  	self assert: needsFrame.
+ 	self voidReceiverResultRegContainsSelf.
- 	optStatus isReceiverResultRegLive: false.
  	objectRepresentation getActiveContextAllocatesInMachineCode
  		ifTrue: [self ssAllocateCallReg: ReceiverResultReg
  					and: SendNumArgsReg
  					and: ClassReg]
  		ifFalse: [self ssAllocateCallReg: ReceiverResultReg].
  	objectRepresentation
  		genGetActiveContextNumArgs: methodOrBlockNumArgs
  		large: (coInterpreter methodNeedsLargeContext: methodObj)
  		inBlock: inBlock.
  	^self ssPushRegister: ReceiverResultReg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPushEnclosingObjectAt: (in category 'bytecode generator support') -----
  genPushEnclosingObjectAt: level
  	"Uncached push enclosing object"
+ 	self voidReceiverResultRegContainsSelf.
- 	optStatus isReceiverResultRegLive: false.
  	self ssAllocateCallReg: SendNumArgsReg and: ReceiverResultReg.
  	self MoveCq: level R: SendNumArgsReg.
  	self CallRT: ceEnclosingObjectTrampoline.
  	^self ssPushRegister: ReceiverResultReg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPushMaybeContextSlotIndex: (in category 'bytecode generator support') -----
  genPushMaybeContextSlotIndex: slotIndex
  	<inline: true>
  	"This method expects ReceiverResultReg to hold the object read"
  	| jmpSingle jmpDone |
  	<var: #jmpSingle type: #'AbstractInstruction *'>
  	<var: #jmpDone type: #'AbstractInstruction *'>
  	self assert: needsFrame.
  	(self isCallerSavedReg: ReceiverResultReg) ifTrue:
  		["We have no way of reloading ReceiverResultReg since we need the inst var value as the result."
+ 		self voidReceiverResultRegContainsSelf].
- 		optStatus isReceiverResultRegLive: false].
  	"See CoInterpreter>>contextInstructionPointer:frame: for an explanation
  	 of the instruction pointer slot handling."
  	slotIndex = InstructionPointerIndex ifTrue:
  		[self MoveCq: slotIndex R: SendNumArgsReg.
  		 self CallRT: ceFetchContextInstVarTrampoline.
  		 ^self ssPushRegister: SendNumArgsReg].
  	objectRepresentation
  		genLoadSlot: SenderIndex
  		sourceReg: ReceiverResultReg
  		destReg: TempReg.
  	jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.
  	self MoveCq: slotIndex R: SendNumArgsReg.
  	self CallRT: ceFetchContextInstVarTrampoline.
  	jmpDone := self Jump: 0.
  	jmpSingle jmpTarget: self Label.
  	objectRepresentation
  		genLoadSlot: slotIndex
  		sourceReg: ReceiverResultReg
  		destReg: SendNumArgsReg.
  	jmpDone jmpTarget: self Label.
  	^self ssPushRegister: SendNumArgsReg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPushNewArrayBytecode (in category 'bytecode generators') -----
  genPushNewArrayBytecode
  	| size popValues |
  	self assert: needsFrame.
+ 	self voidReceiverResultRegContainsSelf.
- 	optStatus isReceiverResultRegLive: false.
  	(popValues := byte1 > 127)
  		ifTrue: [self ssFlushTo: simStackPtr]
  		ifFalse: [self ssAllocateCallReg: SendNumArgsReg and: ReceiverResultReg].
  	size := byte1 bitAnd: 127.
  	popValues ifFalse:
  		[(self tryCollapseTempVectorInitializationOfSize: size) ifTrue:
  			[^0]].
  	objectRepresentation genNewArrayOfSize: size initialized: popValues not.
  	popValues ifTrue:
  		[size - 1 to: 0 by: -1 do:
  			[:i|
  			self PopR: TempReg.
  			objectRepresentation
  				genStoreSourceReg: TempReg
  				slotIndex: i
  				intoNewObjectInDestReg: ReceiverResultReg].
  		 self ssPop: size].
  	^self ssPushRegister: ReceiverResultReg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPushReceiverBytecode (in category 'bytecode generators') -----
  genPushReceiverBytecode
  	optStatus isReceiverResultRegLive ifTrue:
  		[^self ssPushRegister: ReceiverResultReg].
+ 	self assert: simSelf registerOrNone = NoReg.
- 	self assert: simSelf liveRegister = NoReg.
  	^self ssPushDesc: simSelf!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genStorePop:RemoteTemp:At:needsStoreCheck: (in category 'bytecode generator stores') -----
  genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex needsStoreCheck: needsStoreCheck
  	<inline: false>
  	"The only reason we assert needsFrame here is that in a frameless method
  	 ReceiverResultReg must and does contain only self, but the ceStoreCheck
  	 trampoline expects the target of the store to be in ReceiverResultReg.  So
  	 in a frameless method we would have a conflict between the receiver and
  	 the temote temp store, unless we we smart enough to realise that
  	 ReceiverResultReg was unused after the literal variable store, unlikely given
  	 that methods return self by default."
  	self assert: needsFrame.
  	"N.B.  No need to check the stack for references because we generate code for
  	 remote temp loads that stores the result in a register, deferring only the register push."
  	self ssAllocateRequiredReg: ReceiverResultReg. 
+ 	self voidReceiverResultRegContainsSelf.
- 	optStatus isReceiverResultRegLive: false.
  	self MoveMw: (self frameOffsetOfTemporary: remoteTempIndex) r: FPReg R: ReceiverResultReg.
  	^self 
  		genGenericStorePop: popBoolean 
  		slotIndex: slotIndex 
  		destReg: ReceiverResultReg 
  		needsStoreCheck: needsStoreCheck
  		needsRestoreRcvr: false "We don't keep ReceiverResultReg live with the receiver across this operation"
  		needsImmutabilityCheck: false "never do immutability check on temp vectors"!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>restoreSimStackAtMergePoint: (in category 'simulation stack') -----
  restoreSimStackAtMergePoint: fixup
  	<inline: true>
  	"All the execution paths reaching a merge point expect everything to be
  	spilled on stack and the optStatus is unknown. Throw away all simStack and 
  	optStatus optimization state."
  	simSpillBase := methodOrBlockNumTemps.
+ 	self voidReceiverOptStatus.
- 	optStatus isReceiverResultRegLive: false.
  	methodOrBlockNumTemps to: simStackPtr do:
  		[:i|
+ 		 (self simStackAt: i)
+ 			type: SSSpill;
+ 			offset: FoxMFReceiver - (i - methodOrBlockNumArgs + 1 * objectMemory bytesPerOop);
+ 			register: FPReg;
+ 			spilled: true].
+ 	LowcodeVM ifTrue:
+ 		[0 to: simNativeStackPtr do:
+ 			[ :i |
- 			(self simStackAt: i)
- 				type: SSSpill;
- 				offset: FoxMFReceiver - (i - methodOrBlockNumArgs + 1 * objectMemory bytesPerOop);
- 				register: FPReg;
- 				spilled: true].
- 	LowcodeVM ifTrue: [
- 		0 to: simNativeStackPtr do: [ :i |
  			(self simNativeStackAt: i)
+ 				ensureIsMarkedAsSpilled].
+ 		simNativeSpillBase := simNativeStackPtr + 1].
- 				ensureIsMarkedAsSpilled
- 		].
- 		simNativeSpillBase := simNativeStackPtr + 1
- 	].
  	^ 0!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>voidReceiverOptStatus (in category 'bytecode generator support') -----
+ voidReceiverOptStatus
+ 	"Used to mark ReceiverResultReg as dead or not containing simSelf.
+ 	 Used when the simStack has already been flushed, e.g. for sends."
+ 	<inline: true>
+ 	optStatus isReceiverResultRegLive: false!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>voidReceiverResultRegContainsSelf (in category 'bytecode generator support') -----
+ voidReceiverResultRegContainsSelf
+ 	"Used when ReceiverResultReg is allocated for other than simSelf, and
+ 	 there may be references to ReceiverResultReg which need to be spilled."
+ 	| spillIndex |
+ 	optStatus isReceiverResultRegLive: false.
+ 	spillIndex := -1.
+ 	(methodOrBlockNumTemps max: simSpillBase) to: simStackPtr do:
+ 		[:i|
+ 		(self simStackAt: i) registerOrNone = ReceiverResultReg ifTrue:
+ 			[spillIndex := i]].
+ 	spillIndex > 0 ifTrue:
+ 		[self ssFlushTo: simStackPtr - spillIndex]!



More information about the Vm-dev mailing list