Hi Clément,

On Wed, Mar 30, 2016 at 7:32 AM, Clément Bera <bera.clement@gmail.com> wrote:
 
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.

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.

It only saves a single byte because the xor to clear the register is 2 bytes and the byte move is 2 bytes so because it saves only a single byte I haven't bothered.  It makes more difference on x64 where the xor is 3 bytes and the full move 10, so xor followed by a 5 byte 32-bit move is 7 bytes, saving 3, for a 30% saving.  I also wonder whether the two byte sequence is slower on any x86 incarnations.

2016-03-30 15:52 GMT+02:00 <commits@source.squeak.org>:

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

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

Name: VMMaker.oscog-cb.1748
Author: cb
Time: 30 March 2016, 3:52:01.732 pm
UUID: db420bcd-e4aa-4cad-9543-047274e49915
Ancestors: VMMaker.oscog-nice.1747

Reworked machine code generation of immutability so for common stores it uses a single trampoline for both store checks and immutability checks.

I have simulation bug due to large integers, so I am not entirely sure everything is working, but generated code looks good.

=============== Diff against VMMaker.oscog-nice.1747 ===============

Item was changed:
  ----- Method: CogObjectRepresentation>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame: (in category 'compile abstract instructions') -----
  genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame
+       <inline: true>
+       self
+               cppIf: IMMUTABILITY
+               ifTrue:
+                       [ ^ self
+                               genStoreWithImmutabilityCheckSourceReg: sourceReg
+                               slotIndex: index
+                               destReg: destReg
+                               scratchReg: scratchReg
+                               needsStoreCheck: true
+                               needRestoreRcvr: false "RcvrResultReg doesn't need to be live across the instructions" ]
+               ifFalse:
+                       [ ^ self
+                               genStoreSourceReg: sourceReg
+                               slotIndex: index
+                               destReg: destReg
+                               scratchReg: scratchReg
+                               inFrame: inFrame
+                               needsStoreCheck: true ]!
-       ^ self
-               genStoreSourceReg: sourceReg
-               slotIndex: index
-               destReg: destReg
-               scratchReg: scratchReg
-               inFrame: inFrame
-               needsStoreCheck: true!

Item was changed:
  CogObjectRepresentation subclass: #CogObjectRepresentationForSpur
+       instanceVariableNames: 'ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceStoreTrampoline'
-       instanceVariableNames: 'ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceCannotAssignToWithIndexTrampoline'
        classVariableNames: ''
        poolDictionaries: 'VMBytecodeConstants VMSqueakClassIndices'
        category: 'VMMaker-JIT'!

Item was removed:
- ----- Method: CogObjectRepresentationForSpur>>genImmutableCheck:slotIndex:sourceReg:scratchReg:needRestoreRcvr: (in category 'compile abstract instructions') -----
- genImmutableCheck: regHoldingObjectMutated slotIndex: index sourceReg: regHoldingValueToStore scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr
-       | mutableJump fail |
-       <var: #mutableJump type: #'AbstractInstruction *'>
-       <var: #fail type: #'AbstractInstruction *'>
-       <inline: true>
-       <option: #IMMUTABILITY>
-       "Trampoline convention:
-       - objectMutated passed in ReceiverResultReg
-       - index (unboxed) passed in TempReg
-       - valueToStore passed in ClassReg.
-       Simulated stack is flushed, but if needRestoreRcvr is true
-       the receiver has to be live after this operation."
-       self assert: regHoldingObjectMutated == ReceiverResultReg.
-       self assert: scratchReg == TempReg.
-       self assert: regHoldingValueToStore == ClassReg.
-       mutableJump := self genJumpMutable: ReceiverResultReg scratchReg: TempReg.
-
-       "We reach this code if the object mutated is immutable."
-       cogit MoveCq: index R: TempReg.
-       "trampoline call and mcpc to bcpc annotation."
-       cogit CallRT: ceCannotAssignToWithIndexTrampoline.
-       cogit annotateBytecode: cogit Label.
-       "restore ReceiverResultReg state if needed, the rest of the state is spilled"
-       needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].
-       fail := cogit Jump: 0.
-
-       "We reach this code is the object mutated is mutable"
-       mutableJump jmpTarget: cogit Label.
-
-       ^ fail!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>genJumpBaseHeaderImmutable: (in category 'compile abstract instructions') -----
  genJumpBaseHeaderImmutable: baseHeaderReg
        "baseHeader holds at least the least significant 32 bits of the object"
        <returnTypeC: #'AbstractInstruction *'>
        <option: #IMMUTABILITY>
