[Vm-dev] VM Maker: VMMaker.oscog-cb.1615.mcz

Clément Bera bera.clement at gmail.com
Wed Jan 6 09:31:16 UTC 2016


Is the bleeding edge of the VM stable ?

If so I will look at it and find a solution and have a working simulator.

To fix:
- error code
- interpreter inst var access

I can do it today fortunately.

This is a shame I have not really understood yet how the interpreter is
translated efficiently to C...


2016-01-06 9:25 GMT+01:00 Eliot Miranda <eliot.miranda at gmail.com>:

>
> Hi Clément,
>
>     also, before I forget, the primitive failure code for immutability
> violations should be PrimErrNoModification, not PrimErrInappropriate.
>
> On Wed, Jan 6, 2016 at 12:00 AM, Eliot Miranda <eliot.miranda at gmail.com>
> wrote:
>
>> Hi Clément,
>>
>> On Tue, Dec 29, 2015 at 1:31 AM, <commits at source.squeak.org> wrote:
>>
>>>
>>> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
>>> http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1615.mcz
>>>
>>> ==================== Summary ====================
>>>
>>> Name: VMMaker.oscog-cb.1615
>>> Author: cb
>>> Time: 29 December 2015, 10:30:37.779 am
>>> UUID: 712a0115-a780-4d2c-b4f8-c0bc78031889
>>> Ancestors: VMMaker.oscog-eem.1614, VMMaker.oscog-cb.1579
>>>
>>> Made a new version of immutability with Eliot's remarks:
>>> - control flow maintained for the simulator
>>> - option pragma everywhere needed
>>> - removed duplication in extStore bytecodes
>>> - removed useless instruction in primitiveClone.
>>>
>>> I tried to use it, it does not work, but it seems the bleeding edge is
>>> not stable.
>>>
>>
>> I see one reason why it doesn't work.  Let me take you
>> through storeAndPopReceiverVariableBytecode
>>
>>
>>> The only thing I noticed is that some assertion may fail in
>>> #maybeCheckStackDepth:sp:pc: .
>>>
>>> =============== Diff against VMMaker.oscog-eem.1614 ===============
>>>
>>> Item was added:
>>> + ----- Method: CoInterpreter>>ceCannotAssignTo:withIndex:valueToAssign:
>>> (in category 'trampolines') -----
>>> + ceCannotAssignTo: immutableObject withIndex: index valueToAssign:
>>> valueToAssign
>>> +       "index is unboxed."
>>> +       <api>
>>> +       <option: #IMMUTABILITY>
>>> +       instructionPointer := self popStack.
>>> +       self push: immutableObject.
>>> +       self push: valueToAssign.
>>> +       self push: (objectMemory integerObjectOf: index).
>>> +       self push: instructionPointer.
>>> +       ^ self
>>> +               ceSendAbort: (objectMemory splObj:
>>> SelectorAttemptToAssign)
>>> +               to: immutableObject
>>> +               numArgs: 2!
>>>
>>> Item was removed:
>>> - ----- Method: CoInterpreter>>extendedStoreBytecode (in category 'stack
>>> bytecodes') -----
>>> - extendedStoreBytecode
>>> -       "Override to use itemporary:in:put:"
>>> -       | descriptor variableType variableIndex |
>>> -       <inline: true>
>>> -       descriptor := self fetchByte.
>>> -       self fetchNextBytecode.
>>> -       variableType := descriptor >> 6 bitAnd: 3.
>>> -       variableIndex := descriptor bitAnd: 63.
>>> -       variableType = 0 ifTrue:
>>> -               [^objectMemory storePointer: variableIndex ofObject:
>>> self receiver withValue: self internalStackTop].
>>> -       variableType = 1 ifTrue:
>>> -               [^self itemporary: variableIndex in: localFP put: self
>>> internalStackTop].
>>> -       variableType = 3 ifTrue:
>>> -               [^self storeLiteralVariable: variableIndex withValue:
>>> self internalStackTop].
>>> -       self error: 'illegal store'!
>>>
>>> Item was added:
>>> + ----- Method: CoInterpreter>>extendedStoreBytecodePop: (in category
>>> 'stack bytecodes') -----
>>> + extendedStoreBytecodePop: popBoolean
>>> +       "Override to use itemporary:in:put:"
>>> +       | descriptor variableType variableIndex value |
>>> +       <inline: true>
>>> +       descriptor := self fetchByte.
>>> +       self fetchNextBytecode.
>>> +       variableType := descriptor >> 6 bitAnd: 3.
>>> +       variableIndex := descriptor bitAnd: 63.
>>> +       value := self internalStackTop.
>>> +       popBoolean ifTrue: [ self internalPop: 1 ].
>>> +       variableType = 0 ifTrue:
>>> +               [^objectMemory storePointerImmutabilityCheck:
>>> variableIndex ofObject: self receiver withValue: value].
>>> +       variableType = 1 ifTrue:
>>> +               [^self itemporary: variableIndex in: localFP put: value].
>>> +       variableType = 3 ifTrue:
>>> +               [^self storeLiteralVariable: variableIndex withValue:
>>> value].
>>> +       self error: 'illegal store'!
>>>
>>> Item was changed:
>>>   ----- Method: CoInterpreterPrimitives>>primitiveObjectAtPut (in
>>> category 'object access primitives') -----
>>>   primitiveObjectAtPut
>>>         "Store a literal into a CompiledMethod at the given index.
>>> Defined for CompiledMethods only."
>>>         | thisReceiver rawHeader realHeader index newValue |
>>>         newValue := self stackValue: 0.
>>>         index := self stackValue: 1.
>>>         (objectMemory isNonIntegerObject: index) ifTrue:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>>         index := objectMemory integerValueOf: index.
>>>         thisReceiver := self stackValue: 2.
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue: [ (objectMemory isImmutable: thisReceiver)
>>> ifTrue: [ ^self primitiveFailFor: PrimErrInappropriate ] ].
>>>         rawHeader := self rawHeaderOf: thisReceiver.
>>>         realHeader := (self isCogMethodReference: rawHeader)
>>>                                         ifTrue: [(self cCoerceSimple:
>>> rawHeader to: #'CogMethod *') methodHeader]
>>>                                         ifFalse: [rawHeader].
>>>         (index > 0
>>>          and: [index <= ((objectMemory literalCountOfMethodHeader:
>>> realHeader) + LiteralStart)]) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadIndex].
>>>         index = 1
>>>                 ifTrue:
>>>                         [((objectMemory isNonIntegerObject: newValue)
>>>                          or: [(objectMemory literalCountOfMethodHeader:
>>> newValue) ~= (objectMemory literalCountOfMethodHeader: realHeader)]) ifTrue:
>>>                                 [^self primitiveFailFor:
>>> PrimErrBadArgument].
>>>                          (self isCogMethodReference: rawHeader)
>>>                                 ifTrue: [(self cCoerceSimple: rawHeader
>>> to: #'CogMethod *') methodHeader: newValue]
>>>                                 ifFalse: [objectMemory
>>> storePointerUnchecked: 0 ofObject: thisReceiver withValue: newValue]]
>>>                 ifFalse:
>>>                         [objectMemory storePointer: index - 1 ofObject:
>>> thisReceiver withValue: newValue].
>>>         self pop: 3 thenPush: newValue!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentation>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:
>>> (in category 'compile abstract instructions') -----
>>> + genStoreSourceReg: sourceReg slotIndex: index destReg: destReg
>>> scratchReg: scratchReg inFrame: inFrame
>>> +       ^ self
>>> +               genStoreSourceReg: sourceReg
>>> +               slotIndex: index
>>> +               destReg: destReg
>>> +               scratchReg: scratchReg
>>> +               inFrame: inFrame
>>> +               needsStoreCheck: true!
>>>
>>> Item was changed:
>>>   ----- Method:
>>> CogObjectRepresentationFor32BitSpur>>genInnerPrimitiveAtPut: (in category
>>> 'primitive generators') -----
>>>   genInnerPrimitiveAtPut: retNoffset
>>>         "Implement the guts of primitiveAtPut"
>>> +       | formatReg jumpImmediate jumpBadIndex jumpImmutable
>>> -       | formatReg jumpImmediate jumpBadIndex
>>>           jumpNotIndexablePointers jumpNotIndexableBits
>>>           jumpIsContext jumpIsCompiledMethod jumpIsBytes
>>> jumpHasFixedFields
>>>           jumpArrayOutOfBounds jumpFixedFieldsOutOfBounds
>>>           jumpWordsOutOfBounds jumpBytesOutOfBounds jumpBytesOutOfRange
>>>           jumpNonSmallIntegerValue jumpNegative jumpShortsUnsupported
>>> jumpNotPointers
>>>           |
>>>         <inline: true>
>>>         "c.f. StackInterpreter>>stSizeOf:
>>> SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length:"
>>>         <var: #jumpIsBytes type: #'AbstractInstruction *'>
>>>         <var: #jumpNegative type: #'AbstractInstruction *'>
>>>         <var: #jumpBadIndex type: #'AbstractInstruction *'>
>>>         <var: #jumpIsContext type: #'AbstractInstruction *'>
>>>         <var: #jumpImmediate type: #'AbstractInstruction *'>
>>>         <var: #jumpHasFixedFields type: #'AbstractInstruction *'>
>>>         <var: #jumpNotIndexableBits type: #'AbstractInstruction *'>
>>>         <var: #jumpArrayOutOfBounds type: #'AbstractInstruction *'>
>>>         <var: #jumpBytesOutOfBounds type: #'AbstractInstruction *'>
>>>         <var: #jumpShortsUnsupported type: #'AbstractInstruction *'>
>>>         <var: #jumpWordsOutOfBounds type: #'AbstractInstruction *'>
>>>         <var: #jumpNotIndexablePointers type: #'AbstractInstruction *'>
>>>
>>>         jumpImmediate := self genJumpImmediate: ReceiverResultReg.
>>>         jumpBadIndex := self genJumpNotSmallInteger: Arg0Reg scratchReg:
>>> TempReg.
>>>         self genConvertSmallIntegerToIntegerInReg: Arg0Reg.
>>>         cogit SubCq: 1 R: Arg0Reg. "1-rel => 0-rel"
>>>
>>>         "formatReg := self formatOf: ReceiverResultReg"
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue:
>>> +               [ self genGetFormatOf: ReceiverResultReg
>>> +                       into: (formatReg := SendNumArgsReg)
>>> +                       leastSignificantHalfOfBaseHeaderIntoScratch:
>>> TempReg.
>>> +               jumpImmutable := self genJumpBaseHeaderImmutable:
>>> TempReg ]
>>> +               ifFalse:
>>> +               [ self genGetFormatOf: ReceiverResultReg
>>> +                       into: (formatReg := SendNumArgsReg)
>>> +                       leastSignificantHalfOfBaseHeaderIntoScratch:
>>> NoReg ].
>>> -       self genGetFormatOf: ReceiverResultReg
>>> -               into: (formatReg := SendNumArgsReg)
>>> -               leastSignificantHalfOfBaseHeaderIntoScratch: NoReg.
>>>
>>>         self genGetNumSlotsOf: ReceiverResultReg into: ClassReg.
>>>
>>>         "dispatch on format in a combination of highest dynamic
>>> frequency order first and convenience.
>>>                   0 = 0 sized objects (UndefinedObject True False et al)
>>>                   1 = non-indexable objects with inst vars (Point et al)
>>>                   2 = indexable objects with no inst vars (Array et al)
>>>                   3 = indexable objects with inst vars (MethodContext
>>> AdditionalMethodState et al)
>>>                   4 = weak indexable objects with inst vars (WeakArray
>>> et al)
>>>                   5 = weak non-indexable objects with inst vars
>>> (ephemerons) (Ephemeron)
>>>                   6 unused, reserved for exotic pointer objects?
>>>                   7 Forwarded Object, 1st field is pointer, rest of
>>> fields are ignored
>>>                   8 unused, reserved for exotic non-pointer objects?
>>>                   9 (?) 64-bit indexable
>>>                 10 - 11 32-bit indexable
>>>                 12 - 15 16-bit indexable
>>>                 16 - 23 byte indexable
>>>                 24 - 31 compiled method"
>>>         cogit CmpCq: objectMemory weakArrayFormat R: formatReg.
>>>         jumpNotPointers := cogit JumpAbove: 0.
>>>         "optimistic store check; assume index in range (almost always
>>> is)."
>>>         self genStoreCheckReceiverReg: ReceiverResultReg
>>>                 valueReg: Arg1Reg
>>>                 scratchReg: TempReg
>>>                 inFrame: false.
>>>
>>>         cogit CmpCq: objectMemory arrayFormat R: formatReg.
>>>         jumpNotIndexablePointers := cogit JumpBelow: 0.
>>>         jumpHasFixedFields := cogit JumpNonZero: 0.
>>>         cogit CmpR: Arg0Reg R: ClassReg.
>>>         jumpArrayOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit AddCq: objectMemory baseHeaderSize >> objectMemory
>>> shiftForWord R: Arg0Reg.
>>>         cogit MoveR: Arg1Reg Xwr: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         cogit RetN: retNoffset.
>>>
>>>         jumpHasFixedFields jmpTarget: cogit Label.
>>>         self genGetClassIndexOfNonImm: ReceiverResultReg into: formatReg.
>>>         cogit CmpCq: ClassMethodContextCompactIndex R: formatReg.
>>>         jumpIsContext := cogit JumpZero: 0.
>>>         "get # fixed fields in formatReg"
>>>         cogit PushR: ClassReg.
>>>         self genGetClassObjectOfClassIndex: formatReg into: ClassReg
>>> scratchReg: TempReg.
>>>         self genLoadSlot: InstanceSpecificationIndex sourceReg: ClassReg
>>> destReg: formatReg.
>>>         cogit PopR: ClassReg.
>>>         self genConvertSmallIntegerToIntegerInReg: formatReg.
>>>         cogit AndCq: objectMemory fixedFieldsOfClassFormatMask R:
>>> formatReg.
>>>         cogit SubR: formatReg R: ClassReg.
>>>         cogit AddCq: objectMemory baseHeaderSize >> objectMemory
>>> shiftForWord R: formatReg.
>>>         cogit CmpR: Arg0Reg R: ClassReg.
>>>         jumpFixedFieldsOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit AddR: formatReg R: Arg0Reg.
>>>         cogit MoveR: Arg1Reg Xwr: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         cogit RetN: retNoffset.
>>>
>>>         jumpNotPointers jmpTarget:
>>>                 (cogit CmpCq: objectMemory firstCompiledMethodFormat R:
>>> formatReg).
>>>         jumpIsCompiledMethod := cogit JumpAboveOrEqual: 0.
>>>         jumpNonSmallIntegerValue := self genJumpNotSmallInteger: Arg1Reg
>>> scratchReg: TempReg.
>>>                                         cogit CmpCq: objectMemory
>>> firstByteFormat R: formatReg.
>>>         jumpIsBytes := cogit JumpAboveOrEqual: 0.
>>>                                         cogit CmpCq: objectMemory
>>> firstShortFormat R: formatReg.
>>>         jumpShortsUnsupported := cogit JumpAboveOrEqual: 0.
>>>                                         cogit CmpCq: objectMemory
>>> firstLongFormat R: formatReg.
>>>         "For now ignore 64-bit indexability."
>>>         jumpNotIndexableBits := cogit JumpBelow: 0.
>>>
>>>         cogit CmpR: Arg0Reg R: ClassReg.
>>>         jumpWordsOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         self genConvertSmallIntegerToIntegerInReg: TempReg.
>>>         (cogit lastOpcode setsConditionCodesFor: JumpNegative) ifFalse:
>>>                 [self CmpCq: 0 R: ClassReg]. "N.B. FLAGS := ClassReg - 0"
>>>         jumpNegative := cogit JumpNegative: 0.
>>>         cogit AddCq: objectMemory baseHeaderSize >> objectMemory
>>> shiftForWord R: Arg0Reg.
>>>         cogit MoveR: TempReg Xwr: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         cogit RetN: retNoffset.
>>>
>>>         jumpIsBytes jmpTarget:
>>>                 (cogit CmpCq: (objectMemory integerObjectOf: 255) R:
>>> Arg1Reg).
>>>         jumpBytesOutOfRange := cogit JumpAbove: 0.
>>>         cogit LogicalShiftLeftCq: objectMemory shiftForWord R: ClassReg.
>>>         cogit AndCq: objectMemory wordSize - 1 R: formatReg.
>>>         cogit SubR: formatReg R: ClassReg;
>>>         CmpR: Arg0Reg R: ClassReg.
>>>         jumpBytesOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         self genConvertSmallIntegerToIntegerInReg: TempReg.
>>>         cogit AddCq: objectMemory baseHeaderSize R: Arg0Reg.
>>>         cogit MoveR: TempReg Xbr: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         cogit RetN: retNoffset.
>>>
>>>         "there are no shorts as yet.  so this is dead code:
>>>         jumpIsShorts jmpTarget:
>>>                 (cogit CmpCq: (objectMemory integerObjectOf: 65535) R:
>>> Arg1Reg).
>>>         jumpShortsOutOfRange := cogit JumpAbove: 0.
>>>         cogit LogicalShiftLeftCq: objectMemory shiftForWord - 1 R:
>>> ClassReg.
>>>         cogit AndCq: 1 R: formatReg.
>>>         cogit SubR: formatReg R: ClassReg;
>>>         CmpR: Arg0Reg R: ClassReg.
>>>         jumpShortsOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         cogit genConvertSmallIntegerToIntegerInReg: TempReg.
>>>         cogit AddR: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: TempReg M16: objectMemory baseHeaderSize r:
>>> ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         jumpShortsDone := cogit Jump: 0."
>>>
>>>         jumpIsContext jmpTarget:
>>>         (jumpNegative jmpTarget:
>>>         (jumpNotIndexableBits jmpTarget:
>>>         (jumpBytesOutOfRange jmpTarget:
>>>         (jumpIsCompiledMethod jmpTarget:
>>>         (jumpArrayOutOfBounds jmpTarget:
>>>         (jumpBytesOutOfBounds jmpTarget:
>>>         (jumpShortsUnsupported jmpTarget:
>>>         (jumpWordsOutOfBounds jmpTarget:
>>>         (jumpNotIndexablePointers jmpTarget:
>>>         (jumpNonSmallIntegerValue jmpTarget:
>>>         (jumpFixedFieldsOutOfBounds jmpTarget: cogit Label))))))))))).
>>> +
>>> +       self cppIf: IMMUTABILITY ifTrue: [ jumpImmutable jmpTarget:
>>> cogit Label ].
>>>
>>>         cogit AddCq: 1 R: Arg0Reg. "0-rel => 1-rel"
>>>         self genConvertIntegerToSmallIntegerInReg: Arg0Reg.
>>>
>>>         jumpBadIndex jmpTarget: (jumpImmediate jmpTarget: cogit Label).
>>>
>>>         ^0!
>>>
>>> Item was changed:
>>>   ----- Method:
>>> CogObjectRepresentationFor32BitSpur>>genInnerPrimitiveStringAtPut: (in
>>> category 'primitive generators') -----
>>>   genInnerPrimitiveStringAtPut: retNoffset
>>>         "Implement the guts of primitiveStringAtPut"
>>>         | formatReg jumpBadIndex jumpBadArg jumpWordsDone
>>> jumpBytesOutOfRange
>>> +         jumpIsBytes jumpNotString jumpIsCompiledMethod jumpImmutable
>>> -         jumpIsBytes jumpNotString jumpIsCompiledMethod
>>>           jumpBytesOutOfBounds jumpWordsOutOfBounds
>>> jumpShortsUnsupported |
>>>         <inline: true>
>>>         "c.f. StackInterpreter>>stSizeOf:
>>> SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length:"
>>>         <var: #jumpBadArg type: #'AbstractInstruction *'>
>>>         <var: #jumpIsBytes type: #'AbstractInstruction *'>
>>>         <var: #jumpBadIndex type: #'AbstractInstruction *'>
>>>         <var: #jumpWordsDone type: #'AbstractInstruction *'>
>>>         <var: #jumpBytesOutOfBounds type: #'AbstractInstruction *'>
>>>         <var: #jumpShortsUnsupported type: #'AbstractInstruction *'>
>>>         <var: #jumpWordsOutOfBounds type: #'AbstractInstruction *'>
>>>
>>>         jumpBadIndex := self genJumpNotSmallInteger: Arg0Reg.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         jumpBadArg := self genJumpNotCharacterInScratchReg: TempReg.
>>>         self genConvertSmallIntegerToIntegerInReg: Arg0Reg.
>>>         cogit SubCq: 1 R: Arg0Reg. "1-rel => 0-rel"
>>>
>>>         "formatReg := self formatOf: ReceiverResultReg"
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue:
>>> +               [ self genGetFormatOf: ReceiverResultReg
>>> +                       into: (formatReg := SendNumArgsReg)
>>> +                       leastSignificantHalfOfBaseHeaderIntoScratch:
>>> TempReg.
>>> +               jumpImmutable := self genJumpBaseHeaderImmutable:
>>> TempReg ]
>>> +               ifFalse:
>>> +               [ self genGetFormatOf: ReceiverResultReg
>>> +                       into: (formatReg := SendNumArgsReg)
>>> +                       leastSignificantHalfOfBaseHeaderIntoScratch:
>>> NoReg ].
>>> -       self genGetFormatOf: ReceiverResultReg
>>> -               into: (formatReg := SendNumArgsReg)
>>> -               leastSignificantHalfOfBaseHeaderIntoScratch: NoReg.
>>>
>>>         self genGetNumSlotsOf: ReceiverResultReg into: ClassReg.
>>>
>>>         "dispatch on format; words and/or bytes.
>>>                   0 to 8 = pointer objects, forwarders, reserved.
>>>                   9 (?) 64-bit indexable
>>>                 10 - 11 32-bit indexable
>>>                 12 - 15 16-bit indexable (but unused)
>>>                 16 - 23 byte indexable
>>>                 24 - 31 compiled method"
>>>         cogit CmpCq: objectMemory firstLongFormat R: formatReg.
>>>         jumpNotString := cogit JumpBelowOrEqual: 0.
>>>                                         cogit CmpCq: objectMemory
>>> firstCompiledMethodFormat R: formatReg.
>>>         jumpIsCompiledMethod := cogit JumpAboveOrEqual: 0.
>>>                                         cogit CmpCq: objectMemory
>>> firstByteFormat R: formatReg.
>>>         jumpIsBytes := cogit JumpGreaterOrEqual: 0.
>>>                                         cogit CmpCq: objectMemory
>>> firstShortFormat R: formatReg.
>>>         jumpShortsUnsupported := cogit JumpGreaterOrEqual: 0.
>>>
>>>         cogit CmpR: Arg0Reg R: ClassReg.
>>>         jumpWordsOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         self genConvertSmallIntegerToIntegerInReg: TempReg.
>>>         cogit AddCq: objectMemory baseHeaderSize >> objectMemory
>>> shiftForWord R: Arg0Reg.
>>>         cogit MoveR: TempReg Xwr: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         jumpWordsDone := cogit Jump: 0.
>>>
>>>         "there are no shorts as yet.  so this is dead code:
>>>         jumpIsShorts jmpTarget:
>>>                 (cogit CmpCq: (objectMemory integerObjectOf: 65535) R:
>>> Arg1Reg).
>>>         jumpShortsOutOfRange := cogit JumpAbove: 0.
>>>         cogit LogicalShiftLeftCq: objectMemory shiftForWord - 1 R:
>>> ClassReg.
>>>         cogit AndCq: 1 R: formatReg.
>>>         cogit SubR: formatReg R: ClassReg;
>>>         CmpR: Arg0Reg R: ClassReg.
>>>         jumpShortsOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         cogit genConvertSmallIntegerToIntegerInReg: TempReg.
>>>         cogit AddR: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: TempReg M16: objectMemory baseHeaderSize r:
>>> ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>         jumpShortsDone := cogit Jump: 0."
>>>
>>>         jumpIsBytes jmpTarget:
>>>                 (cogit CmpCq: (objectMemory characterObjectOf: 255) R:
>>> Arg1Reg).
>>>         jumpBytesOutOfRange := cogit JumpAbove: 0.
>>>         cogit LogicalShiftLeftCq: objectMemory shiftForWord R: ClassReg.
>>>         cogit AndCq: objectMemory wordSize - 1 R: formatReg.
>>>         cogit SubR: formatReg R: ClassReg;
>>>         CmpR: Arg0Reg R: ClassReg.
>>>         jumpBytesOutOfBounds := cogit JumpBelowOrEqual: 0.
>>>         cogit MoveR: Arg1Reg R: TempReg.
>>>         self genConvertCharacterToCodeInReg: TempReg.
>>>         cogit AddCq: objectMemory baseHeaderSize R: Arg0Reg.
>>>         cogit MoveR: TempReg Xbr: Arg0Reg R: ReceiverResultReg.
>>>         cogit MoveR: Arg1Reg R: ReceiverResultReg.
>>>
>>>         jumpWordsDone jmpTarget:
>>>                 (cogit RetN: retNoffset).
>>>
>>>         jumpBadArg jmpTarget:
>>>         (jumpNotString jmpTarget:
>>>         (jumpBytesOutOfRange jmpTarget:
>>>         (jumpIsCompiledMethod jmpTarget:
>>>         (jumpBytesOutOfBounds jmpTarget:
>>>         (jumpShortsUnsupported jmpTarget:
>>>         (jumpWordsOutOfBounds jmpTarget: cogit Label)))))).
>>>
>>> +       self cppIf: IMMUTABILITY ifTrue: [ jumpImmutable jmpTarget:
>>> cogit Label ].
>>> +
>>>         cogit AddCq: 1 R: Arg0Reg. "0-rel => 1-rel"
>>>         self genConvertIntegerToSmallIntegerInReg: Arg0Reg.
>>>
>>>         jumpBadIndex jmpTarget: cogit Label.
>>>
>>>         ^0!
>>>
>>> Item was changed:
>>>   CogObjectRepresentation subclass: #CogObjectRepresentationForSpur
>>> +       instanceVariableNames: 'ceScheduleScavengeTrampoline
>>> ceSmallActiveContextInMethodTrampoline
>>> ceSmallActiveContextInBlockTrampoline
>>> ceLargeActiveContextInMethodTrampoline
>>> ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline
>>> ceCannotAssignToWithIndexTrampoline'
>>> -       instanceVariableNames: 'ceScheduleScavengeTrampoline
>>> ceSmallActiveContextInMethodTrampoline
>>> ceSmallActiveContextInBlockTrampoline
>>> ceLargeActiveContextInMethodTrampoline
>>> ceLargeActiveContextInBlockTrampoline ceStoreCheckContextReceiverTrampoline'
>>>         classVariableNames: ''
>>>         poolDictionaries: 'VMBytecodeConstants VMSqueakClassIndices'
>>>         category: 'VMMaker-JIT'!
>>>
>>> Item was changed:
>>>   ----- Method: CogObjectRepresentationForSpur class>>numTrampolines (in
>>> category 'accessing') -----
>>>   numTrampolines
>>> +       (initializationOptions at: #IMMUTABILITY ifAbsent: [false])
>>> +               ifTrue: [ ^ super numTrampolines + 7 ]
>>> +               ifFalse: [ ^ super numTrampolines + 6 ]!
>>> -       ^super numTrampolines + 6!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSpur>>genImmutableCheck:slotIndex:sourceReg:scratchReg:popBoolean:needRestoreRcvr:
>>> (in category 'compile abstract instructions') -----
>>> + genImmutableCheck: regHoldingObjectMutated slotIndex: index sourceReg:
>>> regHoldingValueToStore scratchReg: scratchReg popBoolean: popBoolean
>>> needRestoreRcvr: needRestoreRcvr
>>> +       | mutableJump fail |
>>> +       <var: #mutableJump type: #'AbstractInstruction *'>
>>> +       <var: #fail type: #'AbstractInstruction *'>
>>> +       <inline: true>
>>> +       <option: #IMMUTABILITY>
>>> +       "Trampoline convention:
>>> +       - objectMutated passed in RcvrResultReg
>>> +       - index (unboxed) passed in TempReg
>>> +       - valueToStore passed in Arg1Reg.
>>> +       Simulated stack is flushed until simulatedStackPointer - 1,
>>> which implies full flush
>>> +       if popBoolean is true, else top value may not be flushed.
>>> +       We spill the top value (the value to store) for the trampoline
>>> if needed."
>>> +       self assert: regHoldingObjectMutated == ReceiverResultReg.
>>> +       self assert: scratchReg == TempReg.
>>> +       self assert: regHoldingValueToStore == ClassReg.
>>> +       mutableJump := self genJumpMutable: ClassReg scratchReg: TempReg.
>>> +
>>> +       "We reach this code if the object mutated is immutable."
>>> +       "simulatedStack state altered for the trampoline, spill top
>>> value if needed"
>>> +       (popBoolean or: [ cogit ssTop spilled ]) ifFalse:
>>> +               [ self assert: (cogit ssTop type = SSRegister and:
>>> [cogit ssTop register = ClassReg]).
>>> +                 cogit PushR: ClassReg ].
>>> +       "pass the unboxed index using TempReg"
>>> +       cogit MoveCq: index R: TempReg.
>>> +       "trampoline call and mcpc to bcpc annotation."
>>> +       cogit CallRT: ceCannotAssignToWithIndexTrampoline.
>>> +       cogit annotateBytecode: cogit Label.
>>> +       "Top of stack is consumed by the trampoline. In case of store
>>> with non spilled value,
>>> +       restore ClassReg to match simulated stack state"
>>> +       (popBoolean or: [ cogit ssTop spilled ]) ifFalse:
>>> +               [cogit popR: ClassReg].
>>> +       "restore ReceiverResultReg state if needed"
>>> +       needRestoreRcvr ifTrue: [ self putSelfInReceiverResultReg ].
>>> +       fail := cogit Jump: 0.
>>> +
>>> +       "We reach this code is the object mutated is mutable"
>>> +       mutableJump jmpTarget: cogit Label.
>>> +
>>> +       ^ fail!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSpur>>genJumpBaseHeaderImmutable: (in category
>>> 'compile abstract instructions') -----
>>> + genJumpBaseHeaderImmutable: baseHeaderReg
>>> +       "baseHeader holds at least the least significant 32 bits of the
>>> object"
>>> +       <returnTypeC: #'AbstractInstruction *'>
>>> +       <option: #IMMUTABILITY>
>>> +       cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.
>>> +       ^ cogit JumpNonZero: 0!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSpur>>genJumpBaseHeaderMutable: (in category
>>> 'compile abstract instructions') -----
>>> + genJumpBaseHeaderMutable: baseHeaderReg
>>> +       "baseHeader holds at least the least significant 32 bits of the
>>> object"
>>> +       <returnTypeC: #'AbstractInstruction *'>
>>> +       <option: #IMMUTABILITY>
>>> +       cogit TstCq: objectMemory immutableBitMask R: baseHeaderReg.
>>> +       ^ cogit JumpZero: 0!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSpur>>genJumpImmutable:scratchReg: (in category
>>> 'compile abstract instructions') -----
>>> + genJumpImmutable: sourceReg scratchReg: scratchReg
>>> +       <returnTypeC: #'AbstractInstruction *'>
>>> +       <option: #IMMUTABILITY>
>>> +       cogit MoveMw: 0 r: sourceReg R: scratchReg.
>>> +       ^ self genJumpBaseHeaderImmutable: scratchReg!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSpur>>genJumpMutable:scratchReg: (in category
>>> 'compile abstract instructions') -----
>>> + genJumpMutable: sourceReg scratchReg: scratchReg
>>> +       <returnTypeC: #'AbstractInstruction *'>
>>> +       <option: #IMMUTABILITY>
>>> +       cogit MoveMw: 0 r: sourceReg R: scratchReg.
>>> +       ^ self genJumpBaseHeaderMutable: scratchReg!
>>>
>>> Item was changed:
>>>   ----- Method:
>>> CogObjectRepresentationForSpur>>genStoreCheckReceiverReg:valueReg:scratchReg:inFrame:
>>> (in category 'compile abstract instructions') -----
>>>   genStoreCheckReceiverReg: destReg valueReg: valueReg scratchReg:
>>> scratchReg inFrame: inFrame
>>>         "Generate the code for a store check of valueReg into destReg."
>>>         | jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRemembered
>>> mask rememberedBitByteOffset |
>>>         <var: #jmpImmediate type: #'AbstractInstruction *'>
>>>         <var: #jmpDestYoung type: #'AbstractInstruction *'>
>>>         <var: #jmpSourceOld type: #'AbstractInstruction *'>
>>>         <var: #jmpAlreadyRemembered type: #'AbstractInstruction *'>
>>>         "Is value stored an integer?  If so we're done"
>>>         cogit MoveR: valueReg R: scratchReg.
>>>         cogit AndCq: objectMemory tagMask R: scratchReg.
>>>         jmpImmediate := cogit JumpNonZero: 0.
>>>         "Get the old/new boundary in scratchReg"
>>>         cogit MoveCw: objectMemory storeCheckBoundary R: scratchReg.
>>>         "Is target young?  If so we're done"
>>>         cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg -
>>> scratchReg"
>>>         jmpDestYoung := cogit JumpBelow: 0.
>>>         "Is value stored old?  If so we're done."
>>>         cogit CmpR: scratchReg R: valueReg. "N.B. FLAGS := valueReg -
>>> scratchReg"
>>>         jmpSourceOld := cogit JumpAboveOrEqual: 0.
>>>         "value is young and target is old.
>>>          Need to remember this only if the remembered bit is not already
>>> set.
>>>          Test the remembered bit.  Only need to fetch the byte
>>> containing it,
>>>          which reduces the size of the mask constant."
>>>         rememberedBitByteOffset := jmpSourceOld isBigEndian
>>>
>>> ifTrue: [objectMemory baseHeaderSize - 1 - (objectMemory rememberedBitShift
>>> // 8)]
>>>
>>> ifFalse:[objectMemory rememberedBitShift // 8].
>>>         mask := 1 << (objectMemory rememberedBitShift \\ 8).
>>>         cogit MoveMb: rememberedBitByteOffset r: destReg R: scratchReg.
>>>         cogit AndCq: mask R: scratchReg.
>>>         jmpAlreadyRemembered := cogit JumpNonZero: 0.
>>>         "Remembered bit is not set.  Call store check to insert dest
>>> into remembered table."
>>>         self assert: destReg == ReceiverResultReg.
>>> +       cogit
>>> +               evaluateTrampolineCallBlock:
>>> -       inFrame
>>> -               ifTrue:
>>>                         [cogit
>>>                                 CallRT: ceStoreCheckTrampoline
>>>                                 registersToBeSavedMask: (((cogit
>>> registerMaskFor: valueReg)
>>>
>>>                         bitOr: cogit callerSavedRegMask)
>>>
>>>                         bitClear: (cogit registerMaskFor:
>>> ReceiverResultReg))]
>>> +               protectLinkRegIfNot: inFrame.
>>> -               ifFalse:
>>> -                       [cogit backEnd saveAndRestoreLinkRegAround:
>>> -                               [cogit
>>> -                                       CallRT: ceStoreCheckTrampoline
>>> -                                       registersToBeSavedMask: (((cogit
>>> registerMaskFor: valueReg)
>>> -
>>>                                bitOr: cogit callerSavedRegMask)
>>> -
>>>                                bitClear: (cogit registerMaskFor:
>>> ReceiverResultReg))]].
>>>         jmpImmediate jmpTarget:
>>>         (jmpDestYoung jmpTarget:
>>>         (jmpSourceOld jmpTarget:
>>>         (jmpAlreadyRemembered jmpTarget:
>>>                 cogit Label))).
>>>         ^0!
>>>
>>> Item was removed:
>>> - ----- Method:
>>> CogObjectRepresentationForSpur>>genStoreImmediateInSourceReg:slotIndex:destReg:
>>> (in category 'compile abstract instructions') -----
>>> - genStoreImmediateInSourceReg: sourceReg slotIndex: index destReg:
>>> destReg
>>> -       cogit MoveR: sourceReg
>>> -                  Mw: index * objectMemory wordSize + objectMemory
>>> baseHeaderSize
>>> -                  r: destReg.
>>> -       ^0!
>>>
>>> Item was removed:
>>> - ----- Method:
>>> CogObjectRepresentationForSpur>>genStoreSourceReg:slotIndex:destReg:scratchReg:
>>> (in category 'compile abstract instructions') -----
>>> - genStoreSourceReg: sourceReg slotIndex: index destReg: destReg
>>> scratchReg: scratchReg
>>> -       "do the store"
>>> -       cogit MoveR: sourceReg
>>> -                  Mw: index * objectMemory wordSize + objectMemory
>>> baseHeaderSize
>>> -                  r: destReg.
>>> -       "now the check"
>>> -       ^self genStoreCheckReceiverReg: destReg valueReg: sourceReg
>>> scratchReg: scratchReg inFrame: true!
>>>
>>> Item was removed:
>>> - ----- Method:
>>> CogObjectRepresentationForSpur>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:
>>> (in category 'compile abstract instructions') -----
>>> - genStoreSourceReg: sourceReg slotIndex: index destReg: destReg
>>> scratchReg: scratchReg inFrame: inFrame
>>> -       "do the store"
>>> -       cogit MoveR: sourceReg
>>> -                  Mw: index * objectMemory wordSize + objectMemory
>>> baseHeaderSize
>>> -                  r: destReg.
>>> -       "now the check"
>>> -       ^self genStoreCheckReceiverReg: destReg valueReg: sourceReg
>>> scratchReg: scratchReg inFrame: inFrame!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSpur>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck:
>>> (in category 'compile abstract instructions') -----
>>> + genStoreSourceReg: sourceReg slotIndex: index destReg: destReg
>>> scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck
>>> +       "do the store"
>>> +       cogit MoveR: sourceReg
>>> +                  Mw: index * objectMemory wordSize + objectMemory
>>> baseHeaderSize
>>> +                  r: destReg.
>>> +       "now the check. needStoreCheck is false if the JIT has figured
>>> out that the value stored does not need the check (immediate, nil, true,
>>> false)"
>>> +       needsStoreCheck ifTrue:
>>> +               [ ^ self
>>> +                       genStoreCheckReceiverReg: destReg
>>> +                       valueReg: sourceReg
>>> +                       scratchReg: scratchReg
>>> +                       inFrame: inFrame ].
>>> +       ^ 0!
>>>
>>> Item was changed:
>>>   ----- Method:
>>> CogObjectRepresentationForSpur>>genStoreSourceReg:slotIndex:intoNewObjectInDestReg:
>>> (in category 'compile abstract instructions') -----
>>>   genStoreSourceReg: sourceReg slotIndex: index intoNewObjectInDestReg:
>>> destReg
>>> +       "This method is used for unchecked stores in objects after their
>>> creation (typically, inlined creation of Array, closures and some temp
>>> vectors).
>>> +       Currently there is no need to do the immutability check here"
>>>         cogit MoveR: sourceReg
>>>                    Mw: index * objectMemory wordSize + objectMemory
>>> baseHeaderSize
>>>                    r: destReg.
>>>         ^0!
>>>
>>> Item was changed:
>>>   ----- Method:
>>> CogObjectRepresentationForSpur>>generateObjectRepresentationTrampolines (in
>>> category 'initialization') -----
>>>   generateObjectRepresentationTrampolines
>>>         "Do the store check.  Answer the argument for the benefit of the
>>> code generator;
>>>          ReceiverResultReg may be caller-saved and hence smashed by this
>>> call.  Answering
>>>          it allows the code generator to reload ReceiverResultReg
>>> cheaply.
>>>          In Spur the only thing we leave to the run-time is adding the
>>> receiver to the
>>>          remembered set and setting its isRemembered bit."
>>> +       self
>>> +               cppIf: IMMUTABILITY
>>> +               ifTrue:
>>> +                       [ "Arg1Reg is used as resultReg because cogit
>>> needs to restore the valueToStore
>>> +                       in the reg expected. The reg for the
>>> valueToStore is dynamically allocated, but
>>> +                       in most case, in the non-sista VM, it ends up
>>> being Arg1Reg."
>>> +                         ceCannotAssignToWithIndexTrampoline := cogit
>>> +
>>>  genTrampolineFor: #ceCannotAssignTo:withIndex:valueToAssign:
>>> +
>>>  called: 'ceCannotAssignToWithIndexTrampoline'
>>> +
>>>  arg: ReceiverResultReg
>>> +
>>>  arg: TempReg
>>> +
>>>  arg: ClassReg ].
>>>         ceStoreCheckTrampoline := cogit
>>>
>>> genTrampolineFor: #remember:
>>>
>>> called: 'ceStoreCheckTrampoline'
>>>
>>> arg: ReceiverResultReg
>>>
>>> result: cogit returnRegForStoreCheck.
>>>         ceStoreCheckContextReceiverTrampoline := self
>>> genStoreCheckContextReceiverTrampoline.
>>>         ceScheduleScavengeTrampoline := cogit
>>>
>>>                 genSafeTrampolineFor: #ceScheduleScavenge
>>>
>>>                 called: 'ceScheduleScavengeTrampoline'.
>>>         ceSmallActiveContextInMethodTrampoline := self
>>> genActiveContextTrampolineLarge: false inBlock: false called:
>>> 'ceSmallMethodContext'.
>>>         ceSmallActiveContextInBlockTrampoline := self
>>> genActiveContextTrampolineLarge: false inBlock: true called:
>>> 'ceSmallBlockContext'.
>>>         ceLargeActiveContextInMethodTrampoline := self
>>> genActiveContextTrampolineLarge: true inBlock: false called:
>>> 'ceLargeMethodContext'.
>>>         ceLargeActiveContextInBlockTrampoline := self
>>> genActiveContextTrampolineLarge: true inBlock: true called:
>>> 'ceLargeBlockContext'!
>>>
>>> Item was removed:
>>> - ----- Method:
>>> CogObjectRepresentationForSqueakV3>>genStoreImmediateInSourceReg:slotIndex:destReg:
>>> (in category 'compile abstract instructions') -----
>>> - genStoreImmediateInSourceReg: sourceReg slotIndex: index destReg:
>>> destReg
>>> -       cogit MoveR: sourceReg Mw: index * objectMemory wordSize +
>>> objectMemory baseHeaderSize r: destReg.
>>> -       ^0!
>>>
>>> Item was removed:
>>> - ----- Method:
>>> CogObjectRepresentationForSqueakV3>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:
>>> (in category 'compile abstract instructions') -----
>>> - genStoreSourceReg: sourceReg slotIndex: index destReg: destReg
>>> scratchReg: scratchReg inFrame: inFrame
>>> -       | jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRoot mask
>>> rootBitByteOffset |
>>> -       <var: #jmpImmediate type: #'AbstractInstruction *'>
>>> -       <var: #jmpDestYoung type: #'AbstractInstruction *'>
>>> -       <var: #jmpSourceOld type: #'AbstractInstruction *'>
>>> -       <var: #jmpAlreadyRoot type: #'AbstractInstruction *'>
>>> -       "do the store"
>>> -       cogit MoveR: sourceReg Mw: index * objectMemory wordSize +
>>> objectMemory baseHeaderSize r: destReg.
>>> -       "now the check.  Is value stored an integer?  If so we're done"
>>> -       cogit MoveR: sourceReg R: scratchReg.
>>> -       cogit AndCq: 1 R: scratchReg.
>>> -       jmpImmediate := cogit JumpNonZero: 0.
>>> -       "Get the old/new boundary in scratchReg"
>>> -       cogit MoveAw: objectMemory youngStartAddress R: scratchReg.
>>> -       "Is target young?  If so we're done"
>>> -       cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg -
>>> scratchReg"
>>> -       jmpDestYoung := cogit JumpAboveOrEqual: 0.
>>> -       "Is value stored old?  If so we're done."
>>> -       cogit CmpR: scratchReg R: sourceReg. "N.B. FLAGS := sourceReg -
>>> scratchReg"
>>> -       jmpSourceOld := cogit JumpBelow: 0.
>>> -       "value is young and target is old.
>>> -        Need to make this a root if the root bit is not already set.
>>> -        Test the root bit.  Only need to fetch the byte containing it,
>>> -        which reduces the size of the mask constant."
>>> -       rootBitByteOffset := jmpSourceOld isBigEndian
>>> -                                                       ifTrue:
>>> [objectMemory wordSize - RootBitDigitLength]
>>> -
>>>  ifFalse:[RootBitDigitLength - 1].
>>> -       mask := RootBitDigitLength > 1
>>> -                               ifTrue: [RootBit >> (RootBitDigitLength
>>> - 1 * 8)]
>>> -                               ifFalse: [RootBit].
>>> -       cogit MoveMb: rootBitByteOffset r: destReg R: scratchReg.
>>> -       cogit AndCq: mask R: scratchReg.
>>> -       jmpAlreadyRoot := cogit JumpNonZero: 0.
>>> -       "Root bit is not set.  Call store check to insert dest into root
>>> table."
>>> -       self assert: destReg == ReceiverResultReg.
>>> -       inFrame
>>> -               ifTrue:
>>> -                       [cogit
>>> -                               CallRT: ceStoreCheckTrampoline
>>> -                               registersToBeSavedMask: (((cogit
>>> registerMaskFor: sourceReg)
>>> -
>>>                        bitOr: cogit callerSavedRegMask)
>>> -
>>>                        bitClear: (cogit registerMaskFor:
>>> ReceiverResultReg))]
>>> -               ifFalse:
>>> -                       [cogit backEnd saveAndRestoreLinkRegAround:
>>> -                               [cogit
>>> -                                       CallRT: ceStoreCheckTrampoline
>>> -                                       registersToBeSavedMask: (((cogit
>>> registerMaskFor: sourceReg)
>>> -
>>>                                bitOr: cogit callerSavedRegMask)
>>> -
>>>                                bitClear: (cogit registerMaskFor:
>>> ReceiverResultReg))]].
>>> -       jmpImmediate jmpTarget:
>>> -       (jmpDestYoung jmpTarget:
>>> -       (jmpSourceOld jmpTarget:
>>> -       (jmpAlreadyRoot jmpTarget:
>>> -               cogit Label))).
>>> -       ^0!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CogObjectRepresentationForSqueakV3>>genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck:
>>> (in category 'compile abstract instructions') -----
>>> + genStoreSourceReg: sourceReg slotIndex: index destReg: destReg
>>> scratchReg: scratchReg inFrame: inFrame needsStoreCheck: needsStoreCheck
>>> +       | jmpImmediate jmpDestYoung jmpSourceOld jmpAlreadyRoot mask
>>> rootBitByteOffset |
>>> +       <var: #jmpImmediate type: #'AbstractInstruction *'>
>>> +       <var: #jmpDestYoung type: #'AbstractInstruction *'>
>>> +       <var: #jmpSourceOld type: #'AbstractInstruction *'>
>>> +       <var: #jmpAlreadyRoot type: #'AbstractInstruction *'>
>>> +       "do the store"
>>> +       cogit MoveR: sourceReg Mw: index * objectMemory wordSize +
>>> objectMemory baseHeaderSize r: destReg.
>>> +       "if no need for the store check then returns"
>>> +       needsStoreCheck ifFalse: [ ^ 0 ].
>>> +       "now the check.  Is value stored an integer?  If so we're done"
>>> +       cogit MoveR: sourceReg R: scratchReg.
>>> +       cogit AndCq: 1 R: scratchReg.
>>> +       jmpImmediate := cogit JumpNonZero: 0.
>>> +       "Get the old/new boundary in scratchReg"
>>> +       cogit MoveAw: objectMemory youngStartAddress R: scratchReg.
>>> +       "Is target young?  If so we're done"
>>> +       cogit CmpR: scratchReg R: destReg. "N.B. FLAGS := destReg -
>>> scratchReg"
>>> +       jmpDestYoung := cogit JumpAboveOrEqual: 0.
>>> +       "Is value stored old?  If so we're done."
>>> +       cogit CmpR: scratchReg R: sourceReg. "N.B. FLAGS := sourceReg -
>>> scratchReg"
>>> +       jmpSourceOld := cogit JumpBelow: 0.
>>> +       "value is young and target is old.
>>> +        Need to make this a root if the root bit is not already set.
>>> +        Test the root bit.  Only need to fetch the byte containing it,
>>> +        which reduces the size of the mask constant."
>>> +       rootBitByteOffset := jmpSourceOld isBigEndian
>>> +                                                       ifTrue:
>>> [objectMemory wordSize - RootBitDigitLength]
>>> +
>>>  ifFalse:[RootBitDigitLength - 1].
>>> +       mask := RootBitDigitLength > 1
>>> +                               ifTrue: [RootBit >> (RootBitDigitLength
>>> - 1 * 8)]
>>> +                               ifFalse: [RootBit].
>>> +       cogit MoveMb: rootBitByteOffset r: destReg R: scratchReg.
>>> +       cogit AndCq: mask R: scratchReg.
>>> +       jmpAlreadyRoot := cogit JumpNonZero: 0.
>>> +       "Root bit is not set.  Call store check to insert dest into root
>>> table."
>>> +       self assert: destReg == ReceiverResultReg.
>>> +       cogit
>>> +               evaluateTrampolineCallBlock:
>>> +                       [cogit
>>> +                               CallRT: ceStoreCheckTrampoline
>>> +                               registersToBeSavedMask: (((cogit
>>> registerMaskFor: sourceReg)
>>> +
>>>                        bitOr: cogit callerSavedRegMask)
>>> +
>>>                        bitClear: (cogit registerMaskFor:
>>> ReceiverResultReg))]
>>> +               protectLinkRegIfNot: inFrame.
>>> +       jmpImmediate jmpTarget:
>>> +       (jmpDestYoung jmpTarget:
>>> +       (jmpSourceOld jmpTarget:
>>> +       (jmpAlreadyRoot jmpTarget:
>>> +               cogit Label))).
>>> +       ^0!
>>>
>>> Item was changed:
>>>   ----- Method: CogVMSimulator>>maybeCheckStackDepth:sp:pc: (in category
>>> 'debug support') -----
>>>   maybeCheckStackDepth: delta sp: sp pc: mcpc
>>>         | asp bcpc startbcpc cogHomeMethod cogBlockMethod csp
>>> debugStackPointers |
>>>         debugStackDepthDictionary ifNil: [^self].
>>>         (self isMachineCodeFrame: framePointer) ifFalse: [^self].
>>>         cogBlockMethod := self mframeCogMethod: framePointer.
>>>         cogHomeMethod := self asCogHomeMethod: cogBlockMethod.
>>>         debugStackPointers := debugStackDepthDictionary
>>>                                                                 at:
>>> cogHomeMethod methodObject
>>>
>>> ifAbsentPut: [self debugStackPointersFor: cogHomeMethod methodObject].
>>>         startbcpc := cogHomeMethod = cogBlockMethod
>>>                                         ifTrue: [self startPCOfMethod:
>>> cogHomeMethod methodObject]
>>>                                         ifFalse: [self startPCOfClosure:
>>> (self pushedReceiverOrClosureOfFrame: framePointer)].
>>>         bcpc := cogit bytecodePCFor: mcpc startBcpc: startbcpc in:
>>> cogBlockMethod.
>>>         self assert: bcpc ~= 0.
>>>         cogBlockMethod ~= cogHomeMethod ifTrue:
>>>                 [| lastbcpc |
>>>                  lastbcpc := cogit lastBytecodePCForBlockAt: startbcpc
>>> in: cogHomeMethod methodObject.
>>>                  bcpc > lastbcpc ifTrue:
>>>                         [bcpc := lastbcpc]].
>>>         asp := self stackPointerIndexForFrame: framePointer WithSP: sp +
>>> objectMemory wordSize.
>>>         csp := debugStackPointers at: bcpc.
>>>         "Compensate lazily for absent receiver sends."
>>>         (NewspeakVM
>>>          and: [asp - delta = csp
>>>          and: [cogit isAbsentReceiverSendAt: mcpc in: cogHomeMethod]])
>>> ifTrue:
>>>                 [csp := debugStackPointers at: bcpc put: csp + 1].
>>>         self assert: asp - delta + 1 = csp!
>>>
>>> Item was added:
>>> + ----- Method:
>>> CurrentImageCoInterpreterFacadeForSpurObjectRepresentation>>immutableBitMask
>>> (in category 'accessing') -----
>>> + immutableBitMask
>>> +       ^objectMemory immutableBitMask!
>>>
>>> Item was added:
>>> + ----- Method: InterpreterPrimitives>>canBeImmutable: (in category
>>> 'object access primitives') -----
>>> + canBeImmutable: oop
>>> +       <option: #IMMUTABILITY>
>>> +       | scheduler processLists |
>>> +
>>> +       self assert: (objectMemory isNonImmediate: oop).
>>> +
>>> +       "For now we fail the primitive for contexts to we ensure there
>>> are no immutable contexts.
>>> +       Later we can consider having immutable contexts and send
>>> cannotReturn callback
>>> +       when returning to an immutable context. That would mean that
>>> setting a context
>>> +       to immutable would require a divorce and returns to immutable
>>> context are
>>> +       necessarily across stack pages"
>>> +       (objectMemory isContext: oop) ifTrue: [ ^ false ].
>>> +
>>> +       "I don't get it for semaphores so they can't be immutable"
>>> +       (objectMemory isSemaphoreObj: oop) ifTrue: [^ false].
>>> +
>>> +       "simple version of process management: we forbid Process and
>>> LinkedList instances to be immutable
>>> +       as well as the Processor and the array of activeProcess"
>>> +       scheduler := self fetchPointer: ValueIndex ofObject: (self
>>> splObj: SchedulerAssociation).
>>> +       processLists := objectMemory fetchPointer: ProcessListsIndex
>>> ofObject: scheduler.
>>> +       oop = scheduler ifTrue: [ ^ false ].
>>> +       oop = processLists ifTrue: [ ^ false ].
>>> +       "Is it a linkedList ?"
>>> +       (objectMemory classIndexOf: (processLists at: 1)) =
>>> (objectMemory classIndexOf: oop) ifTrue: [ ^ false ].
>>> +       "is it a Process ?"
>>> +       (objectMemory classIndexOf: (objectMemory fetchPointer:
>>> ActiveProcessIndex ofObject: scheduler)) =  (objectMemory classIndexOf:
>>> oop) ifTrue: [ ^ false ].
>>> +
>>> +       "The rest of the code is relative to process management: the
>>> Processor (the active
>>> +       process scheduler) can't be immutable, as well as all the
>>> objects relative to Process management "
>>> +       "scheduler := self fetchPointer: ValueIndex ofObject: (self
>>> splObj: SchedulerAssociation).
>>> +       processLists := objectMemory fetchPointer: ProcessListsIndex
>>> ofObject: scheduler.
>>> +       ((objectMemory formatOf: oop) = objectMemory
>>> nonIndexablePointerFormat)
>>> +               ifFalse:
>>> +                       [ (objectMemory isArrayNonImm: oop) ifFalse: [ ^
>>> true ].
>>> +                         ^ (oop = processLists) not ].
>>> +       (objectMemory numSlotsOf: oop) >= 2 ifFalse: [ ^ true ].
>>> +       ""is the oop the scheduler itself ?""
>>> +       oop = scheduler ifTrue: [ ^ false ].
>>> +       1 to: (objectMemory numSlotsOf: processLists) do: [ :i |
>>> +               ""is the oop one of the linked lists ?""
>>> +               (list := processLists at: i) = oop ifTrue: [^ false].
>>> +               ""is the oop one of the runnable process ?""
>>> +               first := objectMemory fetchPointer: FirstLinkIndex
>>> ofObject: list.
>>> +               first = objectMemory nilObject ifFalse:
>>> +                       [ last := objectMemory fetchPointer:
>>> LastLinkIndex ofObject: list.
>>> +                         link := first.
>>> +                         [ link = last ] whileFalse:
>>> +                               [ link = oop ifTrue: [ ^ false ].
>>> +                                 link := objectMemory fetchPointer:
>>> NextLinkIndex ofObject: link. ] ] ]."
>>> +       ^ true!
>>>
>>> Item was changed:
>>>   ----- Method: InterpreterPrimitives>>primitiveFloatAtPut (in category
>>> 'indexing primitives') -----
>>>   primitiveFloatAtPut
>>>         "Provide platform-independent access to 32-bit words comprising
>>>          a Float.  Map index 1 onto the most significant word and index 2
>>>          onto the least significant word."
>>>         | rcvr index oopToStore valueToStore |
>>>         <var: #valueToStore type: #usqInt>
>>>         oopToStore := self stackTop.
>>>         valueToStore := self positive32BitValueOf: oopToStore.
>>>         self successful ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>>         rcvr := self stackValue: 2.
>>>         index := self stackValue: 1.
>>>         (objectMemory isImmediateFloat: rcvr) ifTrue:
>>>                 [^self primitiveFailFor: PrimErrBadReceiver].
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue: [ (objectMemory isImmutable: rcvr) ifTrue:
>>> [^self primitiveFailFor: PrimErrBadReceiver] ].
>>>         index = ConstOne ifTrue:
>>>                 [objectMemory storeLong32: (VMBIGENDIAN ifTrue: [0]
>>> ifFalse: [1])
>>>                         ofObject: rcvr
>>>                         withValue: valueToStore.
>>>                 ^self pop: 3 thenPush: oopToStore].
>>>         index = ConstTwo ifTrue:
>>>                 [objectMemory storeLong32: (VMBIGENDIAN ifTrue: [1]
>>> ifFalse: [0])
>>>                         ofObject: rcvr
>>>                         withValue: valueToStore.
>>>                 ^self pop: 3 thenPush: oopToStore].
>>>         self primitiveFailFor: ((objectMemory isIntegerObject: index)
>>>                                                         ifTrue:
>>> [PrimErrBadIndex]
>>>                                                         ifFalse:
>>> [PrimErrBadArgument])!
>>>
>>> Item was added:
>>> + ----- Method: InterpreterPrimitives>>primitiveGetImmutability (in
>>> category 'object access primitives') -----
>>> + primitiveGetImmutability
>>> +       <option: #IMMUTABILITY>
>>> +       | rcvr bool |
>>> +       rcvr := self stackValue: 0.
>>> +       bool := (objectMemory isOopImmutable: rcvr)
>>> +               ifTrue: [ TrueObject ]
>>> +               ifFalse: [ FalseObject ].
>>> +       self pop: argumentCount thenPush: (self splObj: bool)!
>>>
>>> Item was changed:
>>>   ----- Method: InterpreterPrimitives>>primitiveIntegerAtPut (in
>>> category 'sound primitives') -----
>>>   primitiveIntegerAtPut
>>>         "Return the 32bit signed integer contents of a words receiver"
>>>         | index rcvr sz addr value valueOop |
>>>         <var: 'value' type: 'int'>
>>>         valueOop := self stackValue: 0.
>>>         index := self stackIntegerValue: 1.
>>>         value := self signed32BitValueOf: valueOop.
>>>         self successful ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>>         rcvr := self stackValue: 2.
>>>         (objectMemory isWords: rcvr) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrInappropriate].
>>> +       self cppIf: IMMUTABILITY "isWords: ensure non immediate"
>>> +               ifTrue: [ (objectMemory isImmutable: rcvr) ifTrue: [
>>> ^self primitiveFailFor: PrimErrInappropriate ] ].
>>>         sz := objectMemory lengthOf: rcvr.  "number of fields"
>>>         (index >= 1 and: [index <= sz]) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadIndex].
>>>         "4 = 32 bits / 8"
>>>         addr := rcvr + objectMemory baseHeaderSize + (index - 1 * 4).
>>> "for zero indexing"
>>>         value := objectMemory intAt: addr put: value.
>>>         self pop: 3 thenPush: valueOop "pop all; return value"
>>>   !
>>>
>>> Item was changed:
>>>   ----- Method: InterpreterPrimitives>>primitiveObjectAtPut (in category
>>> 'object access primitives') -----
>>>   primitiveObjectAtPut
>>>         "Store a literal into a CompiledMethod at the given index.
>>> Defined for CompiledMethods only."
>>>         | thisReceiver index newValue |
>>>         newValue := self stackValue: 0.
>>>         index := self stackValue: 1.
>>>         ((objectMemory isNonIntegerObject: index)
>>>          or: [index = ConstOne and: [(objectMemory isNonIntegerObject:
>>> newValue)]]) ifTrue:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>>         index := objectMemory integerValueOf: index.
>>>         thisReceiver := self stackValue: 2.
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue: [ (objectMemory isImmutable: thisReceiver)
>>> ifTrue: [ ^self primitiveFailFor: PrimErrInappropriate ] ].
>>>         (index > 0 and: [index <= ((objectMemory literalCountOf:
>>> thisReceiver) + LiteralStart)]) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadIndex].
>>>         objectMemory storePointer: index - 1 ofObject: thisReceiver
>>> withValue: newValue.
>>>         self pop: 3 thenPush: newValue!
>>>
>>> Item was added:
>>> + ----- Method: InterpreterPrimitives>>primitiveSetImmutability (in
>>> category 'object access primitives') -----
>>> + primitiveSetImmutability
>>> +       <option: #IMMUTABILITY>
>>> +       | rcvr boolean wasImmutable |
>>> +       rcvr := self stackValue: 1.
>>> +       (objectMemory isImmediate: rcvr) ifTrue: [ ^ self
>>> primitiveFailFor: PrimErrInappropriate ].
>>> +       boolean := self booleanValueOf: self stackTop.
>>> +       self successful ifFalse:
>>> +               [^self primitiveFailFor: PrimErrBadArgument].
>>> +       boolean ifTrue:
>>> +               [ (self canBeImmutable: rcvr) ifFalse: [ ^ self
>>> primitiveFailFor: PrimErrInappropriate ] ].
>>> +       wasImmutable := (objectMemory isOopImmutable: rcvr)
>>> +               ifTrue: [ TrueObject ]
>>> +               ifFalse: [ FalseObject ].
>>> +       objectMemory setIsImmutableOf: rcvr to: boolean.
>>> +       self pop: argumentCount thenPush: (self splObj: wasImmutable)!
>>>
>>> Item was changed:
>>>   ----- Method: InterpreterPrimitives>>primitiveShortAtPut (in category
>>> 'sound primitives') -----
>>>   primitiveShortAtPut
>>>         "Treat the receiver, which can be indexible by either bytes or
>>> words, as an array
>>>          of signed 16-bit values. Set the contents of the given index to
>>> the given value.
>>>          Note that the index specifies the i-th 16-bit entry, not the
>>> i-th byte or word."
>>>
>>>         | index rcvr value |
>>>         value := self stackTop.
>>>         index := self stackValue: 1.
>>>         ((objectMemory isIntegerObject: value)
>>>          and: [(objectMemory isIntegerObject: index)
>>>          and: [value := objectMemory integerValueOf: value.
>>>                   (value >= -32768) and: [value <= 32767]]]) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>>         rcvr := self stackValue: 2.
>>>         (objectMemory isWordsOrBytes: rcvr) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrInappropriate].
>>> +       self cppIf: IMMUTABILITY "isWordsOrBytes ensure non immediate"
>>> +               ifTrue: [ (objectMemory isImmutable: rcvr) ifTrue: [
>>> ^self primitiveFailFor: PrimErrInappropriate ] ].
>>>         index := objectMemory integerValueOf: index.
>>>         (index >= 1 and: [index <= (objectMemory num16BitUnitsOf:
>>> rcvr)]) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadIndex].
>>>         objectMemory storeShort16: index - 1 ofObject: rcvr withValue:
>>> value.
>>>         self pop: 3 thenPush: (objectMemory integerObjectOf: value)!
>>>
>>> Item was added:
>>> + ----- Method:
>>> ObjectMemory>>storePointerImmutabilityCheck:ofObject:withValue: (in
>>> category 'object access') -----
>>> + storePointerImmutabilityCheck: index ofObject: rcvr withValue: top
>>> +       <inline: true>
>>> +       ^ self storePointer: index ofObject: rcvr withValue: top!
>>>
>>> Item was changed:
>>>   ----- Method: SpurMemoryManager>>clone: (in category 'allocation')
>>> -----
>>>   clone: objOop
>>>         | numSlots fmt newObj |
>>>         numSlots := self numSlotsOf: objOop.
>>>         fmt := self formatOf: objOop.
>>>         numSlots > self maxSlotsForNewSpaceAlloc
>>>                 ifTrue:
>>>                         [newObj := self allocateSlotsInOldSpace: numSlots
>>>                                                         format: fmt
>>>                                                         classIndex:
>>> (self classIndexOf: objOop)]
>>>                 ifFalse:
>>>                         [newObj := self allocateSlots: numSlots
>>>                                                         format: fmt
>>>                                                         classIndex:
>>> (self classIndexOf: objOop)].
>>>         newObj ifNil:
>>>                 [^0].
>>>         (self isPointersFormat: fmt)
>>>                 ifTrue:
>>>                         [| hasYoung |
>>>                          hasYoung := false.
>>>                          0 to: numSlots - 1 do:
>>>                                 [:i| | oop |
>>>                                 oop := self fetchPointer: i ofObject:
>>> objOop.
>>>                                 (self isNonImmediate: oop) ifTrue:
>>>                                         [(self isForwarded: oop) ifTrue:
>>>                                                 [oop := self
>>> followForwarded: oop].
>>>                                         ((self isNonImmediate: oop)
>>>                                          and: [self isYoungObject: oop])
>>> ifTrue:
>>>                                                 [hasYoung := true]].
>>>                                 self storePointerUnchecked: i
>>>                                         ofObject: newObj
>>>                                         withValue: oop].
>>>                         (hasYoung
>>>                          and: [(self isYoungObject: newObj) not]) ifTrue:
>>>                                 [scavenger remember: newObj]]
>>>                 ifFalse:
>>>                         [0 to: numSlots - 1 do:
>>>                                 [:i|
>>>                                 self storePointerUnchecked: i
>>>                                         ofObject: newObj
>>>                                         withValue: (self fetchPointer: i
>>> ofObject: objOop)].
>>>                          fmt >= self firstCompiledMethodFormat ifTrue:
>>>                                 [coInterpreter
>>> maybeFixClonedCompiledMethod: newObj.
>>>                                  ((self isOldObject: newObj)
>>>                                   and: [(self isYoungObject: objOop) or:
>>> [self isRemembered: objOop]]) ifTrue:
>>>                                         [scavenger remember: newObj]]].
>>>         ^newObj!
>>>
>>> Item was changed:
>>>   ----- Method: SpurMemoryManager>>containsOnlyValidBecomeObjects: (in
>>> category 'become implementation') -----
>>>   containsOnlyValidBecomeObjects: array
>>>         "Answer 0 if the array contains only unpinned non-immediates.
>>>          Otherwise answer an informative error code.
>>>          Can't become: immediates!!  Shouldn't become pinned objects."
>>> +       | fieldOffset effectsFlags oop errCode |
>>> -       | fieldOffset effectsFlags oop |
>>>         fieldOffset := self lastPointerOfArray: array.
>>>         effectsFlags := 0.
>>>         "same size as array2"
>>>         [fieldOffset >= self baseHeaderSize] whileTrue:
>>>                 [oop := self longAt: array + fieldOffset.
>>>                  (self isOopForwarded: oop) ifTrue:
>>>                         [oop := self followForwarded: oop.
>>>                          self longAt: array + fieldOffset put: oop].
>>> +                (errCode := self isOopValidBecome: oop) = 0 ifFalse: [^
>>> errCode].
>>> -                (self isImmediate: oop) ifTrue: [^PrimErrInappropriate].
>>> -                (self isPinned: oop) ifTrue: [^PrimErrObjectIsPinned].
>>>                  effectsFlags := effectsFlags bitOr: (self
>>> becomeEffectFlagsFor: oop).
>>>                  fieldOffset := fieldOffset - self bytesPerOop].
>>>         "only set flags after checking all args."
>>>         becomeEffectsFlags := effectsFlags.
>>>         ^0!
>>>
>>> Item was changed:
>>>   ----- Method: SpurMemoryManager>>forward:to: (in category 'become
>>> implementation') -----
>>>   forward: obj1 to: obj2
>>>         self set: obj1 classIndexTo: self isForwardedObjectClassIndexPun
>>> formatTo: self forwardedFormat.
>>> +       self cppIf: IMMUTABILITY ifTrue: [ self setIsImmutableOf: obj1
>>> to: false ].
>>>         self storePointer: 0 ofForwarder: obj1 withValue: obj2.
>>>         "For safety make sure the forwarder has a slot count that
>>> includes its contents."
>>>         (self rawNumSlotsOf: obj1) = 0 ifTrue:
>>>                 [self rawNumSlotsOf: obj1 put: 1]!
>>>
>>> Item was added:
>>> + ----- Method: SpurMemoryManager>>immutableBitMask (in category 'header
>>> format') -----
>>> + immutableBitMask
>>> +       "mask the immutable bit in the base header word"
>>> +       <option: #IMMUTABILITY>
>>> +       ^ 1 << self immutableBitShift!
>>>
>>> Item was added:
>>> + ----- Method: SpurMemoryManager>>isOopValidBecome: (in category
>>> 'become implementation') -----
>>> + isOopValidBecome: oop
>>> +       "Answers 0 if the oop can be become.
>>> +       Answers an error code in the other case"
>>> +       (self isImmediate: oop) ifTrue: [^PrimErrInappropriate].
>>> +       (self isPinned: oop) ifTrue: [^PrimErrObjectIsPinned].
>>> +       self
>>> +               cppIf: IMMUTABILITY
>>> +               ifTrue: [ (self isImmutable: oop) ifTrue:
>>> [^PrimErrInappropriate] ].
>>> +       ^ 0!
>>>
>>> Item was added:
>>> + ----- Method:
>>> SpurMemoryManager>>storePointerImmutabilityCheck:ofObject:withValue: (in
>>> category 'object access') -----
>>> + storePointerImmutabilityCheck: fieldIndex ofObject: objOop withValue:
>>> valuePointer
>>> +       "Note must check here for stores of young objects into old ones."
>>> +       <inline: true> "normal send in cannotAssign"
>>> +
>>> +       self cppIf: IMMUTABILITY ifTrue:
>>> +               [ self assert: (self isImmediate: objOop) not.
>>> +               (self isImmutable: objOop) ifTrue:
>>> +                       [ ^ coInterpreter cannotAssign: valuePointer to:
>>> objOop withIndex: fieldIndex ] ].
>>> +
>>> +       ^ self storePointer: fieldIndex ofObject: objOop withValue:
>>> valuePointer!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter class>>initializePrimitiveTable (in
>>> category 'initialization') -----
>>> (excessive size, no diff calculated)
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>bytecodePrimAtPut (in category 'common
>>> selector sends') -----
>>>   bytecodePrimAtPut
>>>         "BytecodePrimAtPut will only succeed if the receiver is in the
>>> atCache.
>>>         Otherwise it will fail so that the more general primitiveAtPut
>>> will put it in the
>>>         cache after validating that message lookup results in a
>>> primitive response.
>>>          Override to insert in the atCache here.  This is necessary
>>> since once there
>>>          is a compiled at:[put:] primitive method (which doesn't use the
>>> at: cache) the
>>>          only way something can get installed in the atCache is here."
>>> +       | index rcvr atIx value correctRcvr |
>>> -       | index rcvr atIx value |
>>>         value := self internalStackTop.
>>>         index := self internalStackValue: 1.
>>>         rcvr := self internalStackValue: 2.
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue: [ correctRcvr := objectMemory isOopMutable: rcvr
>>> ]
>>> +               ifFalse: [ correctRcvr := objectMemory isNonImmediate:
>>> rcvr ].
>>> +       (correctRcvr
>>> -       ((objectMemory isNonImmediate: rcvr)
>>>          and: [objectMemory isIntegerObject: index]) ifTrue:
>>>                 [atIx := (rcvr bitAnd: AtCacheMask) + AtPutBase.  "Index
>>> into atPutCache"
>>>                  (atCache at: atIx+AtCacheOop) ~= rcvr ifTrue:
>>>                         [lkupClassTag := objectMemory
>>> fetchClassTagOfNonImm: rcvr.
>>>                          messageSelector := self specialSelector: 17.
>>>                          (self lookupInMethodCacheSel: messageSelector
>>> classTag: lkupClassTag) ifFalse:
>>>                                 [argumentCount := 2.
>>>                                  ^self commonSendOrdinary].
>>>                          primitiveFunctionPointer == #primitiveAtPut
>>>                                 ifTrue: [self install: rcvr inAtCache:
>>> atCache at: atIx string: false]
>>>                                 ifFalse:
>>>                                         [primitiveFunctionPointer ==
>>> #primitiveStringAtPut
>>>                                                 ifTrue: [self install:
>>> rcvr inAtCache: atCache at: atIx string: true]
>>>                                                 ifFalse:
>>>                                                         [argumentCount
>>> := 2.
>>>                                                          ^self
>>> commonSendOrdinary]]].
>>>                  self successful ifTrue:
>>>                         [self commonVariable: rcvr at: (objectMemory
>>> integerValueOf: index) put: value cacheIndex: atIx].
>>>                  self successful ifTrue:
>>>                         [self fetchNextBytecode.
>>>                          ^self internalPop: 3 thenPush: value].
>>>                  self initPrimCall].
>>>
>>>         messageSelector := self specialSelector: 17.
>>>         argumentCount := 2.
>>>         self normalSend!
>>>
>>> Item was added:
>>> + ----- Method: StackInterpreter>>cannotAssign:to:withIndex: (in
>>> category 'stack bytecodes') -----
>>> + cannotAssign: resultObj to: targetObj withIndex: index
>>> +       <option: #IMMUTABILITY>
>>> +       <inline: true> "because of use of normalSend..."
>>> +       self internalPush: targetObj.
>>> +       self internalPush: resultObj.
>>> +       self internalPush: (self integerObjectOf: index + 1).
>>> +       messageSelector := self splObj: SelectorAttemptToAssign.
>>> +       argumentCount := 2.
>>> +       ^ self normalSend!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>commonAtPut: (in category 'indexing
>>> primitive support') -----
>>>   commonAtPut: stringy
>>>         "This code is called if the receiver responds primitively to
>>> at:Put:.
>>>          N.B. this does *not* use the at cache, instead inlining
>>> stObject:at:put:.
>>>          Using the at cache here would require that callers set
>>> messageSelector
>>>          and lkupClass and that is onerous and error-prone, and in any
>>> case,
>>>          inlining produces much better performance than using the at
>>> cache here."
>>> +       | value index rcvr badRcvr |
>>> -       | value index rcvr |
>>>         <inline: true> "to get it inlined in primitiveAtPut and
>>> primitiveStringAtPut"
>>>         self initPrimCall.
>>>         rcvr := self stackValue: 2.
>>>         index := self stackValue: 1.
>>>         value := self stackTop.
>>> +       self cppIf: IMMUTABILITY
>>> +               ifTrue: [ badRcvr := objectMemory isOopImmutable: rcvr ]
>>> +               ifFalse: [ badRcvr := objectMemory isImmediate: rcvr ].
>>> +       badRcvr ifTrue:
>>> -       (objectMemory isImmediate: rcvr) ifTrue:
>>>                 [^self primitiveFailFor: PrimErrInappropriate].
>>>         "No need to test for large positive integers here.  No object
>>> has 1g elements"
>>>         ((objectMemory isNonIntegerObject: index)
>>>          or: [argumentCount > 2 "e.g. object:basicAt:put:"
>>>                  and: [objectMemory isForwarded: rcvr]]) ifTrue:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>>         index := objectMemory integerValueOf: index.
>>>         stringy
>>>                 ifTrue: [self stObject: rcvr at: index put: (self
>>> asciiOfCharacter: value)]
>>>                 ifFalse: [self stObject: rcvr at: index put: value].
>>>         self successful ifTrue:
>>>                 [self pop: argumentCount+1 thenPush: value]!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>extStoreAndPopLiteralVariableBytecode
>>> (in category 'stack bytecodes') -----
>>>   extStoreAndPopLiteralVariableBytecode
>>>         "236            11101100        i i i i i i i i Pop and Store
>>> Literal Variable #iiiiiiii (+ Extend A * 256)"
>>> +       | variableIndex value |
>>> +       variableIndex := self fetchByte + (extA << 8).
>>> +       self fetchNextBytecode.
>>> +       value := self internalStackTop.
>>> +       self internalPop: 1.
>>> +       extA := 0.
>>> +       self storeLiteralVariable: variableIndex withValue: value!
>>> -       self extStoreLiteralVariableBytecode.
>>> -       self internalPop: 1!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>extStoreAndPopReceiverVariableBytecode
>>> (in category 'stack bytecodes') -----
>>>   extStoreAndPopReceiverVariableBytecode
>>>         "235            11101011        i i i i i i i i Pop and Store
>>> Receiver Variable #iiiiiii (+ Extend A * 256)"
>>> +       | variableIndex value |
>>> +       variableIndex := self fetchByte + (extA << 8).
>>> +       self fetchNextBytecode.
>>> +       extA := 0.
>>> +       value := self internalStackTop.
>>> +       self internalPop: 1.
>>> +       self storeMaybeContextReceiverVariable: variableIndex withValue:
>>> value!
>>> -       self extStoreReceiverVariableBytecode.
>>> -       self internalPop: 1!
>>>
>>
>>
>> This used to read
>>
>> storeAndPopReceiverVariableBytecode
>> | rcvr top |
>> rcvr := self receiver.
>> top := self internalStackTop.
>> objectMemory storePointer: (currentBytecode bitAnd: 7) ofObject: rcvr
>> withValue: top.
>> self fetchNextBytecode.
>> self internalPop: 1
>>
>> Note how currentBytecode is used before fetchNextBytecode.
>>  fetchNextBytecode assigns currentBytecode:
>>
>> fetchNextBytecode
>> "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."
>>
>> self cppIf: MULTIPLEBYTECODESETS
>> ifTrue: [currentBytecode := self fetchByte + bytecodeSetSelector]
>> ifFalse: [currentBytecode := self fetchByte]
>>
>> So your rewrite to
>>
>> storeAndPopReceiverVariableBytecode
>> | rcvr top |
>> rcvr := self receiver.
>> top := self internalStackTop.
>> self internalPop: 1.
>> self fetchNextBytecode.
>> objectMemory storePointerImmutabilityCheck: (currentBytecode bitAnd: 7)
>> ofObject: rcvr withValue: top
>>
>> 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:
>>
>> storeAndPopReceiverVariableBytecode
>> | rcvr top |
>> rcvr := self receiver.
>> top := self internalStackTop.
>> self internalPop: 1.
>> self
>> cCode: "Slang will inline currentBytecode to a constant so this will work
>> in C"
>> [self fetchNextBytecode.
>> objectMemory
>> storePointerImmutabilityCheck: (currentBytecode bitAnd: 7)
>> ofObject: rcvr
>> withValue: top]
>> inSmalltalk: "But in Smalltalk we must use the currentBytecode's value,
>> not the next"
>> [| instVarIndex |
>> instVarIndex := currentBytecode bitAnd: 7.
>> self fetchNextBytecode.
>> objectMemory
>> storePointerImmutabilityCheck: instVarIndex
>> ofObject: rcvr
>> withValue: top]
>>
>> This needs to happen anywhere you use currentBytecode in the new
>> immutability code.  We /don't/ want to use a variable to hold
>> currentBytecode because that won't get inlined quite as nicely by Slang.
>>
>> Item was changed:
>>>   ----- Method: StackInterpreter>>extendedStoreAndPopBytecode (in
>>> category 'stack bytecodes') -----
>>>   extendedStoreAndPopBytecode
>>> +       <inline: true>
>>> +       self extendedStoreBytecodePop: true
>>> -
>>> -       self extendedStoreBytecode.
>>> -       self internalPop: 1.
>>>   !
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>extendedStoreBytecode (in category
>>> 'stack bytecodes') -----
>>>   extendedStoreBytecode
>>> -       | descriptor variableType variableIndex |
>>>         <inline: true>
>>> +       self extendedStoreBytecodePop: false!
>>> -       descriptor := self fetchByte.
>>> -       self fetchNextBytecode.
>>> -       variableType := descriptor >> 6 bitAnd: 3.
>>> -       variableIndex := descriptor bitAnd: 63.
>>> -       variableType = 0 ifTrue:
>>> -               [^objectMemory storePointer: variableIndex ofObject:
>>> self receiver withValue: self internalStackTop].
>>> -       variableType = 1 ifTrue:
>>> -               [^self temporary: variableIndex in: localFP put: self
>>> internalStackTop].
>>> -       variableType = 3 ifTrue:
>>> -               [^self storeLiteralVariable: variableIndex withValue:
>>> self internalStackTop].
>>> -       self error: 'illegal store'!
>>>
>>> Item was added:
>>> + ----- Method: StackInterpreter>>extendedStoreBytecodePop: (in category
>>> 'stack bytecodes') -----
>>> + extendedStoreBytecodePop: popBoolean
>>> +       | descriptor variableType variableIndex value |
>>> +       <inline: true>
>>> +       descriptor := self fetchByte.
>>> +       self fetchNextBytecode.
>>> +       variableType := descriptor >> 6 bitAnd: 3.
>>> +       variableIndex := descriptor bitAnd: 63.
>>> +       value := self internalStackTop.
>>> +       popBoolean ifTrue: [ self internalPop: 1 ].
>>> +       variableType = 0 ifTrue:
>>> +               [^objectMemory storePointerImmutabilityCheck:
>>> variableIndex ofObject: self receiver withValue: value].
>>> +       variableType = 1 ifTrue:
>>> +               [^self temporary: variableIndex in: localFP put: value].
>>> +       variableType = 3 ifTrue:
>>> +               [^self storeLiteralVariable: variableIndex withValue:
>>> value].
>>> +       self error: 'illegal store'
>>> + !
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>storeAndPopReceiverVariableBytecode
>>> (in category 'stack bytecodes') -----
>>>   storeAndPopReceiverVariableBytecode
>>>         "Note: This code uses
>>>         storePointerUnchecked:ofObject:withValue: and does the
>>>         store check explicitely in order to help the translator
>>>         produce better code."
>>>         | rcvr top |
>>>         rcvr := self receiver.
>>>         top := self internalStackTop.
>>> +       self internalPop: 1.
>>> -       objectMemory storePointer: (currentBytecode bitAnd: 7) ofObject:
>>> rcvr withValue: top.
>>>         self fetchNextBytecode.
>>> +       objectMemory storePointerImmutabilityCheck: (currentBytecode
>>> bitAnd: 7) ofObject: rcvr withValue: top.!
>>> -       self internalPop: 1!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>storeLiteralVariable:withValue: (in
>>> category 'stack bytecodes') -----
>>>   storeLiteralVariable: literalIndex withValue: anObject
>>>         | litVar |
>>>         litVar := self literal: literalIndex.
>>>         "push/store/popLiteralVariable all fetch a literal, and either
>>> read or write the literal's value field.
>>>          The fetch of the literal needs an explicit check (otherwise we
>>> would have to scan all literals in
>>>          all methods in the stack zone, and the entire method on return,
>>> and global variables are relatively
>>>          rare; in my work image 8.7% of literals are globals)."
>>>
>>>         (objectMemory isForwarded: litVar) ifTrue:
>>>                 [litVar := objectMemory followForwarded: litVar].
>>> +       ^objectMemory storePointerImmutabilityCheck: ValueIndex
>>> ofObject: litVar withValue: anObject!
>>> -       ^objectMemory storePointer: ValueIndex ofObject: litVar
>>> withValue: anObject!
>>>
>>> Item was changed:
>>>   ----- Method:
>>> StackInterpreter>>storeMaybeContextReceiverVariable:withValue: (in category
>>> 'stack bytecodes') -----
>>>   storeMaybeContextReceiverVariable: fieldIndex withValue: anObject
>>>         "Must trap accesses to married and widowed contexts.
>>>          But don't want to check on all inst var accesses.  This
>>>          method is only used by the long-form bytecodes, evading the
>>> cost."
>>>         | rcvr |
>>>         rcvr := self receiver.
>>>         ((self isWriteMediatedContextInstVarIndex: fieldIndex)
>>>         and: [(objectMemory isContextNonImm: rcvr)
>>>         and: [self isMarriedOrWidowedContext: rcvr]])
>>>                 ifTrue:
>>>                         [self instVar: fieldIndex ofContext: rcvr put:
>>> anObject]
>>>                 ifFalse:
>>> +                       [objectMemory storePointerImmutabilityCheck:
>>> fieldIndex ofObject: rcvr withValue: anObject]
>>> -                       [objectMemory storePointer: fieldIndex ofObject:
>>> rcvr withValue: anObject]
>>>   !
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreter>>trinaryInlinePrimitive: (in category
>>> 'miscellaneous bytecodes') -----
>>>   trinaryInlinePrimitive: primIndex
>>>         "SistaV1:       248             11111000        iiiiiiii
>>>         mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256)
>>> m=1 means inlined primitive, no hard return after execution."
>>>         <option: #SistaVM>
>>>         | result |
>>>         primIndex caseOf: {
>>>
>>>                 "3000   unchecked Pointer Object>>at:put:.
>>>         The receiver is guaranteed to be a pointer object.  The 0-relative
>>> (1-relative?) index is an in-range SmallInteger"
>>>                 [0]     ->      [result := self internalStackTop.
>>>                                  objectMemory
>>>                                         storePointer: (objectMemory
>>> integerValueOf: (self internalStackValue: 1)) - 1
>>>                                         ofObject: (self
>>> internalStackValue: 2)
>>>                                         withValue: result.
>>>                                  self internalPop: 2;
>>> internalStackTopPut: result].
>>>                 "3001   unchecked Byte Object>>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."
>>>                 [1]     ->      [result := self internalStackTop.
>>>                                  objectMemory
>>>                                         storeByte: (objectMemory
>>> integerValueOf: (self internalStackValue: 1)) - 1
>>>                                         ofObject: (self
>>> internalStackValue: 2)
>>>                                         withValue: (objectMemory
>>> integerValueOf: result).
>>>                                  self internalPop: 2;
>>> internalStackTopPut: result].
>>>                 "3002   unchecked Word Object>>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."
>>>                 [2]     ->      [result := self internalStackTop.
>>>                                  objectMemory
>>>                                         storeShort16: (objectMemory
>>> integerValueOf: (self internalStackValue: 1)) - 1
>>>                                         ofObject: (self
>>> internalStackValue: 2)
>>>                                         withValue: (objectMemory
>>> integerValueOf: result).
>>>                                  self internalPop: 2;
>>> internalStackTopPut: result].
>>>                 "3003   unchecked DoubleWord Object>>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."
>>>                 [3]     ->      [result := self internalStackTop.
>>>                                  objectMemory
>>>                                         storeLong32: (objectMemory
>>> integerValueOf: (self internalStackValue: 1)) - 1
>>>                                         ofObject: (self
>>> internalStackValue: 2)
>>>                                         withValue: (objectMemory
>>> integerValueOf: result).
>>>                                  self internalPop: 2;
>>> internalStackTopPut: result].
>>>                 "3004   unchecked QuadWord Object>>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."
>>>                 [4]     ->      [result := self internalStackTop.
>>>                                  objectMemory
>>>                                         storeLong64: (objectMemory
>>> integerValueOf: (self internalStackValue: 1)) - 1
>>>                                         ofObject: (self
>>> internalStackValue: 2)
>>>                                         withValue: (objectMemory
>>> integerValueOf: result).
>>>                                  self internalPop: 2;
>>> internalStackTopPut: result] }
>>>         otherwise:
>>>                 [localIP := localIP - 3.
>>>                  self respondToUnknownBytecode]!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreterPrimitives>>primitiveInstVarAt (in
>>> category 'object access primitives') -----
>>>   primitiveInstVarAt
>>>         | index rcvr hdr fmt totalLength fixedFields value |
>>>         index := self stackTop.
>>>         rcvr := self stackValue: 1.
>>>         ((objectMemory isNonIntegerObject: index)
>>>          or: [argumentCount > 1 "e.g. object:instVarAt:"
>>>                 and: [objectMemory isOopForwarded: rcvr]]) ifTrue:
>>>                 [^self primitiveFailFor: PrimErrBadArgument].
>>> +       (objectMemory isImmediate: rcvr) ifTrue: [^self
>>> primitiveFailFor: PrimErrInappropriate].
>>>         index := objectMemory integerValueOf: index.
>>>         hdr := objectMemory baseHeader: rcvr.
>>>         fmt := objectMemory formatOfHeader: hdr.
>>>         totalLength := objectMemory lengthOf: rcvr baseHeader: hdr
>>> format: fmt.
>>>         fixedFields := objectMemory fixedFieldsOf: rcvr format: fmt
>>> length: totalLength.
>>>         (index >= 1 and: [index <= fixedFields]) ifFalse:
>>>                 [^self primitiveFailFor: PrimErrBadIndex].
>>>         (fmt = objectMemory indexablePointersFormat
>>>          and: [objectMemory isContextHeader: hdr])
>>>                 ifTrue: [value := self externalInstVar: index - 1
>>> ofContext: rcvr]
>>>                 ifFalse: [value := self subscript: rcvr with: index
>>> format: fmt].
>>>         self pop: argumentCount + 1 thenPush: value!
>>>
>>> Item was changed:
>>>   ----- Method: StackInterpreterPrimitives>>primitiveInstVarAtPut (in
>>> category 'object access primitives') -----
>>>   primitiveInstVarAtPut
>>>         | newValue index rcvr hdr fmt totalLength fixedFields |
>>>         newValue := self stackTop.
>>>         index := self stackValue: 1.
>>>         rcvr := self stackValue: 2.
>>>         ((objectMemory isNonIntegerObject: index)
>>>          or: [argumentCount > 2 "e.g. object:instVarAt:put:"
>>>
>>
>>
> ...
>
> [Message tronqué]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20160106/969b4951/attachment-0001.htm


More information about the Vm-dev mailing list