VM Maker: VMMaker.oscogSPC-eem.2114.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscogSPC-eem.2114.mcz

commits-2
 
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscogSPC-eem.2114.mcz

==================== Summary ====================

Name: VMMaker.oscogSPC-eem.2114
Author: eem
Time: 26 January 2017, 3:20:49.726653 pm
UUID: 68d01a10-0243-46de-b1cb-65d460eecf2b
Ancestors: VMMaker.oscogSPC-eem.2113

Temporary branch for SpurPlanningCompactor as default compactor.

Get the termination condition for copyAndUnmarkMobileObjects right.  Only exit prematurely when finding a marked object beyond lastMobileObject.  Nuke the nonsense added to freeFrom:upTo:previousPin: in the previous commit.


Use objectAfter:limit: in SpurPlannignCompactor and add oldSpaceObjectAfter: and use appropriately to avoid the overhead in objectAfter:.

Add printOopsSuchThat: for debugging.

=============== Diff against VMMaker.oscogSPC-eem.2113 ===============

Item was changed:
  ----- Method: SpurMemoryManager>>adjustAllOopsBy: (in category 'snapshot') -----
  adjustAllOopsBy: bytesToShift
  "Adjust all oop references by the given number of bytes. This is
  done just after reading in an image when the new base address
  of the object heap is different from the base address in the image,
  or when loading multiple segments that have been coalesced.  Also
  set bits in the classTableBitmap corresponding to used classes."
 
  | obj classIndex |
  self assert: self newSpaceIsEmpty.
  self countNumClassPagesPreSwizzle: bytesToShift.
  (bytesToShift ~= 0
  or: [segmentManager numSegments > 1]) ifTrue:
  [obj := self objectStartingAt: oldSpaceStart.
  [self oop: obj isLessThan: freeOldSpaceStart] whileTrue:
  [classIndex := self classIndexOf: obj.
  classIndex >= self isForwardedObjectClassIndexPun
  ifTrue:
  [self swizzleFieldsOfObject: obj]
  ifFalse:
  [classIndex = self isFreeObjectClassIndexPun ifTrue:
  [self swizzleFieldsOfFreeChunk: obj]].
+ obj := self objectAfter: obj limit: endOfMemory]]!
- obj := self objectAfter: obj]]!

Item was changed:
  ----- Method: SpurMemoryManager>>freeListsObj (in category 'free space') -----
  freeListsObj
+ self assert: (self firstIndexableField: (self oldSpaceObjectAfter: trueObj)) = freeLists.
+ ^self oldSpaceObjectAfter: trueObj!
- self assert: (self firstIndexableField: (self objectAfter: trueObj)) = freeLists.
- ^self objectAfter: trueObj!

Item was changed:
  ----- Method: SpurMemoryManager>>initializeObjectMemory: (in category 'initialization') -----
  initializeObjectMemory: bytesToShift
  "Initialize object memory variables at startup time. Assume endOfMemory at al are
  initialised by the image-reading code via setHeapBase:memoryLimit:endOfMemory:.
  endOfMemory is assumed to point to the end of the last object in the image.
  Assume: image reader also initializes the following variables:
  specialObjectsOop
  lastHash"
  <inline: false>
  | freeListObj |
  "Catch mis-initializations leading to bad translations to C"
  self assert: self baseHeaderSize = self baseHeaderSize.
  self assert: (self maxSlotsForAlloc * self wordSize) asInteger > 0.
  self bootstrapping ifFalse:
  [self
  initSegmentBridgeWithBytes: self bridgeSize
  at: endOfMemory - self bridgeSize].
  segmentManager adjustSegmentSwizzlesBy: bytesToShift.
  "image may be at a different address; adjust oops for new location"
  self adjustAllOopsBy: bytesToShift.
  specialObjectsOop := segmentManager swizzleObj: specialObjectsOop.
 
  "heavily used special objects"
  nilObj := self splObj: NilObject.
  falseObj := self splObj: FalseObject.
  trueObj := self splObj: TrueObject.
 
  "In Cog we insist that nil, true & false are next to each other (Cogit generates tighter
  conditional branch code as a result).  In addition, Spur places the free lists and
  class table root page immediately following them."
  self assert: nilObj = oldSpaceStart.