+       <inline: true>
        cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.
        ^ cogit JumpNonZero: 0!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>genJumpBaseHeaderMutable: (in category 'compile abstract instructions') -----
  genJumpBaseHeaderMutable: baseHeaderReg
        "baseHeader holds at least the least significant 32 bits of the object"
        <returnTypeC: #'AbstractInstruction *'>
        <option: #IMMUTABILITY>
+       <inline: true>
        cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.
        ^ cogit JumpZero: 0!

Item was added:
+ ----- 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 changed:
  ----- Method: CogObjectRepresentationForSpur>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: (in category 'compile abstract instructions') -----
  genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck
+
+       cogit genTraceStores.
        "do the store"
        cogit MoveR: sourceReg
                   Mw: index * objectMemory wordSize + objectMemory baseHeaderSize
                   r: destReg.
        "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)"
        needsStoreCheck ifTrue:
                [ ^ self
                        genStoreCheckReceiverReg: destReg
                        valueReg: sourceReg
                        scratchReg: scratchReg
                        inFrame: inFrame ].
        ^ 0!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>genStoreTrampolineCalled: (in category 'initialization') -----
+ genStoreTrampolineCalled: trampolineName
+       "This can be entered in one of two states, depending on TempReg.
+       TempReg = 0 => store check
+       TempReg > 0 => immutability failure
+       TempReg holds index + 1 in this case as the value 0 is reserved for store checks.
+       In addition the 0 value is convenient to save one instruction for store checks."
+       | jumpSC |
+       <var: #trampolineName type: #'char *'>
+       <var: #jumpSC type: #'AbstractInstruction *'>
+       <inline: false>
+       cogit zeroOpcodeIndex.
+       cogit CmpCq: 0 R: TempReg.
+       jumpSC := cogit JumpZero: 0.
+
+       "CannotAssignTo:, we restore the index."
+       cogit SubCq: 1 R: TempReg.
+       cogit
+               compileTrampolineFor: #ceCannotAssignTo:withIndex:valueToAssign:
+               numArgs: 3
+               arg: ReceiverResultReg
+               arg: TempReg
+               arg: ClassReg
+               arg: nil
+               regsToSave: cogit emptyRegisterMask
+               pushLinkReg: true
+               resultReg: NoReg.
+
+       "Store check"
+       jumpSC jmpTarget: cogit Label.
+       ^ cogit genTrampolineFor: #remember:
+               called: trampolineName
+               numArgs: 1
+               arg: ReceiverResultReg
+               arg: nil
+               arg: nil
+               arg: nil
+               regsToSave: cogit emptyRegisterMask
+               pushLinkReg: true
+               resultReg: NoReg
+               appendOpcodes: true!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>genStoreWithImmutabilityAndStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: (in category 'compile abstract instructions') -----
+ genStoreWithImmutabilityAndStoreCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr
+       "Store check code is duplicated to use a single trampoline"
+       <var: #immutableJump type: #'AbstractInstruction *'>
+       <var: #trampJump type: #'AbstractInstruction *'>
+       <var: #jmpImmediate type: #'AbstractInstruction *'>
+       <var: #jmpDestYoung type: #'AbstractInstruction *'>
+       <var: #jmpSourceOld type: #'AbstractInstruction *'>
+       <var: #jmpAlreadyRemembered type: #'AbstractInstruction *'>
+       | immutableJump trampJump jmpImmediate jmpDestYoung jmpSourceOld rememberedBitByteOffset jmpAlreadyRemembered mask |
+
+       immutableJump := self genJumpImmutable: destReg scratchReg: scratchReg.
+
+       cogit genTraceStores.
+
+       "do the store"
+       cogit MoveR: sourceReg
+                  Mw: index * objectMemory wordSize + objectMemory baseHeaderSize
+                  r: destReg.
+
+       "store check"
+       jmpImmediate := self genJumpImmediate: sourceReg.
+       "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: sourceReg. "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.
+       "We know scratchReg now holds 0, this is convenient because the trampoline
+       convention expects 0 for store check in scratchReg. What a coincidence ;-)"
+       "Remembered bit is not set.  Call store check to insert dest into remembered table."
+       trampJump := cogit Jump: 0.
+       "Here we reach the trampoline for Immutability failure"
+       immutableJump jmpTarget: (cogit MoveCq: index + 1 R: scratchReg). "index + 1 as 0 is reserved for store checks"
+       trampJump jmpTarget: (cogit CallRT: ceStoreTrampoline).
+       cogit annotateBytecode: cogit Label.
+       needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].
+
+       jmpImmediate jmpTarget:
+       (jmpDestYoung jmpTarget:
+       (jmpSourceOld jmpTarget:
+       (jmpAlreadyRemembered jmpTarget:
+               cogit Label))).
+
+       ^ 0!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>genStoreWithImmutabilityButNoStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: (in category 'compile abstract instructions') -----
+ genStoreWithImmutabilityButNoStoreCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr
+
+       <var: #immutableJump type: #'AbstractInstruction *'>
+       <var: #immutabilityFailure type: #'AbstractInstruction *'>
+       | immutabilityFailure mutableJump |
+
+       "imm check has its own trampoline"
+       mutableJump := self genJumpMutable: destReg scratchReg: scratchReg.
+       cogit MoveCq: index + 1 R: TempReg. "index + 1 as 0 is reserved for store checks"
+       cogit CallRT: ceStoreTrampoline.
+       cogit annotateBytecode: cogit Label.
+       needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].
+       immutabilityFailure := cogit Jump: 0.
+       mutableJump jmpTarget: cogit Label.
+
+       cogit genTraceStores.
+
+       "do the store"
+       cogit MoveR: sourceReg
+                  Mw: index * objectMemory wordSize + objectMemory baseHeaderSize
+                  r: destReg.
+
+       immutabilityFailure jmpTarget: cogit Label.
+
+       ^ 0!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>genStoreWithImmutabilityCheckSourceReg:slotIndex:destReg:scratchReg:needsStoreCheck:needRestoreRcvr: (in category 'compile abstract instructions') -----
+ genStoreWithImmutabilityCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needsStoreCheck: needsStoreCheck needRestoreRcvr: needRestoreRcvr
+       "We know there is a frame as immutability check requires a frame"
+       "needRestoreRcvr has to be true to keep RcvrResultReg live with the receiver in it across the trampoline"
+
+       "Trampoline convention..."
+       self assert: destReg == ReceiverResultReg.
+       self assert: scratchReg == TempReg.
+       self assert: sourceReg == ClassReg.
+
+       needsStoreCheck
+               ifTrue:
+                       [ self
+                               genStoreWithImmutabilityAndStoreCheckSourceReg: sourceReg
+                               slotIndex: index
+                               destReg: destReg
+                               scratchReg: scratchReg
+                               needRestoreRcvr: needRestoreRcvr ]
+               ifFalse:
+                       [ self
+                               genStoreWithImmutabilityButNoStoreCheckSourceReg: sourceReg
+                               slotIndex: index
+                               destReg: destReg
+                               scratchReg: scratchReg
+                               needRestoreRcvr: needRestoreRcvr ].
+       ^ 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: [ceStoreTrampoline := self genStoreTrampolineCalled: 'ceStoreTrampoline'].
-               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.
        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: 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 *'>
