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

commits at source.squeak.org commits at source.squeak.org
Fri Mar 4 01:04:42 UTC 2016


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

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

Name: VMMaker.oscog-eem.1707
Author: eem
Time: 3 March 2016, 5:02:18.222299 pm
UUID: 6073be04-c0ce-4791-8ada-b2d1ec54f4a4
Ancestors: VMMaker.oscog-tfel.1706

Cogit:
Revise the register saving convention for trampoline calls.  Instead of passing in a boolean to indicate if all registers should be saved or not (an aproach Ryan correctly notes is bogus), pass in a register mask of registers to be saved.  If the trampoline call has a machine code continuation then the argument is usually callerSavedRegMask, and on MIPS and ARM this is empty.

Use the above to move the saving of registers in the store-check into the store-check trampoline and out of the call of the trampoline.  Further, use genJumpImmediate: in the immediate test, which saves an instruction.

Nuke some obsolete methods.

Simulator:
Change the ByteCountsPerMicrosecond to better accord with a contemporary Mac.

=============== Diff against VMMaker.oscog-tfel.1706 ===============

Item was removed:
- ----- Method: CogARMCompiler>>genRestoreRegs (in category 'abi') -----
- genRestoreRegs
- 	"Restore the general purpose registers for a trampoline call."
- 	"Restore none, because the ARM ABI only defines callee saved registers, no caller-saved regs."
- 	"cogit gen: LDMFD operand: 16r7F"!

Item was added:
+ ----- Method: CogARMCompiler>>genRestoreRegs: (in category 'abi') -----
+ genRestoreRegs: regMask
+ 	"Restore the registers in regMask as saved by genSaveRegs:.
+ 	 Restore none, because the ARM ABI only defines callee saved registers, no caller-saved regs.
+ 	 But for the future..."
+ 	self assert: regMask = 0.
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: SP and: FPReg and: LR and: PC)).
+ 	R0 to: R12 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PopR: reg]].
+ 	^0!

Item was added:
+ ----- Method: CogARMCompiler>>genSaveRegs: (in category 'abi') -----
+ genSaveRegs: regMask
+ 	"Save the registers in regMask for a call into the C run-time from a trampoline.
+ 	 Save none, because the ARM ABI only defines callee saved registers, no caller-saved regs.
+ 	 But for the future..."
+ 	self assert: regMask = 0.
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: SP and: FPReg and: LR and: PC)).
+ 	R12 to: R0 by: -1 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PushR: reg]].
+ 	^0!

Item was removed:
- ----- Method: CogARMCompiler>>genSaveRegsForCCall (in category 'abi') -----
- genSaveRegsForCCall
- 	"Save the general purpose registers for a trampoline call."
- 	"Save none, because the ARM ABI only defines callee saved registers, no caller-saved regs."
- 	"cogit gen: STMFD operand: 16r7F"
- 	self flag: 'this will change with Sista when we hope to be able to allocate arbitrary registers'!

Item was changed:
  ----- Method: CogAbstractInstruction>>genAlignCStackSavingRegisters:numArgs:wordAlignment: (in category 'abi') -----
+ genAlignCStackSavingRegisters: registerMask numArgs: numArgs wordAlignment: alignment
+ 	<inline: true>
+ 	| regMaskCopy numRegsPushed wordsPushedModAlignment delta |
+ 	<var: 'regMaskCopy' type: #usqInt>
+ 	regMaskCopy := registerMask asUnsignedInteger.
+ 	numRegsPushed := 0.
+ 	[regMaskCopy ~= 0] whileTrue:
+ 		[numRegsPushed := numRegsPushed + (regMaskCopy bitAnd: 1).
+ 		 regMaskCopy := regMaskCopy bitShift: -1].
+ 	(numRegsPushed = 0
+ 	 and: [self numIntRegArgs >= numArgs]) ifTrue:
- genAlignCStackSavingRegisters: saveRegs numArgs: numArgs wordAlignment: alignment 
- 	| wordsPushedModAlignment delta |
- 	self numIntRegArgs >= (saveRegs
- 								ifTrue: [self numberOfSaveableRegisters + numArgs]
- 								ifFalse: [numArgs])  ifTrue:
  		[^0].
+ 	wordsPushedModAlignment := numRegsPushed + numArgs \\ alignment.
- 	wordsPushedModAlignment := ((saveRegs ifTrue: [self numberOfSaveableRegisters] ifFalse: [0])
- 									+ numArgs)
- 									\\ alignment.
  	wordsPushedModAlignment ~= 0 ifTrue:
  		[delta := alignment - wordsPushedModAlignment.
  		 cogit SubCq: delta * objectMemory wordSize R: SPReg].
  	^0!

Item was removed:
- ----- Method: CogAbstractInstruction>>maxAbstractGeneralPurposeReg (in category 'accessing') -----
- maxAbstractGeneralPurposeReg
- 	"Answer the largest index of an abstract general-purpose register used by this compiler.
- 	 N.B.  Abstract registers are negative numbers."
- 	<inline: true>
- 	^ReceiverResultReg!

Item was removed:
- ----- Method: CogIA32Compiler>>genRestoreRegs (in category 'abi') -----
- genRestoreRegs
- 	EAX to: EDI do:
- 		[:reg|
- 		 (reg between: ESP and: EBP) ifFalse:
- 			[cogit PopR: reg]].
- 	^0!

Item was added:
+ ----- Method: CogIA32Compiler>>genRestoreRegs: (in category 'abi') -----
+ genRestoreRegs: regMask
+ 	"Restore the registers in regMask as saved by genSaveRegs:."
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: ESP and: EBP)).
+ 	EAX to: EDI do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PopR: reg]].
+ 	^0!

Item was added:
+ ----- Method: CogIA32Compiler>>genSaveRegs: (in category 'abi') -----
+ genSaveRegs: regMask
+ 	"Save the registers in regMask for a call into the C run-time from a trampoline."
+ 
+ 	self assert: (EDI > EAX and: [EDI - EAX + 1 = 8]).
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: ESP and: EBP)).
+ 	EDI to: EAX by: -1 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PushR: reg]].
+ 	^0!

Item was removed:
- ----- Method: CogIA32Compiler>>genSaveRegsForCCall (in category 'abi') -----
- genSaveRegsForCCall
- 	"Save the general purpose registers for a call into the C run-time from a trampoline."
- 
- 	self assert: (EDI > EAX and: [EDI - EAX + 1 = 8]).
- 	EDI to: EAX by: -1 do:
- 		[:reg|
- 		 (reg between: ESP and: EBP) ifFalse:
- 			[cogit PushR: reg]].
- 	^0!

Item was removed:
- ----- Method: CogMIPSELCompiler>>genRestoreRegs (in category 'abi') -----
- genRestoreRegs
- 	"This method is poorly named. Is this for a Smalltalk -> C call or C -> Smalltalk call?
- 	 If the former we don't need to do anything because all of the abstract registers are
- 	 allocated to C preserved registers."
- 	self flag: #bogus.!

Item was added:
+ ----- Method: CogMIPSELCompiler>>genRestoreRegs: (in category 'abi') -----
+ genRestoreRegs: regMask
+ 	"Restore the registers in regMask as saved by genSaveRegs:.
+ 	 We don't need to do anything because all of the abstract registers are
+ 	 allocated to C preserved registers.  But for the future..."
+ 	self assert: regMask = 0.
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: SP and: FP and: RA)).
+ 	R0 to: R28 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PopR: reg]].
+ 	^0!

Item was added:
+ ----- Method: CogMIPSELCompiler>>genSaveRegs: (in category 'abi') -----
+ genSaveRegs: regMask
+ 	"Save the registers in regMask for a call into the C run-time from a trampoline.
+ 	 We don't need to do anything because all of the abstract registers are
+ 	 allocated to C preserved registers.  But for the future..."
+ 	self assert: regMask = 0.
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: SP and: FP and: RA)).
+ 	R28 to: R0 by: -1 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PushR: reg]].
+ 	^0!

Item was removed:
- ----- Method: CogMIPSELCompiler>>genSaveRegsForCCall (in category 'abi') -----
- genSaveRegsForCCall
- 	"Save the general purpose registers for a call into the C run-time from a trampoline.
- 	 We don't need to do anything because all of the abstract registers are
- 	 allocated to C preserved registers."
- 	self flag: 'this will change with Sista when we hope to be able to allocate arbitrary registers'!

Item was removed:
- ----- Method: CogMIPSELCompiler>>maxAbstractGeneralPurposeReg (in category 'accessing') -----
- maxAbstractGeneralPurposeReg
- 	"Answer the largest index of an abstract general-purpose register used by this compiler.
- 	 N.B.  Abstract registers are negative numbers."
- 	<inline: true>
- 	self flag: #bogus. "The caller should ask for a register mask, not a range."
- 	^TempReg!

Item was removed:
- ----- Method: CogObjectRepresentationForSpur>>genJumpImmediateInScratchReg: (in category 'compile abstract instructions') -----
- genJumpImmediateInScratchReg: aRegister
- 	<returnTypeC: #'AbstractInstruction *'>
- 	cogit AndCq: objectMemory tagMask R: aRegister.
- 	^cogit JumpNonZero: 0!

Item was removed:
- ----- Method: CogObjectRepresentationForSpur>>genJumpImmutable:scratchReg: (in category 'compile abstract instructions') -----
- genJumpImmutable: sourceReg scratchReg: scratchReg
- 	<returnTypeC: #'AbstractInstruction *'>
- 	<option: #IMMUTABILITY>
- 	cogit MoveMw: 0 r: sourceReg R: scratchReg. 
- 	^ self genJumpBaseHeaderImmutable: scratchReg!

