Tom Braun uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog.seperateMarking-WoC.3338.mcz
==================== Summary ====================
Name: VMMaker.oscog.seperateMarking-WoC.3338 Author: WoC Time: 13 July 2023, 12:53:32.386403 am UUID: 0a4a4524-db9d-4cca-b029-cb4ca9f6eb6c Ancestors: VMMaker.oscog.seperateMarking-WoC.3337
- add object creation barrier at multiple missing points
- add tricolor barrier at missing spots
- change free chunk assignment to unchecked version
=============== Diff against VMMaker.oscog.seperateMarking-WoC.3337 ===============
Item was changed: ----- Method: Cogit>>cogCodeConstituents: (in category 'profiling primitives') ----- cogCodeConstituents: withDetails "Answer the contents of the code zone as an array of pair-wise element, address in ascending address order. Answer a string for a runtime routine or abstract label (beginning, end, etc), a CompiledMethod for a CMMethod, or a selector (presumably a Symbol) for a PIC. If withDetails is true - answer machine-code to bytecode pc mapping information for methods - answer class, target pair information for closed PIC N.B. Since the class tag for the first case of a closed PIC is stored at the send site, it must be collected by scanning methods (see collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method:). Since closed PICs are never shared they always come after the method that references them, so we don't need an extra pass to collect the first case class tags, which are (temporarily) assigned to each closed PIC's methodObject field. But we do need to reset the methodObject fields to zero. This is done in createPICData:, unless memory runs out, in which case it is done by cleanUpFailingCogCodeConstituents:." <api> + <staticallyResolveReceiver: 'objectMemory gc' to: #SpurIncrementalGarbageCollector> | count cogMethod constituents label value | <var: #cogMethod type: #'CogMethod *'> count := trampolineTableIndex / 2 + 3. "+ 3 for start, freeStart and end" cogMethod := self cCoerceSimple: methodZoneBase to: #'CogMethod *'. [cogMethod < methodZone limitZony] whileTrue: [cogMethod isCMFree ifFalse: [count := count + 1]. cogMethod := methodZone methodAfter: cogMethod]. constituents := coInterpreter instantiateClass: coInterpreter classArray indexableSize: count * 2. constituents ifNil: [^constituents]. coInterpreter pushRemappableOop: constituents. ((label := objectMemory stringForCString: 'CogCode') isNil or: [(value := self positiveMachineIntegerFor: codeBase) isNil]) ifTrue: [coInterpreter popRemappableOop. ^nil]. coInterpreter storePointerUnchecked: 0 ofObject: (self maybeTopRemapped: constituents) withValue: label; storePointerUnchecked: 1 ofObject: (self maybeTopRemapped: constituents) withValue: value. 0 to: trampolineTableIndex - 1 by: 2 do: [:i| ((label := objectMemory stringForCString: (trampolineAddresses at: i)) isNil or: [(value := self positiveMachineIntegerFor: (trampolineAddresses at: i + 1) asUnsignedInteger) isNil]) ifTrue: [coInterpreter popRemappableOop. ^nil]. coInterpreter storePointerUnchecked: 2 + i ofObject: (self maybeTopRemapped: constituents) withValue: label; storePointerUnchecked: 3 + i ofObject: (self maybeTopRemapped: constituents) withValue: value]. count := trampolineTableIndex + 2. cogMethod := self cCoerceSimple: methodZoneBase to: #'CogMethod *'. [cogMethod < methodZone limitZony] whileTrue: [cogMethod isCMFree ifFalse: [| profileData | profileData := self profileDataFor: cogMethod withDetails: withDetails. profileData ifNil: [^self cleanUpFailingCogCodeConstituents: cogMethod]. coInterpreter storePointerUnchecked: count ofObject: (self maybeTopRemapped: constituents) withValue: profileData. value := withDetails ifTrue: [self collectCogMethodConstituent: cogMethod] ifFalse: [self positiveMachineIntegerFor: cogMethod asUnsignedInteger]. value ifNil: [^self cleanUpFailingCogCodeConstituents: cogMethod]. coInterpreter storePointerUnchecked: count + 1 ofObject: (self maybeTopRemapped: constituents) withValue: value. count := count + 2]. cogMethod := methodZone methodAfter: cogMethod]. ((label := objectMemory stringForCString: 'CCFree') isNil or: [(value := self positiveMachineIntegerFor: methodZone zoneFree) isNil]) ifTrue: [coInterpreter popRemappableOop. ^nil]. coInterpreter storePointerUnchecked: count ofObject: (self maybeTopRemapped: constituents) withValue: label; storePointerUnchecked: count + 1 ofObject: (self maybeTopRemapped: constituents) withValue: value. ((label := objectMemory stringForCString: 'CCEnd') isNil or: [(value := self positiveMachineIntegerFor: methodZone zoneEnd) isNil]) ifTrue: [coInterpreter popRemappableOop. ^nil]. coInterpreter storePointerUnchecked: count + 2 ofObject: (self maybeTopRemapped: constituents) withValue: label; storePointerUnchecked: count + 3 ofObject: (self maybeTopRemapped: constituents) withValue: value. constituents := coInterpreter popRemappableOop. coInterpreter beRootIfOld: constituents. + objectMemory gc maybeModifyGCFlagsOf: constituents. "would like to assert this, but it requires the leak checked be run :-( self assert: self allMachineCodeObjectReferencesValid." ^constituents!
Item was changed: ----- Method: Cogit>>createCPICData: (in category 'profiling primitives') ----- createCPICData: cPIC "Answer an Array of the PIC's selector, followed by class and targetMethod/doesNotUnderstand: for each entry in the PIC." <var: #cPIC type: #'CogMethod *'> + <staticallyResolveReceiver: 'objectMemory gc' to: #SpurIncrementalGarbageCollector> | picData | <var: #targetMethod type: #'CogMethod *'> self assert: (cPIC methodObject = 0 or: [objectMemory addressCouldBeOop: cPIC methodObject]). picData := objectMemory instantiateClass: objectMemory classArray indexableSize: cPIC cPICNumCases * 2 + 1. picData ifNil: [^picData]. objectMemory storePointerUnchecked: 0 ofObject: picData withValue: cPIC selector. 1 to: cPIC cPICNumCases do: [:i| | pc entryPoint target targetMethod class | pc := self addressOfEndOfCase: i inCPIC: cPIC. i = 1 ifTrue: [class := cPIC methodObject. "first case may have been collected and stored here by collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method:" class = 0 ifTrue: [class := objectMemory nilObject]. "cPIC is unreferenced; likely evolved to OpenPIC" entryPoint := backEnd jumpLongTargetBeforeFollowingAddress: pc] ifFalse: [class := objectRepresentation classForInlineCacheTag: (backEnd literal32BeforeFollowingAddress: pc - backEnd jumpLongConditionalByteSize). entryPoint := backEnd jumpLongConditionalTargetBeforeFollowingAddress: pc]. "Find target from jump. A jump to the MNU entry-point should collect #doesNotUnderstand:" (cPIC containsAddress: entryPoint) ifTrue: [target := objectMemory splObj: SelectorDoesNotUnderstand] ifFalse: [targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'. self assert: targetMethod isCMMethodEtAl. target := targetMethod methodObject]. objectMemory storePointerUnchecked: i * 2 - 1 ofObject: picData withValue: class; storePointerUnchecked: i * 2 ofObject: picData withValue: target]. objectMemory beRootIfOld: picData. + objectMemory gc maybeModifyGCFlagsOf: picData. cPIC methodObject: 0. "restore invariant." ^picData!
Item was changed: ----- Method: InterpreterPrimitives>>primitiveSpurStringReplace (in category 'indexing primitives') ----- primitiveSpurStringReplace "<array> primReplaceFrom: start to: stop with: replacement startingAt: repStart <primitive: 105>" <inline: true> <staticallyResolveReceiver: 'objectMemory gc' to: #SpurIncrementalGarbageCollector> | array start stop repl replStart arrayFmt arrayLength arrayInstSize replFmt replLength replInstSize srcDelta | array := self stackValue: 4. start := self stackValue: 3. stop := self stackValue: 2. repl := self stackValue: 1. replStart := self stackValue: 0.
((objectMemory isNonIntegerObject: start) or: [(objectMemory isNonIntegerObject: stop) or: [(objectMemory isNonIntegerObject: replStart) or: [objectMemory isImmediate: repl]]]) ifTrue: "can happen in LgInt copy" [^self primitiveFailFor: PrimErrBadArgument].
start := objectMemory integerValueOf: start. stop := objectMemory integerValueOf: stop. replStart := objectMemory integerValueOf: replStart.
(stop >= start and: [objectMemory isObjImmutable: array]) ifTrue: [^self primitiveFailFor: PrimErrNoModification].
arrayFmt := objectMemory formatOf: array. replFmt := objectMemory formatOf: repl.
"N.B. In the below start - 1 to: stop - 1 do:, Slang is intelligent enough to use < instead of <= so avoiding the stop - 1." arrayFmt <= objectMemory lastPointerFormat ifTrue: ["Array formats must be the same; but for copying, weak arrays are equivalent to arrays." arrayFmt = objectMemory weakArrayFormat ifTrue: [arrayFmt := objectMemory arrayFormat]. replFmt = objectMemory weakArrayFormat ifTrue: [replFmt := objectMemory arrayFormat]. arrayFmt ~= replFmt ifTrue: [^self primitiveFailFor: PrimErrInappropriate].
arrayLength := objectMemory numSlotsOf: array. arrayInstSize := objectMemory fixedFieldsOf: array format: arrayFmt length: arrayLength. replLength := objectMemory numSlotsOf: repl. replInstSize := objectMemory fixedFieldsOf: repl format: replFmt length: replLength. (start >= 1 and: [start - 1 <= stop and: [stop + arrayInstSize <= arrayLength and: [replStart >= 1 and: [stop - start + replStart + replInstSize <= replLength]]]]) ifFalse: [^self primitiveFailFor: PrimErrBadIndex].
start := start + arrayInstSize. stop := stop + arrayInstSize. srcDelta := (replStart + replInstSize) - start. (objectMemory isOldObject: array) ifTrue: [| mustRemember oop | mustRemember := false. start - 1 to: stop - 1 do: [:i | oop := objectMemory fetchPointer: srcDelta + i ofObject: repl. (objectMemory isYoung: oop) ifTrue: [mustRemember := true]. objectMemory storePointerUnchecked: i ofObject: array withValue: oop]. mustRemember + ifTrue: [objectMemory possibleRootStoreInto: array]. + + objectMemory gc isIncremental + ifTrue: [ + "We push the work to the gc. Otherwise we would have to check for every replacement if it is marked. " + (objectMemory marker isCurrentlyMarking and: [objectMemory isMarked: array]) + ifTrue: [objectMemory gc retractWavefrontFrom: array startingAt: start]]] - ifTrue: [objectMemory possibleRootStoreInto: array] - ifFalse: [ - objectMemory gc isIncremental - ifTrue: [ - "We push the work to the gc. Otherwise we would have to check for every replacement if it is marked. " - (objectMemory marker isCurrentlyMarking and: [objectMemory isMarked: array]) - ifTrue: [objectMemory gc retractWavefrontFrom: array startingAt: start]]]] ifFalse: [start - 1 to: stop - 1 do: [:i | objectMemory storePointerUnchecked: i ofObject: array withValue: (objectMemory fetchPointer: srcDelta + i ofObject: repl)]]. "We might consider comparing stop - start to some value here and using forceInterruptCheck" ^self pop: argumentCount "leave rcvr on stack"].
"Non-pointer array formats must match" arrayLength := objectMemory lengthOf: array format: arrayFmt. replLength := objectMemory lengthOf: repl format: replFmt. arrayFmt := objectMemory classFormatFromInstFormat: arrayFmt. replFmt := objectMemory classFormatFromInstFormat: replFmt. (arrayFmt = replFmt and: [arrayFmt >= objectMemory sixtyFourBitIndexableFormat and: [arrayFmt < objectMemory firstCompiledMethodFormat]]) ifFalse: [^self primitiveFailFor: PrimErrInappropriate]. (start >= 1 and: [start - 1 <= stop and: [stop <= arrayLength and: [replStart >= 1 and: [stop - start + replStart <= replLength]]]]) ifFalse: [^self primitiveFailFor: PrimErrBadIndex]. srcDelta := replStart - start. arrayFmt >= objectMemory firstShortFormat ifTrue: "8 & 16-bit word type objects" [arrayFmt >= objectMemory firstByteFormat ifTrue: "byte-type objects" [start - 1 to: stop - 1 do: [:i | objectMemory storeByte: i ofObject: array withValue: (objectMemory fetchByte: srcDelta + i ofObject: repl)]] ifFalse: "short type objects" [start - 1 to: stop - 1 do: [:i | objectMemory storeShort16: i ofObject: array withValue: (objectMemory fetchShort16: srcDelta + i ofObject: repl)]]] ifFalse: "32 & 64-bit word type objects" [arrayFmt >= objectMemory firstLongFormat ifTrue: "word-type objects" [start - 1 to: stop - 1 do: [:i | objectMemory storeLong32: i ofObject: array withValue: (objectMemory fetchLong32: srcDelta + i ofObject: repl)]] ifFalse: "long type objects" [start - 1 to: stop - 1 do: [:i | objectMemory storeLong64: i ofObject: array withValue: (objectMemory fetchLong64: srcDelta + i ofObject: repl)]]]. "We might consider comparing stop - start to some value here and using forceInterruptCheck" ^self pop: argumentCount "leave rcvr on stack"!
Item was changed: ----- Method: SpurIncrementalGarbageCollector>>maybeModifyGCFlagsOf: (in category 'object creation barriers') ----- maybeModifyGCFlagsOf: objOop
"when allocating a new object behind the current sweeping high mark it should be allocated black so it does not get garbage collected although we do not know if this is correct (but to know this we would need to mark again and that is expensive + the object was allocated in old space therefore lets assume we want to keep it around (black allocation))" + <api> <inline: true> ((manager isOldObject: objOop) and: [self inSweepingAheadOfSweepersPosition: objOop]) ifTrue: [manager setIsMarkedOf: objOop to: true]!
Item was changed: + ----- Method: SpurIncrementalGarbageCollector>>retractWavefrontFrom:startingAt: (in category 'barrier') ----- - ----- Method: SpurIncrementalGarbageCollector>>retractWavefrontFrom:startingAt: (in category 'as yet unclassified') ----- retractWavefrontFrom: objOop startingAt: index
"inspired by Boehm write barrier. Retract the color of an already black object. Do not unmark it, as we want to be smart and continue marking from the given index. This method is currently intended for genPrimitiveStringReplace and should not be used from anywhere else" <api> self assert: (manager isOldObject: objOop). self assert: (marker isCurrentlyMarking). + self assert: (manager isMarked: objOop). + + marker isCurrentlyMarking ifFalse: [manager debugger]. + + coInterpreter cr; print: 'retract: '; printHex: objOop; tab; printNum: index; cr; tab; flush. + manager push: objOop onObjStack: manager markStack. + manager + push: (manager integerObjectOf: index) + onObjStack: manager markStack! - (manager isMarked: objOop) - ifTrue: [ - manager push: objOop onObjStack: manager markStack. - manager - push: (manager integerObjectOf: index) - onObjStack: manager markStack]!
Item was changed: ----- Method: SpurIncrementalSweeper>>cleanUpLilliputianChunks (in category 'as yet unclassified') ----- cleanUpLilliputianChunks
"- remove all lilliputian chunks in the range of this sweep - patch the lilliputian free list with the saved values on the MarkStack - append all newly created (or already existing but previously here removed) lilliputian chunks" self flag: #Todo. "it would be nicer if we appened lilliputian chunk lists instead of prepending. Not sure if it has any preformance impact"
(manager isEmptyObjStack: manager markStack) not ifTrue: [ | node prev | node := manager freeLists at: 2. prev := 0. [node ~= 0 or: [(manager isEmptyObjStack: manager markStack) not]] whileTrue: [ "we already found the end of the list, although we did not connect all links from the list in the swept area" node = 0 ifTrue: [node := (manager popObjStack: manager markStack). manager noCheckPush: 0 onObjStack: manager markStack. "attach the element to the previous tail of the list" manager setNextFreeChunkOf: prev withValue: node isLilliputianSize: true]. (node >= sweepingStart and: [node < currentSweepingEntity]) ifTrue: [ "the node is in the swept area" self assert: (manager sizeOfObjStack: manager markStack) > 0. node := (manager popObjStack: manager markStack).
"We popped the end of the list. As there are more links use them first" (node = 0 and: [(manager sizeOfObjStack: manager markStack) > 0]) ifTrue: [ node := (manager popObjStack: manager markStack). manager noCheckPush: 0 onObjStack: manager markStack]. manager totalFreeOldSpace: manager totalFreeOldSpace - manager lilliputianChunkSize. prev = 0 ifTrue: [manager freeLists at: 2 put: node] + ifFalse: ["we do not know what node points to at this point. Could be a valid chunk or to some corrupted data. + If corrupted data we will correct this in further iterations, but for now suppress assert" + manager storePointerNoAssert: manager freeChunkNextIndex ofFreeChunk: prev withValue: node]] - ifFalse: [manager setNextFreeChunkOf: prev withValue: node isLilliputianSize: true]] ifFalse: [ prev := node. node := (manager fetchPointer: manager freeChunkNextIndex ofFreeChunk: node)]]].
self assert: (manager isEmptyObjStack: manager markStack). lilliputianListEnd ~= 0 ifTrue: [ manager setNextFreeChunkOf: lilliputianListEnd withValue: (manager freeLists at: 2) isLilliputianSize: true. manager freeLists at: 2 put: lilliputianList. manager totalFreeOldSpace: manager totalFreeOldSpace + (lilliputianListSize * manager lilliputianChunkSize)]. self assert: manager totalFreeOldSpace = manager totalFreeListBytes. "update free lists mask just to be sure as we probably manipulated it here" (manager freeLists at: 2) = 0 ifTrue: [manager freeListsMask: (manager freeListsMask bitClear: 2)] ifFalse: [manager freeListsMask: (manager freeListsMask bitOr: 2r100)]. self assert: manager bitsSetInFreeSpaceMaskForAllFreeLists !
Item was changed: ----- Method: SpurMemoryManager>>inPlaceBecome:and:copyHashFlag: (in category 'become implementation') ----- inPlaceBecome: obj1 and: obj2 copyHashFlag: copyHashFlag <inline: #never> "in an effort to fix a compiler bug with two-way become post r3427" "Do become in place by swapping object contents." | o1HasYoung o2HasYoung fmt | self assert: (self numSlotsOf: obj1) = (self numSlotsOf: obj2). self assert: ((self rawHashBitsOf: obj1) = 0 or: [(self classOrNilAtIndex: (self rawHashBitsOf: obj1)) ~= obj1]). self assert: ((self rawHashBitsOf: obj2) = 0 or: [(self classOrNilAtIndex: (self rawHashBitsOf: obj2)) ~= obj2]). "swap headers, but swapping headers swaps remembered bits and hashes; remembered bits must be unswapped and hashes may be unswapped if copyHash is false." false ifTrue: [self naiveSwapHeaders: obj1 and: obj2 copyHashFlag: copyHashFlag] ifFalse: [self cleverSwapHeaders: obj1 and: obj2 copyHashFlag: copyHashFlag]. o1HasYoung := o2HasYoung := false. 0 to: (self numSlotsOf: obj1) - 1 do: [:i| | temp1 temp2 | temp1 := self fetchPointer: i ofObject: obj1. temp2 := self fetchPointer: i ofObject: obj2. self storePointerUnchecked: i ofObject: obj1 withValue: temp2. self storePointerUnchecked: i ofObject: obj2 withValue: temp1. (self isYoung: temp2) ifTrue: [o1HasYoung := true]. (self isYoung: temp1) ifTrue: [o2HasYoung := true]]. + + (self isOldObject: obj1) + ifTrue: [o2HasYoung + ifTrue: [fmt := self formatOf: obj1. + (self isPureBitsFormat: fmt) ifFalse: + [self possibleRootStoreInto: obj1]]. + + gc isIncremental + ifTrue: [ + "We push the work to the gc. Otherwise we would have to check for every replacement if it is marked. " + (marker isCurrentlyMarking and: [self isMarked: obj1]) + ifTrue: [gc retractWavefrontFrom: obj1 startingAt: 0]]]. + + (self isOldObject: obj2) + ifTrue: [o2HasYoung + ifTrue: [fmt := self formatOf: obj2. + (self isPureBitsFormat: fmt) ifFalse: + [self possibleRootStoreInto: obj2]]. + + gc isIncremental + ifTrue: [ + "We push the work to the gc. Otherwise we would have to check for every replacement if it is marked. " + (marker isCurrentlyMarking and: [self isMarked: obj2]) + ifTrue: [gc retractWavefrontFrom: obj2 startingAt: 0]]]. + + ! - (o1HasYoung and: [self isOldObject: obj1]) ifTrue: - [fmt := self formatOf: obj1. - (self isPureBitsFormat: fmt) ifFalse: - [self possibleRootStoreInto: obj1]]. - (o2HasYoung and: [self isOldObject: obj2]) ifTrue: - [fmt := self formatOf: obj2. - (self isPureBitsFormat: fmt) ifFalse: - [self possibleRootStoreInto: obj2]]!
Item was changed: ----- Method: SpurStopTheWorldGarbageCollector>>maybeModifyGCFlagsOf: (in category 'object creation barriers') ----- + maybeModifyGCFlagsOf: objOop + + <api>! - maybeModifyGCFlagsOf: objOop!
Item was changed: ----- Method: StackInterpreterPrimitives>>primitiveAllVMParameters: (in category 'system control primitives') ----- (excessive size, no diff calculated)
Item was changed: ----- Method: StackInterpreterPrimitives>>primitiveGCInfo (in category 'system control primitives') ----- primitiveGCInfo "VM parameters are numbered as follows: 0 stopTheWorld (0) or incremental gc (1) 1 if incremental gc: current gc phase -> 0 marking; 1 sweeping; 2 compacting if stopTheWorld -> -1 2 eden start 3 eden limit 4 freeStart 5 scavengeThreshold 6 amount of old space segments " <staticallyResolveReceiver: 'objectMemory gc' to: #SpurIncrementalGarbageCollector>
| result staticCount oldSpaceSegmentCount segmentInfoCount | staticCount := 8. segmentInfoCount := 5. oldSpaceSegmentCount := objectMemory numSegments. result := objectMemory instantiateClass: (objectMemory splObj: ClassArray) indexableSize: staticCount + (oldSpaceSegmentCount * segmentInfoCount). objectMemory storePointerUnchecked: 0 ofObject: result withValue: (objectMemory integerObjectOf: objectMemory gc gcIdentifier). objectMemory storePointerUnchecked: 1 ofObject: result withValue: (objectMemory integerObjectOf: (objectMemory gc isIncremental ifTrue: [objectMemory gc phase] ifFalse: [-1])). objectMemory storePointerUnchecked: 2 ofObject: result withValue: (objectMemory integerObjectOf: objectMemory scavenger eden start). objectMemory storePointerUnchecked: 3 ofObject: result withValue: (objectMemory integerObjectOf: objectMemory scavenger eden limit). objectMemory storePointerUnchecked: 4 ofObject: result withValue: (objectMemory integerObjectOf: objectMemory freeStart). objectMemory storePointerUnchecked: 5 ofObject: result withValue: (objectMemory integerObjectOf: objectMemory scavengeThreshold). objectMemory storePointerUnchecked: 6 ofObject: result withValue: (objectMemory integerObjectOf: objectMemory statSurvivorCount). objectMemory storePointerUnchecked: 7 ofObject: result withValue: (self positiveMachineIntegerFor: oldSpaceSegmentCount). 0 to: oldSpaceSegmentCount - 1 do: [:index | | baseIndex segInfo | segInfo := objectMemory segInfoAt: index. baseIndex := staticCount + (index * segmentInfoCount). objectMemory storePointerUnchecked: baseIndex ofObject: result withValue: (objectMemory integerObjectOf: segInfo segStart). objectMemory storePointerUnchecked: baseIndex + 1 ofObject: result withValue: (objectMemory integerObjectOf: segInfo segSize). objectMemory gc gcIdentifier = 2 ifTrue: [objectMemory storePointerUnchecked: baseIndex + 2 ofObject: result withValue: (objectMemory integerObjectOf: (segInfo lastFreeObject ifNil: [0]))] ifFalse: [objectMemory storePointerUnchecked: baseIndex + 2 ofObject: result withValue: (objectMemory integerObjectOf: (segInfo swizzle bitAnd: 16rFFFF))]. objectMemory storePointerUnchecked: baseIndex + 3 ofObject: result withValue: (objectMemory integerObjectOf: (segInfo containsPinned ifTrue: [1] ifFalse: [0])). objectMemory storePointerUnchecked: baseIndex + 4 ofObject: result withValue: (objectMemory integerObjectOf: (segInfo swizzle bitOr: 1 << 16))].
+ objectMemory gc maybeModifyGCFlagsOf: result. - objectMemory beRootIfOld: result. self methodReturnValue: result!
vm-dev@lists.squeakfoundation.org