+
+       cogit genTraceStores.
        "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.
        "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]
                protectLinkRegIfNot: inFrame.
        jmpImmediate jmpTarget:
        (jmpDestYoung jmpTarget:
        (jmpSourceOld jmpTarget:
        (jmpAlreadyRoot jmpTarget:
                cogit Label))).
        ^0!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genStorePop:LiteralVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean LiteralVariable: litVarIndex
        <inline: false>
+       | association |
-       | association immutabilityFailure |
-       <var: #immutabilityFailure type: #'AbstractInstruction *'>
        "The only reason we assert needsFrame here is that in a frameless method
         ReceiverResultReg must and does contain only self, but the ceStoreCheck
         trampoline expects the target of the store to be in ReceiverResultReg.  So
         in a frameless method we would have a conflict between the receiver and
         the literal store, unless we we smart enough to realise that ReceiverResultReg
         was unused after the literal variable store, unlikely given that methods
         return self by default."
        self assert: needsFrame.
        association := self getLiteral: litVarIndex.
        self genMoveConstant: association R: ReceiverResultReg.
        objectRepresentation
                genEnsureObjInRegNotForwarded: ReceiverResultReg
                scratchReg: TempReg.
        popBoolean
                ifTrue: [self PopR: ClassReg]
                ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg].
+       self
+               genStoreSourceReg: ClassReg
+               slotIndex: ValueIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
-       traceStores > 0 ifTrue:
-               [self CallRT: ceTraceStoreTrampoline].
-       self cppIf: IMMUTABILITY ifTrue:
-               [immutabilityFailure := objectRepresentation
-                                                                       genImmutableCheck: ReceiverResultReg
-                                                                       slotIndex: ValueIndex
-                                                                       sourceReg: ClassReg
-                                                                       scratchReg: TempReg
-                                                                       needRestoreRcvr: true].
-       objectRepresentation
-               genStoreSourceReg: ClassReg
-               slotIndex: ValueIndex
-               destReg: ReceiverResultReg
-               scratchReg: TempReg
                inFrame: needsFrame.
-
-       self cppIf: IMMUTABILITY ifTrue:
-               [immutabilityFailure jmpTarget: self Label].
-
        ^0!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean MaybeContextReceiverVariable: slotIndex
        <inline: false>