Item was removed:
- ----- Method: CogObjectRepresentationForSpur>>genJumpNotImmediateInScratchReg: (in category 'compile abstract instructions') -----
- genJumpNotImmediateInScratchReg: aRegister
- 	<returnTypeC: #'AbstractInstruction *'>
- 	cogit AndCq: objectMemory tagMask R: aRegister.
- 	^cogit JumpZero: 0!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>genStoreCheckReceiverReg:valueReg:scratchReg:inFrame: (in category 'compile abstract instructions') -----
  genStoreCheckReceiverReg: destReg valueReg: valueReg scratchReg: scratchReg inFrame: inFrame
  	"Generate the code for a store check of valueReg into destReg."
  	| jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRemembered mask rememberedBitByteOffset |
  	<var: #jmpImmediate type: #'AbstractInstruction *'>
  	<var: #jmpDestYoung type: #'AbstractInstruction *'>
  	<var: #jmpSourceOld type: #'AbstractInstruction *'>
  	<var: #jmpAlreadyRemembered type: #'AbstractInstruction *'>
+ 	"Is value stored an immediate?  If so we're done"
+ 	jmpImmediate := self genJumpImmediate: valueReg.
- 	"Is value stored an integer?  If so we're done"
- 	cogit MoveR: valueReg R: scratchReg.
- 	cogit AndCq: objectMemory tagMask R: scratchReg.
- 	jmpImmediate := cogit JumpNonZero: 0.
  	"Get the old/new boundary in scratchReg"
  	cogit MoveCw: objectMemory storeCheckBoundary R: scratchReg.
  	"Is target young?  If so we're done"
  	cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg - scratchReg"
  	jmpDestYoung := cogit JumpBelow: 0.
  	"Is value stored old?  If so we're done."
  	cogit CmpR: scratchReg R: valueReg. "N.B. FLAGS := valueReg - scratchReg"
  	jmpSourceOld := cogit JumpAboveOrEqual: 0.
  	"value is young and target is old.
  	 Need to remember this only if the remembered bit is not already set.
  	 Test the remembered bit.  Only need to fetch the byte containing it,
  	 which reduces the size of the mask constant."
  	rememberedBitByteOffset := jmpSourceOld isBigEndian
  									ifTrue: [objectMemory baseHeaderSize - 1 - (objectMemory rememberedBitShift // 8)]
  									ifFalse:[objectMemory rememberedBitShift // 8].
  	mask := 1 << (objectMemory rememberedBitShift \\ 8).
  	cogit MoveMb: rememberedBitByteOffset r: destReg R: scratchReg.
  	cogit AndCq: mask R: scratchReg.
  	jmpAlreadyRemembered := cogit JumpNonZero: 0.
  	"Remembered bit is not set.  Call store check to insert dest into remembered table."
+ 	self assert: destReg = ReceiverResultReg.
- 	self assert: destReg == ReceiverResultReg.
  	cogit 
+ 		evaluateTrampolineCallBlock: [cogit CallRT: ceStoreCheckTrampoline]
- 		evaluateTrampolineCallBlock:
- 			[cogit
- 				CallRT: ceStoreCheckTrampoline
- 				registersToBeSavedMask: (((cogit registerMaskFor: valueReg)
- 												bitOr: cogit callerSavedRegMask)
- 												bitClear: (cogit registerMaskFor: ReceiverResultReg and: scratchReg))]
  		protectLinkRegIfNot: inFrame.
  	jmpImmediate jmpTarget:
  	(jmpDestYoung jmpTarget:
  	(jmpSourceOld jmpTarget:
  	(jmpAlreadyRemembered jmpTarget:
  		cogit Label))).
  	^0!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>generateObjectRepresentationTrampolines (in category 'initialization') -----
  generateObjectRepresentationTrampolines
  	"Do the store check.  Answer the argument for the benefit of the code generator;
  	 ReceiverResultReg may be caller-saved and hence smashed by this call.  Answering
  	 it allows the code generator to reload ReceiverResultReg cheaply.
  	 In Spur the only thing we leave to the run-time is adding the receiver to the
  	 remembered set and setting its isRemembered bit."
  	self 
  		cppIf: IMMUTABILITY
  		ifTrue: "c.f. genImmutableCheck:slotIndex:sourceReg:scratchReg:popBoolean:needRestoreRcvr:"
  			[ceCannotAssignToWithIndexTrampoline := cogit
  															genTrampolineFor: #ceCannotAssignTo:withIndex:valueToAssign:
  															called: 'ceCannotAssignToWithIndexTrampoline'
  															arg: ReceiverResultReg 
  															arg: TempReg
  															arg: ClassReg].
  	ceStoreCheckTrampoline := cogit
  									genTrampolineFor: #remember:
  									called: 'ceStoreCheckTrampoline'
  									arg: ReceiverResultReg
+ 									regsToSave: (cogit callerSavedRegMask bitClear: (cogit registerMaskFor: ReceiverResultReg))
  									result: cogit returnRegForStoreCheck.
  	ceStoreCheckContextReceiverTrampoline := self genStoreCheckContextReceiverTrampoline.
  	ceScheduleScavengeTrampoline := cogit
+ 											genTrampolineFor: #ceScheduleScavenge
+ 											called: 'ceScheduleScavengeTrampoline'
+ 											regsToSave: cogit callerSavedRegMask.
- 											genSafeTrampolineFor: #ceScheduleScavenge
- 											called: 'ceScheduleScavengeTrampoline'.
  	ceSmallActiveContextInMethodTrampoline := self genActiveContextTrampolineLarge: false inBlock: false called: 'ceSmallMethodContext'.
  	ceSmallActiveContextInBlockTrampoline := self genActiveContextTrampolineLarge: false inBlock: true called: 'ceSmallBlockContext'.
  	ceLargeActiveContextInMethodTrampoline := self genActiveContextTrampolineLarge: true inBlock: false called: 'ceLargeMethodContext'.
  	ceLargeActiveContextInBlockTrampoline := self genActiveContextTrampolineLarge: true inBlock: true called: 'ceLargeBlockContext'!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>maybeCompileRetry:onPrimitiveFail: (in category 'primitive generators') -----
  maybeCompileRetry: retryInst onPrimitiveFail: primIndex
  	<var: #retryInst type: #'AbstractInstruction *'>
  	"If primIndex has an accessorDepth, check for primitive failure and call
  	 ceCheckForAndFollowForwardedPrimitiveState if so  If ceCheck.... answers
  	 true, retry the primitive."
  	| jmp |
  	<var: #jmp type: #'AbstractInstruction *'>
  	(coInterpreter accessorDepthForPrimitiveIndex: primIndex) < 0 ifTrue:
  		[^0].
  	cogit MoveAw: coInterpreter primFailCodeAddress R: TempReg.
  	cogit CmpCq: 0 R: TempReg.
  	jmp := cogit JumpZero: 0.
  	cogit
  		compileCallFor: #ceCheckForAndFollowForwardedPrimitiveState
  		numArgs: 0
  		arg: nil
  		arg: nil
  		arg: nil
  		arg: nil
  		resultReg: TempReg
+ 		regsToSave: cogit emptyRegisterMask.
- 		saveRegs: false.
  	cogit CmpCq: 0 R: TempReg.
  	cogit JumpNonZero: retryInst.
  	jmp jmpTarget: cogit Label.
  	^0!

Item was changed:
  ----- Method: CogObjectRepresentationForSqueakV3>>genActiveContextTrampoline (in category 'initialization') -----
  genActiveContextTrampoline
  	"Short-circuit the interpreter call if a frame is already married."
  	| jumpSingle |
  	<var: #jumpSingle type: #'AbstractInstruction *'>
  	cogit
  		zeroOpcodeIndex;
  		MoveMw: FoxMethod r: FPReg R: TempReg;
  		AndCq: MFMethodFlagHasContextFlag R: TempReg.
  	jumpSingle := cogit JumpZero: 0.
  	cogit
  		MoveMw: FoxThisContext r: FPReg R: ReceiverResultReg;
  		RetN: 0.
  	jumpSingle jmpTarget: cogit Label.
  	^cogit genTrampolineFor: #ceActiveContext
  		called: 'ceActiveContextTrampoline'
  		numArgs: 0
  		arg: nil
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: cogit emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: ReceiverResultReg
  		appendOpcodes: true!

Item was removed:
- ----- Method: CogObjectRepresentationForSqueakV3>>genJumpImmediateInScratchReg: (in category 'compile abstract instructions') -----
- genJumpImmediateInScratchReg: aRegister
- 	^self genJumpSmallIntegerInScratchReg: aRegister!

Item was changed:
  ----- Method: CogObjectRepresentationForSqueakV3>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: (in category 'compile abstract instructions') -----
  genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck
  	| jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRoot mask rootBitByteOffset |
  	<var: #jmpImmediate type: #'AbstractInstruction *'>
  	<var: #jmpDestYoung type: #'AbstractInstruction *'>
  	<var: #jmpSourceOld type: #'AbstractInstruction *'>
  	<var: #jmpAlreadyRoot type: #'AbstractInstruction *'>
  	"do the store"
  	cogit MoveR: sourceReg Mw: index * objectMemory wordSize + objectMemory baseHeaderSize r: destReg.
  	"if no need for the store check then returns"
  	needsStoreCheck ifFalse: [ ^ 0 ].
  	"now the check.  Is value stored an integer?  If so we're done"
+ 	jmpImmediate := self genJumpImmediate: sourceReg.
- 	cogit MoveR: sourceReg R: scratchReg.
- 	cogit AndCq: 1 R: scratchReg.
- 	jmpImmediate := cogit JumpNonZero: 0.
  	"Get the old/new boundary in scratchReg"
  	cogit MoveAw: objectMemory youngStartAddress R: scratchReg.
  	"Is target young?  If so we're done"
  	cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg - scratchReg"
  	jmpDestYoung := cogit JumpAboveOrEqual: 0.
  	"Is value stored old?  If so we're done."
  	cogit CmpR: scratchReg R: sourceReg. "N.B. FLAGS := sourceReg - scratchReg"
  	jmpSourceOld := cogit JumpBelow: 0.
  	"value is young and target is old.
  	 Need to make this a root if the root bit is not already set.
  	 Test the root bit.  Only need to fetch the byte containing it,
  	 which reduces the size of the mask constant."
  	rootBitByteOffset := jmpSourceOld isBigEndian
  							ifTrue: [objectMemory wordSize - RootBitDigitLength]
  							ifFalse:[RootBitDigitLength - 1].
  	mask := RootBitDigitLength > 1
  				ifTrue: [RootBit >> (RootBitDigitLength - 1 * 8)]
  				ifFalse: [RootBit].
  	cogit MoveMb: rootBitByteOffset r: destReg R: scratchReg.
  	cogit AndCq: mask R: scratchReg.
  	jmpAlreadyRoot := cogit JumpNonZero: 0.
  	"Root bit is not set.  Call store check to insert dest into root table."
  	self assert: destReg == ReceiverResultReg.
  	cogit 
+ 		evaluateTrampolineCallBlock: [cogit CallRT: ceStoreCheckTrampoline]
- 		evaluateTrampolineCallBlock: 
- 			[cogit
- 				CallRT: ceStoreCheckTrampoline
- 				registersToBeSavedMask: (((cogit registerMaskFor: sourceReg)
- 												bitOr: cogit callerSavedRegMask)
- 												bitClear: (cogit registerMaskFor: ReceiverResultReg))]
  		protectLinkRegIfNot: inFrame.
  	jmpImmediate jmpTarget:
  	(jmpDestYoung jmpTarget:
  	(jmpSourceOld jmpTarget:
  	(jmpAlreadyRoot jmpTarget:
  		cogit Label))).
  	^0!

Item was changed:
  ----- Method: CogObjectRepresentationForSqueakV3>>generateObjectRepresentationTrampolines (in category 'initialization') -----
  generateObjectRepresentationTrampolines
  	"Do the store check.  Answer the argument for the benefit of the code generator;
  	 ReceiverResultReg may be caller-saved and hence smashed by this call.  Answering
  	 it allows the code generator to reload ReceiverResultReg cheaply."
  	ceStoreCheckTrampoline := cogit
  									genTrampolineFor: #ceStoreCheck:
  									called: 'ceStoreCheckTrampoline'
  									arg: ReceiverResultReg
+ 									regsToSave: (cogit callerSavedRegMask bitClear: (cogit registerMaskFor: ReceiverResultReg))
  									result: cogit returnRegForStoreCheck.
  	ceCreateNewArrayTrampoline := cogit genTrampolineFor: #ceNewArraySlotSize:
  											called: 'ceCreateNewArrayTrampoline'
  											arg: SendNumArgsReg
+ 											regsToSave: (cogit callerSavedRegMask bitClear: (cogit registerMaskFor: ReceiverResultReg))
  											result: ReceiverResultReg.
  	cePositive32BitIntegerTrampoline := cogit genTrampolineFor: #positive32BitIntegerFor:
  												called: 'cePositive32BitIntegerTrampoline'
  												arg: ReceiverResultReg
+ 												regsToSave: (cogit callerSavedRegMask bitClear: (cogit registerMaskFor: ReceiverResultReg))
  												result: TempReg.
  	ceActiveContextTrampoline := self genActiveContextTrampoline.
  	ceClosureCopyTrampoline := cogit genTrampolineFor: #ceClosureCopyDescriptor:
  										called: 'ceClosureCopyTrampoline'
  										arg: SendNumArgsReg
+ 										regsToSave: (cogit callerSavedRegMask bitClear: (cogit registerMaskFor: ReceiverResultReg))
  										result: ReceiverResultReg!

Item was changed:
  ----- Method: CogVMSimulator class>>initializeWithOptions:objectMemoryClass: (in category 'class initialization') -----
  initializeWithOptions: optionsDictionaryOrArray objectMemoryClass: objectMemoryClassOrNil
  	"The relevant ObjectMemory, Interpreter and Cogit classes must be initialized in order.
  	 This happens notionally every time we start the simulator,
  	 but in fact happens when ever we instantiate a simulator."
  	initializationOptions := optionsDictionaryOrArray isArray
  							ifTrue: [Dictionary newFromPairs: optionsDictionaryOrArray]
  							ifFalse: [optionsDictionaryOrArray].
  	(objectMemoryClassOrNil ifNil: [self objectMemoryClass])
  		initializeWithOptions: initializationOptions.
  
  	self initializeWithOptions: initializationOptions.
  
  	((initializationOptions at: #COGMTVM ifAbsent: [false])
  			ifTrue: [CoInterpreterMT]
  			ifFalse: [CoInterpreter])
  		initializeWithOptions: initializationOptions.
  
  	ByteCountsPerMicrosecond := initializationOptions
  										at: #ByteCountsPerMicrosecond
+ 										ifAbsent: [100].
- 										ifAbsent: [10].
  
  	(self cogitClass withAllSuperclasses copyUpTo: Cogit) reverseDo:
  		[:c| c initializeWithOptions: initializationOptions]!

Item was removed:
- ----- Method: CogX64Compiler>>genRestoreRegs (in category 'abi') -----
- genRestoreRegs
- 	"Restore the general purpose registers for a trampoline call.
- 	 c.f. genSaveRegisters"
- 	RAX to: R15 do:
- 		[:reg|
- 		 (reg between: RSP and: RBP) ifFalse:
- 			[cogit PopR: reg]].
- 	^0!

Item was added:
+ ----- Method: CogX64Compiler>>genRestoreRegs: (in category 'abi') -----
+ genRestoreRegs: regMask
+ 	"Restore the registers in regMask as saved by genSaveRegs:."
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: RSP and: RBP)).
+ 	RAX to: R15 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PopR: reg]].
+ 	^0!