+ self assert: falseObj = (self oldSpaceObjectAfter: nilObj).
+ self assert: trueObj = (self oldSpaceObjectAfter: falseObj).
+ freeListObj := self oldSpaceObjectAfter: trueObj.
+ self setHiddenRootsObj: (self oldSpaceObjectAfter: freeListObj).
- self assert: falseObj = (self objectAfter: nilObj).
- self assert: trueObj = (self objectAfter: falseObj).
- freeListObj := self objectAfter: trueObj.
- self setHiddenRootsObj: (self objectAfter: freeListObj).
  markStack := self swizzleObjStackAt: MarkStackRootIndex.
  weaklingStack := self swizzleObjStackAt: WeaklingStackRootIndex.
  mournQueue := self swizzleObjStackAt: MournQueueRootIndex.
  self assert: self validObjStacks.
  self assert: (self isEmptyObjStack: markStack).
  self assert: (self isEmptyObjStack: weaklingStack).
 
  self initializeFreeSpacePostLoad: freeListObj.
  segmentManager collapseSegmentsPostSwizzle.
  self computeFreeSpacePostSwizzle.
  self initializeOldSpaceFirstFree: freeOldSpaceStart. "initializes endOfMemory, freeStart, free space"
  self initializeNewSpaceVariables.
  scavenger initializeRememberedSet.
  segmentManager checkSegments.
  compactor biasForGC.
 
  "These defaults should depend on machine size; e.g. too small on a powerful laptop, too big on a Pi."
  growHeadroom := 16*1024*1024. "headroom when growing"
  shrinkThreshold := 32*1024*1024. "free space before shrinking"
  self setHeapSizeAtPreviousGC.
  heapGrowthToSizeGCRatio := 0.333333. "By default GC after scavenge if heap has grown by a third since the last GC"!

Item was added:
+ ----- Method: SpurMemoryManager>>oldSpaceObjectAfter: (in category 'object enumeration') -----
+ oldSpaceObjectAfter: objOop
+ <api>
+ "Object parsing.
+ 1. all objects have at least a word following the header, for a forwarding pointer.
+ 2. objects with an overflow size have a preceeing word with a saturated slotSize.  If the word following
+    an object doesn't have a saturated size field it must be a single-header object.  If the word following
+   does have a saturated slotSize it must be the overflow size word."
+ <inline: false>
+ ^self objectAfter: objOop limit: endOfMemory!

Item was added:
+ ----- Method: SpurMemoryManager>>printOopsSuchThat: (in category 'debug printing') -----
+ printOopsSuchThat: function
+ <api>
+ <var: #function declareC: 'sqInt (*function)(sqInt)'>
+ self allHeapEntitiesDo:
+ [:o|
+ (self perform: function with: o) ifTrue:
+ [self printEntity: o]]!

Item was changed:
  ----- Method: SpurPlanningCompactor>>compact (in category 'compaction - api') -----
  compact
  "Sweep all of old space, sliding unpinned marked objects down over free and unmarked objects.
  Let the segmentManager mark which segments contain pinned objects via notePinned:."
  | onePass firstPass |
  <inline: #never> "for profiling"
  self initializeScanCheckingForFullyCompactedHeap ifTrue:
  [^self unmarkObjectsInFullyCompactedHeap].
  self initializeCompaction.
  firstPass := true.
  [onePass := self planCompactSavingForwarders.
  self assert: (self validRelocationPlanInPass: onePass) = 0.
+ objectAfterLastMobileObject := manager oldSpaceObjectAfter: lastMobileObject.
- objectAfterLastMobileObject := manager objectAfter: lastMobileObject.
  self updatePointers.
  self copyAndUnmark: firstPass.
  manager checkFreeSpace: GCModeFull.
  onePass or: [biasForGC]] whileFalse:
  [firstPass := false.
  self reinitializeScan;
  updateSavedFirstFieldsSpaceIfNecessary].
  self endCompaction!