+       | jmpSingle jmpDone |
-       | jmpSingle jmpDone immutabilityFailure |
-       <var: #immutabilityFailure type: #'AbstractInstruction *'>
        <var: #jmpSingle type: #'AbstractInstruction *'>
        <var: #jmpDone type: #'AbstractInstruction *'>
        "The reason we need a frame here is that assigning to an inst var of a context may
         involve wholesale reorganization of stack pages, and the only way to preserve the
         execution state of an activation in that case is if it has a frame."
        self assert: needsFrame.
        self putSelfInReceiverResultReg.
        objectRepresentation
                genLoadSlot: SenderIndex
                sourceReg: ReceiverResultReg
                destReg: TempReg.
        self MoveMw: 0 r: SPReg R: ClassReg.
        jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.
        self MoveCq: slotIndex R: SendNumArgsReg.
        self CallRT: ceStoreContextInstVarTrampoline.
        jmpDone := self Jump: 0.
        jmpSingle jmpTarget: self Label.
-       traceStores > 0 ifTrue:
-               [self CallRT: ceTraceStoreTrampoline].
-       self cppIf: IMMUTABILITY ifTrue:
-               [immutabilityFailure := objectRepresentation
-                                                                       genImmutableCheck: ReceiverResultReg
-                                                                       slotIndex: slotIndex
-                                                                       sourceReg: ClassReg
-                                                                       scratchReg: TempReg
-                                                                       needRestoreRcvr: true].
-       objectRepresentation
-               genStoreSourceReg: ClassReg
-               slotIndex: slotIndex
-               destReg: ReceiverResultReg
-               scratchReg: TempReg
-               inFrame: true.
-       jmpDone jmpTarget: self Label.
        popBoolean ifTrue:
                [self AddCq: objectMemory wordSize R: SPReg].
+       self
+               genStoreSourceReg: ClassReg
+               slotIndex: slotIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               inFrame: needsFrame.
+       jmpDone jmpTarget: self Label.
-       self cppIf: IMMUTABILITY ifTrue:
-               [immutabilityFailure jmpTarget: self Label].
        ^0!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genStorePop:ReceiverVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean ReceiverVariable: slotIndex
        <inline: false>
-       | immutabilityFailure |
-       <var: #immutabilityFailure type: #'AbstractInstruction *'>
        needsFrame ifTrue:
                [self putSelfInReceiverResultReg].
        popBoolean
                ifTrue: [self PopR: ClassReg]
                ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg].
+       self
+               genStoreSourceReg: ClassReg
+               slotIndex: slotIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
-       traceStores > 0 ifTrue:
-               [self CallRT: ceTraceStoreTrampoline].
-       self cppIf: IMMUTABILITY ifTrue:
-               [immutabilityFailure := objectRepresentation
-                                                                       genImmutableCheck: ReceiverResultReg
-                                                                       slotIndex: slotIndex
-                                                                       sourceReg: ClassReg
-                                                                       scratchReg: TempReg
-                                                                       needRestoreRcvr: true].
-       objectRepresentation
-               genStoreSourceReg: ClassReg
-               slotIndex: slotIndex
-               destReg: ReceiverResultReg
-               scratchReg: TempReg
                inFrame: needsFrame.
-
-       self cppIf: IMMUTABILITY ifTrue:
-               [immutabilityFailure jmpTarget: self Label].
-
        ^0!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genStorePop:RemoteTemp:At: (in category 'bytecode generator support') -----
  genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex
        <inline: false>
        "The only reason we assert needsFrame here is that in a frameless method
         ReceiverResultReg must and does contain only self, but the ceStoreCheck
         trampoline expects the target of the store to be in ReceiverResultReg.  So
         in a frameless method we would have a conflict between the receiver and
         the temote temp store, unless we we smart enough to realise that
         ReceiverResultReg was unused after the literal variable store, unlikely given
         that methods return self by default."
        self assert: needsFrame.
        popBoolean
                ifTrue: [self PopR: ClassReg]
                ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg].
        self MoveMw: (self frameOffsetOfTemporary: remoteTempIndex) r: FPReg R: ReceiverResultReg.
-       traceStores > 0 ifTrue:
-               [self CallRT: ceTraceStoreTrampoline].
        ^objectRepresentation
                genStoreSourceReg: ClassReg
                slotIndex: slotIndex
                destReg: ReceiverResultReg
                scratchReg: TempReg
                inFrame: needsFrame!