Item was added:
+ ----- Method: CogX64Compiler>>genSaveRegs: (in category 'abi') -----
+ genSaveRegs: regMask
+ 	"Save the registers in regMask for a call into the C run-time from a trampoline."
+ 
+ 	self assert: (R15 > RAX and: [R15 - RAX + 1 = 16]).
+ 	self deny: (regMask anyMask: (cogit registerMaskFor: RSP and: RBP)).
+ 	R15 to: RAX by: -1 do:
+ 		[:reg|
+ 		 (regMask anyMask: (cogit registerMaskFor: reg)) ifTrue:
+ 			[cogit PushR: reg]].
+ 	^0!

Item was removed:
- ----- Method: CogX64Compiler>>genSaveRegsForCCall (in category 'abi') -----
- genSaveRegsForCCall
- 	"Save the general purpose registers for a trampoline call."
- 
- 	self assert: (R15 > RAX and: [R15 - RAX + 1 = 16]).
- 	R15 to: RAX by: -1 do:
- 		[:reg|
- 		 (reg between: RSP and: RBP) ifFalse:
- 			[cogit PushR: reg]].
- 	^0!

Item was removed:
- ----- Method: Cogit>>CallRT:registersToBeSavedMask: (in category 'compile abstract instructions') -----
- CallRT: callTarget registersToBeSavedMask: registersToBeSaved
- 	<returnTypeC: #'AbstractInstruction *'>
- 	| callerSavedRegsToBeSaved lastInst reg registersToBePushed |
- 	<var: 'lastInst' type: #'AbstractInstruction *'>
- 	callerSavedRegsToBeSaved := callerSavedRegMask bitAnd: registersToBeSaved.
- 
- 	registersToBePushed := callerSavedRegsToBeSaved.
- 	reg := 0.
- 	[registersToBePushed ~= 0] whileTrue:
- 		[(registersToBePushed anyMask: 1) ifTrue:
- 			[self PushR: reg].
- 		 reg := reg + 1.
- 		 registersToBePushed := registersToBePushed >>> 1].
- 	
- 	lastInst := self CallRT: callTarget.
- 
- 	[reg >= 0] whileTrue:
- 		[(callerSavedRegsToBeSaved anyMask: 1 << reg) ifTrue:
- 			[lastInst := self PopR: reg].
- 		 reg := reg - 1].
- 
- 	^lastInst!

