<div dir="ltr">It saves 2 bytes for inst var 0 and 5 bytes for inst var between 1 and 255 in x86. There is one less branch to take on the common path too. Not sure if this matters a lot. The difference should be better on x64 as in x86 MoveCq:R: calls MoveCw:R: if the quick constant is not 0, and we have many little constants more than 0.<div><br></div><div>Isn't there a better way to move quick constant to register on x86 than the full word constant ? Maybe we should change MoveCq:R: on x86 to do a xor reg,reg, movq r8 as suggested in the comment.</div><div><div><div><div><br></div><div><br></div><div><br></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">2016-03-30 15:52 GMT+02:00 <span dir="ltr"><<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1748.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1748.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-cb.1748<br>
Author: cb<br>
Time: 30 March 2016, 3:52:01.732 pm<br>
UUID: db420bcd-e4aa-4cad-9543-047274e49915<br>
Ancestors: VMMaker.oscog-nice.1747<br>
<br>
Reworked machine code generation of immutability so for common stores it uses a single trampoline for both store checks and immutability checks.<br>
<br>
I have simulation bug due to large integers, so I am not entirely sure everything is working, but generated code looks good.<br>
<br>
=============== Diff against VMMaker.oscog-nice.1747 ===============<br>
<br>
Item was changed:<br>
----- Method: CogObjectRepresentation>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame: (in category 'compile abstract instructions') -----<br>
genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame<br>
+ <inline: true><br>
+ self<br>
+ cppIf: IMMUTABILITY<br>
+ ifTrue:<br>
+ [ ^ self<br>
+ genStoreWithImmutabilityCheckSourceReg: sourceReg<br>
+ slotIndex: index<br>
+ destReg: destReg<br>
+ scratchReg: scratchReg<br>
+ needsStoreCheck: true<br>
+ needRestoreRcvr: false "RcvrResultReg doesn't need to be live across the instructions" ]<br>
+ ifFalse:<br>
+ [ ^ self<br>
+ genStoreSourceReg: sourceReg<br>
+ slotIndex: index<br>
+ destReg: destReg<br>
+ scratchReg: scratchReg<br>
+ inFrame: inFrame<br>
+ needsStoreCheck: true ]!<br>
- ^ self<br>
- genStoreSourceReg: sourceReg<br>
- slotIndex: index<br>
- destReg: destReg<br>
- scratchReg: scratchReg<br>
- inFrame: inFrame<br>
- needsStoreCheck: true!<br>
<br>
Item was changed:<br>
CogObjectRepresentation subclass: #CogObjectRepresentationForSpur<br>
+ instanceVariableNames: 'ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceStoreTrampoline'<br>
- instanceVariableNames: 'ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceCannotAssignToWithIndexTrampoline'<br>
classVariableNames: ''<br>
poolDictionaries: 'VMBytecodeConstants VMSqueakClassIndices'<br>
category: 'VMMaker-JIT'!<br>
<br>
Item was removed:<br>
- ----- Method: CogObjectRepresentationForSpur>>genImmutableCheck:slotIndex:sourceReg:scratchReg:needRestoreRcvr: (in category 'compile abstract instructions') -----<br>
- genImmutableCheck: regHoldingObjectMutated slotIndex: index sourceReg: regHoldingValueToStore scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr<br>
- | mutableJump fail |<br>
- <var: #mutableJump type: #'AbstractInstruction *'><br>
- <var: #fail type: #'AbstractInstruction *'><br>
- <inline: true><br>
- <option: #IMMUTABILITY><br>
- "Trampoline convention:<br>
- - objectMutated passed in ReceiverResultReg<br>
- - index (unboxed) passed in TempReg<br>
- - valueToStore passed in ClassReg.<br>
- Simulated stack is flushed, but if needRestoreRcvr is true<br>
- the receiver has to be live after this operation."<br>
- self assert: regHoldingObjectMutated == ReceiverResultReg.<br>
- self assert: scratchReg == TempReg.<br>
- self assert: regHoldingValueToStore == ClassReg.<br>
- mutableJump := self genJumpMutable: ReceiverResultReg scratchReg: TempReg.<br>
-<br>
- "We reach this code if the object mutated is immutable."<br>
- cogit MoveCq: index R: TempReg.<br>
- "trampoline call and mcpc to bcpc annotation."<br>
- cogit CallRT: ceCannotAssignToWithIndexTrampoline.<br>
- cogit annotateBytecode: cogit Label.<br>
- "restore ReceiverResultReg state if needed, the rest of the state is spilled"<br>
- needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].<br>
- fail := cogit Jump: 0.<br>
-<br>
- "We reach this code is the object mutated is mutable"<br>
- mutableJump jmpTarget: cogit Label.<br>
-<br>
- ^ fail!<br>
<br>
Item was changed:<br>
----- Method: CogObjectRepresentationForSpur>>genJumpBaseHeaderImmutable: (in category 'compile abstract instructions') -----<br>
genJumpBaseHeaderImmutable: baseHeaderReg<br>
"baseHeader holds at least the least significant 32 bits of the object"<br>
<returnTypeC: #'AbstractInstruction *'><br>
<option: #IMMUTABILITY><br>
+ <inline: true><br>
cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.<br>
^ cogit JumpNonZero: 0!<br>
<br>
Item was changed:<br>
----- Method: CogObjectRepresentationForSpur>>genJumpBaseHeaderMutable: (in category 'compile abstract instructions') -----<br>
genJumpBaseHeaderMutable: baseHeaderReg<br>
"baseHeader holds at least the least significant 32 bits of the object"<br>
<returnTypeC: #'AbstractInstruction *'><br>
<option: #IMMUTABILITY><br>
+ <inline: true><br>
cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.<br>
^ cogit JumpZero: 0!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur>>genJumpImmutable:scratchReg: (in category 'compile abstract instructions') -----<br>
+ genJumpImmutable: sourceReg scratchReg: scratchReg<br>
+ <returnTypeC: #'AbstractInstruction *'><br>
+ <option: #IMMUTABILITY><br>
+ cogit MoveMw: 0 r: sourceReg R: scratchReg.<br>
+ ^ self genJumpBaseHeaderImmutable: scratchReg!<br>
<br>
Item was changed:<br>
----- Method: CogObjectRepresentationForSpur>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: (in category 'compile abstract instructions') -----<br>
genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck<br>
+<br>
+ cogit genTraceStores.<br>
"do the store"<br>
cogit MoveR: sourceReg<br>
Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
r: destReg.<br>
"now the check. needStoreCheck is false if the JIT has figured out that the value stored does not need the check (immediate, nil, true, false)"<br>
needsStoreCheck ifTrue:<br>
[ ^ self<br>
genStoreCheckReceiverReg: destReg<br>
valueReg: sourceReg<br>
scratchReg: scratchReg<br>
inFrame: inFrame ].<br>
^ 0!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur>>genStoreTrampolineCalled: (in category 'initialization') -----<br>
+ genStoreTrampolineCalled: trampolineName<br>
+ "This can be entered in one of two states, depending on TempReg.<br>
+ TempReg = 0 => store check<br>
+ TempReg > 0 => immutability failure<br>
+ TempReg holds index + 1 in this case as the value 0 is reserved for store checks.<br>
+ In addition the 0 value is convenient to save one instruction for store checks."<br>
+ | jumpSC |<br>
+ <var: #trampolineName type: #'char *'><br>
+ <var: #jumpSC type: #'AbstractInstruction *'><br>
+ <inline: false><br>
+ cogit zeroOpcodeIndex.<br>
+ cogit CmpCq: 0 R: TempReg.<br>
+ jumpSC := cogit JumpZero: 0.<br>
+<br>
+ "CannotAssignTo:, we restore the index."<br>
+ cogit SubCq: 1 R: TempReg.<br>
+ cogit<br>
+ compileTrampolineFor: #ceCannotAssignTo:withIndex:valueToAssign:<br>
+ numArgs: 3<br>
+ arg: ReceiverResultReg<br>
+ arg: TempReg<br>
+ arg: ClassReg<br>
+ arg: nil<br>
+ regsToSave: cogit emptyRegisterMask<br>
+ pushLinkReg: true<br>
+ resultReg: NoReg.<br>
+<br>
+ "Store check"<br>
+ jumpSC jmpTarget: cogit Label.<br>
+ ^ cogit genTrampolineFor: #remember:<br>
+ called: trampolineName<br>
+ numArgs: 1<br>
+ arg: ReceiverResultReg<br>
+ arg: nil<br>
+ arg: nil<br>
+ arg: nil<br>
+ regsToSave: cogit emptyRegisterMask<br>
+ pushLinkReg: true<br>
+ resultReg: NoReg<br>
+ appendOpcodes: true!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur>>genStoreWithImmutabilityAndStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: (in category 'compile abstract instructions') -----<br>
+ genStoreWithImmutabilityAndStoreCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr<br>
+ "Store check code is duplicated to use a single trampoline"<br>
+ <var: #immutableJump type: #'AbstractInstruction *'><br>
+ <var: #trampJump type: #'AbstractInstruction *'><br>
+ <var: #jmpImmediate type: #'AbstractInstruction *'><br>
+ <var: #jmpDestYoung type: #'AbstractInstruction *'><br>
+ <var: #jmpSourceOld type: #'AbstractInstruction *'><br>
+ <var: #jmpAlreadyRemembered type: #'AbstractInstruction *'><br>
+ | immutableJump trampJump jmpImmediate jmpDestYoung jmpSourceOld rememberedBitByteOffset jmpAlreadyRemembered mask |<br>
+<br>
+ immutableJump := self genJumpImmutable: destReg scratchReg: scratchReg.<br>
+<br>
+ cogit genTraceStores.<br>
+<br>
+ "do the store"<br>
+ cogit MoveR: sourceReg<br>
+ Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
+ r: destReg.<br>
+<br>
+ "store check"<br>
+ jmpImmediate := self genJumpImmediate: sourceReg.<br>
+ "Get the old/new boundary in scratchReg"<br>
+ cogit MoveCw: objectMemory storeCheckBoundary R: scratchReg.<br>
+ "Is target young? If so we're done"<br>
+ cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg - scratchReg"<br>
+ jmpDestYoung := cogit JumpBelow: 0.<br>
+ "Is value stored old? If so we're done."<br>
+ cogit CmpR: scratchReg R: sourceReg. "N.B. FLAGS := valueReg - scratchReg"<br>
+ jmpSourceOld := cogit JumpAboveOrEqual: 0.<br>
+ "value is young and target is old.<br>
+ Need to remember this only if the remembered bit is not already set.<br>
+ Test the remembered bit. Only need to fetch the byte containing it,<br>
+ which reduces the size of the mask constant."<br>
+ rememberedBitByteOffset := jmpSourceOld isBigEndian<br>
+ ifTrue: [objectMemory baseHeaderSize - 1 - (objectMemory rememberedBitShift // 8)]<br>
+ ifFalse:[objectMemory rememberedBitShift // 8].<br>
+ mask := 1 << (objectMemory rememberedBitShift \\ 8).<br>
+ cogit MoveMb: rememberedBitByteOffset r: destReg R: scratchReg.<br>
+ cogit AndCq: mask R: scratchReg.<br>
+ jmpAlreadyRemembered := cogit JumpNonZero: 0.<br>
+ "We know scratchReg now holds 0, this is convenient because the trampoline<br>
+ convention expects 0 for store check in scratchReg. What a coincidence ;-)"<br>
+ "Remembered bit is not set. Call store check to insert dest into remembered table."<br>
+ trampJump := cogit Jump: 0.<br>
+ "Here we reach the trampoline for Immutability failure"<br>
+ immutableJump jmpTarget: (cogit MoveCq: index + 1 R: scratchReg). "index + 1 as 0 is reserved for store checks"<br>
+ trampJump jmpTarget: (cogit CallRT: ceStoreTrampoline).<br>
+ cogit annotateBytecode: cogit Label.<br>
+ needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].<br>
+<br>
+ jmpImmediate jmpTarget:<br>
+ (jmpDestYoung jmpTarget:<br>
+ (jmpSourceOld jmpTarget:<br>
+ (jmpAlreadyRemembered jmpTarget:<br>
+ cogit Label))).<br>
+<br>
+ ^ 0!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur>>genStoreWithImmutabilityButNoStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: (in category 'compile abstract instructions') -----<br>
+ genStoreWithImmutabilityButNoStoreCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr<br>
+<br>
+ <var: #immutableJump type: #'AbstractInstruction *'><br>
+ <var: #immutabilityFailure type: #'AbstractInstruction *'><br>
+ | immutabilityFailure mutableJump |<br>
+<br>
+ "imm check has its own trampoline"<br>
+ mutableJump := self genJumpMutable: destReg scratchReg: scratchReg.<br>
+ cogit MoveCq: index + 1 R: TempReg. "index + 1 as 0 is reserved for store checks"<br>
+ cogit CallRT: ceStoreTrampoline.<br>
+ cogit annotateBytecode: cogit Label.<br>
+ needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].<br>
+ immutabilityFailure := cogit Jump: 0.<br>
+ mutableJump jmpTarget: cogit Label.<br>
+<br>
+ cogit genTraceStores.<br>
+<br>
+ "do the store"<br>
+ cogit MoveR: sourceReg<br>
+ Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
+ r: destReg.<br>
+<br>
+ immutabilityFailure jmpTarget: cogit Label.<br>
+<br>
+ ^ 0!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur>>genStoreWithImmutabilityCheckSourceReg:slotIndex:destReg:scratchReg:needsStoreCheck:needRestoreRcvr: (in category 'compile abstract instructions') -----<br>
+ genStoreWithImmutabilityCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needsStoreCheck: needsStoreCheck needRestoreRcvr: needRestoreRcvr<br>
+ "We know there is a frame as immutability check requires a frame"<br>
+ "needRestoreRcvr has to be true to keep RcvrResultReg live with the receiver in it across the trampoline"<br>
+<br>
+ "Trampoline convention..."<br>
+ self assert: destReg == ReceiverResultReg.<br>
+ self assert: scratchReg == TempReg.<br>
+ self assert: sourceReg == ClassReg.<br>
+<br>
+ needsStoreCheck<br>
+ ifTrue:<br>
+ [ self<br>
+ genStoreWithImmutabilityAndStoreCheckSourceReg: sourceReg<br>
+ slotIndex: index<br>
+ destReg: destReg<br>
+ scratchReg: scratchReg<br>
+ needRestoreRcvr: needRestoreRcvr ]<br>
+ ifFalse:<br>
+ [ self<br>
+ genStoreWithImmutabilityButNoStoreCheckSourceReg: sourceReg<br>
+ slotIndex: index<br>
+ destReg: destReg<br>
+ scratchReg: scratchReg<br>
+ needRestoreRcvr: needRestoreRcvr ].<br>
+ ^ 0!<br>
<br>
Item was changed:<br>
----- Method: CogObjectRepresentationForSpur>>generateObjectRepresentationTrampolines (in category 'initialization') -----<br>
generateObjectRepresentationTrampolines<br>
"Do the store check. Answer the argument for the benefit of the code generator;<br>
ReceiverResultReg may be caller-saved and hence smashed by this call. Answering<br>
it allows the code generator to reload ReceiverResultReg cheaply.<br>
In Spur the only thing we leave to the run-time is adding the receiver to the<br>
remembered set and setting its isRemembered bit."<br>
self<br>
cppIf: IMMUTABILITY<br>
+ ifTrue: [ceStoreTrampoline := self genStoreTrampolineCalled: 'ceStoreTrampoline'].<br>
- ifTrue: "c.f. genImmutableCheck:slotIndex:sourceReg:scratchReg:popBoolean:needRestoreRcvr:"<br>
- [ceCannotAssignToWithIndexTrampoline := cogit<br>
- genTrampolineFor: #ceCannotAssignTo:withIndex:valueToAssign:<br>
- called: 'ceCannotAssignToWithIndexTrampoline'<br>
- arg: ReceiverResultReg<br>
- arg: TempReg<br>
- arg: ClassReg].<br>
ceStoreCheckTrampoline := cogit<br>
genTrampolineFor: #remember:<br>
called: 'ceStoreCheckTrampoline'<br>
arg: ReceiverResultReg<br>
regsToSave: (cogit callerSavedRegMask bitClear: (cogit registerMaskFor: ReceiverResultReg))<br>
result: cogit returnRegForStoreCheck.<br>
ceStoreCheckContextReceiverTrampoline := self genStoreCheckContextReceiverTrampoline.<br>
ceScheduleScavengeTrampoline := cogit<br>
genTrampolineFor: #ceScheduleScavenge<br>
called: 'ceScheduleScavengeTrampoline'<br>
regsToSave: cogit callerSavedRegMask.<br>
ceSmallActiveContextInMethodTrampoline := self genActiveContextTrampolineLarge: false inBlock: false called: 'ceSmallMethodContext'.<br>
ceSmallActiveContextInBlockTrampoline := self genActiveContextTrampolineLarge: false inBlock: true called: 'ceSmallBlockContext'.<br>
ceLargeActiveContextInMethodTrampoline := self genActiveContextTrampolineLarge: true inBlock: false called: 'ceLargeMethodContext'.<br>
ceLargeActiveContextInBlockTrampoline := self genActiveContextTrampolineLarge: true inBlock: true called: 'ceLargeBlockContext'!<br>
<br>
Item was changed:<br>
----- Method: CogObjectRepresentationForSqueakV3>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: (in category 'compile abstract instructions') -----<br>
genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck<br>
| jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRoot mask rootBitByteOffset |<br>
<var: #jmpImmediate type: #'AbstractInstruction *'><br>
<var: #jmpDestYoung type: #'AbstractInstruction *'><br>
<var: #jmpSourceOld type: #'AbstractInstruction *'><br>
<var: #jmpAlreadyRoot type: #'AbstractInstruction *'><br>
+<br>
+ cogit genTraceStores.<br>
"do the store"<br>
cogit MoveR: sourceReg Mw: index * objectMemory wordSize + objectMemory baseHeaderSize r: destReg.<br>
"if no need for the store check then returns"<br>
needsStoreCheck ifFalse: [ ^ 0 ].<br>
"now the check. Is value stored an integer? If so we're done"<br>
jmpImmediate := self genJumpImmediate: sourceReg.<br>
"Get the old/new boundary in scratchReg"<br>
cogit MoveAw: objectMemory youngStartAddress R: scratchReg.<br>
"Is target young? If so we're done"<br>
cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg - scratchReg"<br>
jmpDestYoung := cogit JumpAboveOrEqual: 0.<br>
"Is value stored old? If so we're done."<br>
cogit CmpR: scratchReg R: sourceReg. "N.B. FLAGS := sourceReg - scratchReg"<br>
jmpSourceOld := cogit JumpBelow: 0.<br>
"value is young and target is old.<br>
Need to make this a root if the root bit is not already set.<br>
Test the root bit. Only need to fetch the byte containing it,<br>
which reduces the size of the mask constant."<br>
rootBitByteOffset := jmpSourceOld isBigEndian<br>
ifTrue: [objectMemory wordSize - RootBitDigitLength]<br>
ifFalse:[RootBitDigitLength - 1].<br>
mask := RootBitDigitLength > 1<br>
ifTrue: [RootBit >> (RootBitDigitLength - 1 * 8)]<br>
ifFalse: [RootBit].<br>
cogit MoveMb: rootBitByteOffset r: destReg R: scratchReg.<br>
cogit AndCq: mask R: scratchReg.<br>
jmpAlreadyRoot := cogit JumpNonZero: 0.<br>
"Root bit is not set. Call store check to insert dest into root table."<br>
self assert: destReg == ReceiverResultReg.<br>
cogit<br>
evaluateTrampolineCallBlock: [cogit CallRT: ceStoreCheckTrampoline]<br>
protectLinkRegIfNot: inFrame.<br>
jmpImmediate jmpTarget:<br>
(jmpDestYoung jmpTarget:<br>
(jmpSourceOld jmpTarget:<br>
(jmpAlreadyRoot jmpTarget:<br>
cogit Label))).<br>
^0!<br>
<br>
Item was changed:<br>
----- Method: SimpleStackBasedCogit>>genStorePop:LiteralVariable: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean LiteralVariable: litVarIndex<br>
<inline: false><br>
+ | association |<br>
- | association immutabilityFailure |<br>
- <var: #immutabilityFailure type: #'AbstractInstruction *'><br>
"The only reason we assert needsFrame here is that in a frameless method<br>
ReceiverResultReg must and does contain only self, but the ceStoreCheck<br>
trampoline expects the target of the store to be in ReceiverResultReg. So<br>
in a frameless method we would have a conflict between the receiver and<br>
the literal store, unless we we smart enough to realise that ReceiverResultReg<br>
was unused after the literal variable store, unlikely given that methods<br>
return self by default."<br>
self assert: needsFrame.<br>
association := self getLiteral: litVarIndex.<br>
self genMoveConstant: association R: ReceiverResultReg.<br>
objectRepresentation<br>
genEnsureObjInRegNotForwarded: ReceiverResultReg<br>
scratchReg: TempReg.<br>
popBoolean<br>
ifTrue: [self PopR: ClassReg]<br>
ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg].<br>
+ self<br>
+ genStoreSourceReg: ClassReg<br>
+ slotIndex: ValueIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
- traceStores > 0 ifTrue:<br>
- [self CallRT: ceTraceStoreTrampoline].<br>
- self cppIf: IMMUTABILITY ifTrue:<br>
- [immutabilityFailure := objectRepresentation<br>
- genImmutableCheck: ReceiverResultReg<br>
- slotIndex: ValueIndex<br>
- sourceReg: ClassReg<br>
- scratchReg: TempReg<br>
- needRestoreRcvr: true].<br>
- objectRepresentation<br>
- genStoreSourceReg: ClassReg<br>
- slotIndex: ValueIndex<br>
- destReg: ReceiverResultReg<br>
- scratchReg: TempReg<br>
inFrame: needsFrame.<br>
-<br>
- self cppIf: IMMUTABILITY ifTrue:<br>
- [immutabilityFailure jmpTarget: self Label].<br>
-<br>
^0!<br>
<br>
Item was changed:<br>
----- Method: SimpleStackBasedCogit>>genStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
<inline: false><br>
+ | jmpSingle jmpDone |<br>
- | jmpSingle jmpDone immutabilityFailure |<br>
- <var: #immutabilityFailure type: #'AbstractInstruction *'><br>
<var: #jmpSingle type: #'AbstractInstruction *'><br>
<var: #jmpDone type: #'AbstractInstruction *'><br>
"The reason we need a frame here is that assigning to an inst var of a context may<br>
involve wholesale reorganization of stack pages, and the only way to preserve the<br>
execution state of an activation in that case is if it has a frame."<br>
self assert: needsFrame.<br>
self putSelfInReceiverResultReg.<br>
objectRepresentation<br>
genLoadSlot: SenderIndex<br>
sourceReg: ReceiverResultReg<br>
destReg: TempReg.<br>
self MoveMw: 0 r: SPReg R: ClassReg.<br>
jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.<br>
self MoveCq: slotIndex R: SendNumArgsReg.<br>
self CallRT: ceStoreContextInstVarTrampoline.<br>
jmpDone := self Jump: 0.<br>
jmpSingle jmpTarget: self Label.<br>
- traceStores > 0 ifTrue:<br>
- [self CallRT: ceTraceStoreTrampoline].<br>
- self cppIf: IMMUTABILITY ifTrue:<br>
- [immutabilityFailure := objectRepresentation<br>
- genImmutableCheck: ReceiverResultReg<br>
- slotIndex: slotIndex<br>
- sourceReg: ClassReg<br>
- scratchReg: TempReg<br>
- needRestoreRcvr: true].<br>
- objectRepresentation<br>
- genStoreSourceReg: ClassReg<br>
- slotIndex: slotIndex<br>
- destReg: ReceiverResultReg<br>
- scratchReg: TempReg<br>
- inFrame: true.<br>
- jmpDone jmpTarget: self Label.<br>
popBoolean ifTrue:<br>
[self AddCq: objectMemory wordSize R: SPReg].<br>
+ self<br>
+ genStoreSourceReg: ClassReg<br>
+ slotIndex: slotIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ inFrame: needsFrame.<br>
+ jmpDone jmpTarget: self Label.<br>
- self cppIf: IMMUTABILITY ifTrue:<br>
- [immutabilityFailure jmpTarget: self Label].<br>
^0!<br>
<br>
Item was changed:<br>
----- Method: SimpleStackBasedCogit>>genStorePop:ReceiverVariable: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean ReceiverVariable: slotIndex<br>
<inline: false><br>
- | immutabilityFailure |<br>
- <var: #immutabilityFailure type: #'AbstractInstruction *'><br>
needsFrame ifTrue:<br>
[self putSelfInReceiverResultReg].<br>
popBoolean<br>
ifTrue: [self PopR: ClassReg]<br>
ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg].<br>
+ self<br>
+ genStoreSourceReg: ClassReg<br>
+ slotIndex: slotIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
- traceStores > 0 ifTrue:<br>
- [self CallRT: ceTraceStoreTrampoline].<br>
- self cppIf: IMMUTABILITY ifTrue:<br>
- [immutabilityFailure := objectRepresentation<br>
- genImmutableCheck: ReceiverResultReg<br>
- slotIndex: slotIndex<br>
- sourceReg: ClassReg<br>
- scratchReg: TempReg<br>
- needRestoreRcvr: true].<br>
- objectRepresentation<br>
- genStoreSourceReg: ClassReg<br>
- slotIndex: slotIndex<br>
- destReg: ReceiverResultReg<br>
- scratchReg: TempReg<br>
inFrame: needsFrame.<br>
-<br>
- self cppIf: IMMUTABILITY ifTrue:<br>
- [immutabilityFailure jmpTarget: self Label].<br>
-<br>
^0!<br>
<br>
Item was changed:<br>
----- Method: SimpleStackBasedCogit>>genStorePop:RemoteTemp:At: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex<br>
<inline: false><br>
"The only reason we assert needsFrame here is that in a frameless method<br>
ReceiverResultReg must and does contain only self, but the ceStoreCheck<br>
trampoline expects the target of the store to be in ReceiverResultReg. So<br>
in a frameless method we would have a conflict between the receiver and<br>
the temote temp store, unless we we smart enough to realise that<br>
ReceiverResultReg was unused after the literal variable store, unlikely given<br>
that methods return self by default."<br>
self assert: needsFrame.<br>
popBoolean<br>
ifTrue: [self PopR: ClassReg]<br>
ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg].<br>
self MoveMw: (self frameOffsetOfTemporary: remoteTempIndex) r: FPReg R: ReceiverResultReg.<br>
- traceStores > 0 ifTrue:<br>
- [self CallRT: ceTraceStoreTrampoline].<br>
^objectRepresentation<br>
genStoreSourceReg: ClassReg<br>
slotIndex: slotIndex<br>
destReg: ReceiverResultReg<br>
scratchReg: TempReg<br>
inFrame: needsFrame!<br>
<br>
Item was added:<br>
+ ----- Method: SimpleStackBasedCogit>>genTraceStores (in category 'bytecode generator support') -----<br>
+ genTraceStores<br>
+ <inline: true><br>
+ traceStores > 0 ifTrue: [ self CallRT: ceTraceStoreTrampoline ].!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genImmutabilityCheckStorePop:LiteralVariable: (in category 'bytecode generator support') -----<br>
+ genImmutabilityCheckStorePop: popBoolean LiteralVariable: litVarIndex<br>
+ <inline: true><br>
+ | association needStoreCheck |<br>
+ "The only reason we assert needsFrame here is that in a frameless method<br>
+ ReceiverResultReg must and does contain only self, but the ceStoreCheck<br>
+ trampoline expects the target of the store to be in ReceiverResultReg. So<br>
+ in a frameless method we would have a conflict between the receiver and<br>
+ the literal store, unless we we smart enough to realise that ReceiverResultReg<br>
+ was unused after the literal variable store, unlikely given that methods<br>
+ return self by default."<br>
+ self assert: needsFrame.<br>
+ "N.B. No need to check the stack for references because we generate code for<br>
+ literal variable loads that stores the result in a register, deferring only the register push."<br>
+ needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+ association := self getLiteral: litVarIndex.<br>
+ optStatus isReceiverResultRegLive: false.<br>
+ self ssAllocateRequiredReg: ReceiverResultReg. "for store trampoline call in genStoreSourceReg: has to be ReceiverResultReg"<br>
+ self genMoveConstant: association R: ReceiverResultReg.<br>
+ objectRepresentation genEnsureObjInRegNotForwarded: ReceiverResultReg scratchReg: TempReg.<br>
+ self ssAllocateRequiredReg: ClassReg.<br>
+ self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
+ self ssFlushTo: simStackPtr.<br>
+ objectRepresentation<br>
+ genStoreWithImmutabilityCheckSourceReg: ClassReg<br>
+ slotIndex: ValueIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ needsStoreCheck: needStoreCheck<br>
+ needRestoreRcvr: false.<br>
+ ^ 0!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genImmutabilityCheckStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----<br>
+ genImmutabilityCheckStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
+ <inline: true><br>
+ | jmpSingle jmpDone needStoreCheck |<br>
+ <var: #jmpSingle type: #'AbstractInstruction *'><br>
+ <var: #jmpDone type: #'AbstractInstruction *'><br>
+ "The reason we need a frame here is that assigning to an inst var of a context may<br>
+ involve wholesale reorganization of stack pages, and the only way to preserve the<br>
+ execution state of an activation in that case is if it has a frame."<br>
+ self assert: needsFrame.<br>
+ needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+ "Note that ReceiverResultReg remains live after both<br>
+ ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline."<br>
+ self ensureReceiverResultRegContainsSelf.<br>
+ self ssPop: 1.<br>
+ self ssAllocateCallReg: ClassReg and: SendNumArgsReg. "for ceStoreContextInstVarTrampoline"<br>
+ self ssPush: 1.<br>
+ objectRepresentation<br>
+ genLoadSlot: SenderIndex<br>
+ sourceReg: ReceiverResultReg<br>
+ destReg: TempReg.<br>
+ self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
+ "stack is flushed except maybe ssTop if popBoolean is false.<br>
+ ssTop is a SSregister in this case due to #ssStoreAndReplacePop:<br>
+ to avoid a second indirect read / annotation in case of SSConstant<br>
+ or SSBaseRegister"<br>
+ self ssFlushTo: simStackPtr.<br>
+ jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.<br>
+ self MoveCq: slotIndex R: SendNumArgsReg.<br>
+ self CallRT: ceStoreContextInstVarTrampoline.<br>
+ jmpDone := self Jump: 0.<br>
+ jmpSingle jmpTarget: self Label.<br>
+ objectRepresentation<br>
+ genStoreWithImmutabilityCheckSourceReg: ClassReg<br>
+ slotIndex: slotIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ needsStoreCheck: needStoreCheck<br>
+ needRestoreRcvr: true.<br>
+ jmpDone jmpTarget: self Label.<br>
+ ^0!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genImmutabilityCheckStorePop:ReceiverVariable: (in category 'bytecode generator support') -----<br>
+ genImmutabilityCheckStorePop: popBoolean ReceiverVariable: slotIndex<br>
+ <inline: true><br>
+ | needStoreCheck |<br>
+ self assert: needsFrame.<br>
+ needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+ "Note that ReceiverResultReg remains live after the trampoline."<br>
+ self ensureReceiverResultRegContainsSelf.<br>
+ self ssAllocateRequiredReg: ClassReg.<br>
+ self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
+ self ssFlushTo: simStackPtr.<br>
+ objectRepresentation<br>
+ genStoreWithImmutabilityCheckSourceReg: ClassReg<br>
+ slotIndex: slotIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ needsStoreCheck: needStoreCheck<br>
+ needRestoreRcvr: true.<br>
+<br>
+ ^ 0!<br>
<br>
Item was changed:<br>
----- Method: StackToRegisterMappingCogit>>genStorePop:LiteralVariable: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean LiteralVariable: litVarIndex<br>
<inline: false><br>
- | topReg association needStoreCheck immutabilityFailure |<br>
- "The only reason we assert needsFrame here is that in a frameless method<br>
- ReceiverResultReg must and does contain only self, but the ceStoreCheck<br>
- trampoline expects the target of the store to be in ReceiverResultReg. So<br>
- in a frameless method we would have a conflict between the receiver and<br>
- the literal store, unless we we smart enough to realise that ReceiverResultReg<br>
- was unused after the literal variable store, unlikely given that methods<br>
- return self by default."<br>
- self assert: needsFrame.<br>
- self cppIf: IMMUTABILITY ifTrue: [ self ssFlushTo: simStackPtr - 1 ].<br>
- "N.B. No need to check the stack for references because we generate code for<br>
- literal variable loads that stores the result in a register, deferring only the register push."<br>
- needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
- association := self getLiteral: litVarIndex.<br>
- optStatus isReceiverResultRegLive: false.<br>
- self ssAllocateRequiredReg: ReceiverResultReg. "for ceStoreCheck call in genStoreSourceReg: has to be ReceiverResultReg"<br>
- self genMoveConstant: association R: ReceiverResultReg.<br>
- objectRepresentation genEnsureObjInRegNotForwarded: ReceiverResultReg scratchReg: TempReg.<br>
self<br>
cppIf: IMMUTABILITY<br>
+ ifTrue: [ ^ self genImmutabilityCheckStorePop: popBoolean LiteralVariable: litVarIndex ]<br>
+ ifFalse: [ ^ self genVanillaStorePop: popBoolean LiteralVariable: litVarIndex ]<br>
+ !<br>
- ifTrue:<br>
- [ self ssAllocateRequiredReg: ClassReg.<br>
- topReg := ClassReg.<br>
- self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
- "stack is flushed except maybe ssTop if popBoolean is false.<br>
- ssTop is a SSregister in this case due to #ssStoreAndReplacePop:<br>
- to avoid a second indirect read / annotation in case of SSConstant<br>
- or SSBaseRegister"<br>
- self ssFlushTo: simStackPtr.<br>
- immutabilityFailure := objectRepresentation<br>
- genImmutableCheck: ReceiverResultReg<br>
- slotIndex: ValueIndex<br>
- sourceReg: ClassReg<br>
- scratchReg: TempReg<br>
- needRestoreRcvr: false ]<br>
- ifFalse:<br>
- [ topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
- self ssStorePop: popBoolean toReg: topReg ].<br>
- traceStores > 0 ifTrue:<br>
- [self MoveR: topReg R: TempReg.<br>
- self CallRT: ceTraceStoreTrampoline].<br>
- objectRepresentation<br>
- genStoreSourceReg: topReg<br>
- slotIndex: ValueIndex<br>
- destReg: ReceiverResultReg<br>
- scratchReg: TempReg<br>
- inFrame: needsFrame<br>
- needsStoreCheck: needStoreCheck.<br>
- self cppIf: IMMUTABILITY ifTrue: [ immutabilityFailure jmpTarget: self Label ].<br>
- ^ 0!<br>
<br>
Item was changed:<br>
----- Method: StackToRegisterMappingCogit>>genStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
<inline: false><br>
- | jmpSingle jmpDone needStoreCheck immutabilityFailure |<br>
- <var: #jmpSingle type: #'AbstractInstruction *'><br>
- <var: #jmpDone type: #'AbstractInstruction *'><br>
- "The reason we need a frame here is that assigning to an inst var of a context may<br>
- involve wholesale reorganization of stack pages, and the only way to preserve the<br>
- execution state of an activation in that case is if it has a frame."<br>
- self assert: needsFrame.<br>
- self cppIf: IMMUTABILITY ifTrue: [ self ssFlushTo: simStackPtr - 1 ].<br>
- self ssFlushUpThroughReceiverVariable: slotIndex.<br>
- needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
- "Note that ReceiverResultReg remains live after both<br>
- ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline."<br>
- self ensureReceiverResultRegContainsSelf.<br>
- self ssPop: 1.<br>
- self ssAllocateCallReg: ClassReg and: SendNumArgsReg. "for ceStoreContextInstVarTrampoline"<br>
- self ssPush: 1.<br>
- objectRepresentation<br>
- genLoadSlot: SenderIndex<br>
- sourceReg: ReceiverResultReg<br>
- destReg: TempReg.<br>
self<br>
cppIf: IMMUTABILITY<br>
+ ifTrue: [ ^ self genImmutabilityCheckStorePop: popBoolean MaybeContextReceiverVariable: slotIndex ]<br>
+ ifFalse: [ ^ self genVanillaStorePop: popBoolean MaybeContextReceiverVariable: slotIndex ]!<br>
- ifTrue:<br>
- [ self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
- "stack is flushed except maybe ssTop if popBoolean is false.<br>
- ssTop is a SSregister in this case due to #ssStoreAndReplacePop:<br>
- to avoid a second indirect read / annotation in case of SSConstant<br>
- or SSBaseRegister"<br>
- self ssFlushTo: simStackPtr. ]<br>
- ifFalse: [ self ssStorePop: popBoolean toReg: ClassReg ].<br>
- jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.<br>
- self MoveCq: slotIndex R: SendNumArgsReg.<br>
- self CallRT: ceStoreContextInstVarTrampoline.<br>
- jmpDone := self Jump: 0.<br>
- jmpSingle jmpTarget: self Label.<br>
- traceStores > 0 ifTrue:<br>
- [self MoveR: ClassReg R: TempReg.<br>
- self CallRT: ceTraceStoreTrampoline].<br>
- self<br>
- cppIf: IMMUTABILITY<br>
- ifTrue:<br>
- [ immutabilityFailure := objectRepresentation<br>
- genImmutableCheck: ReceiverResultReg<br>
- slotIndex: ValueIndex<br>
- sourceReg: ClassReg<br>
- scratchReg: TempReg<br>
- needRestoreRcvr: true ].<br>
- objectRepresentation<br>
- genStoreSourceReg: ClassReg<br>
- slotIndex: slotIndex<br>
- destReg: ReceiverResultReg<br>
- scratchReg: TempReg<br>
- inFrame: true<br>
- needsStoreCheck: needStoreCheck.<br>
- jmpDone jmpTarget: self Label.<br>
- self cppIf: IMMUTABILITY ifTrue: [ immutabilityFailure jmpTarget: self Label ].<br>
- ^0!<br>
<br>
Item was changed:<br>
----- Method: StackToRegisterMappingCogit>>genStorePop:ReceiverVariable: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean ReceiverVariable: slotIndex<br>
<inline: false><br>
- | topReg needStoreCheck immutabilityFailure |<br>
- self cppIf: IMMUTABILITY ifTrue: [ self assert: needsFrame. self ssFlushTo: simStackPtr - 1 ].<br>
- self ssFlushUpThroughReceiverVariable: slotIndex.<br>
- needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
- "Note that ReceiverResultReg remains live after ceStoreCheckTrampoline."<br>
- self ensureReceiverResultRegContainsSelf.<br>
self<br>
cppIf: IMMUTABILITY<br>
+ ifTrue: [ ^ self genImmutabilityCheckStorePop: popBoolean ReceiverVariable: slotIndex ]<br>
+ ifFalse: [ ^ self genVanillaStorePop: popBoolean ReceiverVariable: slotIndex ]<br>
+ !<br>
- ifTrue:<br>
- [ self ssAllocateRequiredReg: ClassReg.<br>
- topReg := ClassReg.<br>
- self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
- "stack is flushed except maybe ssTop if popBoolean is false.<br>
- ssTop is a SSregister in this case due to #ssStoreAndReplacePop:<br>
- to avoid a second indirect read / annotation in case of SSConstant<br>
- or SSBaseRegister"<br>
- self ssFlushTo: simStackPtr.<br>
- immutabilityFailure := objectRepresentation<br>
- genImmutableCheck: ReceiverResultReg<br>
- slotIndex: slotIndex<br>
- sourceReg: ClassReg<br>
- scratchReg: TempReg<br>
- needRestoreRcvr: true ]<br>
- ifFalse:<br>
- [ topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
- self ssStorePop: popBoolean toReg: topReg ].<br>
- traceStores > 0 ifTrue:<br>
- [ self MoveR: topReg R: TempReg.<br>
- self evaluateTrampolineCallBlock: [ self CallRT: ceTraceStoreTrampoline ] protectLinkRegIfNot: needsFrame ].<br>
- objectRepresentation<br>
- genStoreSourceReg: topReg<br>
- slotIndex: slotIndex<br>
- destReg: ReceiverResultReg<br>
- scratchReg: TempReg<br>
- inFrame: needsFrame<br>
- needsStoreCheck: needStoreCheck.<br>
- self cppIf: IMMUTABILITY ifTrue: [ immutabilityFailure jmpTarget: self Label ].<br>
- ^ 0!<br>
<br>
Item was changed:<br>
----- Method: StackToRegisterMappingCogit>>genStorePop:RemoteTemp:At: (in category 'bytecode generator support') -----<br>
genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex<br>
<inline: false><br>
| topReg needStoreCheck |<br>
"The only reason we assert needsFrame here is that in a frameless method<br>
ReceiverResultReg must and does contain only self, but the ceStoreCheck<br>
trampoline expects the target of the store to be in ReceiverResultReg. So<br>
in a frameless method we would have a conflict between the receiver and<br>
the temote temp store, unless we we smart enough to realise that<br>
ReceiverResultReg was unused after the literal variable store, unlikely given<br>
that methods return self by default."<br>
self assert: needsFrame.<br>
"N.B. No need to check the stack for references because we generate code for<br>
remote temp loads that stores the result in a register, deferring only the register push."<br>
needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
self ssAllocateRequiredReg: ReceiverResultReg.<br>
optStatus isReceiverResultRegLive: false.<br>
self ssStoreAndReplacePop: popBoolean toReg: topReg.<br>
self MoveMw: (self frameOffsetOfTemporary: remoteTempIndex) r: FPReg R: ReceiverResultReg.<br>
- traceStores > 0 ifTrue:<br>
- [ self MoveR: topReg R: TempReg.<br>
- self CallRT: ceTraceStoreTrampoline. ].<br>
^objectRepresentation<br>
genStoreSourceReg: topReg<br>
slotIndex: slotIndex<br>
destReg: ReceiverResultReg<br>
scratchReg: TempReg<br>
inFrame: needsFrame<br>
needsStoreCheck: needStoreCheck!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genTraceStores (in category 'bytecode generator support') -----<br>
+ genTraceStores<br>
+ <inline: true><br>
+ traceStores > 0 ifTrue:<br>
+ [ self MoveR: ClassReg R: TempReg.<br>
+ self CallRT: ceTraceStoreTrampoline ].!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genVanillaStorePop:LiteralVariable: (in category 'bytecode generator support') -----<br>
+ genVanillaStorePop: popBoolean LiteralVariable: litVarIndex<br>
+ <inline: true><br>
+ | topReg association needStoreCheck |<br>
+ "The only reason we assert needsFrame here is that in a frameless method<br>
+ ReceiverResultReg must and does contain only self, but the ceStoreCheck<br>
+ trampoline expects the target of the store to be in ReceiverResultReg. So<br>
+ in a frameless method we would have a conflict between the receiver and<br>
+ the literal store, unless we we smart enough to realise that ReceiverResultReg<br>
+ was unused after the literal variable store, unlikely given that methods<br>
+ return self by default."<br>
+ self assert: needsFrame.<br>
+ "N.B. No need to check the stack for references because we generate code for<br>
+ literal variable loads that stores the result in a register, deferring only the register push."<br>
+ needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+ association := self getLiteral: litVarIndex.<br>
+ optStatus isReceiverResultRegLive: false.<br>
+ self ssAllocateRequiredReg: ReceiverResultReg. "for ceStoreCheck call in genStoreSourceReg: has to be ReceiverResultReg"<br>
+ self genMoveConstant: association R: ReceiverResultReg.<br>
+ objectRepresentation genEnsureObjInRegNotForwarded: ReceiverResultReg scratchReg: TempReg.<br>
+ topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
+ self ssStorePop: popBoolean toReg: topReg.<br>
+ objectRepresentation<br>
+ genStoreSourceReg: topReg<br>
+ slotIndex: ValueIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ inFrame: needsFrame<br>
+ needsStoreCheck: needStoreCheck.<br>
+ ^ 0!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genVanillaStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----<br>
+ genVanillaStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
+ <inline: true><br>
+ | jmpSingle jmpDone needStoreCheck |<br>
+ <var: #jmpSingle type: #'AbstractInstruction *'><br>
+ <var: #jmpDone type: #'AbstractInstruction *'><br>
+ "The reason we need a frame here is that assigning to an inst var of a context may<br>
+ involve wholesale reorganization of stack pages, and the only way to preserve the<br>
+ execution state of an activation in that case is if it has a frame."<br>
+ self assert: needsFrame.<br>
+ self ssFlushUpThroughReceiverVariable: slotIndex.<br>
+ needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+ "Note that ReceiverResultReg remains live after both<br>
+ ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline."<br>
+ self ensureReceiverResultRegContainsSelf.<br>
+ self ssPop: 1.<br>
+ self ssAllocateCallReg: ClassReg and: SendNumArgsReg. "for ceStoreContextInstVarTrampoline"<br>
+ self ssPush: 1.<br>
+ objectRepresentation<br>
+ genLoadSlot: SenderIndex<br>
+ sourceReg: ReceiverResultReg<br>
+ destReg: TempReg.<br>
+ self ssStorePop: popBoolean toReg: ClassReg.<br>
+ jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.<br>
+ self MoveCq: slotIndex R: SendNumArgsReg.<br>
+ self CallRT: ceStoreContextInstVarTrampoline.<br>
+ jmpDone := self Jump: 0.<br>
+ jmpSingle jmpTarget: self Label.<br>
+ objectRepresentation<br>
+ genStoreSourceReg: ClassReg<br>
+ slotIndex: slotIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ inFrame: true<br>
+ needsStoreCheck: needStoreCheck.<br>
+ jmpDone jmpTarget: self Label.<br>
+<br>
+ ^0!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit>>genVanillaStorePop:ReceiverVariable: (in category 'bytecode generator support') -----<br>
+ genVanillaStorePop: popBoolean ReceiverVariable: slotIndex<br>
+ <inline: true><br>
+ | topReg needStoreCheck |<br>
+ self ssFlushUpThroughReceiverVariable: slotIndex.<br>
+ needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+ "Note that ReceiverResultReg remains live after ceStoreCheckTrampoline."<br>
+ self ensureReceiverResultRegContainsSelf.<br>
+ topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
+ self ssStorePop: popBoolean toReg: topReg.<br>
+ objectRepresentation<br>
+ genStoreSourceReg: topReg<br>
+ slotIndex: slotIndex<br>
+ destReg: ReceiverResultReg<br>
+ scratchReg: TempReg<br>
+ inFrame: needsFrame<br>
+ needsStoreCheck: needStoreCheck.<br>
+ ^ 0!<br>
<br>
</blockquote></div><br></div>