Item was added:
+ ----- Method: SimpleStackBasedCogit>>genTraceStores (in category 'bytecode generator support') -----
+ genTraceStores
+       <inline: true>
+       traceStores > 0 ifTrue: [ self CallRT: ceTraceStoreTrampoline ].!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genImmutabilityCheckStorePop:LiteralVariable: (in category 'bytecode generator support') -----
+ genImmutabilityCheckStorePop: popBoolean LiteralVariable: litVarIndex
+       <inline: true>
+       | association needStoreCheck |
+       "The only reason we assert needsFrame here is that in a frameless method
+        ReceiverResultReg must and does contain only self, but the ceStoreCheck
+        trampoline expects the target of the store to be in ReceiverResultReg.  So
+        in a frameless method we would have a conflict between the receiver and
+        the literal store, unless we we smart enough to realise that ReceiverResultReg
+        was unused after the literal variable store, unlikely given that methods
+        return self by default."
+       self assert: needsFrame.
+       "N.B.  No need to check the stack for references because we generate code for
+        literal variable loads that stores the result in a register, deferring only the register push."
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+       association := self getLiteral: litVarIndex.
+       optStatus isReceiverResultRegLive: false.
+       self ssAllocateRequiredReg: ReceiverResultReg. "for store trampoline call in genStoreSourceReg: has to be ReceiverResultReg"
+       self genMoveConstant: association R: ReceiverResultReg.
+       objectRepresentation genEnsureObjInRegNotForwarded: ReceiverResultReg scratchReg: TempReg.
+       self ssAllocateRequiredReg: ClassReg.
+       self ssStoreAndReplacePop: popBoolean toReg: ClassReg.
+       self ssFlushTo: simStackPtr.
+       objectRepresentation
+               genStoreWithImmutabilityCheckSourceReg: ClassReg
+               slotIndex: ValueIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               needsStoreCheck: needStoreCheck
+               needRestoreRcvr: false.
+       ^ 0!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genImmutabilityCheckStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----
+ genImmutabilityCheckStorePop: popBoolean MaybeContextReceiverVariable: slotIndex
+       <inline: true>
+       | jmpSingle jmpDone needStoreCheck |
+       <var: #jmpSingle type: #'AbstractInstruction *'>
+       <var: #jmpDone type: #'AbstractInstruction *'>
+       "The reason we need a frame here is that assigning to an inst var of a context may
+        involve wholesale reorganization of stack pages, and the only way to preserve the
+        execution state of an activation in that case is if it has a frame."
+       self assert: needsFrame.
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+       "Note that ReceiverResultReg remains live after both
+        ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline."
+       self ensureReceiverResultRegContainsSelf.
+       self ssPop: 1.
+       self ssAllocateCallReg: ClassReg and: SendNumArgsReg. "for ceStoreContextInstVarTrampoline"
+       self ssPush: 1.
+       objectRepresentation
+               genLoadSlot: SenderIndex
+               sourceReg: ReceiverResultReg
+               destReg: TempReg.
+       self ssStoreAndReplacePop: popBoolean toReg: ClassReg.
+       "stack is flushed except maybe ssTop if popBoolean is false.
+         ssTop is a SSregister in this case due to #ssStoreAndReplacePop:
+         to avoid a second indirect read / annotation in case of SSConstant
+         or SSBaseRegister"
+       self ssFlushTo: simStackPtr.
+       jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.
+       self MoveCq: slotIndex R: SendNumArgsReg.
+       self CallRT: ceStoreContextInstVarTrampoline.
+       jmpDone := self Jump: 0.
+       jmpSingle jmpTarget: self Label.
+       objectRepresentation
+               genStoreWithImmutabilityCheckSourceReg: ClassReg
+               slotIndex: slotIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               needsStoreCheck: needStoreCheck
+               needRestoreRcvr: true.
+       jmpDone jmpTarget: self Label.
+       ^0!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genImmutabilityCheckStorePop:ReceiverVariable: (in category 'bytecode generator support') -----
+ genImmutabilityCheckStorePop: popBoolean ReceiverVariable: slotIndex
+       <inline: true>
+       | needStoreCheck |
+       self assert: needsFrame.
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+       "Note that ReceiverResultReg remains live after the trampoline."
+       self ensureReceiverResultRegContainsSelf.
+       self ssAllocateRequiredReg: ClassReg.
+       self ssStoreAndReplacePop: popBoolean toReg: ClassReg.
+       self ssFlushTo: simStackPtr.
+       objectRepresentation
+               genStoreWithImmutabilityCheckSourceReg: ClassReg
+               slotIndex: slotIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               needsStoreCheck: needStoreCheck
+               needRestoreRcvr: true.
+
+       ^ 0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genStorePop:LiteralVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean LiteralVariable: litVarIndex
        <inline: false>
