[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