Item was added:
+ ----- Method: Cogit>>compileCallFor:numArgs:arg:arg:arg:arg:resultReg:regsToSave: (in category 'initialization') -----
+ compileCallFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 resultReg: resultRegOrNone regsToSave: regMask
+ 	"Generate a call to aRoutine with up to 4 arguments.  If resultRegOrNone is not
+ 	 NoReg assign the C result to resultRegOrNone.  If saveRegs, save all registers.
+ 	 Hack: a negative arg value indicates an abstract register, a non-negative value
+ 	 indicates a constant."
+ 	<var: #aRoutine type: #'void *'>
+ 	<inline: false>
+ 	| regsToSave |
+ 	regsToSave := resultRegOrNone = NoReg
+ 						ifTrue: [regMask]
+ 						ifFalse: [regMask bitClear: (self registerMaskFor: resultRegOrNone)].
+ 	cStackAlignment > objectMemory wordSize ifTrue:
+ 		[backEnd
+ 			genAlignCStackSavingRegisters: regsToSave
+ 			numArgs: numArgs
+ 			wordAlignment: cStackAlignment / objectMemory wordSize].
+ 	backEnd
+ 		genSaveRegs: regsToSave;
+ 		genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3.
+ 	self CallFullRT: (self cCode: [aRoutine asUnsignedInteger]
+ 						inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
+ 	resultRegOrNone ~= NoReg ifTrue:
+ 		[backEnd genWriteCResultIntoReg: resultRegOrNone].
+ 	 numArgs > 0 ifTrue:
+ 		[backEnd genRemoveNArgsFromStack: numArgs].
+ 	backEnd genRestoreRegs: regsToSave!

Item was removed:
- ----- Method: Cogit>>compileCallFor:numArgs:arg:arg:arg:arg:resultReg:saveRegs: (in category 'initialization') -----
- compileCallFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 resultReg: resultRegOrNone saveRegs: saveRegs
- 	"Generate a call to aRoutine with up to 4 arguments.  If resultRegOrNone is not
- 	 NoReg assign the C result to resultRegOrNone.  If saveRegs, save all registers.
- 	 Hack: a negative arg value indicates an abstract register, a non-negative value
- 	 indicates a constant."
- 	<var: #aRoutine type: #'void *'>
- 	<inline: false>
- 	cStackAlignment > objectMemory wordSize ifTrue:
- 		[backEnd
- 			genAlignCStackSavingRegisters: saveRegs
- 			numArgs: numArgs
- 			wordAlignment: cStackAlignment / objectMemory wordSize].
- 	saveRegs ifTrue:
- 		[backEnd genSaveRegsForCCall].
- 	backEnd genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3.
- 	self CallFullRT: (self cCode: [aRoutine asUnsignedInteger]
- 					   inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
- 	resultRegOrNone ~= NoReg ifTrue:
- 		[backEnd genWriteCResultIntoReg: resultRegOrNone].
- 	 saveRegs ifTrue:
- 		[numArgs > 0 ifTrue:
- 			[backEnd genRemoveNArgsFromStack: numArgs].
- 		resultRegOrNone ~= NoReg
- 			ifTrue: [backEnd genRestoreRegsExcept: resultRegOrNone]
- 			ifFalse: [backEnd genRestoreRegs]]!

Item was added:
+ ----- Method: Cogit>>compileTrampolineFor:numArgs:arg:arg:arg:arg:regsToSave:pushLinkReg:resultReg: (in category 'initialization') -----
+ compileTrampolineFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 regsToSave: regMask pushLinkReg: pushLinkReg resultReg: resultRegOrNone
+ 	"Generate a trampoline with up to four arguments.  Generate either a call or a jump to aRoutine
+ 	 as requested by callJumpBar.  If generating a call and resultRegOrNone is not NoReg pass the C
+ 	 result back in resultRegOrNone.
+ 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
+ 	<var: #aRoutine type: #'void *'>
+ 	<inline: false>
+ 	self genSmalltalkToCStackSwitch: pushLinkReg.
+ 	self
+ 		compileCallFor: aRoutine
+ 		numArgs: numArgs
+ 		arg: regOrConst0
+ 		arg: regOrConst1
+ 		arg: regOrConst2
+ 		arg: regOrConst3
+ 		resultReg: resultRegOrNone
+ 		regsToSave: regMask.
+ 	backEnd genLoadStackPointers.
+ 	(pushLinkReg and: [backEnd hasLinkRegister])
+ 		ifTrue:
+ 			[backEnd hasPCRegister
+ 				ifTrue: [self PopR: PCReg]
+ 				ifFalse: [self PopR: LinkReg. 
+ 						self RetN: 0]]
+ 		ifFalse: [self RetN: 0]!

Item was removed:
- ----- Method: Cogit>>compileTrampolineFor:numArgs:arg:arg:arg:arg:saveRegs:pushLinkReg:resultReg: (in category 'initialization') -----
- compileTrampolineFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 saveRegs: saveRegs pushLinkReg: pushLinkReg resultReg: resultRegOrNone
- 	"Generate a trampoline with up to four arguments.  Generate either a call or a jump to aRoutine
- 	 as requested by callJumpBar.  If generating a call and resultRegOrNone is not NoReg pass the C
- 	 result back in resultRegOrNone.
- 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
- 	<var: #aRoutine type: #'void *'>
- 	<inline: false>
- 	self genSmalltalkToCStackSwitch: pushLinkReg.
- 	self
- 		compileCallFor: aRoutine
- 		numArgs: numArgs
- 		arg: regOrConst0
- 		arg: regOrConst1
- 		arg: regOrConst2
- 		arg: regOrConst3
- 		resultReg: resultRegOrNone
- 		saveRegs: saveRegs.
- 	backEnd genLoadStackPointers.
- 	(pushLinkReg and: [backEnd hasLinkRegister])
- 		ifTrue:
- 			[backEnd hasPCRegister
- 				ifTrue: [self PopR: PCReg]
- 				ifFalse: [self PopR: LinkReg. 
- 						self RetN: 0]]
- 		ifFalse: [self RetN: 0]!

Item was added:
+ ----- Method: Cogit>>emptyRegisterMask (in category 'register management') -----
+ emptyRegisterMask
+ 	<inline: true>
+ 	^0!

Item was changed:
  ----- Method: Cogit>>genCheckForInterruptsTrampoline (in category 'initialization') -----
  genCheckForInterruptsTrampoline
  	self zeroOpcodeIndex.
  	"if we have a link register we will assume that it does not get automatically pushed onto the stack
  	and thus there is no need to pop it before saving to instructionPointerAddress"
  	backEnd hasLinkRegister
  		ifTrue:
  			[self MoveR: LinkReg Aw: coInterpreter instructionPointerAddress]
  		ifFalse:
  			[self PopR: TempReg. "instruction pointer"
  			 self MoveR: TempReg Aw: coInterpreter instructionPointerAddress].
  	^self genTrampolineFor: #ceCheckForInterrupts
  		called: 'ceCheckForInterruptsTrampoline'
  		numArgs: 0
  		arg: nil
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: Cogit>>genInnerPICAbortTrampoline: (in category 'initialization') -----
  genInnerPICAbortTrampoline: name
  	"Generate the abort for a PIC.  This abort performs either a call of
  	 ceInterpretMethodFromPIC:receiver: to handle invoking an uncogged target
  	 or a call of ceMNUFromPICMNUMethod:receiver: to handle an MNU dispatch
  	 in a closed PIC.  It distinguishes the two by testing ClassReg.  If the register
  	 is zero then this is an MNU.
  	
  	 This poses a problem in 32-bit Spur, where zero is the cache tag for immediate
  	 characters (tag pattern 2r10) because SmallIntegers have tag patterns 2r11
  	 and 2r01, so anding with 1 reduces these to 0 & 1.  We solve the ambiguity by
  	 patching send sites with a 0 cache tag to open PICs instead of closed PICs."
  	<var: #name type: #'char *'>
  	| jumpMNUCase |
  	<var: #jumpMNUCase type: #'AbstractInstruction *'>
  	self CmpCq: self picAbortDiscriminatorValue R: ClassReg.
  	jumpMNUCase := self JumpZero: 0.
  	self compileTrampolineFor: #ceInterpretMethodFromPIC:receiver:
  		numArgs: 2
  		arg: SendNumArgsReg
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false
  		resultReg: NoReg.
  	jumpMNUCase jmpTarget: self Label.
  	^self genTrampolineFor: #ceMNUFromPICMNUMethod:receiver:
  		called: name
  		numArgs: 2
  		arg: SendNumArgsReg
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: Cogit>>genMethodAbortTrampoline (in category 'initialization') -----
  genMethodAbortTrampoline
  	"Generate the abort for a method.  This abort performs either a call of ceSICMiss:
  	 to handle a single-in-line cache miss or a call of ceStackOverflow: to handle a
  	 stack overflow.  It distinguishes the two by testing ResultReceiverReg.  If the
  	 register is zero then this is a stack-overflow because a) the receiver has already
  	 been pushed and so can be set to zero before calling the abort, and b) the
  	 receiver must always contain an object (and hence be non-zero) on SIC miss."
  	| jumpSICMiss |
  	<var: #jumpSICMiss type: #'AbstractInstruction *'>
  	self zeroOpcodeIndex.
  	self CmpCq: 0 R: ReceiverResultReg.
  	jumpSICMiss := self JumpNonZero: 0.
  
  	"The abort sequencer has pushed the LinkReg a second time.
  	 Overwrite it with the right one."
  	backEnd hasLinkRegister ifTrue:
  		[self MoveR: LinkReg Mw: 0 r: SPReg].
  	self compileTrampolineFor: #ceStackOverflow:
  		numArgs: 1
  		arg: SendNumArgsReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false "The LinkReg has already been set above."
  		resultReg: NoReg.
  	jumpSICMiss jmpTarget: self Label.
  	^self genTrampolineFor: #ceSICMiss:
  		called: 'ceMethodAbort'
  		numArgs: 1
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true "Push the LinkReg for the ceMethodAbort call."
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: Cogit>>genNSSendTrampolineFor:numArgs:enclosingObjectCheck:called: (in category 'initialization') -----
  genNSSendTrampolineFor: aRoutine numArgs: numArgs enclosingObjectCheck: eoCheckFlag called: aString
  	"ReceiverResultReg: method receiver
  	SendNumArgsReg: the NSSendCache cache"
  	<option: #NewspeakVM>
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	| jumpMiss jumpItsTheReceiverStupid |
  	<var: #jumpMiss type: #'AbstractInstruction *'>
  	<var: #jumpItsTheReceiverStupid type: #'AbstractInstruction *'>
  	self zeroOpcodeIndex.
  	objectRepresentation
  		genGetInlineCacheClassTagFrom: ReceiverResultReg
  		into: ClassReg
  		forEntry: false.
  	self MoveMw: NSCClassTagIndex * objectMemory wordSize r: SendNumArgsReg R: TempReg.
  	self CmpR: ClassReg R: TempReg.
  	jumpMiss := self JumpNonZero: 0.
  
  	eoCheckFlag ifTrue:
  		[self MoveMw: NSCEnclosingObjectIndex * objectMemory wordSize r: SendNumArgsReg R: TempReg.
  		self CmpCq: 0 R: TempReg.
  		jumpItsTheReceiverStupid := self JumpZero: 0.
  		self MoveR: TempReg R: ReceiverResultReg.
  		"Now set the stacked receiver, if needed.  If there are reg args this is
  		 not required; see genPushRegisterArgsForNumArgs:numArgs: below."
  		(self numRegArgs = 0 or: [numArgs > self numRegArgs]) ifTrue:
  			[numArgs >= (NumSendTrampolines - 1)
  				ifTrue: "arbitrary argument count"
  					[self MoveMw: NSCNumArgsIndex * objectMemory wordSize r: SendNumArgsReg R: TempReg.
  					 backEnd hasLinkRegister ifFalse:
  						[self AddCq: 1 R: TempReg]..
  					 self MoveR: ReceiverResultReg Xwr: TempReg R: SPReg]
  				ifFalse: "Known argument count"
  					[self MoveR: TempReg Mw: (backEnd hasLinkRegister ifTrue: [0] ifFalse: [1]) + numArgs * objectMemory wordSize r: SPReg]].
  		jumpItsTheReceiverStupid jmpTarget: self Label].
  
  	self MoveMw: NSCTargetIndex * objectMemory wordSize r: SendNumArgsReg R: TempReg.
  	self JumpR: TempReg.
  
  	jumpMiss jmpTarget: self Label.
  	objectRepresentation
  		genEnsureOopInRegNotForwarded: ReceiverResultReg
  		scratchReg: TempReg
  		updatingMw: FoxMFReceiver
  		r: FPReg.
  	self numRegArgs > 0 ifTrue:
  		[backEnd genPushRegisterArgsForNumArgs: numArgs scratchReg: TempReg].
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 2
  		arg: SendNumArgsReg "The NSSendCache"
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: Cogit>>genNonLocalReturnTrampoline (in category 'initialization') -----
  genNonLocalReturnTrampoline
  	self zeroOpcodeIndex.
  	"write the return address to the coInterpreter instructionPointerAddress;
  	 following the CallRT to this CISCs will have pushed it on the stack, so pop it first; RISCs will have it in
  	 their link register so just write it directly."
  	backEnd hasLinkRegister
  		ifTrue:
  			[self MoveR: LinkReg Aw: coInterpreter instructionPointerAddress]
  		ifFalse:
  			[self PopR: TempReg. "instruction pointer"
  			 self MoveR: TempReg Aw: coInterpreter instructionPointerAddress].
  	^self genTrampolineFor: #ceNonLocalReturn:
  		called: 'ceNonLocalReturnTrampoline'
  		numArgs: 1
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: Cogit>>genReturnTrampolineFor:called:arg: (in category 'initialization') -----
  genReturnTrampolineFor: aRoutine  called: aString arg: regOrConst0
  	"Generate a trampoline for a routine used as a return address, that has one argument.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 1
  		arg: regOrConst0
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false "Since the routine is reached by a return instruction it should /not/ push the link register."
  		resultReg: NoReg
  		appendOpcodes: false!