-       | topReg association needStoreCheck immutabilityFailure |
-       "The only reason we assert needsFrame here is that in a frameless method
-        ReceiverResultReg must and does contain only self, but the ceStoreCheck
-        trampoline expects the target of the store to be in ReceiverResultReg.  So
-        in a frameless method we would have a conflict between the receiver and
-        the literal store, unless we we smart enough to realise that ReceiverResultReg
-        was unused after the literal variable store, unlikely given that methods
-        return self by default."
-       self assert: needsFrame.
-       self cppIf: IMMUTABILITY ifTrue: [ self ssFlushTo: simStackPtr - 1 ].
-       "N.B.  No need to check the stack for references because we generate code for
-        literal variable loads that stores the result in a register, deferring only the register push."
-       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
-       association := self getLiteral: litVarIndex.
-       optStatus isReceiverResultRegLive: false.
-       self ssAllocateRequiredReg: ReceiverResultReg. "for ceStoreCheck call in genStoreSourceReg: has to be ReceiverResultReg"
-       self genMoveConstant: association R: ReceiverResultReg.
-       objectRepresentation genEnsureObjInRegNotForwarded: ReceiverResultReg scratchReg: TempReg.
        self
                cppIf: IMMUTABILITY
+               ifTrue: [ ^ self genImmutabilityCheckStorePop: popBoolean LiteralVariable: litVarIndex ]
+               ifFalse: [ ^ self genVanillaStorePop: popBoolean LiteralVariable: litVarIndex ]
+               !
-               ifTrue:
-                       [ self ssAllocateRequiredReg: ClassReg.
-                         topReg := ClassReg.
-                         self ssStoreAndReplacePop: popBoolean toReg: ClassReg.
-                         "stack is flushed except maybe ssTop if popBoolean is false.
-                         ssTop is a SSregister in this case due to #ssStoreAndReplacePop:
-                         to avoid a second indirect read / annotation in case of SSConstant
-                         or SSBaseRegister"
-                         self ssFlushTo: simStackPtr.
-                         immutabilityFailure := objectRepresentation
-                                                                               genImmutableCheck: ReceiverResultReg
-                                                                               slotIndex: ValueIndex
-                                                                               sourceReg: ClassReg
-                                                                               scratchReg: TempReg
-                                                                               needRestoreRcvr: false ]
-               ifFalse:
-                       [ topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).
-                         self ssStorePop: popBoolean toReg: topReg ].
-       traceStores > 0 ifTrue:
-               [self MoveR: topReg R: TempReg.
-                self CallRT: ceTraceStoreTrampoline].
-       objectRepresentation
-               genStoreSourceReg: topReg
-               slotIndex: ValueIndex
-               destReg: ReceiverResultReg
-               scratchReg: TempReg
-               inFrame: needsFrame
-               needsStoreCheck: needStoreCheck.
-       self cppIf: IMMUTABILITY ifTrue: [ immutabilityFailure jmpTarget: self Label ].
-       ^ 0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean MaybeContextReceiverVariable: slotIndex
        <inline: false>
-       | jmpSingle jmpDone needStoreCheck immutabilityFailure |
-       <var: #jmpSingle type: #'AbstractInstruction *'>
-       <var: #jmpDone type: #'AbstractInstruction *'>
-       "The reason we need a frame here is that assigning to an inst var of a context may
-        involve wholesale reorganization of stack pages, and the only way to preserve the
-        execution state of an activation in that case is if it has a frame."
-       self assert: needsFrame.
-       self cppIf: IMMUTABILITY ifTrue: [ self ssFlushTo: simStackPtr - 1 ].
-       self ssFlushUpThroughReceiverVariable: slotIndex.
-       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
-       "Note that ReceiverResultReg remains live after both
-        ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline."
-       self ensureReceiverResultRegContainsSelf.
-       self ssPop: 1.
-       self ssAllocateCallReg: ClassReg and: SendNumArgsReg. "for ceStoreContextInstVarTrampoline"
-       self ssPush: 1.
-       objectRepresentation
-               genLoadSlot: SenderIndex
-               sourceReg: ReceiverResultReg
-               destReg: TempReg.
        self
                cppIf: IMMUTABILITY
