<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&#39;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">&lt;<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>&gt;</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&gt;&gt;genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame: (in category &#39;compile abstract instructions&#39;) -----<br>
  genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame<br>
+       &lt;inline: true&gt;<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 &quot;RcvrResultReg doesn&#39;t need to be live across the instructions&quot; ]<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: &#39;ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceStoreTrampoline&#39;<br>
-       instanceVariableNames: &#39;ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceCannotAssignToWithIndexTrampoline&#39;<br>
        classVariableNames: &#39;&#39;<br>
        poolDictionaries: &#39;VMBytecodeConstants VMSqueakClassIndices&#39;<br>
        category: &#39;VMMaker-JIT&#39;!<br>
<br>
Item was removed:<br>
- ----- Method: CogObjectRepresentationForSpur&gt;&gt;genImmutableCheck:slotIndex:sourceReg:scratchReg:needRestoreRcvr: (in category &#39;compile abstract instructions&#39;) -----<br>
- genImmutableCheck: regHoldingObjectMutated slotIndex: index sourceReg: regHoldingValueToStore scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr<br>
-       | mutableJump fail |<br>
-       &lt;var: #mutableJump type: #&#39;AbstractInstruction *&#39;&gt;<br>
-       &lt;var: #fail type: #&#39;AbstractInstruction *&#39;&gt;<br>
-       &lt;inline: true&gt;<br>
-       &lt;option: #IMMUTABILITY&gt;<br>
-       &quot;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.&quot;<br>
-       self assert: regHoldingObjectMutated == ReceiverResultReg.<br>
-       self assert: scratchReg == TempReg.<br>
-       self assert: regHoldingValueToStore == ClassReg.<br>
-       mutableJump := self genJumpMutable: ReceiverResultReg scratchReg: TempReg.<br>
-<br>
-       &quot;We reach this code if the object mutated is immutable.&quot;<br>
-       cogit MoveCq: index R: TempReg.<br>
-       &quot;trampoline call and mcpc to bcpc annotation.&quot;<br>
-       cogit CallRT: ceCannotAssignToWithIndexTrampoline.<br>
-       cogit annotateBytecode: cogit Label.<br>
-       &quot;restore ReceiverResultReg state if needed, the rest of the state is spilled&quot;<br>
-       needRestoreRcvr ifTrue: [ cogit putSelfInReceiverResultReg ].<br>
-       fail := cogit Jump: 0.<br>
-<br>
-       &quot;We reach this code is the object mutated is mutable&quot;<br>
-       mutableJump jmpTarget: cogit Label.<br>
-<br>
-       ^ fail!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationForSpur&gt;&gt;genJumpBaseHeaderImmutable: (in category &#39;compile abstract instructions&#39;) -----<br>
  genJumpBaseHeaderImmutable: baseHeaderReg<br>
        &quot;baseHeader holds at least the least significant 32 bits of the object&quot;<br>
        &lt;returnTypeC: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;option: #IMMUTABILITY&gt;<br>
+       &lt;inline: true&gt;<br>
        cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.<br>
        ^ cogit JumpNonZero: 0!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationForSpur&gt;&gt;genJumpBaseHeaderMutable: (in category &#39;compile abstract instructions&#39;) -----<br>
  genJumpBaseHeaderMutable: baseHeaderReg<br>
        &quot;baseHeader holds at least the least significant 32 bits of the object&quot;<br>
        &lt;returnTypeC: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;option: #IMMUTABILITY&gt;<br>
+       &lt;inline: true&gt;<br>
        cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.<br>
        ^ cogit JumpZero: 0!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur&gt;&gt;genJumpImmutable:scratchReg: (in category &#39;compile abstract instructions&#39;) -----<br>
+ genJumpImmutable: sourceReg scratchReg: scratchReg<br>
+       &lt;returnTypeC: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       cogit MoveMw: 0 r: sourceReg R: scratchReg.<br>
+       ^ self genJumpBaseHeaderImmutable: scratchReg!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationForSpur&gt;&gt;genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: (in category &#39;compile abstract instructions&#39;) -----<br>
  genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck<br>
+<br>
+       cogit genTraceStores.<br>
        &quot;do the store&quot;<br>
        cogit MoveR: sourceReg<br>
                   Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
                   r: destReg.<br>
        &quot;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)&quot;<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&gt;&gt;genStoreTrampolineCalled: (in category &#39;initialization&#39;) -----<br>
+ genStoreTrampolineCalled: trampolineName<br>
+       &quot;This can be entered in one of two states, depending on TempReg.<br>
+       TempReg = 0 =&gt; store check<br>
+       TempReg &gt; 0 =&gt; 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.&quot;<br>
+       | jumpSC |<br>
+       &lt;var: #trampolineName type: #&#39;char *&#39;&gt;<br>
+       &lt;var: #jumpSC type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;inline: false&gt;<br>
+       cogit zeroOpcodeIndex.<br>
+       cogit CmpCq: 0 R: TempReg.<br>
+       jumpSC := cogit JumpZero: 0.<br>
+<br>
+       &quot;CannotAssignTo:, we restore the index.&quot;<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>
+       &quot;Store check&quot;<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&gt;&gt;genStoreWithImmutabilityAndStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: (in category &#39;compile abstract instructions&#39;) -----<br>
+ genStoreWithImmutabilityAndStoreCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr<br>
+       &quot;Store check code is duplicated to use a single trampoline&quot;<br>
+       &lt;var: #immutableJump type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #trampJump type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #jmpImmediate type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #jmpDestYoung type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #jmpSourceOld type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #jmpAlreadyRemembered type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       | immutableJump trampJump jmpImmediate jmpDestYoung jmpSourceOld rememberedBitByteOffset jmpAlreadyRemembered mask |<br>
+<br>
+       immutableJump := self genJumpImmutable: destReg scratchReg: scratchReg.<br>
+<br>
+       cogit genTraceStores.<br>
+<br>
+       &quot;do the store&quot;<br>
+       cogit MoveR: sourceReg<br>
+                  Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
+                  r: destReg.<br>
+<br>
+       &quot;store check&quot;<br>
+       jmpImmediate := self genJumpImmediate: sourceReg.<br>
+       &quot;Get the old/new boundary in scratchReg&quot;<br>
+       cogit MoveCw: objectMemory storeCheckBoundary R: scratchReg.<br>
+       &quot;Is target young?  If so we&#39;re done&quot;<br>
+       cogit CmpR: scratchReg R: destReg. &quot;N.B. FLAGS := destReg - scratchReg&quot;<br>
+       jmpDestYoung := cogit JumpBelow: 0.<br>
+       &quot;Is value stored old?  If so we&#39;re done.&quot;<br>
+       cogit CmpR: scratchReg R: sourceReg. &quot;N.B. FLAGS := valueReg - scratchReg&quot;<br>
+       jmpSourceOld := cogit JumpAboveOrEqual: 0.<br>
+       &quot;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.&quot;<br>
+       rememberedBitByteOffset := jmpSourceOld isBigEndian<br>
+                                                                       ifTrue: [objectMemory baseHeaderSize - 1 - (objectMemory rememberedBitShift // 8)]<br>
+                                                                       ifFalse:[objectMemory rememberedBitShift // 8].<br>
+       mask := 1 &lt;&lt; (objectMemory rememberedBitShift \\ 8).<br>
+       cogit MoveMb: rememberedBitByteOffset r: destReg R: scratchReg.<br>
+       cogit AndCq: mask R: scratchReg.<br>
+       jmpAlreadyRemembered := cogit JumpNonZero: 0.<br>
+       &quot;We know scratchReg now holds 0, this is convenient because the trampoline<br>
+       convention expects 0 for store check in scratchReg. What a coincidence ;-)&quot;<br>
+       &quot;Remembered bit is not set.  Call store check to insert dest into remembered table.&quot;<br>
+       trampJump := cogit Jump: 0.<br>
+       &quot;Here we reach the trampoline for Immutability failure&quot;<br>
+       immutableJump jmpTarget: (cogit MoveCq: index + 1 R: scratchReg). &quot;index + 1 as 0 is reserved for store checks&quot;<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&gt;&gt;genStoreWithImmutabilityButNoStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: (in category &#39;compile abstract instructions&#39;) -----<br>
+ genStoreWithImmutabilityButNoStoreCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needRestoreRcvr: needRestoreRcvr<br>
+<br>
+       &lt;var: #immutableJump type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #immutabilityFailure type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       | immutabilityFailure mutableJump |<br>
+<br>
+       &quot;imm check has its own trampoline&quot;<br>
+       mutableJump := self genJumpMutable: destReg scratchReg: scratchReg.<br>
+       cogit MoveCq: index + 1 R: TempReg. &quot;index + 1 as 0 is reserved for store checks&quot;<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>
+       &quot;do the store&quot;<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&gt;&gt;genStoreWithImmutabilityCheckSourceReg:slotIndex:destReg:scratchReg:needsStoreCheck:needRestoreRcvr: (in category &#39;compile abstract instructions&#39;) -----<br>
+ genStoreWithImmutabilityCheckSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg needsStoreCheck: needsStoreCheck needRestoreRcvr: needRestoreRcvr<br>
+       &quot;We know there is a frame as immutability check requires a frame&quot;<br>
+       &quot;needRestoreRcvr has to be true to keep RcvrResultReg live with the receiver in it across the trampoline&quot;<br>
+<br>
+       &quot;Trampoline convention...&quot;<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&gt;&gt;generateObjectRepresentationTrampolines (in category &#39;initialization&#39;) -----<br>
  generateObjectRepresentationTrampolines<br>
        &quot;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.&quot;<br>
        self<br>
                cppIf: IMMUTABILITY<br>
+               ifTrue: [ceStoreTrampoline := self genStoreTrampolineCalled: &#39;ceStoreTrampoline&#39;].<br>
-               ifTrue: &quot;c.f. genImmutableCheck:slotIndex:sourceReg:scratchReg:popBoolean:needRestoreRcvr:&quot;<br>
-                       [ceCannotAssignToWithIndexTrampoline := cogit<br>
-                                                                                                                       genTrampolineFor: #ceCannotAssignTo:withIndex:valueToAssign:<br>
-                                                                                                                       called: &#39;ceCannotAssignToWithIndexTrampoline&#39;<br>
-                                                                                                                       arg: ReceiverResultReg<br>
-                                                                                                                       arg: TempReg<br>
-                                                                                                                       arg: ClassReg].<br>
        ceStoreCheckTrampoline := cogit<br>
                                                                        genTrampolineFor: #remember:<br>
                                                                        called: &#39;ceStoreCheckTrampoline&#39;<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: &#39;ceScheduleScavengeTrampoline&#39;<br>
                                                                                        regsToSave: cogit callerSavedRegMask.<br>
        ceSmallActiveContextInMethodTrampoline := self genActiveContextTrampolineLarge: false inBlock: false called: &#39;ceSmallMethodContext&#39;.<br>
        ceSmallActiveContextInBlockTrampoline := self genActiveContextTrampolineLarge: false inBlock: true called: &#39;ceSmallBlockContext&#39;.<br>
        ceLargeActiveContextInMethodTrampoline := self genActiveContextTrampolineLarge: true inBlock: false called: &#39;ceLargeMethodContext&#39;.<br>
        ceLargeActiveContextInBlockTrampoline := self genActiveContextTrampolineLarge: true inBlock: true called: &#39;ceLargeBlockContext&#39;!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationForSqueakV3&gt;&gt;genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: (in category &#39;compile abstract instructions&#39;) -----<br>
  genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck<br>
        | jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRoot mask rootBitByteOffset |<br>
        &lt;var: #jmpImmediate type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jmpDestYoung type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jmpSourceOld type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jmpAlreadyRoot type: #&#39;AbstractInstruction *&#39;&gt;<br>
+<br>
+       cogit genTraceStores.<br>
        &quot;do the store&quot;<br>
        cogit MoveR: sourceReg Mw: index * objectMemory wordSize + objectMemory baseHeaderSize r: destReg.<br>
        &quot;if no need for the store check then returns&quot;<br>
        needsStoreCheck ifFalse: [ ^ 0 ].<br>
        &quot;now the check.  Is value stored an integer?  If so we&#39;re done&quot;<br>
        jmpImmediate := self genJumpImmediate: sourceReg.<br>
        &quot;Get the old/new boundary in scratchReg&quot;<br>
        cogit MoveAw: objectMemory youngStartAddress R: scratchReg.<br>
        &quot;Is target young?  If so we&#39;re done&quot;<br>
        cogit CmpR: scratchReg R: destReg. &quot;N.B. FLAGS := destReg - scratchReg&quot;<br>
        jmpDestYoung := cogit JumpAboveOrEqual: 0.<br>
        &quot;Is value stored old?  If so we&#39;re done.&quot;<br>
        cogit CmpR: scratchReg R: sourceReg. &quot;N.B. FLAGS := sourceReg - scratchReg&quot;<br>
        jmpSourceOld := cogit JumpBelow: 0.<br>
        &quot;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.&quot;<br>
        rootBitByteOffset := jmpSourceOld isBigEndian<br>
                                                        ifTrue: [objectMemory wordSize - RootBitDigitLength]<br>
                                                        ifFalse:[RootBitDigitLength - 1].<br>
        mask := RootBitDigitLength &gt; 1<br>
                                ifTrue: [RootBit &gt;&gt; (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>
        &quot;Root bit is not set.  Call store check to insert dest into root table.&quot;<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&gt;&gt;genStorePop:LiteralVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean LiteralVariable: litVarIndex<br>
        &lt;inline: false&gt;<br>
+       | association |<br>
-       | association immutabilityFailure |<br>
-       &lt;var: #immutabilityFailure type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &quot;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.&quot;<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 &gt; 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&gt;&gt;genStorePop:MaybeContextReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
        &lt;inline: false&gt;<br>
+       | jmpSingle jmpDone |<br>
-       | jmpSingle jmpDone immutabilityFailure |<br>
-       &lt;var: #immutabilityFailure type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jmpSingle type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jmpDone type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &quot;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.&quot;<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 &gt; 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&gt;&gt;genStorePop:ReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean ReceiverVariable: slotIndex<br>
        &lt;inline: false&gt;<br>
-       | immutabilityFailure |<br>
-       &lt;var: #immutabilityFailure type: #&#39;AbstractInstruction *&#39;&gt;<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 &gt; 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&gt;&gt;genStorePop:RemoteTemp:At: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex<br>
        &lt;inline: false&gt;<br>
        &quot;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.&quot;<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 &gt; 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&gt;&gt;genTraceStores (in category &#39;bytecode generator support&#39;) -----<br>
+ genTraceStores<br>
+       &lt;inline: true&gt;<br>
+       traceStores &gt; 0 ifTrue: [ self CallRT: ceTraceStoreTrampoline ].!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;genImmutabilityCheckStorePop:LiteralVariable: (in category &#39;bytecode generator support&#39;) -----<br>
+ genImmutabilityCheckStorePop: popBoolean LiteralVariable: litVarIndex<br>
+       &lt;inline: true&gt;<br>
+       | association needStoreCheck |<br>
+       &quot;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.&quot;<br>
+       self assert: needsFrame.<br>
+       &quot;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.&quot;<br>
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+       association := self getLiteral: litVarIndex.<br>
+       optStatus isReceiverResultRegLive: false.<br>
+       self ssAllocateRequiredReg: ReceiverResultReg. &quot;for store trampoline call in genStoreSourceReg: has to be ReceiverResultReg&quot;<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&gt;&gt;genImmutabilityCheckStorePop:MaybeContextReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
+ genImmutabilityCheckStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
+       &lt;inline: true&gt;<br>
+       | jmpSingle jmpDone needStoreCheck |<br>
+       &lt;var: #jmpSingle type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #jmpDone type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &quot;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.&quot;<br>
+       self assert: needsFrame.<br>
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+       &quot;Note that ReceiverResultReg remains live after both<br>
+        ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline.&quot;<br>
+       self ensureReceiverResultRegContainsSelf.<br>
+       self ssPop: 1.<br>
+       self ssAllocateCallReg: ClassReg and: SendNumArgsReg. &quot;for ceStoreContextInstVarTrampoline&quot;<br>
+       self ssPush: 1.<br>
+       objectRepresentation<br>
+               genLoadSlot: SenderIndex<br>
+               sourceReg: ReceiverResultReg<br>
+               destReg: TempReg.<br>
+       self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
+       &quot;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&quot;<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&gt;&gt;genImmutabilityCheckStorePop:ReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
+ genImmutabilityCheckStorePop: popBoolean ReceiverVariable: slotIndex<br>
+       &lt;inline: true&gt;<br>
+       | needStoreCheck |<br>
+       self assert: needsFrame.<br>
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+       &quot;Note that ReceiverResultReg remains live after the trampoline.&quot;<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&gt;&gt;genStorePop:LiteralVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean LiteralVariable: litVarIndex<br>
        &lt;inline: false&gt;<br>
-       | topReg association needStoreCheck immutabilityFailure |<br>
-       &quot;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.&quot;<br>
-       self assert: needsFrame.<br>
-       self cppIf: IMMUTABILITY ifTrue: [ self ssFlushTo: simStackPtr - 1 ].<br>
-       &quot;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.&quot;<br>
-       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
-       association := self getLiteral: litVarIndex.<br>
-       optStatus isReceiverResultRegLive: false.<br>
-       self ssAllocateRequiredReg: ReceiverResultReg. &quot;for ceStoreCheck call in genStoreSourceReg: has to be ReceiverResultReg&quot;<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>
-                         &quot;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&quot;<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 &gt; 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&gt;&gt;genStorePop:MaybeContextReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
        &lt;inline: false&gt;<br>
-       | jmpSingle jmpDone needStoreCheck immutabilityFailure |<br>
-       &lt;var: #jmpSingle type: #&#39;AbstractInstruction *&#39;&gt;<br>
-       &lt;var: #jmpDone type: #&#39;AbstractInstruction *&#39;&gt;<br>
-       &quot;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.&quot;<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>
-       &quot;Note that ReceiverResultReg remains live after both<br>
-        ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline.&quot;<br>
-       self ensureReceiverResultRegContainsSelf.<br>
-       self ssPop: 1.<br>
-       self ssAllocateCallReg: ClassReg and: SendNumArgsReg. &quot;for ceStoreContextInstVarTrampoline&quot;<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>
-                         &quot;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&quot;<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 &gt; 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&gt;&gt;genStorePop:ReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean ReceiverVariable: slotIndex<br>
        &lt;inline: false&gt;<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>
-       &quot;Note that ReceiverResultReg remains live after ceStoreCheckTrampoline.&quot;<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>
-                         &quot;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&quot;<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 &gt; 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&gt;&gt;genStorePop:RemoteTemp:At: (in category &#39;bytecode generator support&#39;) -----<br>
  genStorePop: popBoolean RemoteTemp: slotIndex At: remoteTempIndex<br>
        &lt;inline: false&gt;<br>
        | topReg needStoreCheck |<br>
        &quot;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.&quot;<br>
        self assert: needsFrame.<br>
        &quot;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.&quot;<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 &gt; 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&gt;&gt;genTraceStores (in category &#39;bytecode generator support&#39;) -----<br>
+ genTraceStores<br>
+       &lt;inline: true&gt;<br>
+       traceStores &gt; 0 ifTrue:<br>
+               [ self MoveR: ClassReg R: TempReg.<br>
+               self CallRT: ceTraceStoreTrampoline ].!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;genVanillaStorePop:LiteralVariable: (in category &#39;bytecode generator support&#39;) -----<br>
+ genVanillaStorePop: popBoolean LiteralVariable: litVarIndex<br>
+       &lt;inline: true&gt;<br>
+       | topReg association needStoreCheck |<br>
+       &quot;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.&quot;<br>
+       self assert: needsFrame.<br>
+       &quot;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.&quot;<br>
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+       association := self getLiteral: litVarIndex.<br>
+       optStatus isReceiverResultRegLive: false.<br>
+       self ssAllocateRequiredReg: ReceiverResultReg. &quot;for ceStoreCheck call in genStoreSourceReg: has to be ReceiverResultReg&quot;<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&gt;&gt;genVanillaStorePop:MaybeContextReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
+ genVanillaStorePop: popBoolean MaybeContextReceiverVariable: slotIndex<br>
+       &lt;inline: true&gt;<br>
+       | jmpSingle jmpDone needStoreCheck |<br>
+       &lt;var: #jmpSingle type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &lt;var: #jmpDone type: #&#39;AbstractInstruction *&#39;&gt;<br>
+       &quot;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.&quot;<br>
+       self assert: needsFrame.<br>
+       self ssFlushUpThroughReceiverVariable: slotIndex.<br>
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+       &quot;Note that ReceiverResultReg remains live after both<br>
+        ceStoreContextInstVarTrampoline and ceStoreCheckTrampoline.&quot;<br>
+       self ensureReceiverResultRegContainsSelf.<br>
+       self ssPop: 1.<br>
+       self ssAllocateCallReg: ClassReg and: SendNumArgsReg. &quot;for ceStoreContextInstVarTrampoline&quot;<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&gt;&gt;genVanillaStorePop:ReceiverVariable: (in category &#39;bytecode generator support&#39;) -----<br>
+ genVanillaStorePop: popBoolean ReceiverVariable: slotIndex<br>
+       &lt;inline: true&gt;<br>
+       | topReg needStoreCheck |<br>
+       self ssFlushUpThroughReceiverVariable: slotIndex.<br>
+       needStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
+       &quot;Note that ReceiverResultReg remains live after ceStoreCheckTrampoline.&quot;<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>