Item was removed:
- ----- Method: Cogit>>genSafeTrampolineFor:called: (in category 'initialization') -----
- genSafeTrampolineFor: aRoutine called: aString
- 	"Generate a trampoline with no arguments that will
- 	 save and restore all registers around the call"
- 	<var: #aRoutine type: #'void *'>
- 	<var: #aString type: #'char *'>
- 	^self
- 		genTrampolineFor: aRoutine
- 		called: aString
- 		numArgs: 0
- 		arg: nil
- 		arg: nil
- 		arg: nil
- 		arg: nil
- 		saveRegs: true
- 		pushLinkReg: true
- 		resultReg: NoReg
- 		appendOpcodes: false!

Item was removed:
- ----- Method: Cogit>>genSafeTrampolineFor:called:arg: (in category 'initialization') -----
- genSafeTrampolineFor: aRoutine called: aString arg: regOrConst0
- 	"Generate a trampoline with one argument that will
- 	 save and restore all registers around the call"
- 	<var: #aRoutine type: #'void *'>
- 	<var: #aString type: #'char *'>
- 	^self
- 		genTrampolineFor: aRoutine
- 		called: aString
- 		numArgs: 1
- 		arg: regOrConst0
- 		arg: nil
- 		arg: nil
- 		arg: nil
- 		saveRegs: true
- 		pushLinkReg: true
- 		resultReg: NoReg
- 		appendOpcodes: false!

Item was removed:
- ----- Method: Cogit>>genSafeTrampolineFor:called:arg:arg: (in category 'initialization') -----
- genSafeTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1
- 	"Generate a trampoline with two arguments that
- 	 will save and restore all registers around the call"
- 	<var: #aRoutine type: #'void *'>
- 	<var: #aString type: #'char *'>
- 	^self
- 		genTrampolineFor: aRoutine
- 		called: aString
- 		numArgs: 2
- 		arg: regOrConst0
- 		arg: regOrConst1
- 		arg: nil
- 		arg: nil
- 		saveRegs: true
- 		pushLinkReg: true
- 		resultReg: NoReg
- 		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString
  	"Generate a trampoline with no arguments"
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 0
  		arg: nil
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg: (in category 'initialization') -----
  genTrampolineFor: aRoutine  called: aString arg: regOrConst0
  	"Generate a trampoline with one argument.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 1
  		arg: regOrConst0
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg:arg: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1
  	"Generate a trampoline with two arguments.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 2
  		arg: regOrConst0
  		arg: regOrConst1
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg:arg:arg: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1 arg: regOrConst2
  	"Generate a trampoline with three arguments.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 3
  		arg: regOrConst0
  		arg: regOrConst1
  		arg: regOrConst2
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg:arg:arg:arg: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3
  	"Generate a trampoline with four arguments.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 4
  		arg: regOrConst0
  		arg: regOrConst1
  		arg: regOrConst2
  		arg: regOrConst3
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg:arg:arg:result: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 result: resultReg
  	"Generate a trampoline with two arguments that answers a result.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 3
  		arg: regOrConst0
  		arg: regOrConst1
  		arg: regOrConst2
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: resultReg
  		appendOpcodes: false!

Item was added:
+ ----- Method: Cogit>>genTrampolineFor:called:arg:arg:regsToSave: (in category 'initialization') -----
+ genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1 regsToSave: regMask
+ 	"Generate a trampoline with two arguments.
+ 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
+ 	<var: #aRoutine type: #'void *'>
+ 	<var: #aString type: #'char *'>
+ 	^self
+ 		genTrampolineFor: aRoutine
+ 		called: aString
+ 		numArgs: 2
+ 		arg: regOrConst0
+ 		arg: regOrConst1
+ 		arg: nil
+ 		arg: nil
+ 		regsToSave: regMask
+ 		pushLinkReg: true
+ 		resultReg: NoReg
+ 		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg:arg:result: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg: regOrConst1 result: resultReg
  	"Generate a trampoline with two arguments that answers a result.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 2
  		arg: regOrConst0
  		arg: regOrConst1
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: resultReg
  		appendOpcodes: false!

Item was added:
+ ----- Method: Cogit>>genTrampolineFor:called:arg:regsToSave: (in category 'initialization') -----
+ genTrampolineFor: aRoutine  called: aString arg: regOrConst0 regsToSave: regMask
+ 	"Generate a trampoline with one argument.
+ 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
+ 	<var: #aRoutine type: #'void *'>
+ 	<var: #aString type: #'char *'>
+ 	^self
+ 		genTrampolineFor: aRoutine
+ 		called: aString
+ 		numArgs: 1
+ 		arg: regOrConst0
+ 		arg: nil
+ 		arg: nil
+ 		arg: nil
+ 		regsToSave: regMask
+ 		pushLinkReg: true
+ 		resultReg: NoReg
+ 		appendOpcodes: false!

Item was added:
+ ----- Method: Cogit>>genTrampolineFor:called:arg:regsToSave:result: (in category 'initialization') -----
+ genTrampolineFor: aRoutine called: aString arg: regOrConst0 regsToSave: regMask result: resultReg
+ 	"Generate a trampoline with one argument that answers a result.
+ 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
+ 	<var: #aRoutine type: #'void *'>
+ 	<var: #aString type: #'char *'>
+ 	^self
+ 		genTrampolineFor: aRoutine
+ 		called: aString
+ 		numArgs: 1
+ 		arg: regOrConst0
+ 		arg: nil
+ 		arg: nil
+ 		arg: nil
+ 		regsToSave: regMask
+ 		pushLinkReg: true
+ 		resultReg: resultReg
+ 		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>genTrampolineFor:called:arg:result: (in category 'initialization') -----
  genTrampolineFor: aRoutine called: aString arg: regOrConst0 result: resultReg
  	"Generate a trampoline with one argument that answers a result.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	^self
  		genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 1
  		arg: regOrConst0
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: resultReg
  		appendOpcodes: false!