+               ifTrue: [ ^ self genImmutabilityCheckStorePop: popBoolean MaybeContextReceiverVariable: slotIndex ]
+               ifFalse: [ ^ self genVanillaStorePop: popBoolean MaybeContextReceiverVariable: slotIndex ]!
-               ifTrue:
-                       [ self ssStoreAndReplacePop: popBoolean toReg: ClassReg.
-                         "stack is flushed except maybe ssTop if popBoolean is false.
-                         ssTop is a SSregister in this case due to #ssStoreAndReplacePop:
-                         to avoid a second indirect read / annotation in case of SSConstant
-                         or SSBaseRegister"
-                         self ssFlushTo: simStackPtr. ]
-               ifFalse: [ self ssStorePop: popBoolean toReg: ClassReg ].
-       jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.
-       self MoveCq: slotIndex R: SendNumArgsReg.
-       self CallRT: ceStoreContextInstVarTrampoline.
-       jmpDone := self Jump: 0.
-       jmpSingle jmpTarget: self Label.
-       traceStores > 0 ifTrue:
-               [self MoveR: ClassReg R: TempReg.
-                self CallRT: ceTraceStoreTrampoline].
-       self
-               cppIf: IMMUTABILITY
-               ifTrue:
-                       [ immutabilityFailure := objectRepresentation
-                                                                               genImmutableCheck: ReceiverResultReg
-                                                                               slotIndex: ValueIndex
-                                                                               sourceReg: ClassReg
-                                                                               scratchReg: TempReg
-                                                                               needRestoreRcvr: true ].
-       objectRepresentation
-               genStoreSourceReg: ClassReg
-               slotIndex: slotIndex
-               destReg: ReceiverResultReg
-               scratchReg: TempReg
-               inFrame: true
-               needsStoreCheck: needStoreCheck.
-       jmpDone jmpTarget: self Label.
-       self cppIf: IMMUTABILITY ifTrue: [ immutabilityFailure jmpTarget: self Label ].
-       ^0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genStorePop:ReceiverVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean ReceiverVariable: slotIndex
        <inline: false>
-       | topReg needStoreCheck immutabilityFailure |
-       self cppIf: IMMUTABILITY ifTrue: [ self assert: needsFrame. self ssFlushTo: simStackPtr - 1 ].
-       self ssFlushUpThroughReceiverVariable: slotIndex.
-       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
-       "Note that ReceiverResultReg remains live after ceStoreCheckTrampoline."
-       self ensureReceiverResultRegContainsSelf.
        self
                cppIf: IMMUTABILITY
+               ifTrue: [ ^ self genImmutabilityCheckStorePop: popBoolean ReceiverVariable: slotIndex ]
+               ifFalse: [ ^ self genVanillaStorePop: popBoolean ReceiverVariable: slotIndex ]
+               !
-               ifTrue:
-                       [ self ssAllocateRequiredReg: ClassReg.
-                         topReg := ClassReg.
-                         self ssStoreAndReplacePop: popBoolean toReg: ClassReg.
-                         "stack is flushed except maybe ssTop if popBoolean is false.
-                         ssTop is a SSregister in this case due to #ssStoreAndReplacePop:
-                         to avoid a second indirect read / annotation in case of SSConstant
-                         or SSBaseRegister"
-                         self ssFlushTo: simStackPtr.
-                         immutabilityFailure := objectRepresentation
-                                                                               genImmutableCheck: ReceiverResultReg
-                                                                               slotIndex: slotIndex
-                                                                               sourceReg: ClassReg
-                                                                               scratchReg: TempReg
-                                                                               needRestoreRcvr: true ]
-               ifFalse:
-                       [ topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).
-                         self ssStorePop: popBoolean toReg: topReg ].
-       traceStores > 0 ifTrue:
-               [ self MoveR: topReg R: TempReg.
-               self evaluateTrampolineCallBlock: [ self CallRT: ceTraceStoreTrampoline ] protectLinkRegIfNot: needsFrame ].
-       objectRepresentation
-               genStoreSourceReg: topReg
-               slotIndex: slotIndex
-               destReg: ReceiverResultReg
-               scratchReg: TempReg
-               inFrame: needsFrame
-               needsStoreCheck: needStoreCheck.
-       self cppIf: IMMUTABILITY ifTrue: [ immutabilityFailure jmpTarget: self Label ].
-       ^ 0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genStorePop:RemoteTemp:At: (in category 'bytecode generator support') -----
  genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex
        <inline: false>
        | topReg needStoreCheck |
        "The only reason we assert needsFrame here is that in a frameless method
         ReceiverResultReg must and does contain only self, but the ceStoreCheck
         trampoline expects the target of the store to be in ReceiverResultReg.  So
         in a frameless method we would have a conflict between the receiver and
         the temote temp store, unless we we smart enough to realise that
         ReceiverResultReg was unused after the literal variable store, unlikely given
         that methods return self by default."
        self assert: needsFrame.
        "N.B.  No need to check the stack for references because we generate code for
         remote temp loads that stores the result in a register, deferring only the register push."
        needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
        topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).
        self ssAllocateRequiredReg: ReceiverResultReg.
        optStatus isReceiverResultRegLive: false.
        self ssStoreAndReplacePop: popBoolean toReg: topReg.
        self MoveMw: (self frameOffsetOfTemporary: remoteTempIndex) r: FPReg R: ReceiverResultReg.
