<div dir="ltr">Hi Clément,<div><br></div><div>    also, before I forget, the primitive failure code for immutability violations should be PrimErrNoModification, not PrimErrInappropriate.<br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 6, 2016 at 12:00 AM, Eliot Miranda <span dir="ltr">&lt;<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Clément,<br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Dec 29, 2015 at 1:31 AM,  <span dir="ltr">&lt;<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style: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.1615.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1615.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-cb.1615<br>
Author: cb<br>
Time: 29 December 2015, 10:30:37.779 am<br>
UUID: 712a0115-a780-4d2c-b4f8-c0bc78031889<br>
Ancestors: VMMaker.oscog-eem.1614, VMMaker.oscog-cb.1579<br>
<br>
Made a new version of immutability with Eliot&#39;s remarks:<br>
- control flow maintained for the simulator<br>
- option pragma everywhere needed<br>
- removed duplication in extStore bytecodes<br>
- removed useless instruction in primitiveClone.<br>
<br>
I tried to use it, it does not work, but it seems the bleeding edge is not stable.<br></blockquote><div><br></div><div>I see one reason why it doesn&#39;t work.  Let me take you through storeAndPopReceiverVariableBytecode</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
The only thing I noticed is that some assertion may fail in #maybeCheckStackDepth:sp:pc: .<br>
<br>
=============== Diff against VMMaker.oscog-eem.1614 ===============<br>
<br>
Item was added:<br>
+ ----- Method: CoInterpreter&gt;&gt;ceCannotAssignTo:withIndex:valueToAssign: (in category &#39;trampolines&#39;) -----<br>
+ ceCannotAssignTo: immutableObject withIndex: index valueToAssign: valueToAssign<br>
+       &quot;index is unboxed.&quot;<br>
+       &lt;api&gt;<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       instructionPointer := self popStack.<br>
+       self push: immutableObject.<br>
+       self push: valueToAssign.<br>
+       self push: (objectMemory integerObjectOf: index).<br>
+       self push: instructionPointer.<br>
+       ^ self<br>
+               ceSendAbort: (objectMemory splObj: SelectorAttemptToAssign)<br>
+               to: immutableObject<br>
+               numArgs: 2!<br>
<br>
Item was removed:<br>
- ----- Method: CoInterpreter&gt;&gt;extendedStoreBytecode (in category &#39;stack bytecodes&#39;) -----<br>
- extendedStoreBytecode<br>
-       &quot;Override to use itemporary:in:put:&quot;<br>
-       | descriptor variableType variableIndex |<br>
-       &lt;inline: true&gt;<br>
-       descriptor := self fetchByte.<br>
-       self fetchNextBytecode.<br>
-       variableType := descriptor &gt;&gt; 6 bitAnd: 3.<br>
-       variableIndex := descriptor bitAnd: 63.<br>
-       variableType = 0 ifTrue:<br>
-               [^objectMemory storePointer: variableIndex ofObject: self receiver withValue: self internalStackTop].<br>
-       variableType = 1 ifTrue:<br>
-               [^self itemporary: variableIndex in: localFP put: self internalStackTop].<br>
-       variableType = 3 ifTrue:<br>
-               [^self storeLiteralVariable: variableIndex withValue: self internalStackTop].<br>
-       self error: &#39;illegal store&#39;!<br>
<br>
Item was added:<br>
+ ----- Method: CoInterpreter&gt;&gt;extendedStoreBytecodePop: (in category &#39;stack bytecodes&#39;) -----<br>
+ extendedStoreBytecodePop: popBoolean<br>
+       &quot;Override to use itemporary:in:put:&quot;<br>
+       | descriptor variableType variableIndex value |<br>
+       &lt;inline: true&gt;<br>
+       descriptor := self fetchByte.<br>
+       self fetchNextBytecode.<br>
+       variableType := descriptor &gt;&gt; 6 bitAnd: 3.<br>
+       variableIndex := descriptor bitAnd: 63.<br>
+       value := self internalStackTop.<br>
+       popBoolean ifTrue: [ self internalPop: 1 ].<br>
+       variableType = 0 ifTrue:<br>
+               [^objectMemory storePointerImmutabilityCheck: variableIndex ofObject: self receiver withValue: value].<br>
+       variableType = 1 ifTrue:<br>
+               [^self itemporary: variableIndex in: localFP put: value].<br>
+       variableType = 3 ifTrue:<br>
+               [^self storeLiteralVariable: variableIndex withValue: value].<br>
+       self error: &#39;illegal store&#39;!<br>
<br>
Item was changed:<br>
  ----- Method: CoInterpreterPrimitives&gt;&gt;primitiveObjectAtPut (in category &#39;object access primitives&#39;) -----<br>
  primitiveObjectAtPut<br>
        &quot;Store a literal into a CompiledMethod at the given index. Defined for CompiledMethods only.&quot;<br>
        | thisReceiver rawHeader realHeader index newValue |<br>
        newValue := self stackValue: 0.<br>
        index := self stackValue: 1.<br>
        (objectMemory isNonIntegerObject: index) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
        index := objectMemory integerValueOf: index.<br>
        thisReceiver := self stackValue: 2.<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ (objectMemory isImmutable: thisReceiver) ifTrue: [ ^self primitiveFailFor: PrimErrInappropriate ] ].<br>
        rawHeader := self rawHeaderOf: thisReceiver.<br>
        realHeader := (self isCogMethodReference: rawHeader)<br>
                                        ifTrue: [(self cCoerceSimple: rawHeader to: #&#39;CogMethod *&#39;) methodHeader]<br>
                                        ifFalse: [rawHeader].<br>
        (index &gt; 0<br>
         and: [index &lt;= ((objectMemory literalCountOfMethodHeader: realHeader) + LiteralStart)]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadIndex].<br>
        index = 1<br>
                ifTrue:<br>
                        [((objectMemory isNonIntegerObject: newValue)<br>
                         or: [(objectMemory literalCountOfMethodHeader: newValue) ~= (objectMemory literalCountOfMethodHeader: realHeader)]) ifTrue:<br>
                                [^self primitiveFailFor: PrimErrBadArgument].<br>
                         (self isCogMethodReference: rawHeader)<br>
                                ifTrue: [(self cCoerceSimple: rawHeader to: #&#39;CogMethod *&#39;) methodHeader: newValue]<br>
                                ifFalse: [objectMemory storePointerUnchecked: 0 ofObject: thisReceiver withValue: newValue]]<br>
                ifFalse:<br>
                        [objectMemory storePointer: index - 1 ofObject: thisReceiver withValue: newValue].<br>
        self pop: 3 thenPush: newValue!<br>
<br>
Item was added:<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>
+       ^ 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>
  ----- Method: CogObjectRepresentationFor32BitSpur&gt;&gt;genInnerPrimitiveAtPut: (in category &#39;primitive generators&#39;) -----<br>
  genInnerPrimitiveAtPut: retNoffset<br>
        &quot;Implement the guts of primitiveAtPut&quot;<br>
+       | formatReg jumpImmediate jumpBadIndex jumpImmutable<br>
-       | formatReg jumpImmediate jumpBadIndex<br>
          jumpNotIndexablePointers jumpNotIndexableBits<br>
          jumpIsContext jumpIsCompiledMethod jumpIsBytes jumpHasFixedFields<br>
          jumpArrayOutOfBounds jumpFixedFieldsOutOfBounds<br>
          jumpWordsOutOfBounds jumpBytesOutOfBounds jumpBytesOutOfRange<br>
          jumpNonSmallIntegerValue jumpNegative jumpShortsUnsupported jumpNotPointers<br>
          |<br>
        &lt;inline: true&gt;<br>
        &quot;c.f. StackInterpreter&gt;&gt;stSizeOf: SpurMemoryManager&gt;&gt;lengthOf:format: fixedFieldsOf:format:length:&quot;<br>
        &lt;var: #jumpIsBytes type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpNegative type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpBadIndex type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpIsContext type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpImmediate type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpHasFixedFields type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpNotIndexableBits type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpArrayOutOfBounds type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpBytesOutOfBounds type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpShortsUnsupported type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpWordsOutOfBounds type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpNotIndexablePointers type: #&#39;AbstractInstruction *&#39;&gt;<br>
<br>
        jumpImmediate := self genJumpImmediate: ReceiverResultReg.<br>
        jumpBadIndex := self genJumpNotSmallInteger: Arg0Reg scratchReg: TempReg.<br>
        self genConvertSmallIntegerToIntegerInReg: Arg0Reg.<br>
        cogit SubCq: 1 R: Arg0Reg. &quot;1-rel =&gt; 0-rel&quot;<br>
<br>
        &quot;formatReg := self formatOf: ReceiverResultReg&quot;<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue:<br>
+               [ self genGetFormatOf: ReceiverResultReg<br>
+                       into: (formatReg := SendNumArgsReg)<br>
+                       leastSignificantHalfOfBaseHeaderIntoScratch: TempReg.<br>
+               jumpImmutable := self genJumpBaseHeaderImmutable: TempReg ]<br>
+               ifFalse:<br>
+               [ self genGetFormatOf: ReceiverResultReg<br>
+                       into: (formatReg := SendNumArgsReg)<br>
+                       leastSignificantHalfOfBaseHeaderIntoScratch: NoReg ].<br>
-       self genGetFormatOf: ReceiverResultReg<br>
-               into: (formatReg := SendNumArgsReg)<br>
-               leastSignificantHalfOfBaseHeaderIntoScratch: NoReg.<br>
<br>
        self genGetNumSlotsOf: ReceiverResultReg into: ClassReg.<br>
<br>
        &quot;dispatch on format in a combination of highest dynamic frequency order first and convenience.<br>
                  0 = 0 sized objects (UndefinedObject True False et al)<br>
                  1 = non-indexable objects with inst vars (Point et al)<br>
                  2 = indexable objects with no inst vars (Array et al)<br>
                  3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)<br>
                  4 = weak indexable objects with inst vars (WeakArray et al)<br>
                  5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)<br>
                  6 unused, reserved for exotic pointer objects?<br>
                  7 Forwarded Object, 1st field is pointer, rest of fields are ignored<br>
                  8 unused, reserved for exotic non-pointer objects?<br>
                  9 (?) 64-bit indexable<br>
                10 - 11 32-bit indexable<br>
                12 - 15 16-bit indexable<br>
                16 - 23 byte indexable<br>
                24 - 31 compiled method&quot;<br>
        cogit CmpCq: objectMemory weakArrayFormat R: formatReg.<br>
        jumpNotPointers := cogit JumpAbove: 0.<br>
        &quot;optimistic store check; assume index in range (almost always is).&quot;<br>
        self genStoreCheckReceiverReg: ReceiverResultReg<br>
                valueReg: Arg1Reg<br>
                scratchReg: TempReg<br>
                inFrame: false.<br>
<br>
        cogit CmpCq: objectMemory arrayFormat R: formatReg.<br>
        jumpNotIndexablePointers := cogit JumpBelow: 0.<br>
        jumpHasFixedFields := cogit JumpNonZero: 0.<br>
        cogit CmpR: Arg0Reg R: ClassReg.<br>
        jumpArrayOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit AddCq: objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord R: Arg0Reg.<br>
        cogit MoveR: Arg1Reg Xwr: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        cogit RetN: retNoffset.<br>
<br>
        jumpHasFixedFields jmpTarget: cogit Label.<br>
        self genGetClassIndexOfNonImm: ReceiverResultReg into: formatReg.<br>
        cogit CmpCq: ClassMethodContextCompactIndex R: formatReg.<br>
        jumpIsContext := cogit JumpZero: 0.<br>
        &quot;get # fixed fields in formatReg&quot;<br>
        cogit PushR: ClassReg.<br>
        self genGetClassObjectOfClassIndex: formatReg into: ClassReg scratchReg: TempReg.<br>
        self genLoadSlot: InstanceSpecificationIndex sourceReg: ClassReg destReg: formatReg.<br>
        cogit PopR: ClassReg.<br>
        self genConvertSmallIntegerToIntegerInReg: formatReg.<br>
        cogit AndCq: objectMemory fixedFieldsOfClassFormatMask R: formatReg.<br>
        cogit SubR: formatReg R: ClassReg.<br>
        cogit AddCq: objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord R: formatReg.<br>
        cogit CmpR: Arg0Reg R: ClassReg.<br>
        jumpFixedFieldsOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit AddR: formatReg R: Arg0Reg.<br>
        cogit MoveR: Arg1Reg Xwr: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        cogit RetN: retNoffset.<br>
<br>
        jumpNotPointers jmpTarget:<br>
                (cogit CmpCq: objectMemory firstCompiledMethodFormat R: formatReg).<br>
        jumpIsCompiledMethod := cogit JumpAboveOrEqual: 0.<br>
        jumpNonSmallIntegerValue := self genJumpNotSmallInteger: Arg1Reg scratchReg: TempReg.<br>
                                        cogit CmpCq: objectMemory firstByteFormat R: formatReg.<br>
        jumpIsBytes := cogit JumpAboveOrEqual: 0.<br>
                                        cogit CmpCq: objectMemory firstShortFormat R: formatReg.<br>
        jumpShortsUnsupported := cogit JumpAboveOrEqual: 0.<br>
                                        cogit CmpCq: objectMemory firstLongFormat R: formatReg.<br>
        &quot;For now ignore 64-bit indexability.&quot;<br>
        jumpNotIndexableBits := cogit JumpBelow: 0.<br>
<br>
        cogit CmpR: Arg0Reg R: ClassReg.<br>
        jumpWordsOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        self genConvertSmallIntegerToIntegerInReg: TempReg.<br>
        (cogit lastOpcode setsConditionCodesFor: JumpNegative) ifFalse:<br>
                [self CmpCq: 0 R: ClassReg]. &quot;N.B. FLAGS := ClassReg - 0&quot;<br>
        jumpNegative := cogit JumpNegative: 0.<br>
        cogit AddCq: objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord R: Arg0Reg.<br>
        cogit MoveR: TempReg Xwr: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        cogit RetN: retNoffset.<br>
<br>
        jumpIsBytes jmpTarget:<br>
                (cogit CmpCq: (objectMemory integerObjectOf: 255) R: Arg1Reg).<br>
        jumpBytesOutOfRange := cogit JumpAbove: 0.<br>
        cogit LogicalShiftLeftCq: objectMemory shiftForWord R: ClassReg.<br>
        cogit AndCq: objectMemory wordSize - 1 R: formatReg.<br>
        cogit SubR: formatReg R: ClassReg;<br>
        CmpR: Arg0Reg R: ClassReg.<br>
        jumpBytesOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        self genConvertSmallIntegerToIntegerInReg: TempReg.<br>
        cogit AddCq: objectMemory baseHeaderSize R: Arg0Reg.<br>
        cogit MoveR: TempReg Xbr: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        cogit RetN: retNoffset.<br>
<br>
        &quot;there are no shorts as yet.  so this is dead code:<br>
        jumpIsShorts jmpTarget:<br>
                (cogit CmpCq: (objectMemory integerObjectOf: 65535) R: Arg1Reg).<br>
        jumpShortsOutOfRange := cogit JumpAbove: 0.<br>
        cogit LogicalShiftLeftCq: objectMemory shiftForWord - 1 R: ClassReg.<br>
        cogit AndCq: 1 R: formatReg.<br>
        cogit SubR: formatReg R: ClassReg;<br>
        CmpR: Arg0Reg R: ClassReg.<br>
        jumpShortsOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        cogit genConvertSmallIntegerToIntegerInReg: TempReg.<br>
        cogit AddR: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: TempReg M16: objectMemory baseHeaderSize r: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        jumpShortsDone := cogit Jump: 0.&quot;<br>
<br>
        jumpIsContext jmpTarget:<br>
        (jumpNegative jmpTarget:<br>
        (jumpNotIndexableBits jmpTarget:<br>
        (jumpBytesOutOfRange jmpTarget:<br>
        (jumpIsCompiledMethod jmpTarget:<br>
        (jumpArrayOutOfBounds jmpTarget:<br>
        (jumpBytesOutOfBounds jmpTarget:<br>
        (jumpShortsUnsupported jmpTarget:<br>
        (jumpWordsOutOfBounds jmpTarget:<br>
        (jumpNotIndexablePointers jmpTarget:<br>
        (jumpNonSmallIntegerValue jmpTarget:<br>
        (jumpFixedFieldsOutOfBounds jmpTarget: cogit Label))))))))))).<br>
+<br>
+       self cppIf: IMMUTABILITY ifTrue: [ jumpImmutable jmpTarget: cogit Label ].<br>
<br>
        cogit AddCq: 1 R: Arg0Reg. &quot;0-rel =&gt; 1-rel&quot;<br>
        self genConvertIntegerToSmallIntegerInReg: Arg0Reg.<br>
<br>
        jumpBadIndex jmpTarget: (jumpImmediate jmpTarget: cogit Label).<br>
<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationFor32BitSpur&gt;&gt;genInnerPrimitiveStringAtPut: (in category &#39;primitive generators&#39;) -----<br>
  genInnerPrimitiveStringAtPut: retNoffset<br>
        &quot;Implement the guts of primitiveStringAtPut&quot;<br>
        | formatReg jumpBadIndex jumpBadArg jumpWordsDone jumpBytesOutOfRange<br>
+         jumpIsBytes jumpNotString jumpIsCompiledMethod jumpImmutable<br>
-         jumpIsBytes jumpNotString jumpIsCompiledMethod<br>
          jumpBytesOutOfBounds jumpWordsOutOfBounds jumpShortsUnsupported |<br>
        &lt;inline: true&gt;<br>
        &quot;c.f. StackInterpreter&gt;&gt;stSizeOf: SpurMemoryManager&gt;&gt;lengthOf:format: fixedFieldsOf:format:length:&quot;<br>
        &lt;var: #jumpBadArg type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpIsBytes type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpBadIndex type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpWordsDone type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpBytesOutOfBounds type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpShortsUnsupported type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpWordsOutOfBounds type: #&#39;AbstractInstruction *&#39;&gt;<br>
<br>
        jumpBadIndex := self genJumpNotSmallInteger: Arg0Reg.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        jumpBadArg := self genJumpNotCharacterInScratchReg: TempReg.<br>
        self genConvertSmallIntegerToIntegerInReg: Arg0Reg.<br>
        cogit SubCq: 1 R: Arg0Reg. &quot;1-rel =&gt; 0-rel&quot;<br>
<br>
        &quot;formatReg := self formatOf: ReceiverResultReg&quot;<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue:<br>
+               [ self genGetFormatOf: ReceiverResultReg<br>
+                       into: (formatReg := SendNumArgsReg)<br>
+                       leastSignificantHalfOfBaseHeaderIntoScratch: TempReg.<br>
+               jumpImmutable := self genJumpBaseHeaderImmutable: TempReg ]<br>
+               ifFalse:<br>
+               [ self genGetFormatOf: ReceiverResultReg<br>
+                       into: (formatReg := SendNumArgsReg)<br>
+                       leastSignificantHalfOfBaseHeaderIntoScratch: NoReg ].<br>
-       self genGetFormatOf: ReceiverResultReg<br>
-               into: (formatReg := SendNumArgsReg)<br>
-               leastSignificantHalfOfBaseHeaderIntoScratch: NoReg.<br>
<br>
        self genGetNumSlotsOf: ReceiverResultReg into: ClassReg.<br>
<br>
        &quot;dispatch on format; words and/or bytes.<br>
                  0 to 8 = pointer objects, forwarders, reserved.<br>
                  9 (?) 64-bit indexable<br>
                10 - 11 32-bit indexable<br>
                12 - 15 16-bit indexable (but unused)<br>
                16 - 23 byte indexable<br>
                24 - 31 compiled method&quot;<br>
        cogit CmpCq: objectMemory firstLongFormat R: formatReg.<br>
        jumpNotString := cogit JumpBelowOrEqual: 0.<br>
                                        cogit CmpCq: objectMemory firstCompiledMethodFormat R: formatReg.<br>
        jumpIsCompiledMethod := cogit JumpAboveOrEqual: 0.<br>
                                        cogit CmpCq: objectMemory firstByteFormat R: formatReg.<br>
        jumpIsBytes := cogit JumpGreaterOrEqual: 0.<br>
                                        cogit CmpCq: objectMemory firstShortFormat R: formatReg.<br>
        jumpShortsUnsupported := cogit JumpGreaterOrEqual: 0.<br>
<br>
        cogit CmpR: Arg0Reg R: ClassReg.<br>
        jumpWordsOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        self genConvertSmallIntegerToIntegerInReg: TempReg.<br>
        cogit AddCq: objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord R: Arg0Reg.<br>
        cogit MoveR: TempReg Xwr: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        jumpWordsDone := cogit Jump: 0.<br>
<br>
        &quot;there are no shorts as yet.  so this is dead code:<br>
        jumpIsShorts jmpTarget:<br>
                (cogit CmpCq: (objectMemory integerObjectOf: 65535) R: Arg1Reg).<br>
        jumpShortsOutOfRange := cogit JumpAbove: 0.<br>
        cogit LogicalShiftLeftCq: objectMemory shiftForWord - 1 R: ClassReg.<br>
        cogit AndCq: 1 R: formatReg.<br>
        cogit SubR: formatReg R: ClassReg;<br>
        CmpR: Arg0Reg R: ClassReg.<br>
        jumpShortsOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        cogit genConvertSmallIntegerToIntegerInReg: TempReg.<br>
        cogit AddR: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: TempReg M16: objectMemory baseHeaderSize r: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
        jumpShortsDone := cogit Jump: 0.&quot;<br>
<br>
        jumpIsBytes jmpTarget:<br>
                (cogit CmpCq: (objectMemory characterObjectOf: 255) R: Arg1Reg).<br>
        jumpBytesOutOfRange := cogit JumpAbove: 0.<br>
        cogit LogicalShiftLeftCq: objectMemory shiftForWord R: ClassReg.<br>
        cogit AndCq: objectMemory wordSize - 1 R: formatReg.<br>
        cogit SubR: formatReg R: ClassReg;<br>
        CmpR: Arg0Reg R: ClassReg.<br>
        jumpBytesOutOfBounds := cogit JumpBelowOrEqual: 0.<br>
        cogit MoveR: Arg1Reg R: TempReg.<br>
        self genConvertCharacterToCodeInReg: TempReg.<br>
        cogit AddCq: objectMemory baseHeaderSize R: Arg0Reg.<br>
        cogit MoveR: TempReg Xbr: Arg0Reg R: ReceiverResultReg.<br>
        cogit MoveR: Arg1Reg R: ReceiverResultReg.<br>
<br>
        jumpWordsDone jmpTarget:<br>
                (cogit RetN: retNoffset).<br>
<br>
        jumpBadArg jmpTarget:<br>
        (jumpNotString jmpTarget:<br>
        (jumpBytesOutOfRange jmpTarget:<br>
        (jumpIsCompiledMethod jmpTarget:<br>
        (jumpBytesOutOfBounds jmpTarget:<br>
        (jumpShortsUnsupported jmpTarget:<br>
        (jumpWordsOutOfBounds jmpTarget: cogit Label)))))).<br>
<br>
+       self cppIf: IMMUTABILITY ifTrue: [ jumpImmutable jmpTarget: cogit Label ].<br>
+<br>
        cogit AddCq: 1 R: Arg0Reg. &quot;0-rel =&gt; 1-rel&quot;<br>
        self genConvertIntegerToSmallIntegerInReg: Arg0Reg.<br>
<br>
        jumpBadIndex jmpTarget: cogit Label.<br>
<br>
        ^0!<br>
<br>
Item was changed:<br>
  CogObjectRepresentation subclass: #CogObjectRepresentationForSpur<br>
+       instanceVariableNames: &#39;ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline ceCannotAssignToWithIndexTrampoline&#39;<br>
-       instanceVariableNames: &#39;ceScheduleScavengeTrampoline ceSmallActiveContextInMethodTrampoline ceSmallActiveContextInBlockTrampoline ceLargeActiveContextInMethodTrampoline ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline&#39;<br>
        classVariableNames: &#39;&#39;<br>
        poolDictionaries: &#39;VMBytecodeConstants VMSqueakClassIndices&#39;<br>
        category: &#39;VMMaker-JIT&#39;!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationForSpur class&gt;&gt;numTrampolines (in category &#39;accessing&#39;) -----<br>
  numTrampolines<br>
+       (initializationOptions at: #IMMUTABILITY ifAbsent: [false])<br>
+               ifTrue: [ ^ super numTrampolines + 7 ]<br>
+               ifFalse: [ ^ super numTrampolines + 6 ]!<br>
-       ^super numTrampolines + 6!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur&gt;&gt;genImmutableCheck:slotIndex:sourceReg:scratchReg:popBoolean:needRestoreRcvr: (in category &#39;compile abstract instructions&#39;) -----<br>
+ genImmutableCheck: regHoldingObjectMutated slotIndex: index sourceReg: regHoldingValueToStore scratchReg: scratchReg popBoolean: popBoolean 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 RcvrResultReg<br>
+       - index (unboxed) passed in TempReg<br>
+       - valueToStore passed in Arg1Reg.<br>
+       Simulated stack is flushed until simulatedStackPointer - 1, which implies full flush<br>
+       if popBoolean is true, else top value may not be flushed.<br>
+       We spill the top value (the value to store) for the trampoline if needed.&quot;<br>
+       self assert: regHoldingObjectMutated == ReceiverResultReg.<br>
+       self assert: scratchReg == TempReg.<br>
+       self assert: regHoldingValueToStore == ClassReg.<br>
+       mutableJump := self genJumpMutable: ClassReg scratchReg: TempReg.<br>
+<br>
+       &quot;We reach this code if the object mutated is immutable.&quot;<br>
+       &quot;simulatedStack state altered for the trampoline, spill top value if needed&quot;<br>
+       (popBoolean or: [ cogit ssTop spilled ]) ifFalse:<br>
+               [ self assert: (cogit ssTop type = SSRegister and: [cogit ssTop register = ClassReg]).<br>
+                 cogit PushR: ClassReg ].<br>
+       &quot;pass the unboxed index using TempReg&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;Top of stack is consumed by the trampoline. In case of store with non spilled value,<br>
+       restore ClassReg to match simulated stack state&quot;<br>
+       (popBoolean or: [ cogit ssTop spilled ]) ifFalse:<br>
+               [cogit popR: ClassReg].<br>
+       &quot;restore ReceiverResultReg state if needed&quot;<br>
+       needRestoreRcvr ifTrue: [ self 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 added:<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>
+       cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.<br>
+       ^ cogit JumpNonZero: 0!<br>
<br>
Item was added:<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>
+       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 added:<br>
+ ----- Method: CogObjectRepresentationForSpur&gt;&gt;genJumpMutable:scratchReg: (in category &#39;compile abstract instructions&#39;) -----<br>
+ genJumpMutable: 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 genJumpBaseHeaderMutable: scratchReg!<br>
<br>
Item was changed:<br>
  ----- Method: CogObjectRepresentationForSpur&gt;&gt;genStoreCheckReceiverReg:valueReg:scratchReg:inFrame: (in category &#39;compile abstract instructions&#39;) -----<br>
  genStoreCheckReceiverReg: destReg valueReg: valueReg scratchReg: scratchReg inFrame: inFrame<br>
        &quot;Generate the code for a store check of valueReg into destReg.&quot;<br>
        | jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRemembered mask rememberedBitByteOffset |<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>
        &quot;Is value stored an integer?  If so we&#39;re done&quot;<br>
        cogit MoveR: valueReg R: scratchReg.<br>
        cogit AndCq: objectMemory tagMask R: scratchReg.<br>
        jmpImmediate := cogit JumpNonZero: 0.<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: valueReg. &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;Remembered bit is not set.  Call store check to insert dest into remembered table.&quot;<br>
        self assert: destReg == ReceiverResultReg.<br>
+       cogit<br>
+               evaluateTrampolineCallBlock:<br>
-       inFrame<br>
-               ifTrue:<br>
                        [cogit<br>
                                CallRT: ceStoreCheckTrampoline<br>
                                registersToBeSavedMask: (((cogit registerMaskFor: valueReg)<br>
                                                                                                bitOr: cogit callerSavedRegMask)<br>
                                                                                                bitClear: (cogit registerMaskFor: ReceiverResultReg))]<br>
+               protectLinkRegIfNot: inFrame.<br>
-               ifFalse:<br>
-                       [cogit backEnd saveAndRestoreLinkRegAround:<br>
-                               [cogit<br>
-                                       CallRT: ceStoreCheckTrampoline<br>
-                                       registersToBeSavedMask: (((cogit registerMaskFor: valueReg)<br>
-                                                                                                       bitOr: cogit callerSavedRegMask)<br>
-                                                                                                       bitClear: (cogit registerMaskFor: ReceiverResultReg))]].<br>
        jmpImmediate jmpTarget:<br>
        (jmpDestYoung jmpTarget:<br>
        (jmpSourceOld jmpTarget:<br>
        (jmpAlreadyRemembered jmpTarget:<br>
                cogit Label))).<br>
        ^0!<br>
<br>
Item was removed:<br>
- ----- Method: CogObjectRepresentationForSpur&gt;&gt;genStoreImmediateInSourceReg:slotIndex:destReg: (in category &#39;compile abstract instructions&#39;) -----<br>
- genStoreImmediateInSourceReg: sourceReg slotIndex: index destReg: destReg<br>
-       cogit MoveR: sourceReg<br>
-                  Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
-                  r: destReg.<br>
-       ^0!<br>
<br>
Item was removed:<br>
- ----- Method: CogObjectRepresentationForSpur&gt;&gt;genStoreSourceReg:slotIndex:destReg:scratchReg: (in category &#39;compile abstract instructions&#39;) -----<br>
- genStoreSourceReg: sourceReg slotIndex: index destReg: destReg scratchReg: scratchReg<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&quot;<br>
-       ^self genStoreCheckReceiverReg: destReg valueReg: sourceReg scratchReg: scratchReg inFrame: true!<br>
<br>
Item was removed:<br>
- ----- Method: CogObjectRepresentationForSpur&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>
-       &quot;do the store&quot;<br>
-       cogit MoveR: sourceReg<br>
-                  Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
-                  r: destReg.<br>
-       &quot;now the check&quot;<br>
-       ^self genStoreCheckReceiverReg: destReg valueReg: sourceReg scratchReg: scratchReg inFrame: inFrame!<br>
<br>
Item was added:<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>
+       &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 changed:<br>
  ----- Method: CogObjectRepresentationForSpur&gt;&gt;genStoreSourceReg:slotIndex:intoNewObjectInDestReg: (in category &#39;compile abstract instructions&#39;) -----<br>
  genStoreSourceReg: sourceReg slotIndex: index intoNewObjectInDestReg: destReg<br>
+       &quot;This method is used for unchecked stores in objects after their creation (typically, inlined creation of Array, closures and some temp vectors).<br>
+       Currently there is no need to do the immutability check here&quot;<br>
        cogit MoveR: sourceReg<br>
                   Mw: index * objectMemory wordSize + objectMemory baseHeaderSize<br>
                   r: destReg.<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:<br>
+                       [ &quot;Arg1Reg is used as resultReg because cogit needs to restore the valueToStore<br>
+                       in the reg expected. The reg for the valueToStore is dynamically allocated, but<br>
+                       in most case, in the non-sista VM, it ends up being Arg1Reg.&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>
                                                                        result: cogit returnRegForStoreCheck.<br>
        ceStoreCheckContextReceiverTrampoline := self genStoreCheckContextReceiverTrampoline.<br>
        ceScheduleScavengeTrampoline := cogit<br>
                                                                                        genSafeTrampolineFor: #ceScheduleScavenge<br>
                                                                                        called: &#39;ceScheduleScavengeTrampoline&#39;.<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 removed:<br>
- ----- Method: CogObjectRepresentationForSqueakV3&gt;&gt;genStoreImmediateInSourceReg:slotIndex:destReg: (in category &#39;compile abstract instructions&#39;) -----<br>
- genStoreImmediateInSourceReg: sourceReg slotIndex: index destReg: destReg<br>
-       cogit MoveR: sourceReg Mw: index * objectMemory wordSize + objectMemory baseHeaderSize r: destReg.<br>
-       ^0!<br>
<br>
Item was removed:<br>
- ----- Method: CogObjectRepresentationForSqueakV3&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>
-       | 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>
-       &quot;do the store&quot;<br>
-       cogit MoveR: sourceReg Mw: index * objectMemory wordSize + objectMemory baseHeaderSize r: destReg.<br>
-       &quot;now the check.  Is value stored an integer?  If so we&#39;re done&quot;<br>
-       cogit MoveR: sourceReg R: scratchReg.<br>
-       cogit AndCq: 1 R: scratchReg.<br>
-       jmpImmediate := cogit JumpNonZero: 0.<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>
-       inFrame<br>
-               ifTrue:<br>
-                       [cogit<br>
-                               CallRT: ceStoreCheckTrampoline<br>
-                               registersToBeSavedMask: (((cogit registerMaskFor: sourceReg)<br>
-                                                                                               bitOr: cogit callerSavedRegMask)<br>
-                                                                                               bitClear: (cogit registerMaskFor: ReceiverResultReg))]<br>
-               ifFalse:<br>
-                       [cogit backEnd saveAndRestoreLinkRegAround:<br>
-                               [cogit<br>
-                                       CallRT: ceStoreCheckTrampoline<br>
-                                       registersToBeSavedMask: (((cogit registerMaskFor: sourceReg)<br>
-                                                                                                       bitOr: cogit callerSavedRegMask)<br>
-                                                                                                       bitClear: (cogit registerMaskFor: ReceiverResultReg))]].<br>
-       jmpImmediate jmpTarget:<br>
-       (jmpDestYoung jmpTarget:<br>
-       (jmpSourceOld jmpTarget:<br>
-       (jmpAlreadyRoot jmpTarget:<br>
-               cogit Label))).<br>
-       ^0!<br>
<br>
Item was added:<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>
+       &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>
+       cogit MoveR: sourceReg R: scratchReg.<br>
+       cogit AndCq: 1 R: scratchReg.<br>
+       jmpImmediate := cogit JumpNonZero: 0.<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:<br>
+                       [cogit<br>
+                               CallRT: ceStoreCheckTrampoline<br>
+                               registersToBeSavedMask: (((cogit registerMaskFor: sourceReg)<br>
+                                                                                               bitOr: cogit callerSavedRegMask)<br>
+                                                                                               bitClear: (cogit registerMaskFor: ReceiverResultReg))]<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: CogVMSimulator&gt;&gt;maybeCheckStackDepth:sp:pc: (in category &#39;debug support&#39;) -----<br>
  maybeCheckStackDepth: delta sp: sp pc: mcpc<br>
        | asp bcpc startbcpc cogHomeMethod cogBlockMethod csp debugStackPointers |<br>
        debugStackDepthDictionary ifNil: [^self].<br>
        (self isMachineCodeFrame: framePointer) ifFalse: [^self].<br>
        cogBlockMethod := self mframeCogMethod: framePointer.<br>
        cogHomeMethod := self asCogHomeMethod: cogBlockMethod.<br>
        debugStackPointers := debugStackDepthDictionary<br>
                                                                at: cogHomeMethod methodObject<br>
                                                                ifAbsentPut: [self debugStackPointersFor: cogHomeMethod methodObject].<br>
        startbcpc := cogHomeMethod = cogBlockMethod<br>
                                        ifTrue: [self startPCOfMethod: cogHomeMethod methodObject]<br>
                                        ifFalse: [self startPCOfClosure: (self pushedReceiverOrClosureOfFrame: framePointer)].<br>
        bcpc := cogit bytecodePCFor: mcpc startBcpc: startbcpc in: cogBlockMethod.<br>
        self assert: bcpc ~= 0.<br>
        cogBlockMethod ~= cogHomeMethod ifTrue:<br>
                [| lastbcpc |<br>
                 lastbcpc := cogit lastBytecodePCForBlockAt: startbcpc in: cogHomeMethod methodObject.<br>
                 bcpc &gt; lastbcpc ifTrue:<br>
                        [bcpc := lastbcpc]].<br>
        asp := self stackPointerIndexForFrame: framePointer WithSP: sp + objectMemory wordSize.<br>
        csp := debugStackPointers at: bcpc.<br>
        &quot;Compensate lazily for absent receiver sends.&quot;<br>
        (NewspeakVM<br>
         and: [asp - delta = csp<br>
         and: [cogit isAbsentReceiverSendAt: mcpc in: cogHomeMethod]]) ifTrue:<br>
                [csp := debugStackPointers at: bcpc put: csp + 1].<br>
        self assert: asp - delta + 1 = csp!<br>
<br>
Item was added:<br>
+ ----- Method: CurrentImageCoInterpreterFacadeForSpurObjectRepresentation&gt;&gt;immutableBitMask (in category &#39;accessing&#39;) -----<br>
+ immutableBitMask<br>
+       ^objectMemory immutableBitMask!<br>
<br>
Item was added:<br>
+ ----- Method: InterpreterPrimitives&gt;&gt;canBeImmutable: (in category &#39;object access primitives&#39;) -----<br>
+ canBeImmutable: oop<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       | scheduler processLists |<br>
+<br>
+       self assert: (objectMemory isNonImmediate: oop).<br>
+<br>
+       &quot;For now we fail the primitive for contexts to we ensure there are no immutable contexts.<br>
+       Later we can consider having immutable contexts and send cannotReturn callback<br>
+       when returning to an immutable context. That would mean that setting a context<br>
+       to immutable would require a divorce and returns to immutable context are<br>
+       necessarily across stack pages&quot;<br>
+       (objectMemory isContext: oop) ifTrue: [ ^ false ].<br>
+<br>
+       &quot;I don&#39;t get it for semaphores so they can&#39;t be immutable&quot;<br>
+       (objectMemory isSemaphoreObj: oop) ifTrue: [^ false].<br>
+<br>
+       &quot;simple version of process management: we forbid Process and LinkedList instances to be immutable<br>
+       as well as the Processor and the array of activeProcess&quot;<br>
+       scheduler := self fetchPointer: ValueIndex ofObject: (self splObj: SchedulerAssociation).<br>
+       processLists := objectMemory fetchPointer: ProcessListsIndex ofObject: scheduler.<br>
+       oop = scheduler ifTrue: [ ^ false ].<br>
+       oop = processLists ifTrue: [ ^ false ].<br>
+       &quot;Is it a linkedList ?&quot;<br>
+       (objectMemory classIndexOf: (processLists at: 1)) = (objectMemory classIndexOf: oop) ifTrue: [ ^ false ].<br>
+       &quot;is it a Process ?&quot;<br>
+       (objectMemory classIndexOf: (objectMemory fetchPointer: ActiveProcessIndex ofObject: scheduler)) =  (objectMemory classIndexOf: oop) ifTrue: [ ^ false ].<br>
+<br>
+       &quot;The rest of the code is relative to process management: the Processor (the active<br>
+       process scheduler) can&#39;t be immutable, as well as all the objects relative to Process management &quot;<br>
+       &quot;scheduler := self fetchPointer: ValueIndex ofObject: (self splObj: SchedulerAssociation).<br>
+       processLists := objectMemory fetchPointer: ProcessListsIndex ofObject: scheduler.<br>
+       ((objectMemory formatOf: oop) = objectMemory nonIndexablePointerFormat)<br>
+               ifFalse:<br>
+                       [ (objectMemory isArrayNonImm: oop) ifFalse: [ ^ true ].<br>
+                         ^ (oop = processLists) not ].<br>
+       (objectMemory numSlotsOf: oop) &gt;= 2 ifFalse: [ ^ true ].<br>
+       &quot;&quot;is the oop the scheduler itself ?&quot;&quot;<br>
+       oop = scheduler ifTrue: [ ^ false ].<br>
+       1 to: (objectMemory numSlotsOf: processLists) do: [ :i |<br>
+               &quot;&quot;is the oop one of the linked lists ?&quot;&quot;<br>
+               (list := processLists at: i) = oop ifTrue: [^ false].<br>
+               &quot;&quot;is the oop one of the runnable process ?&quot;&quot;<br>
+               first := objectMemory fetchPointer: FirstLinkIndex ofObject: list.<br>
+               first = objectMemory nilObject ifFalse:<br>
+                       [ last := objectMemory fetchPointer: LastLinkIndex ofObject: list.<br>
+                         link := first.<br>
+                         [ link = last ] whileFalse:<br>
+                               [ link = oop ifTrue: [ ^ false ].<br>
+                                 link := objectMemory fetchPointer: NextLinkIndex ofObject: link. ] ] ].&quot;<br>
+       ^ true!<br>
<br>
Item was changed:<br>
  ----- Method: InterpreterPrimitives&gt;&gt;primitiveFloatAtPut (in category &#39;indexing primitives&#39;) -----<br>
  primitiveFloatAtPut<br>
        &quot;Provide platform-independent access to 32-bit words comprising<br>
         a Float.  Map index 1 onto the most significant word and index 2<br>
         onto the least significant word.&quot;<br>
        | rcvr index oopToStore valueToStore |<br>
        &lt;var: #valueToStore type: #usqInt&gt;<br>
        oopToStore := self stackTop.<br>
        valueToStore := self positive32BitValueOf: oopToStore.<br>
        self successful ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
        rcvr := self stackValue: 2.<br>
        index := self stackValue: 1.<br>
        (objectMemory isImmediateFloat: rcvr) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadReceiver].<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ (objectMemory isImmutable: rcvr) ifTrue: [^self primitiveFailFor: PrimErrBadReceiver] ].<br>
        index = ConstOne ifTrue:<br>
                [objectMemory storeLong32: (VMBIGENDIAN ifTrue: [0] ifFalse: [1])<br>
                        ofObject: rcvr<br>
                        withValue: valueToStore.<br>
                ^self pop: 3 thenPush: oopToStore].<br>
        index = ConstTwo ifTrue:<br>
                [objectMemory storeLong32: (VMBIGENDIAN ifTrue: [1] ifFalse: [0])<br>
                        ofObject: rcvr<br>
                        withValue: valueToStore.<br>
                ^self pop: 3 thenPush: oopToStore].<br>
        self primitiveFailFor: ((objectMemory isIntegerObject: index)<br>
                                                        ifTrue: [PrimErrBadIndex]<br>
                                                        ifFalse: [PrimErrBadArgument])!<br>
<br>
Item was added:<br>
+ ----- Method: InterpreterPrimitives&gt;&gt;primitiveGetImmutability (in category &#39;object access primitives&#39;) -----<br>
+ primitiveGetImmutability<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       | rcvr bool |<br>
+       rcvr := self stackValue: 0.<br>
+       bool := (objectMemory isOopImmutable: rcvr)<br>
+               ifTrue: [ TrueObject ]<br>
+               ifFalse: [ FalseObject ].<br>
+       self pop: argumentCount thenPush: (self splObj: bool)!<br>
<br>
Item was changed:<br>
  ----- Method: InterpreterPrimitives&gt;&gt;primitiveIntegerAtPut (in category &#39;sound primitives&#39;) -----<br>
  primitiveIntegerAtPut<br>
        &quot;Return the 32bit signed integer contents of a words receiver&quot;<br>
        | index rcvr sz addr value valueOop |<br>
        &lt;var: &#39;value&#39; type: &#39;int&#39;&gt;<br>
        valueOop := self stackValue: 0.<br>
        index := self stackIntegerValue: 1.<br>
        value := self signed32BitValueOf: valueOop.<br>
        self successful ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
        rcvr := self stackValue: 2.<br>
        (objectMemory isWords: rcvr) ifFalse:<br>
                [^self primitiveFailFor: PrimErrInappropriate].<br>
+       self cppIf: IMMUTABILITY &quot;isWords: ensure non immediate&quot;<br>
+               ifTrue: [ (objectMemory isImmutable: rcvr) ifTrue: [ ^self primitiveFailFor: PrimErrInappropriate ] ].<br>
        sz := objectMemory lengthOf: rcvr.  &quot;number of fields&quot;<br>
        (index &gt;= 1 and: [index &lt;= sz]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadIndex].<br>
        &quot;4 = 32 bits / 8&quot;<br>
        addr := rcvr + objectMemory baseHeaderSize + (index - 1 * 4). &quot;for zero indexing&quot;<br>
        value := objectMemory intAt: addr put: value.<br>
        self pop: 3 thenPush: valueOop &quot;pop all; return value&quot;<br>
  !<br>
<br>
Item was changed:<br>
  ----- Method: InterpreterPrimitives&gt;&gt;primitiveObjectAtPut (in category &#39;object access primitives&#39;) -----<br>
  primitiveObjectAtPut<br>
        &quot;Store a literal into a CompiledMethod at the given index. Defined for CompiledMethods only.&quot;<br>
        | thisReceiver index newValue |<br>
        newValue := self stackValue: 0.<br>
        index := self stackValue: 1.<br>
        ((objectMemory isNonIntegerObject: index)<br>
         or: [index = ConstOne and: [(objectMemory isNonIntegerObject: newValue)]]) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
        index := objectMemory integerValueOf: index.<br>
        thisReceiver := self stackValue: 2.<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ (objectMemory isImmutable: thisReceiver) ifTrue: [ ^self primitiveFailFor: PrimErrInappropriate ] ].<br>
        (index &gt; 0 and: [index &lt;= ((objectMemory literalCountOf: thisReceiver) + LiteralStart)]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadIndex].<br>
        objectMemory storePointer: index - 1 ofObject: thisReceiver withValue: newValue.<br>
        self pop: 3 thenPush: newValue!<br>
<br>
Item was added:<br>
+ ----- Method: InterpreterPrimitives&gt;&gt;primitiveSetImmutability (in category &#39;object access primitives&#39;) -----<br>
+ primitiveSetImmutability<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       | rcvr boolean wasImmutable |<br>
+       rcvr := self stackValue: 1.<br>
+       (objectMemory isImmediate: rcvr) ifTrue: [ ^ self primitiveFailFor: PrimErrInappropriate ].<br>
+       boolean := self booleanValueOf: self stackTop.<br>
+       self successful ifFalse:<br>
+               [^self primitiveFailFor: PrimErrBadArgument].<br>
+       boolean ifTrue:<br>
+               [ (self canBeImmutable: rcvr) ifFalse: [ ^ self primitiveFailFor: PrimErrInappropriate ] ].<br>
+       wasImmutable := (objectMemory isOopImmutable: rcvr)<br>
+               ifTrue: [ TrueObject ]<br>
+               ifFalse: [ FalseObject ].<br>
+       objectMemory setIsImmutableOf: rcvr to: boolean.<br>
+       self pop: argumentCount thenPush: (self splObj: wasImmutable)!<br>
<br>
Item was changed:<br>
  ----- Method: InterpreterPrimitives&gt;&gt;primitiveShortAtPut (in category &#39;sound primitives&#39;) -----<br>
  primitiveShortAtPut<br>
        &quot;Treat the receiver, which can be indexible by either bytes or words, as an array<br>
         of signed 16-bit values. Set the contents of the given index to the given value.<br>
         Note that the index specifies the i-th 16-bit entry, not the i-th byte or word.&quot;<br>
<br>
        | index rcvr value |<br>
        value := self stackTop.<br>
        index := self stackValue: 1.<br>
        ((objectMemory isIntegerObject: value)<br>
         and: [(objectMemory isIntegerObject: index)<br>
         and: [value := objectMemory integerValueOf: value.<br>
                  (value &gt;= -32768) and: [value &lt;= 32767]]]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
        rcvr := self stackValue: 2.<br>
        (objectMemory isWordsOrBytes: rcvr) ifFalse:<br>
                [^self primitiveFailFor: PrimErrInappropriate].<br>
+       self cppIf: IMMUTABILITY &quot;isWordsOrBytes ensure non immediate&quot;<br>
+               ifTrue: [ (objectMemory isImmutable: rcvr) ifTrue: [ ^self primitiveFailFor: PrimErrInappropriate ] ].<br>
        index := objectMemory integerValueOf: index.<br>
        (index &gt;= 1 and: [index &lt;= (objectMemory num16BitUnitsOf: rcvr)]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadIndex].<br>
        objectMemory storeShort16: index - 1 ofObject: rcvr withValue: value.<br>
        self pop: 3 thenPush: (objectMemory integerObjectOf: value)!<br>
<br>
Item was added:<br>
+ ----- Method: ObjectMemory&gt;&gt;storePointerImmutabilityCheck:ofObject:withValue: (in category &#39;object access&#39;) -----<br>
+ storePointerImmutabilityCheck: index ofObject: rcvr withValue: top<br>
+       &lt;inline: true&gt;<br>
+       ^ self storePointer: index ofObject: rcvr withValue: top!<br>
<br>
Item was changed:<br>
  ----- Method: SpurMemoryManager&gt;&gt;clone: (in category &#39;allocation&#39;) -----<br>
  clone: objOop<br>
        | numSlots fmt newObj |<br>
        numSlots := self numSlotsOf: objOop.<br>
        fmt := self formatOf: objOop.<br>
        numSlots &gt; self maxSlotsForNewSpaceAlloc<br>
                ifTrue:<br>
                        [newObj := self allocateSlotsInOldSpace: numSlots<br>
                                                        format: fmt<br>
                                                        classIndex: (self classIndexOf: objOop)]<br>
                ifFalse:<br>
                        [newObj := self allocateSlots: numSlots<br>
                                                        format: fmt<br>
                                                        classIndex: (self classIndexOf: objOop)].<br>
        newObj ifNil:<br>
                [^0].<br>
        (self isPointersFormat: fmt)<br>
                ifTrue:<br>
                        [| hasYoung |<br>
                         hasYoung := false.<br>
                         0 to: numSlots - 1 do:<br>
                                [:i| | oop |<br>
                                oop := self fetchPointer: i ofObject: objOop.<br>
                                (self isNonImmediate: oop) ifTrue:<br>
                                        [(self isForwarded: oop) ifTrue:<br>
                                                [oop := self followForwarded: oop].<br>
                                        ((self isNonImmediate: oop)<br>
                                         and: [self isYoungObject: oop]) ifTrue:<br>
                                                [hasYoung := true]].<br>
                                self storePointerUnchecked: i<br>
                                        ofObject: newObj<br>
                                        withValue: oop].<br>
                        (hasYoung<br>
                         and: [(self isYoungObject: newObj) not]) ifTrue:<br>
                                [scavenger remember: newObj]]<br>
                ifFalse:<br>
                        [0 to: numSlots - 1 do:<br>
                                [:i|<br>
                                self storePointerUnchecked: i<br>
                                        ofObject: newObj<br>
                                        withValue: (self fetchPointer: i ofObject: objOop)].<br>
                         fmt &gt;= self firstCompiledMethodFormat ifTrue:<br>
                                [coInterpreter maybeFixClonedCompiledMethod: newObj.<br>
                                 ((self isOldObject: newObj)<br>
                                  and: [(self isYoungObject: objOop) or: [self isRemembered: objOop]]) ifTrue:<br>
                                        [scavenger remember: newObj]]].<br>
        ^newObj!<br>
<br>
Item was changed:<br>
  ----- Method: SpurMemoryManager&gt;&gt;containsOnlyValidBecomeObjects: (in category &#39;become implementation&#39;) -----<br>
  containsOnlyValidBecomeObjects: array<br>
        &quot;Answer 0 if the array contains only unpinned non-immediates.<br>
         Otherwise answer an informative error code.<br>
         Can&#39;t become: immediates!!  Shouldn&#39;t become pinned objects.&quot;<br>
+       | fieldOffset effectsFlags oop errCode |<br>
-       | fieldOffset effectsFlags oop |<br>
        fieldOffset := self lastPointerOfArray: array.<br>
        effectsFlags := 0.<br>
        &quot;same size as array2&quot;<br>
        [fieldOffset &gt;= self baseHeaderSize] whileTrue:<br>
                [oop := self longAt: array + fieldOffset.<br>
                 (self isOopForwarded: oop) ifTrue:<br>
                        [oop := self followForwarded: oop.<br>
                         self longAt: array + fieldOffset put: oop].<br>
+                (errCode := self isOopValidBecome: oop) = 0 ifFalse: [^ errCode].<br>
-                (self isImmediate: oop) ifTrue: [^PrimErrInappropriate].<br>
-                (self isPinned: oop) ifTrue: [^PrimErrObjectIsPinned].<br>
                 effectsFlags := effectsFlags bitOr: (self becomeEffectFlagsFor: oop).<br>
                 fieldOffset := fieldOffset - self bytesPerOop].<br>
        &quot;only set flags after checking all args.&quot;<br>
        becomeEffectsFlags := effectsFlags.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: SpurMemoryManager&gt;&gt;forward:to: (in category &#39;become implementation&#39;) -----<br>
  forward: obj1 to: obj2<br>
        self set: obj1 classIndexTo: self isForwardedObjectClassIndexPun formatTo: self forwardedFormat.<br>
+       self cppIf: IMMUTABILITY ifTrue: [ self setIsImmutableOf: obj1 to: false ].<br>
        self storePointer: 0 ofForwarder: obj1 withValue: obj2.<br>
        &quot;For safety make sure the forwarder has a slot count that includes its contents.&quot;<br>
        (self rawNumSlotsOf: obj1) = 0 ifTrue:<br>
                [self rawNumSlotsOf: obj1 put: 1]!<br>
<br>
Item was added:<br>
+ ----- Method: SpurMemoryManager&gt;&gt;immutableBitMask (in category &#39;header format&#39;) -----<br>
+ immutableBitMask<br>
+       &quot;mask the immutable bit in the base header word&quot;<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       ^ 1 &lt;&lt; self immutableBitShift!<br>
<br>
Item was added:<br>
+ ----- Method: SpurMemoryManager&gt;&gt;isOopValidBecome: (in category &#39;become implementation&#39;) -----<br>
+ isOopValidBecome: oop<br>
+       &quot;Answers 0 if the oop can be become.<br>
+       Answers an error code in the other case&quot;<br>
+       (self isImmediate: oop) ifTrue: [^PrimErrInappropriate].<br>
+       (self isPinned: oop) ifTrue: [^PrimErrObjectIsPinned].<br>
+       self<br>
+               cppIf: IMMUTABILITY<br>
+               ifTrue: [ (self isImmutable: oop) ifTrue: [^PrimErrInappropriate] ].<br>
+       ^ 0!<br>
<br>
Item was added:<br>
+ ----- Method: SpurMemoryManager&gt;&gt;storePointerImmutabilityCheck:ofObject:withValue: (in category &#39;object access&#39;) -----<br>
+ storePointerImmutabilityCheck: fieldIndex ofObject: objOop withValue: valuePointer<br>
+       &quot;Note must check here for stores of young objects into old ones.&quot;<br>
+       &lt;inline: true&gt; &quot;normal send in cannotAssign&quot;<br>
+<br>
+       self cppIf: IMMUTABILITY ifTrue:<br>
+               [ self assert: (self isImmediate: objOop) not.<br>
+               (self isImmutable: objOop) ifTrue:<br>
+                       [ ^ coInterpreter cannotAssign: valuePointer to: objOop withIndex: fieldIndex ] ].<br>
+<br>
+       ^ self storePointer: fieldIndex ofObject: objOop withValue: valuePointer!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter class&gt;&gt;initializePrimitiveTable (in category &#39;initialization&#39;) -----<br>
(excessive size, no diff calculated)<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;bytecodePrimAtPut (in category &#39;common selector sends&#39;) -----<br>
  bytecodePrimAtPut<br>
        &quot;BytecodePrimAtPut will only succeed if the receiver is in the atCache.<br>
        Otherwise it will fail so that the more general primitiveAtPut will put it in the<br>
        cache after validating that message lookup results in a primitive response.<br>
         Override to insert in the atCache here.  This is necessary since once there<br>
         is a compiled at:[put:] primitive method (which doesn&#39;t use the at: cache) the<br>
         only way something can get installed in the atCache is here.&quot;<br>
+       | index rcvr atIx value correctRcvr |<br>
-       | index rcvr atIx value |<br>
        value := self internalStackTop.<br>
        index := self internalStackValue: 1.<br>
        rcvr := self internalStackValue: 2.<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ correctRcvr := objectMemory isOopMutable: rcvr ]<br>
+               ifFalse: [ correctRcvr := objectMemory isNonImmediate: rcvr ].<br>
+       (correctRcvr<br>
-       ((objectMemory isNonImmediate: rcvr)<br>
         and: [objectMemory isIntegerObject: index]) ifTrue:<br>
                [atIx := (rcvr bitAnd: AtCacheMask) + AtPutBase.  &quot;Index into atPutCache&quot;<br>
                 (atCache at: atIx+AtCacheOop) ~= rcvr ifTrue:<br>
                        [lkupClassTag := objectMemory fetchClassTagOfNonImm: rcvr.<br>
                         messageSelector := self specialSelector: 17.<br>
                         (self lookupInMethodCacheSel: messageSelector classTag: lkupClassTag) ifFalse:<br>
                                [argumentCount := 2.<br>
                                 ^self commonSendOrdinary].<br>
                         primitiveFunctionPointer == #primitiveAtPut<br>
                                ifTrue: [self install: rcvr inAtCache: atCache at: atIx string: false]<br>
                                ifFalse:<br>
                                        [primitiveFunctionPointer == #primitiveStringAtPut<br>
                                                ifTrue: [self install: rcvr inAtCache: atCache at: atIx string: true]<br>
                                                ifFalse:<br>
                                                        [argumentCount := 2.<br>
                                                         ^self commonSendOrdinary]]].<br>
                 self successful ifTrue:<br>
                        [self commonVariable: rcvr at: (objectMemory integerValueOf: index) put: value cacheIndex: atIx].<br>
                 self successful ifTrue:<br>
                        [self fetchNextBytecode.<br>
                         ^self internalPop: 3 thenPush: value].<br>
                 self initPrimCall].<br>
<br>
        messageSelector := self specialSelector: 17.<br>
        argumentCount := 2.<br>
        self normalSend!<br>
<br>
Item was added:<br>
+ ----- Method: StackInterpreter&gt;&gt;cannotAssign:to:withIndex: (in category &#39;stack bytecodes&#39;) -----<br>
+ cannotAssign: resultObj to: targetObj withIndex: index<br>
+       &lt;option: #IMMUTABILITY&gt;<br>
+       &lt;inline: true&gt; &quot;because of use of normalSend...&quot;<br>
+       self internalPush: targetObj.<br>
+       self internalPush: resultObj.<br>
+       self internalPush: (self integerObjectOf: index + 1).<br>
+       messageSelector := self splObj: SelectorAttemptToAssign.<br>
+       argumentCount := 2.<br>
+       ^ self normalSend!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;commonAtPut: (in category &#39;indexing primitive support&#39;) -----<br>
  commonAtPut: stringy<br>
        &quot;This code is called if the receiver responds primitively to at:Put:.<br>
         N.B. this does *not* use the at cache, instead inlining stObject:at:put:.<br>
         Using the at cache here would require that callers set messageSelector<br>
         and lkupClass and that is onerous and error-prone, and in any case,<br>
         inlining produces much better performance than using the at cache here.&quot;<br>
+       | value index rcvr badRcvr |<br>
-       | value index rcvr |<br>
        &lt;inline: true&gt; &quot;to get it inlined in primitiveAtPut and primitiveStringAtPut&quot;<br>
        self initPrimCall.<br>
        rcvr := self stackValue: 2.<br>
        index := self stackValue: 1.<br>
        value := self stackTop.<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ badRcvr := objectMemory isOopImmutable: rcvr ]<br>
+               ifFalse: [ badRcvr := objectMemory isImmediate: rcvr ].<br>
+       badRcvr ifTrue:<br>
-       (objectMemory isImmediate: rcvr) ifTrue:<br>
                [^self primitiveFailFor: PrimErrInappropriate].<br>
        &quot;No need to test for large positive integers here.  No object has 1g elements&quot;<br>
        ((objectMemory isNonIntegerObject: index)<br>
         or: [argumentCount &gt; 2 &quot;e.g. object:basicAt:put:&quot;<br>
                 and: [objectMemory isForwarded: rcvr]]) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
        index := objectMemory integerValueOf: index.<br>
        stringy<br>
                ifTrue: [self stObject: rcvr at: index put: (self asciiOfCharacter: value)]<br>
                ifFalse: [self stObject: rcvr at: index put: value].<br>
        self successful ifTrue:<br>
                [self pop: argumentCount+1 thenPush: value]!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;extStoreAndPopLiteralVariableBytecode (in category &#39;stack bytecodes&#39;) -----<br>
  extStoreAndPopLiteralVariableBytecode<br>
        &quot;236            11101100        i i i i i i i i Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256)&quot;<br>
+       | variableIndex value |<br>
+       variableIndex := self fetchByte + (extA &lt;&lt; 8).<br>
+       self fetchNextBytecode.<br>
+       value := self internalStackTop.<br>
+       self internalPop: 1.<br>
+       extA := 0.<br>
+       self storeLiteralVariable: variableIndex withValue: value!<br>
-       self extStoreLiteralVariableBytecode.<br>
-       self internalPop: 1!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;extStoreAndPopReceiverVariableBytecode (in category &#39;stack bytecodes&#39;) -----<br>
  extStoreAndPopReceiverVariableBytecode<br>
        &quot;235            11101011        i i i i i i i i Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256)&quot;<br>
+       | variableIndex value |<br>
+       variableIndex := self fetchByte + (extA &lt;&lt; 8).<br>
+       self fetchNextBytecode.<br>
+       extA := 0.<br>
+       value := self internalStackTop.<br>
+       self internalPop: 1.<br>
+       self storeMaybeContextReceiverVariable: variableIndex withValue: value!<br>
-       self extStoreReceiverVariableBytecode.<br>
-       self internalPop: 1!<br></blockquote><div><br></div><div><br></div><div>This used to read</div><div><br></div><div>storeAndPopReceiverVariableBytecode</div><div><span style="white-space:pre-wrap">        </span>| rcvr top |</div><div><span style="white-space:pre-wrap">        </span>rcvr := self receiver.</div><div><span style="white-space:pre-wrap">        </span>top := self internalStackTop.</div><div><span style="white-space:pre-wrap">        </span>objectMemory storePointer: (currentBytecode bitAnd: 7) ofObject: rcvr withValue: top.</div><div><span style="white-space:pre-wrap">        </span>self fetchNextBytecode.</div><div><span style="white-space:pre-wrap">        </span>self internalPop: 1</div><div><br></div><div>Note how currentBytecode is used before fetchNextBytecode.  fetchNextBytecode assigns currentBytecode:</div><div><br></div><div><div>fetchNextBytecode</div><div><span style="white-space:pre-wrap">        </span>&quot;This method fetches the next instruction (bytecode). Each bytecode method is responsible for fetching the next bytecode, preferably as early as possible to allow the memory system time to process the request before the next dispatch.&quot;</div><div><br></div><div><span style="white-space:pre-wrap">        </span>self cppIf: MULTIPLEBYTECODESETS</div><div><span style="white-space:pre-wrap">                </span>ifTrue: [currentBytecode := self fetchByte + bytecodeSetSelector]</div><div><span style="white-space:pre-wrap">                </span>ifFalse: [currentBytecode := self fetchByte]</div></div><div><br></div><div>So your rewrite to</div><div><br></div><div><div>storeAndPopReceiverVariableBytecode</div><div><span style="white-space:pre-wrap">        </span>| rcvr top |</div><div><span style="white-space:pre-wrap">        </span>rcvr := self receiver.</div><div><span style="white-space:pre-wrap">        </span>top := self internalStackTop.</div><div><span style="white-space:pre-wrap">        </span>self internalPop: 1.</div><div><span style="white-space:pre-wrap">        </span>self fetchNextBytecode.</div><div><span style="white-space:pre-wrap">        </span>objectMemory storePointerImmutabilityCheck: (currentBytecode bitAnd: 7) ofObject: rcvr withValue: top</div></div><div><br></div><div>breaks things since currentBytecode is now that of the next bytecode and the wrong inst var will probably be assigned.  So you need to rewrite, e.g. like this:</div><div><br></div><div><div>storeAndPopReceiverVariableBytecode</div><div><span style="white-space:pre-wrap">        </span>| rcvr top |</div><div><span style="white-space:pre-wrap">        </span>rcvr := self receiver.</div><div><span style="white-space:pre-wrap">        </span>top := self internalStackTop.</div><div><span style="white-space:pre-wrap">        </span>self internalPop: 1.</div><div><span style="white-space:pre-wrap">        </span>self</div><div><span style="white-space:pre-wrap">                </span>cCode: &quot;Slang will inline currentBytecode to a constant so this will work in C&quot;</div><div><span style="white-space:pre-wrap">                        </span>[self fetchNextBytecode.</div><div><span style="white-space:pre-wrap">                        </span> objectMemory</div><div><span style="white-space:pre-wrap">                                </span>storePointerImmutabilityCheck: (currentBytecode bitAnd: 7)</div><div><span style="white-space:pre-wrap">                                </span>ofObject: rcvr</div><div><span style="white-space:pre-wrap">                                </span>withValue: top]</div><div><span style="white-space:pre-wrap">                </span>inSmalltalk: &quot;But in Smalltalk we must use the currentBytecode&#39;s value, not the next&quot;</div><div><span style="white-space:pre-wrap">                        </span>[| instVarIndex |</div><div><span style="white-space:pre-wrap">                        </span> instVarIndex := currentBytecode bitAnd: 7.</div><div><span style="white-space:pre-wrap">                        </span> self fetchNextBytecode.</div><div><span style="white-space:pre-wrap">                        </span> objectMemory</div><div><span style="white-space:pre-wrap">                                </span>storePointerImmutabilityCheck: instVarIndex</div><div><span style="white-space:pre-wrap">                                </span>ofObject: rcvr</div><div><span style="white-space:pre-wrap">                                </span>withValue: top]</div></div><div><br></div><div>This needs to happen anywhere you use currentBytecode in the new immutability code.  We /don&#39;t/ want to use a variable to hold currentBytecode because that won&#39;t get inlined quite as nicely by Slang.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;extendedStoreAndPopBytecode (in category &#39;stack bytecodes&#39;) -----<br>
  extendedStoreAndPopBytecode<br>
+       &lt;inline: true&gt;<br>
+       self extendedStoreBytecodePop: true<br>
-<br>
-       self extendedStoreBytecode.<br>
-       self internalPop: 1.<br>
  !<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;extendedStoreBytecode (in category &#39;stack bytecodes&#39;) -----<br>
  extendedStoreBytecode<br>
-       | descriptor variableType variableIndex |<br>
        &lt;inline: true&gt;<br>
+       self extendedStoreBytecodePop: false!<br>
-       descriptor := self fetchByte.<br>
-       self fetchNextBytecode.<br>
-       variableType := descriptor &gt;&gt; 6 bitAnd: 3.<br>
-       variableIndex := descriptor bitAnd: 63.<br>
-       variableType = 0 ifTrue:<br>
-               [^objectMemory storePointer: variableIndex ofObject: self receiver withValue: self internalStackTop].<br>
-       variableType = 1 ifTrue:<br>
-               [^self temporary: variableIndex in: localFP put: self internalStackTop].<br>
-       variableType = 3 ifTrue:<br>
-               [^self storeLiteralVariable: variableIndex withValue: self internalStackTop].<br>
-       self error: &#39;illegal store&#39;!<br>
<br>
Item was added:<br>
+ ----- Method: StackInterpreter&gt;&gt;extendedStoreBytecodePop: (in category &#39;stack bytecodes&#39;) -----<br>
+ extendedStoreBytecodePop: popBoolean<br>
+       | descriptor variableType variableIndex value |<br>
+       &lt;inline: true&gt;<br>
+       descriptor := self fetchByte.<br>
+       self fetchNextBytecode.<br>
+       variableType := descriptor &gt;&gt; 6 bitAnd: 3.<br>
+       variableIndex := descriptor bitAnd: 63.<br>
+       value := self internalStackTop.<br>
+       popBoolean ifTrue: [ self internalPop: 1 ].<br>
+       variableType = 0 ifTrue:<br>
+               [^objectMemory storePointerImmutabilityCheck: variableIndex ofObject: self receiver withValue: value].<br>
+       variableType = 1 ifTrue:<br>
+               [^self temporary: variableIndex in: localFP put: value].<br>
+       variableType = 3 ifTrue:<br>
+               [^self storeLiteralVariable: variableIndex withValue: value].<br>
+       self error: &#39;illegal store&#39;<br>
+ !<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;storeAndPopReceiverVariableBytecode (in category &#39;stack bytecodes&#39;) -----<br>
  storeAndPopReceiverVariableBytecode<br>
        &quot;Note: This code uses<br>
        storePointerUnchecked:ofObject:withValue: and does the<br>
        store check explicitely in order to help the translator<br>
        produce better code.&quot;<br>
        | rcvr top |<br>
        rcvr := self receiver.<br>
        top := self internalStackTop.<br>
+       self internalPop: 1.<br>
-       objectMemory storePointer: (currentBytecode bitAnd: 7) ofObject: rcvr withValue: top.<br>
        self fetchNextBytecode.<br>
+       objectMemory storePointerImmutabilityCheck: (currentBytecode bitAnd: 7) ofObject: rcvr withValue: top.!<br>
-       self internalPop: 1!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;storeLiteralVariable:withValue: (in category &#39;stack bytecodes&#39;) -----<br>
  storeLiteralVariable: literalIndex withValue: anObject<br>
        | litVar |<br>
        litVar := self literal: literalIndex.<br>
        &quot;push/store/popLiteralVariable all fetch a literal, and either read or write the literal&#39;s value field.<br>
         The fetch of the literal needs an explicit check (otherwise we would have to scan all literals in<br>
         all methods in the stack zone, and the entire method on return, and global variables are relatively<br>
         rare; in my work image 8.7% of literals are globals).&quot;<br>
<br>
        (objectMemory isForwarded: litVar) ifTrue:<br>
                [litVar := objectMemory followForwarded: litVar].<br>
+       ^objectMemory storePointerImmutabilityCheck: ValueIndex ofObject: litVar withValue: anObject!<br>
-       ^objectMemory storePointer: ValueIndex ofObject: litVar withValue: anObject!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;storeMaybeContextReceiverVariable:withValue: (in category &#39;stack bytecodes&#39;) -----<br>
  storeMaybeContextReceiverVariable: fieldIndex withValue: anObject<br>
        &quot;Must trap accesses to married and widowed contexts.<br>
         But don&#39;t want to check on all inst var accesses.  This<br>
         method is only used by the long-form bytecodes, evading the cost.&quot;<br>
        | rcvr |<br>
        rcvr := self receiver.<br>
        ((self isWriteMediatedContextInstVarIndex: fieldIndex)<br>
        and: [(objectMemory isContextNonImm: rcvr)<br>
        and: [self isMarriedOrWidowedContext: rcvr]])<br>
                ifTrue:<br>
                        [self instVar: fieldIndex ofContext: rcvr put: anObject]<br>
                ifFalse:<br>
+                       [objectMemory storePointerImmutabilityCheck: fieldIndex ofObject: rcvr withValue: anObject]<br>
-                       [objectMemory storePointer: fieldIndex ofObject: rcvr withValue: anObject]<br>
  !<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreter&gt;&gt;trinaryInlinePrimitive: (in category &#39;miscellaneous bytecodes&#39;) -----<br>
  trinaryInlinePrimitive: primIndex<br>
        &quot;SistaV1:       248             11111000        iiiiiiii                mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.&quot;<br>
        &lt;option: #SistaVM&gt;<br>
        | result |<br>
        primIndex caseOf: {<br>
<br>
                &quot;3000   unchecked Pointer Object&gt;&gt;at:put:.                      The receiver is guaranteed to be a pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger&quot;<br>
                [0]     -&gt;      [result := self internalStackTop.<br>
                                 objectMemory<br>
                                        storePointer: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1<br>
                                        ofObject: (self internalStackValue: 2)<br>
                                        withValue: result.<br>
                                 self internalPop: 2; internalStackTopPut: result].<br>
                &quot;3001   unchecked Byte Object&gt;&gt;at:put:.                 The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 8 bits.&quot;<br>
                [1]     -&gt;      [result := self internalStackTop.<br>
                                 objectMemory<br>
                                        storeByte: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1<br>
                                        ofObject: (self internalStackValue: 2)<br>
                                        withValue: (objectMemory integerValueOf: result).<br>
                                 self internalPop: 2; internalStackTopPut: result].<br>
                &quot;3002   unchecked Word Object&gt;&gt;at:put:.                 The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 16 bits.&quot;<br>
                [2]     -&gt;      [result := self internalStackTop.<br>
                                 objectMemory<br>
                                        storeShort16: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1<br>
                                        ofObject: (self internalStackValue: 2)<br>
                                        withValue: (objectMemory integerValueOf: result).<br>
                                 self internalPop: 2; internalStackTopPut: result].<br>
                &quot;3003   unchecked DoubleWord Object&gt;&gt;at:put:.   The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 32 bits.&quot;<br>
                [3]     -&gt;      [result := self internalStackTop.<br>
                                 objectMemory<br>
                                        storeLong32: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1<br>
                                        ofObject: (self internalStackValue: 2)<br>
                                        withValue: (objectMemory integerValueOf: result).<br>
                                 self internalPop: 2; internalStackTopPut: result].<br>
                &quot;3004   unchecked QuadWord Object&gt;&gt;at:put:.             The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 64 bits.&quot;<br>
                [4]     -&gt;      [result := self internalStackTop.<br>
                                 objectMemory<br>
                                        storeLong64: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1<br>
                                        ofObject: (self internalStackValue: 2)<br>
                                        withValue: (objectMemory integerValueOf: result).<br>
                                 self internalPop: 2; internalStackTopPut: result] }<br>
        otherwise:<br>
                [localIP := localIP - 3.<br>
                 self respondToUnknownBytecode]!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreterPrimitives&gt;&gt;primitiveInstVarAt (in category &#39;object access primitives&#39;) -----<br>
  primitiveInstVarAt<br>
        | index rcvr hdr fmt totalLength fixedFields value |<br>
        index := self stackTop.<br>
        rcvr := self stackValue: 1.<br>
        ((objectMemory isNonIntegerObject: index)<br>
         or: [argumentCount &gt; 1 &quot;e.g. object:instVarAt:&quot;<br>
                and: [objectMemory isOopForwarded: rcvr]]) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
+       (objectMemory isImmediate: rcvr) ifTrue: [^self primitiveFailFor: PrimErrInappropriate].<br>
        index := objectMemory integerValueOf: index.<br>
        hdr := objectMemory baseHeader: rcvr.<br>
        fmt := objectMemory formatOfHeader: hdr.<br>
        totalLength := objectMemory lengthOf: rcvr baseHeader: hdr format: fmt.<br>
        fixedFields := objectMemory fixedFieldsOf: rcvr format: fmt length: totalLength.<br>
        (index &gt;= 1 and: [index &lt;= fixedFields]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadIndex].<br>
        (fmt = objectMemory indexablePointersFormat<br>
         and: [objectMemory isContextHeader: hdr])<br>
                ifTrue: [value := self externalInstVar: index - 1 ofContext: rcvr]<br>
                ifFalse: [value := self subscript: rcvr with: index format: fmt].<br>
        self pop: argumentCount + 1 thenPush: value!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreterPrimitives&gt;&gt;primitiveInstVarAtPut (in category &#39;object access primitives&#39;) -----<br>
  primitiveInstVarAtPut<br>
        | newValue index rcvr hdr fmt totalLength fixedFields |<br>
        newValue := self stackTop.<br>
        index := self stackValue: 1.<br>
        rcvr := self stackValue: 2.<br>
        ((objectMemory isNonIntegerObject: index)<br>
         or: [argumentCount &gt; 2 &quot;e.g. object:instVarAt:put:&quot;<br>
                and: [objectMemory isOopForwarded: rcvr]]) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ (objectMemory isOopImmutable: rcvr) ifTrue: [^self primitiveFailFor: PrimErrInappropriate] ]<br>
+               ifFalse: [ (objectMemory isImmediate: rcvr) ifTrue: [^self primitiveFailFor: PrimErrInappropriate] ].<br>
        index := objectMemory integerValueOf: index.<br>
        hdr := objectMemory baseHeader: rcvr.<br>
        fmt := objectMemory formatOfHeader: hdr.<br>
        totalLength := objectMemory lengthOf: rcvr baseHeader: hdr format: fmt.<br>
        fixedFields := objectMemory fixedFieldsOf: rcvr format: fmt length: totalLength.<br>
        (index &gt;= 1 and: [index &lt;= fixedFields]) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadIndex].<br>
        (fmt = objectMemory indexablePointersFormat<br>
         and: [objectMemory isContextHeader: hdr])<br>
                ifTrue: [self externalInstVar: index - 1 ofContext: rcvr put: newValue]<br>
                ifFalse: [self subscript: rcvr with: index storing: newValue format: fmt].<br>
        self pop: argumentCount + 1 thenPush: newValue!<br>
<br>
Item was changed:<br>
  ----- Method: StackInterpreterPrimitives&gt;&gt;primitiveSlotAtPut (in category &#39;object access primitives&#39;) -----<br>
  primitiveSlotAtPut<br>
        &quot;Assign a slot in an object.  This numbers all slots from 1, ignoring the distinction between<br>
         named and indexed inst vars.  In objects with both named and indexed inst vars, the named<br>
         inst vars precede the indexed ones.  In non-object indexed objects (objects that contain<br>
         bits, not object references) this primitive assigns a raw integral value at each slot.&quot;<br>
+       | newValue index rcvr fmt numSlots value badRcvr |<br>
-       | newValue index rcvr fmt numSlots value |<br>
        newValue := self stackTop.<br>
        index := self stackValue: 1.<br>
        rcvr := self stackValue: 2.<br>
        (objectMemory isIntegerObject: index) ifFalse:<br>
                [^self primitiveFailFor: PrimErrBadArgument].<br>
+       self cppIf: IMMUTABILITY<br>
+               ifTrue: [ badRcvr := objectMemory isOopImmutable: rcvr ]<br>
+               ifFalse: [ badRcvr := objectMemory isImmediate: rcvr ].<br>
+       badRcvr ifTrue:<br>
-       (objectMemory isImmediate: rcvr) ifTrue:<br>
                [^self primitiveFailFor: PrimErrBadReceiver].<br>
        fmt := objectMemory formatOf: rcvr.<br>
        index := (objectMemory integerValueOf: index) - 1.<br>
<br>
        fmt &lt;= objectMemory lastPointerFormat ifTrue:<br>
                [numSlots := objectMemory numSlotsOf: rcvr.<br>
                 (self asUnsigned: index) &lt; numSlots ifTrue:<br>
                        [(objectMemory isContextNonImm: rcvr)<br>
                                ifTrue: [self externalInstVar: index ofContext: rcvr put: newValue]<br>
                                ifFalse: [objectMemory storePointer: index ofObject: rcvr withValue: newValue].<br>
                         self pop: argumentCount + 1 thenPush: newValue.<br>
                         ^0].<br>
                 ^self primitiveFailFor: PrimErrBadIndex].<br>
<br>
        value := self positiveMachineIntegerValueOf: newValue.<br>
        self failed ifTrue:<br>
                [primFailCode := PrimErrBadArgument.<br>
                ^0].<br>
<br>
        fmt &gt;= objectMemory firstByteFormat ifTrue:<br>
                [fmt &gt;= objectMemory firstCompiledMethodFormat ifTrue:<br>
                        [^self primitiveFailFor: PrimErrUnsupported].<br>
                 (self asUnsigned: value) &gt; 16rFF ifTrue:<br>
                        [^self primitiveFailFor: PrimErrBadArgument].<br>
                 numSlots := objectMemory numBytesOfBytes: rcvr.<br>
                 (self asUnsigned: index) &lt; numSlots ifTrue:<br>
                        [objectMemory storeByte: index ofObject: rcvr withValue: value.<br>
                         self pop: argumentCount + 1 thenPush: newValue.<br>
                         ^0].<br>
                 ^self primitiveFailFor: PrimErrBadIndex].<br>
<br>
        (objectMemory hasSpurMemoryManagerAPI<br>
         and: [fmt &gt;= objectMemory firstShortFormat]) ifTrue:<br>
                [(self asUnsigned: value) &gt; 16rFFFF ifTrue:<br>
                        [^self primitiveFailFor: PrimErrBadArgument].<br>
                 numSlots := objectMemory num16BitUnitsOf: rcvr.<br>
                 (self asUnsigned: index) &lt; numSlots ifTrue:<br>
                        [objectMemory storeShort16: index ofObject: rcvr withValue: value.<br>
                         self pop: argumentCount + 1 thenPush: newValue.<br>
                         ^0].<br>
                 ^self primitiveFailFor: PrimErrBadIndex].<br>
<br>
        (objectMemory bytesPerOop = 8<br>
         and: [fmt = objectMemory sixtyFourBitIndexableFormat]) ifTrue:<br>
                [numSlots := objectMemory num64BitUnitsOf: rcvr.<br>
                 (self asUnsigned: index) &lt; numSlots ifTrue:<br>
                        [objectMemory storeLong64: index ofObject: rcvr withValue: value.<br>
                         self pop: argumentCount + 1 thenPush: newValue.<br>
                         ^0].<br>
                 ^self primitiveFailFor: PrimErrBadIndex].<br>
<br>
        fmt &gt;= objectMemory firstLongFormat ifTrue:<br>
                [(objectMemory wordSize &gt; 4<br>
                  and: [(self asUnsigned: value) &gt; 16rFFFFFFFF]) ifTrue:<br>
                        [^self primitiveFailFor: PrimErrBadArgument].<br>
                 numSlots := objectMemory num32BitUnitsOf: rcvr.<br>
                 (self asUnsigned: index) &lt; numSlots ifTrue:<br>
                        [objectMemory storeLong32: index ofObject: rcvr withValue: value.<br>
                         self pop: argumentCount + 1 thenPush: newValue.<br>
                         ^0].<br>
                 ^self primitiveFailFor: PrimErrBadIndex].<br>
<br>
        ^self primitiveFailFor: PrimErrBadReceiver!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit class&gt;&gt;initializeBytecodeTableForNewspeakV4 (in category &#39;class initialization&#39;) -----<br>
  initializeBytecodeTableForNewspeakV4<br>
        &quot;StackToRegisterMappingCogit initializeBytecodeTableForNewspeakV4&quot;<br>
<br>
        numPushNilsFunction := #v4:Num:Push:Nils:.<br>
        pushNilSizeFunction := #v4PushNilSize:numInitialNils:.<br>
        NSSendIsPCAnnotated := true. &quot;IsNSSendCall used by SendAbsentImplicit&quot;<br>
        FirstSpecialSelector := 80.<br>
        NumSpecialSelectors := 32.<br>
        self flag:<br>
  &#39;Special selector send class must be inlined to agree with the interpreter, which<br>
   inlines class.  If class is sent to e.g. a general instance of ProtoObject then unless<br>
   class is inlined there will be an MNU.  It must be that the Cointerpreter and Cogit<br>
   have identical semantics.  We get away with not hardwiring the other special<br>
   selectors either because in the Cointerpreter they are not inlined or because they<br>
   are inlined only to instances of classes for which there will always be a method.&#39;.<br>
        self generatorTableFrom: #(<br>
                &quot;1 byte bytecodes&quot;<br>
                (1    0   15 genPushReceiverVariableBytecode isInstVarRef needsFrameNever: 1)<br>
                (1  16   31 genPushLiteralVariable16CasesBytecode needsFrameNever: 1)<br>
                (1  32   63 genPushLiteralConstantBytecode needsFrameNever: 1)<br>
                (1  64   75 genPushTemporaryVariableBytecode needsFrameIfMod16GENumArgs: 1)<br>
                (1  76   76 genPushReceiverBytecode needsFrameNever: 1)<br>
                (1  77   77 genExtPushPseudoVariableOrOuterBytecode needsFrameIfExtBGT2: 1)<br>
                (1  78   78 genPushConstantZeroBytecode needsFrameNever: 1)<br>
                (1  79   79 genPushConstantOneBytecode needsFrameNever: 1)<br>
<br>
                (1   80   80 genSpecialSelectorArithmetic isMapped AddRR)<br>
                (1   81   81 genSpecialSelectorArithmetic isMapped SubRR)<br>
                (1   82   82 genSpecialSelectorComparison isMapped JumpLess)<br>
                (1   83   83 genSpecialSelectorComparison isMapped JumpGreater)<br>
                (1   84   84 genSpecialSelectorComparison isMapped JumpLessOrEqual)<br>
                (1   85   85 genSpecialSelectorComparison isMapped JumpGreaterOrEqual)<br>
                (1   86   86 genSpecialSelectorComparison isMapped JumpZero)<br>
                (1   87   87 genSpecialSelectorComparison isMapped JumpNonZero)<br>
                (1   88   93 genSpecialSelectorSend isMapped)    &quot; #* #/ #\\ #@ #bitShift: //&quot;<br>
                (1   94   94 genSpecialSelectorArithmetic isMapped AndRR)<br>
                (1   95   95 genSpecialSelectorArithmetic isMapped OrRR)<br>
                (1   96 101 genSpecialSelectorSend isMapped) &quot;#at: #at:put: #size #next #nextPut: #atEnd&quot;<br>
                (1 102 102 genSpecialSelectorEqualsEquals needsFrameNever: notMapped -1) &quot;not mapped because it is directly inlined (for now)&quot;<br>
                (1 103 103 genSpecialSelectorClass needsFrameIfStackGreaterThanOne: notMapped 0) &quot;not mapped because it is directly inlined (for now)&quot;<br>
                (1 104 111 genSpecialSelectorSend isMapped) &quot;#blockCopy: #value #value: #do: #new #new: #x #y&quot;<br>
<br>
                (1 112 127 genSendLiteralSelector0ArgsBytecode isMapped)<br>
                (1 128 143 genSendLiteralSelector1ArgBytecode isMapped)<br>
                (1 144 159 genSendLiteralSelector2ArgsBytecode isMapped)<br>
+               (1 160 175      genSendAbsentImplicit0ArgsBytecode isMapped hasIRC)),<br>
+<br>
+               &quot;N.B. not frameless if immutability&quot;<br>
+               ((initializationOptions at: #IMMUTABILITY ifAbsent: [false])<br>
+                       ifTrue: [#((1 176 183 genStoreAndPopReceiverVariableBytecode isMapped isInstVarRef -1))]<br>
+                       ifFalse: [#((1 176 183 genStoreAndPopReceiverVariableBytecode isInstVarRef needsFrameNever: -1)) ]),<br>
+<br>
+               #((1 184 191 genStoreAndPopTemporaryVariableBytecode)<br>
-               (1 160 175      genSendAbsentImplicit0ArgsBytecode isMapped hasIRC)<br>
<br>
-               (1 176 183 genStoreAndPopReceiverVariableBytecode isInstVarRef needsFrameNever: -1) &quot;N.B. not frameless if immutability&quot;<br>
-               (1 184 191 genStoreAndPopTemporaryVariableBytecode)<br>
-<br>
                (1 192 199 genShortUnconditionalJump    branch v3:ShortForward:Branch:Distance:)<br>
                (1 200 207 genShortJumpIfTrue                   branch isBranchTrue isMapped &quot;because of mustBeBoolean&quot;<br>
                                                                                                        v3:ShortForward:Branch:Distance:)<br>
                (1 208 215 genShortJumpIfFalse                  branch isBranchFalse isMapped &quot;because of mustBeBoolean&quot;<br>
                                                                                                        v3:ShortForward:Branch:Distance:)<br>
<br>
                (1 216 216 genReturnReceiver                            return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1 217 217 genReturnTopFromMethod               return needsFrameIfInBlock: isMappedInBlock -1)<br>
                (1 218 218 genExtReturnTopFromBlock     return needsFrameNever: -1)<br>
<br>
                (1 219 219 duplicateTopBytecode                 needsFrameNever: 1)<br>
                (1 220 220 genPopStackBytecode                  needsFrameNever: -1)<br>
                (1 221 221 genExtNopBytecode                    needsFrameNever: 0)<br>
                (1 222 223      unknownBytecode)<br>
<br>
                &quot;2 byte bytecodes&quot;<br>
                (2 224 224 extABytecode extension                                       needsFrameNever: 0)<br>
                (2 225 225 extBBytecode extension                                       needsFrameNever: 0)<br>
                (2 226 226 genExtPushReceiverVariableBytecode isInstVarRef)<br>
                (2 227 227 genExtPushLiteralVariableBytecode            needsFrameNever: 1)<br>
                (2 228 228 genExtPushLiteralBytecode                                    needsFrameNever: 1)<br>
                (2 229 229 genExtPushIntegerBytecode                            needsFrameNever: 1)<br>
                (2 230 230 genLongPushTemporaryVariableBytecode)<br>
                (2 231 231 genPushNewArrayBytecode)<br>
                (2 232 232 genExtStoreReceiverVariableBytecode isInstVarRef)<br>
                (2 233 233 genExtStoreLiteralVariableBytecode)<br>
                (2 234 234 genLongStoreTemporaryVariableBytecode)<br>
                (2 235 235 genExtStoreAndPopReceiverVariableBytecode isInstVarRef)<br>
                (2 236 236 genExtStoreAndPopLiteralVariableBytecode)<br>
                (2 237 237 genLongStoreAndPopTemporaryVariableBytecode)<br>
<br>
                (2 238 238 genExtSendBytecode isMapped)<br>
                (2 239 239 genExtSendSuperBytecode isMapped)<br>
                (2 240 240 genExtSendAbsentImplicitBytecode isMapped hasIRC)<br>
                (2 241 241 genExtSendAbsentDynamicSuperBytecode isMapped hasIRC)<br>
<br>
                (2 242 242 genExtUnconditionalJump      branch isMapped &quot;because of interrupt check&quot; v4:Long:Branch:Distance:)<br>
                (2 243 243 genExtJumpIfTrue                     branch isBranchTrue isMapped &quot;because of mustBeBoolean&quot; v4:Long:Branch:Distance:)<br>
                (2 244 244 genExtJumpIfFalse                    branch isBranchFalse isMapped &quot;because of mustBeBoolean&quot; v4:Long:Branch:Distance:)<br>
<br>
                (2 245 245      genExtSendAbsentSelfBytecode isMapped hasIRC)<br>
<br>
                (2 246 248      unknownBytecode)<br>
<br>
                &quot;3 byte bytecodes&quot;<br>
                (3 249 249 genCallPrimitiveBytecode)<br>
                (3 250 250 genPushRemoteTempLongBytecode)<br>
                (3 251 251 genStoreRemoteTempLongBytecode)<br>
                (3 252 252 genStoreAndPopRemoteTempLongBytecode)<br>
                (3 253 253 genExtPushClosureBytecode block v4:Block:Code:Size:)<br>
                (3 254 254      genExtSendAbsentOuterBytecode isMapped hasIRC)<br>
<br>
                (3 255 255      unknownBytecode))!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit class&gt;&gt;initializeBytecodeTableForSistaV1 (in category &#39;class initialization&#39;) -----<br>
  initializeBytecodeTableForSistaV1<br>
        &quot;StackToRegisterMappingCogit initializeBytecodeTableForSistaV1&quot;<br>
<br>
        numPushNilsFunction := #sistaV1:Num:Push:Nils:.<br>
        pushNilSizeFunction := #sistaV1PushNilSize:numInitialNils:.<br>
        BytecodeSetHasDirectedSuperSend := true.<br>
        FirstSpecialSelector := 96.<br>
        NumSpecialSelectors := 32.<br>
        self flag:<br>
  &#39;Special selector send class must be inlined to agree with the interpreter, which<br>
   inlines class.  If class is sent to e.g. a general instance of ProtoObject then unless<br>
   class is inlined there will be an MNU.  It must be that the Cointerpreter and Cogit<br>
   have identical semantics.  We get away with not hardwiring the other special<br>
   selectors either because in the Cointerpreter they are not inlined or because they<br>
   are inlined only to instances of classes for which there will always be a method.&#39;.<br>
        self generatorTableFrom: #(<br>
                &quot;1 byte bytecodes&quot;<br>
                &quot;pushes&quot;<br>
                (1    0   15 genPushReceiverVariableBytecode isInstVarRef               needsFrameNever: 1)<br>
                (1  16   31 genPushLitVarDirSup16CasesBytecode                          needsFrameNever: 1)<br>
                (1  32   63 genPushLiteralConstantBytecode                                      needsFrameNever: 1)<br>
                (1  64   75 genPushTemporaryVariableBytecode                            needsFrameIfMod16GENumArgs: 1)<br>
                (1  76   76 genPushReceiverBytecode                                                     needsFrameNever: 1)<br>
                (1  77   77 genPushConstantTrueBytecode                                         needsFrameNever: 1)<br>
                (1  78   78 genPushConstantFalseBytecode                                        needsFrameNever: 1)<br>
                (1  79   79 genPushConstantNilBytecode                                          needsFrameNever: 1)<br>
                (1  80   80 genPushConstantZeroBytecode                                         needsFrameNever: 1)<br>
                (1  81   81 genPushConstantOneBytecode                                          needsFrameNever: 1)<br>
                (1  82   82 genExtPushPseudoVariable)<br>
                (1  83   83 duplicateTopBytecode                                                                needsFrameNever: 1)<br>
<br>
                (1  84   87 unknownBytecode)<br>
<br>
                &quot;returns&quot;<br>
                (1  88   88 genReturnReceiver                           return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1  89   89 genReturnTrue                                       return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1  90   90 genReturnFalse                                      return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1  91   91 genReturnNil                                        return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1  92   92 genReturnTopFromMethod              return needsFrameIfInBlock: isMappedInBlock -1)<br>
                (1  93   93 genReturnNilFromBlock                       return needsFrameNever: -1)<br>
                (1  94   94 genReturnTopFromBlock               return needsFrameNever: -1)<br>
                (1  95   95 genExtNopBytecode                   needsFrameNever: 0)<br>
<br>
                &quot;sends&quot;<br>
                (1  96   96 genSpecialSelectorArithmetic isMapped AddRR)<br>
                (1  97   97 genSpecialSelectorArithmetic isMapped SubRR)<br>
                (1  98   98 genSpecialSelectorComparison isMapped JumpLess)<br>
                (1  99   99 genSpecialSelectorComparison isMapped JumpGreater)<br>
                (1 100 100 genSpecialSelectorComparison isMapped JumpLessOrEqual)<br>
                (1 101 101 genSpecialSelectorComparison isMapped JumpGreaterOrEqual)<br>
                (1 102 102 genSpecialSelectorComparison isMapped JumpZero)<br>
                (1 103 103 genSpecialSelectorComparison isMapped JumpNonZero)<br>
                (1 104 109 genSpecialSelectorSend isMapped)      &quot; #* #/ #\\ #@ #bitShift: //&quot;<br>
                (1 110 110 genSpecialSelectorArithmetic isMapped AndRR)<br>
                (1 111 111 genSpecialSelectorArithmetic isMapped OrRR)<br>
                (1 112 117 genSpecialSelectorSend isMapped) &quot;#at: #at:put: #size #next #nextPut: #atEnd&quot;<br>
                (1 118 118 genSpecialSelectorEqualsEquals needsFrameNever: notMapped -1) &quot;not mapped because it is directly inlined (for now)&quot;<br>
                (1 119 119 genSpecialSelectorClass needsFrameIfStackGreaterThanOne: notMapped 0) &quot;not mapped because it is directly inlined (for now)&quot;<br>
                (1 120 127 genSpecialSelectorSend isMapped) &quot;#blockCopy: #value #value: #do: #new #new: #x #y&quot;<br>
<br>
                (1 128 143 genSendLiteralSelector0ArgsBytecode isMapped)<br>
                (1 144 159 genSendLiteralSelector1ArgBytecode isMapped)<br>
                (1 160 175 genSendLiteralSelector2ArgsBytecode isMapped)<br>
<br>
                &quot;jumps&quot;<br>
                (1 176 183 genShortUnconditionalJump    branch v3:ShortForward:Branch:Distance:)<br>
                (1 184 191 genShortJumpIfTrue                   branch isBranchTrue isMapped &quot;because of mustBeBoolean&quot;<br>
                                                                                                        v3:ShortForward:Branch:Distance:)<br>
                (1 192 199 genShortJumpIfFalse                  branch isBranchFalse isMapped &quot;because of mustBeBoolean&quot;<br>
+                                                                                                       v3:ShortForward:Branch:Distance:)),<br>
-                                                                                                       v3:ShortForward:Branch:Distance:)<br>
<br>
                &quot;stores&quot;<br>
+               ((initializationOptions at: #IMMUTABILITY ifAbsent: [false])<br>
+                       ifTrue: [#((1 200 207 genStoreAndPopReceiverVariableBytecode isInstVarRef isMapped -1))]<br>
+                       ifFalse: [#((1 200 207 genStoreAndPopReceiverVariableBytecode isInstVarRef needsFrameNever: -1)) ]),<br>
+<br>
+               #((1 208 215 genStoreAndPopTemporaryVariableBytecode)<br>
-               (1 200 207 genStoreAndPopReceiverVariableBytecode isInstVarRef needsFrameNever: -1) &quot;N.B. not frameless if immutability&quot;<br>
-               (1 208 215 genStoreAndPopTemporaryVariableBytecode)<br>
<br>
                (1 216 216 genPopStackBytecode needsFrameNever: -1)<br>
<br>
                (1 217 217 genUnconditionalTrapBytecode isMapped)<br>
<br>
                (1 218 223 unknownBytecode)<br>
<br>
                &quot;2 byte bytecodes&quot;<br>
                (2 224 224 extABytecode extension)<br>
                (2 225 225 extBBytecode extension)<br>
<br>
                &quot;pushes&quot;<br>
                (2 226 226 genExtPushReceiverVariableBytecode isInstVarRef)             &quot;Needs a frame for context inst var access&quot;<br>
                (2 227 227 genExtPushLitVarDirSupBytecode                       needsFrameNever: 1)<br>
                (2 228 228 genExtPushLiteralBytecode                                    needsFrameNever: 1)<br>
                (2 229 229 genLongPushTemporaryVariableBytecode)<br>
                (2 230 230 genPushClosureTempsBytecode)<br>
                (2 231 231 genPushNewArrayBytecode)<br>
                (2 232 232 genExtPushIntegerBytecode                            needsFrameNever: 1)<br>
                (2 233 233 genExtPushCharacterBytecode                          needsFrameNever: 1)<br>
<br>
                &quot;returns&quot;<br>
                &quot;sends&quot;<br>
                (2 234 234 genExtSendBytecode isMapped)<br>
                (2 235 235 genExtSendSuperBytecode isMapped)<br>
<br>
                &quot;sista bytecodes&quot;<br>
                (2 236 236 unknownBytecode)<br>
<br>
                &quot;jumps&quot;<br>
                (2 237 237 genExtUnconditionalJump      branch isMapped &quot;because of interrupt check&quot; v4:Long:Branch:Distance:)<br>
                (2 238 238 genExtJumpIfTrue                     branch isBranchTrue isMapped &quot;because of mustBeBoolean&quot; v4:Long:Branch:Distance:)<br>
                (2 239 239 genExtJumpIfFalse                    branch isBranchFalse isMapped &quot;because of mustBeBoolean&quot; v4:Long:Branch:Distance:)<br>
<br>
                &quot;stores&quot;<br>
                (2 240 240 genExtStoreAndPopReceiverVariableBytecode isInstVarRef)<br>
                (2 241 241 genExtStoreAndPopLiteralVariableBytecode)<br>
                (2 242 242 genLongStoreAndPopTemporaryVariableBytecode)<br>
                (2 243 243 genExtStoreReceiverVariableBytecode isInstVarRef)<br>
                (2 244 244 genExtStoreLiteralVariableBytecode)<br>
                (2 245 245 genLongStoreTemporaryVariableBytecode)<br>
<br>
                (2 246 247      unknownBytecode)<br>
<br>
                &quot;3 byte bytecodes&quot;<br>
                (3 248 248 genCallPrimitiveBytecode)<br>
                (3 249 249 unknownBytecode) &quot;reserved for Push Float&quot;<br>
                (3 250 250 genExtPushClosureBytecode block v4:Block:Code:Size:)<br>
                (3 251 251 genPushRemoteTempLongBytecode)<br>
                (3 252 252 genStoreRemoteTempLongBytecode)<br>
                (3 253 253 genStoreAndPopRemoteTempLongBytecode)<br>
<br>
                (3 254 254      genExtJumpIfNotInstanceOfBehaviorsOrPopBytecode branch v4:Long:BranchIfNotInstanceOf:Distance:)<br>
<br>
                (3 255 255      unknownBytecode))!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit class&gt;&gt;initializeBytecodeTableForSqueakV3PlusClosures (in category &#39;class initialization&#39;) -----<br>
  initializeBytecodeTableForSqueakV3PlusClosures<br>
        &quot;StackToRegisterMappingCogit initializeBytecodeTableForSqueakV3PlusClosures&quot;<br>
<br>
        numPushNilsFunction := #v3:Num:Push:Nils:.<br>
        pushNilSizeFunction := #v3PushNilSize:numInitialNils:.<br>
        FirstSpecialSelector := 176.<br>
        NumSpecialSelectors := 32.<br>
        self flag:<br>
  &#39;Special selector send class must be inlined to agree with the interpreter, which<br>
   inlines class.  If class is sent to e.g. a general instance of ProtoObject then unless<br>
   class is inlined there will be an MNU.  It must be that the Cointerpreter and Cogit<br>
   have identical semantics.  We get away with not hardwiring the other special<br>
   selectors either because in the Cointerpreter they are not inlined or because they<br>
   are inlined only to instances of classes for which there will always be a method.&#39;.<br>
        self generatorTableFrom: #(<br>
                (1    0   15 genPushReceiverVariableBytecode isInstVarRef needsFrameNever: 1)<br>
                (1  16   31 genPushTemporaryVariableBytecode needsFrameIfMod16GENumArgs: 1)<br>
                (1  32   63 genPushLiteralConstantBytecode needsFrameNever: 1)<br>
+               (1  64   95 genPushLiteralVariableBytecode needsFrameNever: 1)) ,<br>
+<br>
+               &quot;N.B. not frameless if immutability&quot;<br>
+               ((initializationOptions at: #IMMUTABILITY ifAbsent: [false])<br>
+                       ifTrue: [#((1  96 103 genStoreAndPopReceiverVariableBytecode isInstVarRef isMapped -1))]<br>
+                       ifFalse: [#((1  96 103 genStoreAndPopReceiverVariableBytecode isInstVarRef needsFrameNever: -1)) ]),<br>
+<br>
+               #((1 104 111 genStoreAndPopTemporaryVariableBytecode)<br>
-               (1  64   95 genPushLiteralVariableBytecode needsFrameNever: 1)<br>
-               (1  96 103 genStoreAndPopReceiverVariableBytecode isInstVarRef needsFrameNever: -1) &quot;N.B. not frameless if immutability&quot;<br>
-               (1 104 111 genStoreAndPopTemporaryVariableBytecode)<br>
                (1 112 112 genPushReceiverBytecode needsFrameNever: 1)<br>
                (1 113 113 genPushConstantTrueBytecode needsFrameNever: 1)<br>
                (1 114 114 genPushConstantFalseBytecode needsFrameNever: 1)<br>
                (1 115 115 genPushConstantNilBytecode needsFrameNever: 1)<br>
                (1 116 119 genPushQuickIntegerConstantBytecode needsFrameNever: 1)<br>
                &quot;method returns in blocks need a frame because of nonlocalReturn:through:&quot;<br>
                (1 120 120 genReturnReceiver                            return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1 121 121 genReturnTrue                                        return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1 122 122 genReturnFalse                                       return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1 123 123 genReturnNil                                 return needsFrameIfInBlock: isMappedInBlock 0)<br>
                (1 124 124 genReturnTopFromMethod               return needsFrameIfInBlock: isMappedInBlock -1)<br>
                (1 125 125 genReturnTopFromBlock                return needsFrameNever: -1)<br>
<br>
                (1 126 127 unknownBytecode)<br>
<br>
                (2 128 128 extendedPushBytecode isInstVarRef) &quot;well, maybe inst var ref&quot;<br>
                (2 129 129 extendedStoreBytecode isInstVarRef) &quot;well, maybe inst var ref&quot;<br>
                (2 130 130 extendedStoreAndPopBytecode isInstVarRef) &quot;well, maybe inst var ref&quot;<br>
                (2 131 131 genExtendedSendBytecode isMapped)<br>
                (3 132 132 doubleExtendedDoAnythingBytecode isMapped) &quot;well, maybe inst var ref&quot;<br>
                (2 133 133 genExtendedSuperBytecode isInstVarRef isMapped)<br>
                (2 134 134 genSecondExtendedSendBytecode isMapped)<br>
                (1 135 135 genPopStackBytecode needsFrameNever: -1)<br>
                (1 136 136 duplicateTopBytecode needsFrameNever: 1)<br>
<br>
                (1 137 137 genPushActiveContextBytecode)<br>
                (2 138 138 genPushNewArrayBytecode)),<br>
<br>
                ((initializationOptions at: #SpurObjectMemory ifAbsent: [false])<br>
                        ifTrue: [#((3 139 139 genCallPrimitiveBytecode))]<br>
                        ifFalse: [#((1 139 139 unknownBytecode))]),<br>
<br>
           #(<br>
                (3 140 140 genPushRemoteTempLongBytecode)<br>
                (3 141 141 genStoreRemoteTempLongBytecode)<br>
                (3 142 142 genStoreAndPopRemoteTempLongBytecode)<br>
                (4 143 143 genPushClosureCopyCopiedValuesBytecode block v3:Block:Code:Size:)<br>
<br>
                (1 144 151 genShortUnconditionalJump                    branch v3:ShortForward:Branch:Distance:)<br>
                (1 152 159 genShortJumpIfFalse                                  branch isBranchFalse isMapped &quot;because of mustBeBoolean&quot;<br>
                                                                                                                        v3:ShortForward:Branch:Distance:)<br>
                (2 160 163 genLongUnconditionalBackwardJump     branch isMapped &quot;because of interrupt check&quot;<br>
                                                                                                                        v3:Long:Branch:Distance:)<br>
                (2 164 167 genLongUnconditionalForwardJump              branch v3:Long:Branch:Distance:)<br>
                (2 168 171 genLongJumpIfTrue                                    branch isBranchTrue isMapped &quot;because of mustBeBoolean&quot;<br>
                                                                                                                        v3:LongForward:Branch:Distance:)<br>
                (2 172 175 genLongJumpIfFalse                                   branch isBranchFalse isMapped &quot;because of mustBeBoolean&quot;<br>
                                                                                                                        v3:LongForward:Branch:Distance:)<br>
<br>
                (1 176 176 genSpecialSelectorArithmetic isMapped AddRR)<br>
                (1 177 177 genSpecialSelectorArithmetic isMapped SubRR)<br>
                (1 178 178 genSpecialSelectorComparison isMapped JumpLess)<br>
                (1 179 179 genSpecialSelectorComparison isMapped JumpGreater)<br>
                (1 180 180 genSpecialSelectorComparison isMapped JumpLessOrEqual)<br>
                (1 181 181 genSpecialSelectorComparison isMapped JumpGreaterOrEqual)<br>
                (1 182 182 genSpecialSelectorComparison isMapped JumpZero)<br>
                (1 183 183 genSpecialSelectorComparison isMapped JumpNonZero)<br>
                (1 184 189 genSpecialSelectorSend isMapped)      &quot; #* #/ #\\ #@ #bitShift: //&quot;<br>
                (1 190 190 genSpecialSelectorArithmetic isMapped AndRR)<br>
                (1 191 191 genSpecialSelectorArithmetic isMapped OrRR)<br>
                (1 192 197 genSpecialSelectorSend isMapped) &quot;#at: #at:put: #size #next #nextPut: #atEnd&quot;<br>
                (1 198 198 genSpecialSelectorEqualsEquals needsFrameNever: notMapped -1) &quot;not mapped because it is directly inlined (for now)&quot;<br>
                (1 199 199 genSpecialSelectorClass needsFrameIfStackGreaterThanOne: notMapped 0) &quot;not mapped because it is directly inlined (for now)&quot;<br>
                (1 200 207 genSpecialSelectorSend isMapped) &quot;#blockCopy: #value #value: #do: #new #new: #x #y&quot;<br>
                (1 208 223 genSendLiteralSelector0ArgsBytecode isMapped)<br>
                (1 224 239 genSendLiteralSelector1ArgBytecode isMapped)<br>
                (1 240 255 genSendLiteralSelector2ArgsBytecode isMapped))!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;ensureReceiverResultRegContainsSelf (in category &#39;bytecode generator support&#39;) -----<br>
  ensureReceiverResultRegContainsSelf<br>
        needsFrame<br>
                ifTrue:<br>
                        [optStatus isReceiverResultRegLive ifFalse:<br>
                                [self ssAllocateRequiredReg: ReceiverResultReg.<br>
+                               self putSelfInReceiverResultReg ].<br>
-                                (self addressOf: simSelf) storeToReg: ReceiverResultReg].<br>
                        optStatus isReceiverResultRegLive: true]<br>
                ifFalse:<br>
                        [self assert: (simSelf type = SSRegister<br>
                                                  and: [simSelf register = ReceiverResultReg]).<br>
                        self assert: (optStatus isReceiverResultRegLive<br>
                                                  and: [optStatus ssEntry = (self addressOf: simSelf)])]!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;evaluateTrampolineCallBlock:protectLinkRegIfNot: (in category &#39;trampoline support&#39;) -----<br>
+ evaluateTrampolineCallBlock: block protectLinkRegIfNot: inFrame<br>
+       &lt;inline: true&gt;<br>
+       inFrame<br>
+               ifFalse:<br>
+                       [ backEnd saveAndRestoreLinkRegAround: [ block value ] ]<br>
+               ifTrue:<br>
+                       [ block value ].!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genReturnReceiver (in category &#39;bytecode generators&#39;) -----<br>
  genReturnReceiver<br>
        &quot;In a frameless method ReceiverResultReg already contains self.<br>
         In a frameful method, ReceiverResultReg /may/ contain self.&quot;<br>
        needsFrame ifTrue:<br>
                [ optStatus isReceiverResultRegLive ifFalse:<br>
+                       [self putSelfInReceiverResultReg]].<br>
-                       [ (self addressOf: simSelf) storeToReg: ReceiverResultReg]].<br>
        ^self genUpArrowReturn!<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>
-       | topReg assocReg association |<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>
-<br>
-       &quot;Avoid store check for immediate values&quot;<br>
-       (objectRepresentation isUnannotatableConstant: self ssTop) ifTrue:<br>
-                       [ assocReg := self allocateRegNotConflictingWith: 0.<br>
-                       self genMoveConstant: association R: assocReg.<br>
-                        objectRepresentation<br>
-                               genEnsureObjInRegNotForwarded: assocReg<br>
-                               scratchReg: TempReg.<br>
-                       self ssStorePop: popBoolean toReg: TempReg.<br>
-                        traceStores &gt; 0 ifTrue:<br>
-                               [ assocReg = ReceiverResultReg ifFalse:<br>
-                                       [ self ssAllocateRequiredReg: ReceiverResultReg.<br>
-                                       optStatus isReceiverResultRegLive: false.<br>
-                                       self MoveR: assocReg R: ReceiverResultReg ].<br>
-                               self CallRT: ceTraceStoreTrampoline].<br>
-                        ^objectRepresentation<br>
-                               genStoreImmediateInSourceReg: TempReg<br>
-                               slotIndex: ValueIndex<br>
-                               destReg: assocReg ].<br>
-<br>
-       topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
-       self ssStorePop: popBoolean toReg: topReg.<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:<br>
+                       [ self ssAllocateRequiredReg: ClassReg.<br>
+                         topReg := ClassReg.<br>
+                         self ssStoreAndReplacePop: popBoolean toReg: ClassReg.<br>
+                         immutabilityFailure := objectRepresentation<br>
+                               genImmutableCheck: ReceiverResultReg<br>
+                               slotIndex: ValueIndex<br>
+                               sourceReg: ClassReg<br>
+                               scratchReg: TempReg<br>
+                               popBoolean: popBoolean<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>
-       ^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>
-               inFrame: needsFrame!<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>
-       | jmpSingle jmpDone valueReg |<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 ssStoreAndReplacePop: popBoolean toReg: ClassReg. ]<br>
+               ifFalse: [ self ssStorePop: popBoolean toReg: ClassReg ].<br>
-       valueReg := self ssStorePop: popBoolean toPreferredReg: ClassReg.<br>
-       valueReg ~= ClassReg ifTrue:<br>
-               [self MoveR: valueReg 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 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>
+                               popBoolean: popBoolean<br>
+                               needRestoreRcvr: true ].<br>
        objectRepresentation<br>
                genStoreSourceReg: ClassReg<br>
                slotIndex: slotIndex<br>
                destReg: ReceiverResultReg<br>
                scratchReg: TempReg<br>
+               inFrame: true<br>
+               needsStoreCheck: needStoreCheck.<br>
-               inFrame: true.<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>
-       ^ needsFrame<br>
-               ifFalse:<br>
-                       [ self<br>
-                               genStorePop: popBoolean<br>
-                               ReceiverVariable: slotIndex<br>
-                               traceBlock: [ backEnd saveAndRestoreLinkRegAround: [self CallRT: ceTraceStoreTrampoline] ]<br>
-                               inFrame: needsFrame ]<br>
                ifTrue:<br>
+                       [ self ssAllocateRequiredReg: ClassReg.<br>
+                         topReg := ClassReg.<br>
+                         self ssStoreAndReplacePop: popBoolean toReg: topReg.<br>
+                         immutabilityFailure := objectRepresentation<br>
+                               genImmutableCheck: ReceiverResultReg<br>
+                               slotIndex: slotIndex<br>
+                               sourceReg: ClassReg<br>
+                               scratchReg: TempReg<br>
+                               popBoolean: popBoolean<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>
-                       [ self<br>
-                               genStorePop: popBoolean<br>
-                               ReceiverVariable: slotIndex<br>
-                               traceBlock: [ self CallRT: ceTraceStoreTrampoline ]<br>
-                               inFrame: needsFrame ]!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;genStorePop:ReceiverVariable:traceBlock:inFrame: (in category &#39;bytecode generator support&#39;) -----<br>
- genStorePop: popBoolean ReceiverVariable: slotIndex traceBlock: block inFrame: inFrame<br>
-       &lt;inline: true&gt;<br>
-       | topReg |<br>
-       self ssFlushUpThroughReceiverVariable: slotIndex.<br>
-       &quot;Avoid store check for immediate values&quot;<br>
-       ^ (objectRepresentation isUnannotatableConstant: self ssTop)<br>
-               ifTrue:<br>
-                       [self ensureReceiverResultRegContainsSelf.<br>
-                        self ssStorePop: popBoolean toReg: TempReg.<br>
-                        traceStores &gt; 0 ifTrue: [block value].<br>
-                        objectRepresentation<br>
-                               genStoreImmediateInSourceReg: TempReg<br>
-                               slotIndex: slotIndex<br>
-                               destReg: ReceiverResultReg]<br>
-               ifFalse:<br>
-                       [topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
-                       self ssStorePop: popBoolean toReg: topReg.<br>
-                       &quot;Note that ReceiverResultReg remains live after ceStoreCheckTrampoline.&quot;<br>
-                       self ensureReceiverResultRegContainsSelf.<br>
-                       traceStores &gt; 0 ifTrue: [self MoveR: topReg R: TempReg. block value].<br>
-                       objectRepresentation<br>
-                               genStoreSourceReg: topReg<br>
-                               slotIndex: slotIndex<br>
-                               destReg: ReceiverResultReg<br>
-                               scratchReg: TempReg<br>
-                               inFrame: inFrame ]!<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>
-       | topReg topSpilled tempVectReg |<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>
-       &quot;Avoid store check for immediate values&quot;<br>
-       (objectRepresentation isUnannotatableConstant: self ssTop) ifTrue:<br>
-               [ tempVectReg := self allocateRegNotConflictingWith: 0.<br>
-                self MoveMw: (self frameOffsetOfTemporary: remoteTempIndex) r: FPReg R: tempVectReg.<br>
-                self ssStorePop: popBoolean toReg: TempReg.<br>
-                traceStores &gt; 0 ifTrue:<br>
-                       [ tempVectReg = ReceiverResultReg ifFalse:<br>
-                                       [ self ssAllocateRequiredReg: ReceiverResultReg.<br>
-                                       optStatus isReceiverResultRegLive: false.<br>
-                                       self MoveR: tempVectReg R: ReceiverResultReg ].<br>
-                       self CallRT: ceTraceStoreTrampoline].<br>
-                ^objectRepresentation<br>
-                       genStoreImmediateInSourceReg: TempReg<br>
-                       slotIndex: slotIndex<br>
-                       destReg: tempVectReg].<br>
        topReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: ReceiverResultReg).<br>
+       self ssAllocateRequiredReg: ReceiverResultReg.<br>
-       topSpilled := self ssTop spilled.<br>
-       self ssStorePop: (popBoolean or: [topSpilled]) toReg: topReg.<br>
-       popBoolean ifFalse:<br>
-               [topSpilled ifFalse: [self ssPop: 1].<br>
-                self ssPushRegister: topReg].<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>
-               [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>
-               inFrame: needsFrame!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;putSelfInReceiverResultReg (in category &#39;bytecode generator support&#39;) -----<br>
+ putSelfInReceiverResultReg<br>
+       &lt;inline: true&gt;<br>
+        (self addressOf: simSelf) storeToReg: ReceiverResultReg<br>
+               !<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;ssStoreAndReplacePop:toReg: (in category &#39;simulation stack&#39;) -----<br>
+ ssStoreAndReplacePop: popBoolean toReg: reg<br>
+       &quot;In addition to ssStorePop:toReg:, if this is a store and not<br>
+       a popInto and the top of the simulated stack is not spilled,<br>
+       I change the simulated stack to use the register for the value&quot;<br>
+       | topSpilled |<br>
+       topSpilled := self ssTop spilled.<br>
+       self ssStorePop: (popBoolean or: [topSpilled]) toReg: reg.<br>
+       popBoolean ifFalse:<br>
+               [ topSpilled ifFalse: [self ssPop: 1].<br>
+               self ssPushRegister: reg ].!<br>
<br><span class="HOEnZb"><font color="#888888">
</font></span></blockquote></div><span class="HOEnZb"><font color="#888888"><br><br clear="all"><div><br></div>-- <br><div><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</font></span></div></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div></div>