Item was added:
+ ----- Method: Cogit>>genTrampolineFor:called:numArgs:arg:arg:arg:arg:regsToSave:pushLinkReg:resultReg:appendOpcodes: (in category 'initialization') -----
+ genTrampolineFor: aRoutine called: trampolineName numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 regsToSave: regMask pushLinkReg: pushLinkReg resultReg: resultRegOrNone appendOpcodes: appendBoolean
+ 	"Generate a trampoline with up to four arguments.  Generate either a call or a jump to aRoutineOrNil
+ 	 as requested by callJumpBar.  If generating a call and resultRegOrNone is not NoReg pass the C result
+ 	 back in resultRegOrNone.
+ 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
+ 	<var: #aRoutine type: #'void *'>
+ 	<var: #trampolineName type: #'char *'>
+ 	| startAddress |
+ 	<inline: false>
+ 	startAddress := methodZoneBase.
+ 	appendBoolean ifFalse:
+ 		[self zeroOpcodeIndex].
+ 	self compileTrampolineFor: aRoutine
+ 		numArgs: numArgs
+ 		arg: regOrConst0
+ 		arg: regOrConst1
+ 		arg: regOrConst2
+ 		arg: regOrConst3
+ 		regsToSave: regMask
+ 		pushLinkReg: pushLinkReg
+ 		resultReg: resultRegOrNone.
+ 	self outputInstructionsForGeneratedRuntimeAt: startAddress.
+ 	self recordGeneratedRunTime: trampolineName address: startAddress.
+ 	self recordRunTimeObjectReferences.
+ 	^startAddress!

Item was removed:
- ----- Method: Cogit>>genTrampolineFor:called:numArgs:arg:arg:arg:arg:saveRegs:pushLinkReg:resultReg:appendOpcodes: (in category 'initialization') -----
- genTrampolineFor: aRoutine called: trampolineName numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 saveRegs: saveRegs pushLinkReg: pushLinkReg resultReg: resultRegOrNone appendOpcodes: appendBoolean
- 	"Generate a trampoline with up to four arguments.  Generate either a call or a jump to aRoutineOrNil
- 	 as requested by callJumpBar.  If generating a call and resultRegOrNone is not NoReg pass the C result
- 	 back in resultRegOrNone.
- 	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
- 	<var: #aRoutine type: #'void *'>
- 	<var: #trampolineName type: #'char *'>
- 	| startAddress |
- 	<inline: false>
- 	startAddress := methodZoneBase.
- 	appendBoolean ifFalse:
- 		[self zeroOpcodeIndex].
- 	self compileTrampolineFor: aRoutine
- 		numArgs: numArgs
- 		arg: regOrConst0
- 		arg: regOrConst1
- 		arg: regOrConst2
- 		arg: regOrConst3
- 		saveRegs: saveRegs
- 		pushLinkReg: pushLinkReg
- 		resultReg: resultRegOrNone.
- 	self outputInstructionsForGeneratedRuntimeAt: startAddress.
- 	self recordGeneratedRunTime: trampolineName address: startAddress.
- 	self recordRunTimeObjectReferences.
- 	^startAddress!

Item was added:
+ ----- Method: Cogit>>genTrampolineFor:called:regsToSave: (in category 'initialization') -----
+ genTrampolineFor: aRoutine called: aString regsToSave: regMask
+ 	"Generate a trampoline with no arguments"
+ 	<var: #aRoutine type: #'void *'>
+ 	<var: #aString type: #'char *'>
+ 	^self
+ 		genTrampolineFor: aRoutine
+ 		called: aString
+ 		numArgs: 0
+ 		arg: nil
+ 		arg: nil
+ 		arg: nil
+ 		arg: nil
+ 		regsToSave: regMask
+ 		pushLinkReg: true
+ 		resultReg: NoReg
+ 		appendOpcodes: false!

Item was changed:
  ----- Method: Cogit>>registerMaskFor: (in category 'register management') -----
  registerMaskFor: reg
+ 	<inline: true>
  	^1 << reg!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2
+ 	<inline: true>
  	^1 << reg1 bitOr: 1 << reg2!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3