Item was changed:
  ----- Method: SpurPlanningCompactor>>copyAndUnmarkMobileObjects (in category 'compaction') -----
  copyAndUnmarkMobileObjects
  "Sweep the mobile portion of the heap, moving objects to their eventual locations, and clearing their marked bits.
  Remember to update the savedFirstFields of pointer objects, as these have been forwarded.
  Answer if the end of the heap was reached (savedFirstFieldsSpace has not overflowed).
 
  The enumerations in planCompactSavingForwarders, updatePointersInMobileObjects and copyAndUnmarkMobileObjects
  match.  We could implement them as a single enumeration method taking several block arguments, but arguably that
  would make understanding an already tricky algorithm more difficult.  Instead we tolerate the duplication and encourage
  the reader to diff the three methods to see where they diverge (e.g. via Cmd-shift-C)."
  <inline: #never>
  | toFinger top previousPin |
  <var: 'o' type: #usqInt>
  <var: 'top' type: #usqInt>
  <var: 'toFinger' type: #usqInt>
  <var: 'previousPin' type: #usqInt>
  self deny: (manager isMarked: firstFreeObject).
  toFinger := manager startOfObject: firstFreeObject.
  top := savedFirstFieldsSpace start.
  manager allOldSpaceEntitiesForCompactingFrom: firstFreeObject do:
  [:o :n|
  self check: o.
  self assert: (previousPin
  ifNil: [toFinger <= (manager startOfObject: o)]
  ifNotNil: [(manager isMarked: previousPin) and: [toFinger <= (manager startOfObject: previousPin)]]).
  self assert: (savedFirstFieldsSpaceNotInOldSpace or: [toFinger < top]).
- o > lastMobileObject ifTrue:
- [self freeFrom: toFinger upTo: manager endOfMemory previousPin: previousPin.
- ^true].
  (manager isMarked: o) ifTrue:
+ [o > lastMobileObject ifTrue:
+ [self assert: ((manager isPinned: o) not or: [previousPin isNil]).
+ self freeFrom: toFinger upTo: manager endOfMemory previousPin: ((manager isPinned: o) ifTrue: [o] ifFalse: [previousPin]).
+ ^true].
+ (manager isPinned: o)
- [(manager isPinned: o)
  ifTrue:
  [previousPin ifNil:
  [previousPin := o]]
  ifFalse:
  [| availableSpace bytes |
  bytes := manager bytesInObject: o.
  [previousPin notNil
   and: [availableSpace := (manager startOfObject: previousPin) - toFinger.
  bytes ~= availableSpace
  and: [bytes + (2 * manager allocationUnit) > availableSpace]]] whileTrue:
  ["The object does not fit in the space between toFinger and previousPin.
    Move toFinger up to point at the first unmarked or mobile object after
    previousPin, or, if previousPin is contiguous with o, to the start of this
    object.  Update previousPin to be the next pinned object above toFInger
    and below this object, or nil if no such pinned object exists.
    Any unfillable gaps between adjacent pinned objects will be freed."
  availableSpace > 0 ifTrue:
  [manager addFreeChunkWithBytes: availableSpace at: toFinger].
  [self assert: ((manager isMarked: previousPin) and: [manager isPinned: previousPin]).
   self unmarkPinned: previousPin.
   toFinger := manager addressAfter: previousPin.
   previousPin := manager objectStartingAt: toFinger.
   (manager isMarked: previousPin)
    and: [(manager isPinned: previousPin)
    and: [previousPin < o]]]
  whileTrue.
  "Now previousPin is either equal to o or mobile.
   Move it to the next pinned object below o"
  [previousPin >= o
   or: [(manager isMarked: previousPin)
   and: [manager isPinned: previousPin]]] whileFalse:
+ [previousPin := manager oldSpaceObjectAfter: previousPin].
- [previousPin := manager objectAfter: previousPin].
  previousPin >= o ifTrue:
  [previousPin := nil]].
  self copyAndUnmarkObject: o to: toFinger bytes: bytes firstField: (manager longAt: top).
  toFinger := toFinger + bytes.
  (top := top + manager bytesPerOop) >= savedFirstFieldsSpace limit ifTrue:
  [| done |
  self assert: savedFirstFieldsSpace top = (top - manager bytesPerOop).
  done := self noMobileObjectsAfter: n.
  done
  ifTrue: [self freeAllUnpinnedObjectsFromObject: (previousPin ifNil: [n]) toFinger: toFinger]
  ifFalse: [self freeFrom: toFinger upTo: (manager startOfObject: n) previousPin: previousPin].
  ^done]]]].
  self freeFrom: toFinger upTo: manager endOfMemory previousPin: previousPin.
  ^true!

Item was changed:
  ----- Method: SpurPlanningCompactor>>findNextMarkedPinnedAfter: (in category 'private') -----
  findNextMarkedPinnedAfter: unpinnedObj
  <inline: true>
  | nextObj |
  self deny: ((manager isPinned: unpinnedObj) and: [manager isMarked: unpinnedObj]).
  nextObj := unpinnedObj.
+ [nextObj := manager oldSpaceObjectAfter: nextObj.
- [nextObj := manager objectAfter: nextObj limit: manager endOfMemory.
  (self oop: nextObj isGreaterThanOrEqualTo: manager endOfMemory) ifTrue:
  [^nil].
  (manager isPinned: nextObj) and: [manager isMarked: nextObj]] whileFalse.
  ^nextObj!

Item was changed:
  ----- Method: SpurPlanningCompactor>>freeAllUnpinnedObjectsFromObject:toFinger: (in category 'private') -----
  freeAllUnpinnedObjectsFromObject: nextObj toFinger: initialToFinger
  "Free all space from toFinger up, preserving only marked pinned objects, clearning their marked bits."
  | toFinger nextPinnedObj |
  <var: 'toFinger' type: #usqInt>
  <var: 'nextPinnedObj' type: #usqInt>
  toFinger := initialToFinger.
  nextPinnedObj := nextObj.
  [[nextPinnedObj >= manager endOfMemory
   or: [(manager isMarked: nextPinnedObj)
   and: [manager isPinned: nextPinnedObj]]] whileFalse:
+ [nextPinnedObj := manager objectAfter: nextPinnedObj limit: manager endOfMemory].
- [nextPinnedObj := manager objectAfter: nextPinnedObj].
  nextPinnedObj < manager endOfMemory] whileTrue:
  [toFinger < (manager startOfObject: nextPinnedObj) ifTrue:
  [manager addFreeChunkWithBytes: (manager startOfObject: nextPinnedObj) - toFinger at: toFinger].
  self unmarkPinned: nextPinnedObj.
  toFinger := manager addressAfter: nextPinnedObj.
+ nextPinnedObj := manager oldSpaceObjectAfter: nextPinnedObj].
- nextPinnedObj := manager objectAfter: nextPinnedObj].
  toFinger < manager endOfMemory ifTrue:
  [manager addFreeChunkWithBytes: manager endOfMemory - toFinger at: toFinger]!

Item was changed:
  ----- Method: SpurPlanningCompactor>>freeFrom:upTo:previousPin: (in category 'private') -----
  freeFrom: toFinger upTo: limit previousPin: previousPinOrNil
  "Free from toFinger up to limit, dealing with a possible intervening run of pinned objects starting at previousPinOrNil."
  <inline: false>
  <var: 'limit' type: #usqInt>
  <var: 'toFinger' type: #usqInt>
  <var: 'previousPinOrNil' type: #usqInt>
  | effectiveToFinger pin nextUnpinned start seg |
  <var: 'nextUnpinned' type: #usqInt>
  <var: #seg type: #'SpurSegmentInfo *'>
  self cCode: [] inSmalltalk:
  [coInterpreter cr; cr; print: 'freeing at '; printHexnp: toFinger; print: ' up to '; printHexnp: limit; print: ' pin '; printHexnp: previousPinOrNil; cr].
  effectiveToFinger := toFinger.
  pin := previousPinOrNil.
- "If toFinger is past lastMobileObject then it was impossible to move an object past a pin
- and toFinger is pointing at an object. The object may be a pin which must be preserved."
- effectiveToFinger > lastMobileObject ifTrue:
- [effectiveToFinger >= limit ifTrue:
- [^self].
- nextUnpinned := manager objectStartingAt: effectiveToFinger.
- [(manager isPinned: nextUnpinned) and: [manager isMarked: nextUnpinned]] whileTrue:
- [nextUnpinned := manager objectAfter: nextUnpinned.
- nextUnpinned >= limit ifTrue:
- [^self]].
- effectiveToFinger := manager startOfObject: nextUnpinned.
- (previousPinOrNil notNil and: [effectiveToFinger > previousPinOrNil]) ifTrue:
- [pin := nil]].
  "If the range toFinger to limit spans segments but there is no pin (as when freeing to the end of memory)
  segment boundaries must still be observed.  So in this case use the nearest bridge above toFinger as the pin."
  pin ifNil:
  [seg := manager segmentManager segmentContainingObj: toFinger.
  seg segLimit < limit ifTrue:
  [pin := manager segmentManager bridgeFor: seg]].
  [pin notNil] whileTrue:
  [(start := manager startOfObject: pin) > toFinger ifTrue:
  [manager addFreeChunkWithBytes: start - effectiveToFinger at: effectiveToFinger].
  nextUnpinned := self unmarkPinnedObjectsAndFindFirstUnpinnedOrFreeEntityFollowing: pin.
  nextUnpinned >= limit ifTrue:
  [^self].
  effectiveToFinger := manager startOfObject: nextUnpinned.
  pin := self findNextMarkedPinnedAfter: nextUnpinned].
  manager addFreeChunkWithBytes: limit - effectiveToFinger at: effectiveToFinger!

Item was changed:
  ----- Method: SpurPlanningCompactor>>logPhase: (in category 'private') -----
  logPhase: phaseName
  <inline: true>
+ self cCode: '' inSmalltalk: [coInterpreter transcript nextPutAll: phaseName; flush].!
- self break.
- self cCode: '' inSmalltalk: [coInterpreter transcript nextPutAll: phaseName; flush]. !

Item was changed:
  ----- Method: SpurPlanningCompactor>>planCompactSavingForwarders (in category 'compaction') -----
  planCompactSavingForwarders
  "Sweep the heap from firstFreeObject forwarding marked objects to where they
  can be moved to, saving their forwarding pointer in savedFirstFieldsSpace.
  Continue until either the end of the heap is reached or savedFirstFieldsSpace is full.
  Answer if the end of the heap was reached (savedFirstFieldsSpace has not overflowed).
 
  The enumerations in planCompactSavingForwarders, updatePointersInMobileObjects and copyAndUnmarkMobileObjects
  match.  We could implement them as a single enumeration method taking several block arguments, but arguably that
  would make understanding an already tricky algorithm more difficult.  Instead we tolerate the duplication and encourage
  the reader to diff the three methods to see where they diverge (e.g. via Cmd-shift-C)."
  <inline: #never>
  | toFinger top previousPin |
  <var: 'o' type: #usqInt>
  <var: 'top' type: #usqInt>
  <var: 'toFinger' type: #usqInt>
  <var: 'previousPin' type: #usqInt>
  savedFirstFieldsSpace top < savedFirstFieldsSpace start ifTrue:
  [self logPhase: 'planning...'].
  self deny: (manager isMarked: firstFreeObject).
  toFinger := manager startOfObject: firstFreeObject.
  top := savedFirstFieldsSpace start.
  manager allOldSpaceEntitiesFrom: firstFreeObject do:
  [:o|
  self check: o.
  self assert: (previousPin
  ifNil: [toFinger <= (manager startOfObject: o)]
  ifNotNil: [(manager isMarked: previousPin) and: [toFinger <= (manager startOfObject: previousPin)]]).
  self assert: (savedFirstFieldsSpaceNotInOldSpace or: [toFinger < top]).
  (manager isMarked: o) ifTrue:
  [(manager isPinned: o)
  ifTrue:
  [previousPin ifNil:
  [previousPin := o]]
  ifFalse:
  [| availableSpace bytes |
  bytes := manager bytesInObject: o.
  [previousPin notNil
   and: [availableSpace := (manager startOfObject: previousPin) - toFinger.
  bytes ~= availableSpace
  and: [bytes + (2 * manager allocationUnit) > availableSpace]]] whileTrue:
  ["The object does not fit in the space between toFinger and previousPin.
    Move toFinger up to point at the first unmarked or mobile object after
    previousPin, or, if previousPin is contiguous with o, to the start of this
    object.  Update previousPin to be the next pinned object above toFInger
    and below this object, or nil if no such pinned object exists.
    Any unfillable gaps between adjacent pinned objects will be freed."
  [toFinger := manager addressAfter: previousPin.
   previousPin := manager objectStartingAt: toFinger.
   (manager isMarked: previousPin)
    and: [(manager isPinned: previousPin)
    and: [previousPin < o]]]
  whileTrue.
  "Now previousPin is either equal to o or mobile.
   Move it to the next pinned object below o"
  [previousPin >= o
   or: [(manager isMarked: previousPin)
   and: [manager isPinned: previousPin]]] whileFalse:
+ [previousPin := manager oldSpaceObjectAfter: previousPin].
- [previousPin := manager objectAfter: previousPin].
  previousPin >= o ifTrue:
  [previousPin := nil]].
  self forwardMobileObject: o to: toFinger savedFirstFieldPtr: top.
  toFinger := toFinger + bytes.
  (top := top + manager bytesPerOop) >= savedFirstFieldsSpace limit ifTrue:
  [savedFirstFieldsSpace top: top - manager bytesPerOop.
  ^self noMobileObjectsAfter: o]]]].
  savedFirstFieldsSpace top: top - manager bytesPerOop.
  ^true!

Item was changed:
  ----- Method: SpurPlanningCompactor>>unmarkPinnedObjectsAndFindFirstUnpinnedOrFreeEntityFollowing: (in category 'private') -----
  unmarkPinnedObjectsAndFindFirstUnpinnedOrFreeEntityFollowing: pinnedObj
  <inline: true>
  | nextObj |
  self assert: ((manager isPinned: pinnedObj) and: [manager isMarked: pinnedObj]).
  nextObj := pinnedObj.
  [self unmarkPinned: nextObj.
+ nextObj := manager oldSpaceObjectAfter: nextObj.
- nextObj := manager objectAfter: nextObj limit: manager endOfMemory.
  (self oop: nextObj isGreaterThanOrEqualTo: manager endOfMemory) ifTrue:
  [^manager endOfMemory].
  (manager isPinned: nextObj) and: [manager isMarked: nextObj]] whileTrue.
  ^nextObj!

Item was changed:
  ----- Method: SpurPlanningCompactor>>updatePointersInMobileObjects (in category 'compaction') -----
  updatePointersInMobileObjects
  "Sweep the mobile portion of the heap, updating all references to objects to their eventual locations.
  Remember to update the savedFirstFields of pointer objects, as these have been forwarded.
  Answer if the end of the heap was reached (savedFirstFieldsSpace has not overflowed).
 
  The enumerations in planCompactSavingForwarders, updatePointersInMobileObjects and copyAndUnmarkMobileObjects
  match.  We could implement them as a single enumeration method taking several block arguments, but arguably that
  would make understanding an already tricky algorithm more difficult.  Instead we tolerate the duplication and encourage
  the reader to diff the three methods to see where they diverge (e.g. via Cmd-shift-C)."
  | toFinger top previousPin |
  <var: 'o' type: #usqInt>
  <var: 'top' type: #usqInt>
  <var: 'toFinger' type: #usqInt>
  <var: 'previousPin' type: #usqInt>
  self deny: (manager isMarked: firstFreeObject).
  toFinger := manager startOfObject: firstFreeObject.
  top := savedFirstFieldsSpace start.
  manager allOldSpaceEntitiesFrom: firstFreeObject do:
  [:o|
  self check: o.
  self assert: (previousPin
  ifNil: [toFinger <= (manager startOfObject: o)]
  ifNotNil: [(manager isMarked: previousPin) and: [toFinger <= (manager startOfObject: previousPin)]]).
  (manager isMarked: o) ifTrue:
  [(manager isPinned: o)
  ifTrue:
  [previousPin ifNil:
  [previousPin := o].
  self updatePointersIn: o]
  ifFalse:
  [| availableSpace bytes |
  bytes := manager bytesInObject: o.
  [previousPin notNil
   and: [availableSpace := (manager startOfObject: previousPin) - toFinger.
  bytes ~= availableSpace
  and: [bytes + (2 * manager allocationUnit) > availableSpace]]] whileTrue:
  ["The object does not fit in the space between toFinger and previousPin.
    Move toFinger up to point at the first unmarked or mobile object after
    previousPin, or, if previousPin is contiguous with o, to the start of this
    object.  Update previousPin to be the next pinned object above toFInger
    and below this object, or nil if no such pinned object exists.
    Any unfillable gaps between adjacent pinned objects will be freed."
  [toFinger := manager addressAfter: previousPin.
   previousPin := manager objectStartingAt: toFinger.
   (manager isMarked: previousPin)
    and: [(manager isPinned: previousPin)
    and: [previousPin < o]]]
  whileTrue.
  "Now previousPin is either equal to o or mobile.
   Move it to the next pinned object below o"
  [previousPin >= o
   or: [(manager isMarked: previousPin)
   and: [manager isPinned: previousPin]]] whileFalse:
+ [previousPin := manager oldSpaceObjectAfter: previousPin].
- [previousPin := manager objectAfter: previousPin].
  previousPin >= o ifTrue:
  [previousPin := nil]].
  self updatePointersIn: o savedFirstFieldPointer: top.
  toFinger := toFinger + bytes.
  (top := top + manager bytesPerOop) >= savedFirstFieldsSpace limit ifTrue:
  [self assert: savedFirstFieldsSpace top = (top - manager bytesPerOop).
  ^self noMobileObjectsAfter: o]]]].
  self assert: savedFirstFieldsSpace top = (top - manager bytesPerOop).
  ^true!

Item was changed:
  ----- Method: SpurPlanningCompactor>>updatePointersInObjectsOverflowingSavedFirstFieldsSpace (in category 'compaction') -----
  updatePointersInObjectsOverflowingSavedFirstFieldsSpace
  "Sweep the final immobile heap, is any (those objects with no room in savedFirstFieldsSpace
  in the current pass) updating all references to mobile objects to their eventual locations."
+ manager allOldSpaceObjectsFrom: objectAfterLastMobileObject do:
- manager allOldSpaceObjectsFrom: (manager objectAfter: lastMobileObject) do:
  [:o|
  self check: o.
  self assert: (manager isMarked: o).
  self updatePointersIn: o]!