-        traceStores > 0 ifTrue:
-                       [ self MoveR: topReg R: TempReg.
-                       self CallRT: ceTraceStoreTrampoline. ].
        ^objectRepresentation
                genStoreSourceReg: topReg
                slotIndex: slotIndex
                destReg: ReceiverResultReg
                scratchReg: TempReg
                inFrame: needsFrame
                needsStoreCheck: needStoreCheck!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genTraceStores (in category 'bytecode generator support') -----
+ genTraceStores
+       <inline: true>
+       traceStores > 0 ifTrue:
+               [ self MoveR: ClassReg R: TempReg.
+               self CallRT: ceTraceStoreTrampoline ].!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genVanillaStorePop:LiteralVariable: (in category 'bytecode generator support') -----
+ genVanillaStorePop: popBoolean LiteralVariable: litVarIndex
+       <inline: true>
+       | topReg association needStoreCheck |
+       "The only reason we assert needsFrame here is that in a frameless method
+        ReceiverResultReg must and does contain only self, but the ceStoreCheck
+        trampoline expects the target of the store to be in ReceiverResultReg.  So
+        in a frameless method we would have a conflict between the receiver and
+        the literal store, unless we we smart enough to realise that ReceiverResultReg
+        was unused after the literal variable store, unlikely given that methods
+        return self by default."
+       self assert: needsFrame.
+       "N.B.  No need to check the stack for references because we generate code for
+        literal variable loads that stores the result in a register, deferring only the register push."
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+       association := self getLiteral: litVarIndex.
+       optStatus isReceiverResultRegLive: false.
+       self ssAllocateRequiredReg: ReceiverResultReg. "for ceStoreCheck call in genStoreSourceReg: has to be ReceiverResultReg"
+       self genMoveConstant: association R: ReceiverResultReg.
+       objectRepresentation genEnsureObjInRegNotForwarded: ReceiverResultReg scratchReg: TempReg.
+       topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).
+       self ssStorePop: popBoolean toReg: topReg.
+       objectRepresentation
+               genStoreSourceReg: topReg
+               slotIndex: ValueIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               inFrame: needsFrame
+               needsStoreCheck: needStoreCheck.
+       ^ 0!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genVanillaStorePop:MaybeContextReceiverVariable: (in category 'bytecode generator support') -----
+ genVanillaStorePop: popBoolean MaybeContextReceiverVariable: slotIndex
+       <inline: true>
+       | jmpSingle jmpDone needStoreCheck |
+       <var: #jmpSingle type: #'AbstractInstruction *'>
+       <var: #jmpDone type: #'AbstractInstruction *'>
+       "The reason we need a frame here is that assigning to an inst var of a context may
+        involve wholesale reorganization of stack pages, and the only way to preserve the
+        execution state of an activation in that case is if it has a frame."
+       self assert: needsFrame.
+       self ssFlushUpThroughReceiverVariable: slotIndex.
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+       "Note that ReceiverResultReg remains live after both
+        ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline."
+       self ensureReceiverResultRegContainsSelf.
+       self ssPop: 1.
+       self ssAllocateCallReg: ClassReg and: SendNumArgsReg. "for ceStoreContextInstVarTrampoline"
+       self ssPush: 1.
+       objectRepresentation
+               genLoadSlot: SenderIndex
+               sourceReg: ReceiverResultReg
+               destReg: TempReg.
+       self ssStorePop: popBoolean toReg: ClassReg.
+       jmpSingle := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.
+       self MoveCq: slotIndex R: SendNumArgsReg.
+       self CallRT: ceStoreContextInstVarTrampoline.
+       jmpDone := self Jump: 0.
+       jmpSingle jmpTarget: self Label.
+       objectRepresentation
+               genStoreSourceReg: ClassReg
+               slotIndex: slotIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               inFrame: true
+               needsStoreCheck: needStoreCheck.
+       jmpDone jmpTarget: self Label.
+
+       ^0!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genVanillaStorePop:ReceiverVariable: (in category 'bytecode generator support') -----
+ genVanillaStorePop: popBoolean ReceiverVariable: slotIndex
+       <inline: true>
+       | topReg needStoreCheck |
+       self ssFlushUpThroughReceiverVariable: slotIndex.
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+       "Note that ReceiverResultReg remains live after ceStoreCheckTrampoline."
+       self ensureReceiverResultRegContainsSelf.
+       topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).
+       self ssStorePop: popBoolean toReg: topReg.
+       objectRepresentation
+               genStoreSourceReg: topReg
+               slotIndex: slotIndex
+               destReg: ReceiverResultReg
+               scratchReg: TempReg
+               inFrame: needsFrame
+               needsStoreCheck: needStoreCheck.
+       ^ 0!






--
_,,,^..^,,,_
best, Eliot