+ 	<inline: true>
  	^(1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4
+ 	<inline: true>
  	^((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4 and: reg5
+ 	<inline: true>
  	^(((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4) bitOr: 1 << reg5!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4 and: reg5 and: reg6
+ 	<inline: true>
  	^((((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4) bitOr: 1 << reg5) bitOr: 1 << reg6!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4 and: reg5 and: reg6 and: reg7
+ 	<inline: true>
  	^(((((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4) bitOr: 1 << reg5) bitOr: 1 << reg6) bitOr: 1 << reg7!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and:and:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4 and: reg5 and: reg6 and: reg7 and: reg8
+ 	<inline: true>
  	^((((((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4) bitOr: 1 << reg5) bitOr: 1 << reg6) bitOr: 1 << reg7) bitOr: 1 << reg8!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and:and:and:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4 and: reg5 and: reg6 and: reg7 and: reg8 and: reg9
+ 	<inline: true>
  	^(((((((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4) bitOr: 1 << reg5) bitOr: 1 << reg6) bitOr: 1 << reg7) bitOr: 1 << reg8) bitOr: 1 << reg9!

Item was changed:
  ----- Method: Cogit>>registerMaskFor:and:and:and:and:and:and:and:and:and: (in category 'register management') -----
  registerMaskFor: reg1 and: reg2 and: reg3 and: reg4 and: reg5 and: reg6 and: reg7 and: reg8 and: reg9 and: reg10
+ 	<inline: true>
  	^((((((((1 << reg1 bitOr: 1 << reg2) bitOr: 1 << reg3) bitOr: 1 << reg4) bitOr: 1 << reg5) bitOr: 1 << reg6) bitOr: 1 << reg7) bitOr: 1 << reg8) bitOr: 1 << reg9) bitOr: 1 << reg10!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>compileOpenPIC:numArgs: (in category 'in-line cacheing') -----
  compileOpenPIC: selector numArgs: numArgs
  	"Compile the code for an open PIC.  Perform a probe of the first-level method
  	 lookup cache followed by a call of ceSendFromInLineCacheMiss: if the probe fails."
  	| cacheBaseReg jumpSelectorMiss jumpClassMiss itsAHit jumpBCMethod |
  	<var: #jumpSelectorMiss type: #'AbstractInstruction *'>
  	<var: #jumpClassMiss type: #'AbstractInstruction *'>
  	<var: #itsAHit type: #'AbstractInstruction *'>
  	<var: #jumpBCMethod type: #'AbstractInstruction *'>
  	self compilePICAbort: numArgs.
  	entry := objectRepresentation genGetClassTagOf: ReceiverResultReg into: ClassReg scratchReg: TempReg.
  	self MoveR: ClassReg R: SendNumArgsReg.
  
  	self flag: #lookupInMethodCacheSel:classTag:. "so this method shows up as a sender of lookupInMethodCacheSel:class:"
  
  	cacheBaseReg := NoReg.
  	(backEnd isWithinMwOffsetRange: coInterpreter methodCacheAddress) ifFalse:
  		[self MoveCq: coInterpreter methodCacheAddress R: (cacheBaseReg := Scratch0Reg)].
  
  	"Do first of three probes.  See CoInterpreter>>lookupInMethodCacheSel:classTag:"
  	jumpSelectorMiss := self compileOpenPICMethodCacheProbeFor: selector withShift: 0 baseRegOrNone: cacheBaseReg.
  	jumpClassMiss := self JumpNonZero: 0.
  
  	"Fetch the method.  The interpret trampoline requires the bytecoded method in SendNumArgsReg"
  	itsAHit := self MoveMw: (cacheBaseReg = NoReg
  								ifTrue: [coInterpreter methodCacheAddress asUnsignedInteger + (MethodCacheMethod << objectMemory shiftForWord)]
  								ifFalse: [MethodCacheMethod << objectMemory shiftForWord])
  					r: ClassReg
  					R: SendNumArgsReg.
  			.
  	"If the method is compiled jump to its unchecked entry-point, otherwise interpret it."
  	objectRepresentation genLoadSlot: HeaderIndex sourceReg: SendNumArgsReg destReg: ClassReg.
  	jumpBCMethod := objectRepresentation genJumpImmediate: ClassReg.
  	jumpBCMethod jmpTarget: picInterpretAbort.
  	self AddCq: cmNoCheckEntryOffset R: ClassReg.
  	self JumpR: ClassReg.
  
  	"First probe missed.  Do second of three probes.  Shift hash right one and retry."
  	jumpSelectorMiss jmpTarget: (jumpClassMiss jmpTarget: self Label).
  	jumpSelectorMiss := self compileOpenPICMethodCacheProbeFor: selector withShift: 1 baseRegOrNone: cacheBaseReg.
  	self JumpZero: itsAHit.
  
  	"Second probe missed.  Do last probe.  Shift hash right two and retry."
  	jumpSelectorMiss jmpTarget: self Label.
  	jumpSelectorMiss := self compileOpenPICMethodCacheProbeFor: selector withShift: 2 baseRegOrNone: cacheBaseReg.
  	self JumpZero: itsAHit.
  
  	"Last probe missed.  Call ceSendFromInLineCacheMiss: to do the full lookup."
  	jumpSelectorMiss jmpTarget: self Label.
  	self numRegArgs > 0 ifTrue:
  		[backEnd genPushRegisterArgsForNumArgs: numArgs scratchReg: SendNumArgsReg].
  	self genSmalltalkToCStackSwitch: true.
  	methodLabel addDependent: (self annotateAbsolutePCRef: (self MoveCw: methodLabel asInteger R: SendNumArgsReg)).
  	self 
  		compileCallFor: #ceSendFromInLineCacheMiss:
  		numArgs: 1
  		arg: SendNumArgsReg
  		arg: nil
  		arg: nil
  		arg: nil
  		resultReg: NoReg
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  	"Note that this call does not return."!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genMustBeBooleanTrampolineFor:called: (in category 'initialization') -----
  genMustBeBooleanTrampolineFor: boolean called: trampolineName
  	<var: #trampolineName type: #'char *'>
  	<inline: false>
  	self zeroOpcodeIndex.
  	"If the objectRepresentation does want true & false to be mobile then we need to record these addresses."
  	self assert: (objectRepresentation shouldAnnotateObjectReference: boolean) not.
  	self AddCq: boolean R: TempReg.
  	^self genTrampolineFor: #ceSendMustBeBoolean:
  		called: trampolineName
  		numArgs: 1
  		arg: TempReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genPrimReturnEnterCogCodeEnilopmart: (in category 'initialization') -----
  genPrimReturnEnterCogCodeEnilopmart: profiling
  	"Generate the substitute return code for an external or FFI primitive call.
  	 On success simply return, extracting numArgs from newMethod.
  	 On primitive failure call ceActivateFailingPrimitiveMethod: newMethod."
  	| jmpSample continuePostSample jmpFail |
  	<var: #jmpSample type: #'AbstractInstruction *'>
  	<var: #continuePostSample type: #'AbstractInstruction *'>
  	<var: #jmpFail type: #'AbstractInstruction *'>
  	self zeroOpcodeIndex.
  	backEnd hasVarBaseRegister ifTrue:
  		[self MoveCq: self varBaseAddress R: VarBaseReg]. "Must happen sometime"
  
  	profiling ifTrue:
  		["Test nextProfileTick for being non-zero and call checkProfileTick: if so.
  		  N.B. nextProfileTick is 64-bits so 32-bit systems need to test both halves."
  		objectMemory wordSize = 4
  			ifTrue:
  				[self MoveAw: coInterpreter nextProfileTickAddress R: TempReg.
  				 self MoveAw: coInterpreter nextProfileTickAddress + objectMemory wordSize R: ClassReg.
  				 self OrR: TempReg R: ClassReg]
  			ifFalse:
  				[self MoveAw: coInterpreter nextProfileTickAddress R: TempReg.
  				 self CmpCq: 0 R: TempReg].
  		"If set, jump to record sample call."
  		jmpSample := self JumpNonZero: 0.
  		continuePostSample := self Label].
  
  	self maybeCompileAllocFillerCheck.
  
  	"Test primitive failure"
  	self MoveAw: coInterpreter primFailCodeAddress R: TempReg.
  	self flag: 'ask concrete code gen if move sets condition codes?'.
  	self CmpCq: 0 R: TempReg.
  	jmpFail := self JumpNonZero: 0.
  
  	"Switch back to the Smalltalk stack.  Stack better be in either of these two states:
  		success:	stackPointer	->	result (was receiver)
  										arg1
  										...
  										argN
  										return pc
  		failure:							receiver
  										arg1
  										...
  					stackPointer	->	argN
  										return pc
  	We push the instructionPointer to reestablish the return pc in the success case,
  	but leave it to ceActivateFailingPrimitiveMethod: to do so in the failure case."
  
  	backEnd hasLinkRegister
  		ifTrue:
  			[backEnd genLoadStackPointers.											"Switch back to Smalltalk stack."
  			 backEnd hasPCRegister
  				ifTrue:
  					[self PopR: ReceiverResultReg.										"Pop result from stack"
  					 self MoveAw: coInterpreter instructionPointerAddress R: PCReg]	"Return"
  				ifFalse:
  					[self MoveMw: 0 r: SPReg R: ReceiverResultReg.						"Fetch result from stack"
  					 self MoveAw: coInterpreter instructionPointerAddress R: LinkReg.	"Get ret pc"
  					 self RetN: objectMemory wordSize]]								"Return, popping result from stack"
  		ifFalse:
  			[self MoveAw: coInterpreter instructionPointerAddress R: ClassReg.	"Get return pc"
  			 backEnd genLoadStackPointers.									"Switch back to Smalltalk stack."
  			 self MoveMw: 0 r: SPReg R: ReceiverResultReg.						"Fetch result from stack"
  			 self MoveR: ClassReg Mw: 0 r: SPReg.								"Restore return pc"
  			 self RetN: 0].														"Return, popping result from stack"
  
  	"Primitive failed.  Invoke C code to build the frame and continue."
  	jmpFail jmpTarget: (self MoveAw: coInterpreter newMethodAddress R: SendNumArgsReg).
  	"Reload sp with CStackPointer; easier than popping args of checkProfileTick."
  	self MoveAw: self cStackPointerAddress R: SPReg.
  	self 
  		compileCallFor: #ceActivateFailingPrimitiveMethod:
  		numArgs: 1
  		arg: SendNumArgsReg
  		arg: nil
  		arg: nil
  		arg: nil
  		resultReg: NoReg
+ 		regsToSave: self emptyRegisterMask.
- 		saveRegs: false.
  
  	"On Spur ceActivateFailingPrimitiveMethod: may retry the primitive and return if successful.
  	 So continue by returning to the caller.
  	 Switch back to the Smalltalk stack.  Stack should be in this state:
  				success:	stackPointer ->	result (was receiver)
  											arg1
  											...
  											argN
  											return pc
  	 We can push the instructionPointer or load it into the LinkRegister to reestablish the return pc"
  	self MoveAw: coInterpreter instructionPointerAddress
  		R: (backEnd hasLinkRegister ifTrue: [LinkReg] ifFalse: [ClassReg]).
  	backEnd genLoadStackPointers.
  	backEnd hasLinkRegister
  		ifTrue:
  			[self MoveMw: 0 r: SPReg R: ReceiverResultReg]	"Fetch result from stack"
  		ifFalse:
  			[self MoveMw: objectMemory wordSize r: SPReg R: ReceiverResultReg.	"Fetch result from stack"
  			 self PushR: ClassReg].											"Restore return pc on CISCs"
  	self RetN: objectMemory wordSize.	"return to caller, popping receiver"
  
  	profiling ifTrue:
  		["Call ceCheckProfileTick: to record sample and then continue.  newMethod
  		 should be up-to-date.  Need to save and restore the link reg around this call."
  		 jmpSample jmpTarget: self Label.
  		 backEnd saveAndRestoreLinkRegAround:
  			[self CallFullRT: (self cCode: '(unsigned long)ceCheckProfileTick'
  						inSmalltalk: [self simulatedTrampolineFor: #ceCheckProfileTick])].
  		 self Jump: continuePostSample]!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genTraceStoreTrampoline (in category 'initialization') -----
  genTraceStoreTrampoline
+ 	ceTraceStoreTrampoline := self genTrampolineFor: #ceTraceStoreOf:into:
- 	ceTraceStoreTrampoline := self genSafeTrampolineFor: #ceTraceStoreOf:into:
  										called: 'ceTraceStoreTrampoline'
  										arg: ClassReg
+ 										arg: ReceiverResultReg
+ 										regsToSave: callerSavedRegMask!
- 										arg: ReceiverResultReg!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>generateTracingTrampolines (in category 'initialization') -----
  generateTracingTrampolines
  	"Generate trampolines for tracing.  In the simulator we can save a lot of time
  	 and avoid noise instructions in the lastNInstructions log by short-cutting these
  	 trampolines, but we need them in the real vm."
  	ceTraceLinkedSendTrampoline :=
+ 		self genTrampolineFor: #ceTraceLinkedSend:
- 		self genSafeTrampolineFor: #ceTraceLinkedSend:
  			called: 'ceTraceLinkedSendTrampoline'
+ 			arg: ReceiverResultReg
+ 			regsToSave: callerSavedRegMask.
- 			arg: ReceiverResultReg.
  	ceTraceBlockActivationTrampoline :=
  		self genTrampolineFor: #ceTraceBlockActivation
+ 			called: 'ceTraceBlockActivationTrampoline'
+ 			regsToSave: callerSavedRegMask..
- 			called: 'ceTraceBlockActivationTrampoline'.
  	ceTraceStoreTrampoline :=
+ 		self genTrampolineFor: #ceTraceStoreOf:into:
- 		self genSafeTrampolineFor: #ceTraceStoreOf:into:
  			called: 'ceTraceStoreTrampoline'
  			arg: ClassReg
+ 			arg: ReceiverResultReg
+ 			regsToSave: callerSavedRegMask..
- 			arg: ReceiverResultReg.
  	self cCode: [] inSmalltalk:
  		[ceTraceLinkedSendTrampoline := self simulatedTrampolineFor: #ceShortCutTraceLinkedSend:.
  		 ceTraceBlockActivationTrampoline := self simulatedTrampolineFor: #ceShortCutTraceBlockActivation:.
  		 ceTraceStoreTrampoline := self simulatedTrampolineFor: #ceShortCutTraceStore:]!

Item was changed:
  ----- Method: SistaStackToRegisterMappingCogit>>genMustBeBooleanTrampolineFor:called: (in category 'initialization') -----
  genMustBeBooleanTrampolineFor: boolean called: trampolineName
  	"This can be entered in one of two states, depending on SendNumArgsReg. See
  	 e.g. genJumpIf:to:.  If SendNumArgsReg is non-zero then this has been entered via
  	 the initial test of the counter in the jump executed count (i.e. the counter has
  	 tripped).  In this case TempReg contains the boolean to be tested and should not
  	 be offset, and ceCounterTripped should be invoked with the unoffset TempReg.
  	 If SendNumArgsReg is zero then this has been entered for must-be-boolean
  	 processing. TempReg has been offset by boolean and must be corrected and
  	 ceSendMustBeBoolean: invoked with the corrected value."
  	<var: #trampolineName type: #'char *'>
  	| jumpMBB |
  	<var: #jumpMBB type: #'AbstractInstruction *'>
  	<inline: false>
  	self zeroOpcodeIndex.
  	self CmpCq: 0 R: SendNumArgsReg.
  	jumpMBB := self JumpZero: 0.
  	"Open-code self compileTrampolineFor: #ceCounterTripped: numArgs: 1 arg: TempReg ...
  	 so we can restore ResultReceiverReg."
  	self genSmalltalkToCStackSwitch: true.
  	self
  		compileCallFor: #ceCounterTripped:
  		numArgs: 1
  		arg: TempReg
  		arg: nil
  		arg: nil
  		arg: nil
  		resultReg: TempReg "(*)"
+ 		regsToSave: self emptyRegisterMask.
- 		saveRegs: false.
  	"(*) For the case where the ceCounterTripped: call returns (e.g. because there's no callback selector
  	 installed), the call to the ceSendMustBeBooleanAddTrue/FalseTrampoline is followed by a jump
  	 back to the start of the counter/condition test sequence.  For this case copy the C result to
  	 TempReg (the register that is tested), to reload it with the boolean to be tested."
  	backEnd genLoadStackPointers.
  	backEnd hasLinkRegister ifTrue:
  		[self PopR: LinkReg].
  	"To keep ResultReceiverReg live if optStatus thought it was, simply reload it
  	 from the frame pointer.  This avoids having to reload it in the common case
  	 (counter does not trip) if it was live."
  	self putSelfInReceiverResultReg.
  	self RetN: 0.
  	"If the objectRepresentation does want true & false to be mobile then we need to record these addresses."
  	self assert: (objectRepresentation shouldAnnotateObjectReference: boolean) not.
  	jumpMBB jmpTarget: (self AddCq: boolean R: TempReg).
  	^self genTrampolineFor: #ceSendMustBeBoolean:
  		called: trampolineName
  		numArgs: 1
  		arg: TempReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genMethodAbortTrampolineFor: (in category 'initialization') -----
  genMethodAbortTrampolineFor: numArgs
  	"Generate the abort for a method.  This abort performs either a call of ceSICMiss:
  	 to handle a single-in-line cache miss or a call of ceStackOverflow: to handle a
  	 stack overflow.  It distinguishes the two by testing ResultReceiverReg.  If the
  	 register is zero then this is a stack-overflow because a) the receiver has already
  	 been pushed and so can be set to zero before calling the abort, and b) the
  	 receiver must always contain an object (and hence be non-zero) on SIC miss."
  	| jumpSICMiss |
  	<var: #jumpSICMiss type: #'AbstractInstruction *'>
  	self zeroOpcodeIndex.
  	self CmpCq: 0 R: ReceiverResultReg.
  	jumpSICMiss := self JumpNonZero: 0.
  
  	"The abort sequence has pushed the LinkReg a second time - because a stack
  	 overflow can only happen after building a frame, which pushes LinkReg anyway, and
  	 we still need to push LinkReg in case we get to this routine from a sendMissAbort.
  	 (On ARM there is a simpler way; use two separate abort calls since all instructions are 32-bits
  	  but on x86 the zero receiver reg, call methodAbort sequence is smaller; we may fix this one day).
  	 Overwrite that duplicate with the right one - the return address for the call to the abort trampoline.
  	 The only reason it matters is an assert in ceStackOverflow: uses it"
  	backEnd hasLinkRegister ifTrue:
  		[self MoveR: LinkReg Mw: 0 r: SPReg].
  	self compileTrampolineFor: #ceStackOverflow:
  		numArgs: 1
  		arg: SendNumArgsReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false "The LinkReg has already been set above."
  		resultReg: NoReg.
  	jumpSICMiss jmpTarget: self Label.
  	backEnd genPushRegisterArgsForAbortMissNumArgs: numArgs.
  	^self genTrampolineFor: #ceSICMiss:
  		called: (self trampolineName: 'ceMethodAbort' numRegArgs: numArgs)
  		numArgs: 1
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: false "The LinkReg will have been pushed in genPushRegisterArgsForAbortMissNumArgs: above."
  		resultReg: NoReg
  		appendOpcodes: true!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPICMissTrampolineFor: (in category 'initialization') -----
  genPICMissTrampolineFor: numArgs
  	<inline: false>
  	| startAddress |
  	startAddress := methodZoneBase.
  	self zeroOpcodeIndex.
  	"N.B. a closed PIC jumps to the miss routine, not calls it, so there is only one retpc on the stack."
  	backEnd genPushRegisterArgsForNumArgs: numArgs scratchReg: SendNumArgsReg.
  	self genTrampolineFor: #ceCPICMiss:receiver:
  		called: (self trampolineName: 'cePICMiss' numRegArgs: numArgs)
  		numArgs: 2
  		arg: ClassReg
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: true.
  	^startAddress!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genSendTrampolineFor:numArgs:called:arg:arg:arg:arg: (in category 'initialization') -----
  genSendTrampolineFor: aRoutine numArgs: numArgs called: aString arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3
  	"Generate a trampoline with four arguments.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<var: #aString type: #'char *'>
  	| startAddress |
  	<inline: false>
  	startAddress := methodZoneBase.
  	self zeroOpcodeIndex.
  	backEnd genPushRegisterArgsForNumArgs: numArgs scratchReg: SendNumArgsReg.
  	objectRepresentation selectorIndexDereferenceRoutine ifNotNil:
  		[:routine| self Call: routine].
  	self genTrampolineFor: aRoutine
  		called: aString
  		numArgs: 4
  		arg: regOrConst0
  		arg: regOrConst1
  		arg: regOrConst2
  		arg: regOrConst3
+ 		regsToSave: self emptyRegisterMask
- 		saveRegs: false
  		pushLinkReg: true
  		resultReg: NoReg
  		appendOpcodes: true.
  	^startAddress!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>generateTracingTrampolines (in category 'initialization') -----
  generateTracingTrampolines
  	"Generate trampolines for tracing.  In the simulator we can save a lot of time
  	 and avoid noise instructions in the lastNInstructions log by short-cutting these
  	 trampolines, but we need them in the real vm."
  	ceTraceLinkedSendTrampoline :=
+ 		self genTrampolineFor: #ceTraceLinkedSend:
- 		self genSafeTrampolineFor: #ceTraceLinkedSend:
  			called: 'ceTraceLinkedSendTrampoline'
+ 			arg: ReceiverResultReg
+ 			regsToSave: callerSavedRegMask..
- 			arg: ReceiverResultReg.
  	ceTraceBlockActivationTrampoline :=
  		self genTrampolineFor: #ceTraceBlockActivation
+ 			called: 'ceTraceBlockActivationTrampoline'
+ 			regsToSave: callerSavedRegMask..
- 			called: 'ceTraceBlockActivationTrampoline'.
  	ceTraceStoreTrampoline :=
+ 		self genTrampolineFor: #ceTraceStoreOf:into:
- 		self genSafeTrampolineFor: #ceTraceStoreOf:into:
  			called: 'ceTraceStoreTrampoline'
  			arg: TempReg
+ 			arg: ReceiverResultReg
+ 			regsToSave: callerSavedRegMask..
- 			arg: ReceiverResultReg.
  	self cCode: [] inSmalltalk:
  		[ceTraceLinkedSendTrampoline := self simulatedTrampolineFor: #ceShortCutTraceLinkedSend:.
  		 ceTraceBlockActivationTrampoline := self simulatedTrampolineFor: #ceShortCutTraceBlockActivation:.
  		 ceTraceStoreTrampoline := self simulatedTrampolineFor: #ceShortCutTraceStore:]!

Item was changed:
  ----- Method: VMClass class>>initialize (in category 'initialization') -----
  initialize
  	(Utilities classPool at: #CommonRequestStrings ifAbsent: []) ifNotNil:
  		[:commonRequestStringHolder|
  		(commonRequestStringHolder contents asString includesSubString: 'VMClass open') ifFalse:
+ 			[Utilities appendToCommonRequests: '-\VMMaker generateConfiguration\VMMaker generateAllConfigurationsUnderVersionControl\VMMaker generateAllSpurConfigurations\VMClass openCogMultiWindowBrowser\VMClass openObjectMemoriesInterpretersBrowser\VMClass openSpurMultiWindowBrowser\VMClass openCogSpurMultiWindowBrowser' withCRs]].
- 			[Utilities appendToCommonRequests: '-\VMMaker generateConfiguration\VMMaker generateAllConfigurationsUnderVersionControl\VMMaker generateAllSpurConfigurations\VMClass openCogMultiWindowBrowser\VMClass openObjectMemoriesInterpretersBrowser\VMClass openSpurMultiWindowBrowser' withCRs]].
  	ExpensiveAsserts := false!

Item was added:
+ ----- Method: VMClass class>>openCogSpurMultiWindowBrowser (in category 'utilities') -----
+ openCogSpurMultiWindowBrowser
+ 	"Answer a new multi-window browser on the ObjectMemory classes, the Cog Interpreter classes, and the main JIT classes"
+ 	| b |
+ 	b := Browser open.
+ 	#(	SpurMemoryManager Spur32BitMemoryManager Spur32BitCoMemoryManager
+ 		 Spur64BitMemoryManager Spur64BitCoMemoryManager SpurGenerationScavenger
+ 		InterpreterPrimitives StackInterpreter StackInterpreterPrimitives CoInterpreter CoInterpreterPrimitives CoInterpreterMT
+ 		Cogit SimpleStackBasedCogit StackToRegisterMappingCogit
+ 		CogObjectRepresentation CogObjectRepresentationForSpur
+ 		CogObjectRepresentationFor32BitSpur CogObjectRepresentationFor64BitSpur
+ 		VMStructType VMMaker CCodeGenerator TMethod)
+ 		do: [:className|
+ 			(Smalltalk classNamed: className) ifNotNil:
+ 				[:class| b selectCategoryForClass: class; selectClass: class]]
+ 		separatedBy:
+ 			[b multiWindowState addNewWindow].
+ 	b multiWindowState selectWindowIndex: 1!



More information about the Vm-dev mailing list