[Vm-dev] VM Maker: VMMaker.oscog-eem.416.mcz

commits at source.squeak.org commits at source.squeak.org
Fri Sep 27 23:24:54 UTC 2013


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.416.mcz

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

Name: VMMaker.oscog-eem.416
Author: eem
Time: 27 September 2013, 4:22:05.988 pm
UUID: 5fb57fd2-e594-480f-b24c-1a329abd76bd
Ancestors: VMMaker.oscog-eem.415

Add ephemeron support to the scavenger.  As yet incorrect because
my test only fires a single ephemeron and it should fire two.

Refactor the corpse list machinery to allow access to offsets for
list removal in scavengeUnfiredEphemeronsOnEphemeronList.

Note that StackInterpreter>>fireEphemeron: is
shouldBeImplemented.

=============== Diff against VMMaker.oscog-eem.415 ===============

Item was changed:
  CogClass subclass: #SpurGenerationScavenger
+ 	instanceVariableNames: 'coInterpreter manager eden futureSpace pastSpace futureSurvivorStart rememberedSet rememberedSetSize previousRememberedSetSize weakList ephemeronList tenuringThreshold tenuringProportion numRememberedEphemerons'
- 	instanceVariableNames: 'coInterpreter manager eden futureSpace pastSpace futureSurvivorStart rememberedSet rememberedSetSize weakList ephemeronList tenuringThreshold tenuringProportion'
  	classVariableNames: 'RememberedSetLimit RememberedSetRedZone'
  	poolDictionaries: ''
  	category: 'VMMaker-SpurMemoryManager'!
  
+ !SpurGenerationScavenger commentStamp: 'eem 9/27/2013 11:53' prior: 0!
- !SpurGenerationScavenger commentStamp: 'eem 9/24/2013 13:04' prior: 0!
  SpurGenerationScavenger is an implementation of David Ungar's Generation Scavenging garbage collection algorithm.  See
  	Generation Scavenging, A Non-disruptive, High-Performance Storage Reclamation Algorithm
  	David Ungar
  	Proceeding
  	SDE 1 Proceedings of the first ACM SIGSOFT/SIGPLAN software engineering symposium on Practical software development environments
  	Pages 157 - 167 
  	ACM New York, NY, USA ©1984 
- 	ISBN:0-89791-131-8
  
  Also relevant are
  	An adaptive tenuring policy for generation scavengers
  	David Ungar & Frank Jackson
  	ACM Transactions on Programming Languages and Systems (TOPLAS) TOPLAS Homepage archive
  	Volume 14 Issue 1, Jan. 1992 
  	Pages 1 - 27 
+ 	ACM New York, NY, USA ©1992
+ and
+ 	Ephemerons: a new finalization mechanism
+ 	Barry Hayes
+ 	Proceedings of the 12th ACM SIGPLAN conference on Object-oriented programming, systems, languages, and applications
+ 	Pages 176-183 
+ 	ACM New York, NY, USA ©1997
- 	ACM New York, NY, USA
  
  Instance Variables
  	coInterpreter:			<StackInterpreterSimulator|CogVMSimulator>
  	eden:					<SpurNewSpaceSpace>
  	futureSpace:			<SpurNewSpaceSpace>
  	futureSurvivorStart:		<Integer address>
  	manager:				<SpurMemoryManager|Spur32BitMMLESimulator et al>
  	pastSpace:				<SpurNewSpaceSpace>
  	rememberedSet:		<CArrayAccessor on: Array>
  	rememberedSetSize:	<Integer>
  	tenuringProportion:		<Float>
  	tenuringThreshold:		<Integer address>
  
  coInterpreter
  	- the interpreter/vm, in this context, the mutator
  
  eden
  	- the space containing newly created objects
  
  futureSpace
  	- the space to which surviving objects are copied during a scavenge
  
  futureSurvivorStart
  	- the allocation pointer into futureSpace
  
  manager
  	- the Spur memory manager
  
  pastSpace
  	- the space surviving objects live in until the next scavenge
  
  rememberedSet
  	- the root old space objects that refer to objects in new space; a scavenge starts form these roots and the interpreter's stack
  
  rememberedSetSize
  	- the size of the remembered set, also the first unused index in the rememberedSet
  
  tenuringProportion
  	- the amount of pastSpace below which the system will not tenure unless futureSpace fills up, and above which it will eagerly tenure
  
  tenuringThreshold
  	- the pointer into pastSpace below which objects will be tenured
  !

Item was added:
+ ----- Method: SpurGenerationScavenger>>addToEphemeronList: (in category 'weakness and ephemerality') -----
+ addToEphemeronList: ephemeronCorpse
+ 	"ephemeronCorpse is the corpse of an ephemeron that was copied and forwarded.
+ 	 Later on its surviving copy must be scanned to nil weak references.
+ 	 Thread the corpse onto the weakList.  Later, the weakList can be followed, and
+ 	 the forwarding pointer followed to locate the survivor."
+ 	| ephemeronListOffset |
+ 	self assert: (manager isYoung: ephemeronCorpse).
+ 	self assert: (manager isForwarded: ephemeronCorpse).
+ 	self assert: (self isScavengeSurvivor: (manager keyOfEphemeron: (manager followForwarded: ephemeronCorpse))) not.
+ 
+ 	ephemeronListOffset := ephemeronList ifNil: 0.
+ 	self setCorpseOffsetOf: ephemeronCorpse to: ephemeronListOffset.
+ 	ephemeronList := ephemeronCorpse - manager startOfMemory >> manager shiftForWord.
+ 	self assert: (self firstCorpse: ephemeronList) = ephemeronCorpse!

Item was changed:
  ----- Method: SpurGenerationScavenger>>addToWeakList: (in category 'weakness and ephemerality') -----
  addToWeakList: weakCorpse
  	"weakCorpse is the corpse of a weak array that was copied and forwarded.
  	 Later on its surviving copy must be scanned to nil weak references.
  	 Thread the corpse onto the weakList.  Later, the weakList can be followed, and
+ 	 the forwarding pointer followed to locate the survivor."
+ 	| weakListOffset |
- 	 the forwarding pointer followed to locate the survivor.  Use the identityHash
- 	 and format fields to construct a 27 bit offset through non-future newSpace and
- 	 use this to implement the list. 27 bits is 2 ^ 27 slots, or at least 0.5Gb, big enough
- 	 for any newSpace size for the near future."
- 	| weakListIndex |
  	self assert: (manager isYoung: weakCorpse).
+ 	self assert: (manager isForwarded: weakCorpse).
+ 
+ 	weakListOffset := weakList ifNil: 0.
+ 	self setCorpseOffsetOf: weakCorpse to: weakListOffset.
- 	weakListIndex := weakList ifNil: 0.
- 	manager
- 		setHashBitsOf: weakCorpse
- 			to: weakListIndex >> manager formatFieldWidthShift;
- 		setFormatOf: weakCorpse
- 			to: (weakListIndex bitAnd: manager formatMask).
  	weakList := weakCorpse - manager startOfMemory >> manager shiftForWord.
  	self assert: (self firstCorpse: weakList) = weakCorpse!

Item was changed:
  ----- Method: SpurGenerationScavenger>>copyAndForward: (in category 'scavenger') -----
  copyAndForward: survivor
  	"copyAndForward: survivor copies a survivor object either to
  	 futureSurvivorSpace or, if it is to be promoted, to oldSpace.
  	 It leaves a forwarding pointer behind.  If the object is weak
  	 then corpse is threaded onto the weakList for later treatment."
  	<inline: true>
+ 	| bytesInObject newLocation hash |
- 	| bytesInObject newLocation hash isWeak |
  	bytesInObject := manager bytesInObject: survivor.
+ 	"Must remember hash before copying because threading
+ 	 on to the weak & ephemeron lists smashes the hash field."
- 	newLocation := ((self shouldBeTenured: survivor)
- 					  or: [futureSurvivorStart + bytesInObject > futureSpace limit])
- 						ifTrue: [self copyToOldSpace: survivor]
- 						ifFalse: [self copyToFutureSpace: survivor bytes: bytesInObject].
  	hash := manager rawHashBitsOf: survivor.
+ 	((self shouldBeTenured: survivor)
+ 	 or: [futureSurvivorStart + bytesInObject > futureSpace limit])
+ 		ifTrue:
+ 			[newLocation := self copyToOldSpace: survivor.
+ 			 manager forward: survivor to: newLocation]
+ 		ifFalse:
+ 			[newLocation := self copyToFutureSpace: survivor bytes: bytesInObject.
+ 			 manager forward: survivor to: newLocation.
+ 			 "if weak or ephemeron add to the relevant lists if newLocation is young.  If
+ 			  old, newLocation will be remembered and dealt with in the rememberedSet."
+ 			 (manager isWeakNonImm: newLocation) ifTrue:
+ 				[self addToWeakList: survivor].
+ 			 ((manager isEphemeron: newLocation)
+ 			  and: [(self isScavengeSurvivor: (manager keyOfEphemeron: newLocation)) not]) ifTrue:
+ 				[self addToEphemeronList: survivor]].
  	hash ~= 0 ifTrue:
  		[manager setHashBitsOf: newLocation to: hash].
- 	"Alas forward:to: smashes the format field and so destroys the weakness
- 	 property.  Test it before forwarding."
- 	isWeak := manager isWeakNonImm: survivor.
- 	manager forward: survivor to: newLocation.
- 	isWeak ifTrue:
- 		[self addToWeakList: survivor].
  	^newLocation!

Item was added:
+ ----- Method: SpurGenerationScavenger>>corpseForCorpseOffset: (in category 'weakness and ephemerality') -----
+ corpseForCorpseOffset: corpseOffset
+ 	"Use the identityHash and format fields to construct a 27 bit offset through
+ 	 non-future newSpace and use this to implement lists of corpses for weak
+ 	 array and ephemeron processing. 27 bits is 2 ^ 27 slots, or at least 0.5Gb;
+ 	 big enough for any newSpace size for the near future."
+ 	^corpseOffset << manager shiftForWord + manager startOfMemory!

Item was added:
+ ----- Method: SpurGenerationScavenger>>fireEphemeronsInRememberedSet (in category 'weakness and ephemerality') -----
+ fireEphemeronsInRememberedSet
+ 	"There are ephemerons to be fired in the remembered set.
+ 	 Fire them and scavenge their keys.  Leave it to scavengeLoop
+ 	 to remove any scavenged ephemerons that no longer have
+ 	 new referents."
+ 	| i |
+ 	self assert: self noUnfiredEphemeronsAtEndOfRememberedSet.
+ 
+ 	i := 0.
+ 	[i < numRememberedEphemerons] whileTrue:
+ 		[ | ephemeron |
+ 		 ephemeron := rememberedSet at: i.
+ 		 self assert: (manager isEphemeron: ephemeron).
+ 		 self assert: (self isScavengeSurvivor: (manager keyOfEphemeron: ephemeron)) not.
+ 		 coInterpreter fireEphemeron: ephemeron.
+ 		 self copyAndForward: (manager keyOfEphemeron: ephemeron).
+ 		 (self scavengeReferentsOf: ephemeron)
+ 			ifTrue: "keep in set"
+ 				[i := i + 1]
+ 			ifFalse:
+ 				[manager setIsRememberedOf: ephemeron to: false.
+ 				"remove from set by overwriting with next-to-be scanned"
+ 				 numRememberedEphemerons := numRememberedEphemerons - 1.
+ 				 previousRememberedSetSize := previousRememberedSetSize - 1.
+ 				 rememberedSetSize := rememberedSetSize - 1.
+ 				 "First overwrite with last firable ephemeron (could be a noop if this is the last one).
+ 				  Then overwrite last firable entry with next unscanned rememberedSet entry (could also be a noop).
+ 				  Then overwrite next unscanned entry with last unscanned rememberedSet entry (could also be a noop)."
+ 				 rememberedSet
+ 					at: i
+ 						put: (rememberedSet at: numRememberedEphemerons);
+ 					at: numRememberedEphemerons
+ 						put: (rememberedSet at: previousRememberedSetSize);
+ 					at: previousRememberedSetSize
+ 						put: (rememberedSet at: rememberedSetSize)]].
+ 
+ 	"no more firable ephemerons in this cycle.
+ 	 scavengeRememberedSetStartingAt: may find new ones."
+ 	numRememberedEphemerons := 0!

Item was added:
+ ----- Method: SpurGenerationScavenger>>fireEphemeronsOnEphemeronList (in category 'weakness and ephemerality') -----
+ fireEphemeronsOnEphemeronList
+ 	"There are ephemerons to be fired in the remembered set.
+ 	 Fire them and scavenge their keys.  Be careful since copyAndForward:
+ 	 can remember ephemerons (ephemerons pointing to ephemerons)."
+ 	| ephemeron ephemeronCorpse |
+ 	ephemeronList ifNil:
+ 		[^self].
+ 	ephemeronCorpse := self firstCorpse: ephemeronList.
+ 	"Reset the list head so that new ephemerons will get added
+ 	 to a new list, not concatenated on the one we are scanning."
+ 	ephemeronList := nil.
+ 	[ephemeronCorpse notNil] whileTrue:
+ 		[self assert: (manager isForwarded: ephemeronCorpse).
+ 		 ephemeron := manager followForwarded: ephemeronCorpse.
+ 		 self assert: (self isScavengeSurvivor: (manager keyOfEphemeron: ephemeron)) not..
+ 		 coInterpreter fireEphemeron: ephemeron.
+ 		 self copyAndForward: (manager keyOfEphemeron: ephemeron).
+ 		 self cCoerceSimple: (self scavengeReferentsOf: ephemeron) to: #void.
+ 		 ephemeronCorpse := self nextCorpseOrNil: ephemeronCorpse]!

Item was changed:
  ----- Method: SpurGenerationScavenger>>firstCorpse: (in category 'weakness and ephemerality') -----
  firstCorpse: headOfCorpseList
  	"Use the identityHash and format fields to construct a 27 bit offset through
  	 non-future newSpace and use this to implement lists of corpses for weak
  	 array and ephemeron processing. 27 bits is 2 ^ 27 slots, or at least 0.5Gb;
  	 big enough for any newSpace size for the near future."
+ 	^self corpseForCorpseOffset: headOfCorpseList!
- 	^headOfCorpseList << manager shiftForWord + manager startOfMemory!

Item was added:
+ ----- Method: SpurGenerationScavenger>>nextCorpseOffset: (in category 'weakness and ephemerality') -----
+ nextCorpseOffset: corpse
+ 	"Answer the offset of the next corpse to corpse, which is zero if none.
+ 	 Use the identityHash and format fields to construct a 27 bit offset through
+ 	 non-future newSpace and use this to implement the list. 27 bits is 2 ^ 27 slots,
+ 	 or at least 0.5Gb, big enough for any newSpace size for the near future."
+ 	^(manager rawHashBitsOf: corpse) << manager formatFieldWidthShift
+ 	 + (manager formatOf: corpse)!

Item was changed:
  ----- Method: SpurGenerationScavenger>>nextCorpseOrNil: (in category 'weakness and ephemerality') -----
  nextCorpseOrNil: weakCorpse
  	"weakCorpse is the corpse of a weak array that has been added to the weakList.
+ 	 Answer the next object on the list, or nil if none."
+ 	| weakListOffset |
- 	 Answer the next object on the list, or nil if none.
- 	 Use the identityHash and format fields to construct a 27 bit offset through
- 	 non-future newSpace and use this to implement the list. 27 bits is 2 ^ 27 slots,
- 	 or at least 0.5Gb, big enough for any newSpace size for the near future."
- 	| weakListIndex |
  	self assert: (manager isYoung: weakCorpse).
+ 	weakListOffset := self nextCorpseOffset: weakCorpse.
+ 	^weakListOffset ~= 0 ifTrue:
+ 		[weakListOffset << manager shiftForWord + manager startOfMemory]!
- 	weakListIndex := (manager rawHashBitsOf: weakCorpse) << manager formatFieldWidthShift
- 						+ (manager formatOf: weakCorpse).
- 	^weakListIndex ~= 0 ifTrue:
- 		[weakListIndex << manager shiftForWord + manager startOfMemory]!

Item was added:
+ ----- Method: SpurGenerationScavenger>>noUnfiredEphemeronsAtEndOfRememberedSet (in category 'weakness and ephemerality') -----
+ noUnfiredEphemeronsAtEndOfRememberedSet
+ 	"For assert checking only."
+ 	numRememberedEphemerons to: rememberedSetSize - 1 do:
+ 		[:i| | referrer key |
+ 		referrer := rememberedSet at: i.
+ 		(manager isEphemeron: referrer) ifTrue:
+ 			[key := manager keyOfEphemeron: referrer.
+ 			 (manager isForwarded: key) ifTrue:
+ 				[key := manager followForwarded: key].
+ 			(self isScavengeSurvivor: key) ifFalse:
+ 				[^false]]].
+ 	^true!

Item was removed:
- ----- Method: SpurGenerationScavenger>>processEphemeronList (in category 'weakness and ephemerality') -----
- processEphemeronList
- 	"There are ephemerons to be scavenged. Scavenge them
- 	  and fire any whose keys are still in pastSpace and/or eden."
- 	^self shouldBeImplemented!

Item was added:
+ ----- Method: SpurGenerationScavenger>>processEphemerons (in category 'weakness and ephemerality') -----
+ processEphemerons
+ 	"There are ephemerons to be scavenged. Scavenge them
+ 	 and fire any whose keys are still in pastSpace and/or eden.
+ 	 The ephemerons in this cycle can only be fired if all the
+ 	 ephemerons in this cycle are firable, because references
+ 	 to ephemeron keys from unfired ephemerons should prevent
+ 	 the ephemerons with those keys from firing.  So scavenge
+ 	 ephemerons with surviving keys, and only if none are found,
+ 	 fire ephemerons with unreferenced keys, and scavenge them."
+ 	| unfiredEphemeronsScavenged |
+ 	unfiredEphemeronsScavenged := self scavengeUnfiredEphemeronsInRememberedSet.
+ 	self scavengeUnfiredEphemeronsOnEphemeronList ifTrue:
+ 		[unfiredEphemeronsScavenged := true].
+ 	"If no unfired ephemerons were scavenged, then all ephemerons in this cycle can be fired."
+ 	unfiredEphemeronsScavenged ifFalse:
+ 		[self fireEphemeronsInRememberedSet.
+ 		 self fireEphemeronsOnEphemeronList]!

Item was changed:
  ----- Method: SpurGenerationScavenger>>scavengeLoop (in category 'scavenger') -----
  scavengeLoop
  	"This is the inner loop of the main routine, scavenge.  It first scavenges the new objects immediately
  	 reachable from old ones. Then it scavenges those that are transitively reachable.  If this results in a
  	 promotion, the promotee gets remembered, and it first scavenges objects adjacent to the promotee,
  	 then scavenges the ones reachable from the promoted.  This loop continues until no more reachable
  	 objects are left.  At that point, pastSurvivorSpace is exchanged with futureSurvivorSpace.
  
  	 Notice that each pointer in a live object is inspected once and only once.  The previousRememberedSetSize
  	 and previousFutureSurvivorSpaceLimit variables ensure that no object is scanned twice, as well as
  	 detecting closure.  If this were not true, some pointers might get forwarded twice.
  
  	 An extension of the algorithm presented in David's original paper is to handle weak arrays and ephemerons.
  	 Weak arrays should not have their weak referents scavenged unless there are strong references to them.
  	 Ephemerons should fire if their key is not reachable other than from ephemerons and weak arrays.
  	 Handle this by maintaining a list for weak arrays and a list for ephemerons, which allow scavenging these
  	 objects once all other objects in new space have been scavenged, hence allowing the scavenger to
  	 detect which referents in new space of weak arrays are dead and of ephemeron keys are only live due to
  	 ephemerons."
  
+ 	| previousFutureSurvivorStart firstTime |
- 	| firstTime previousRememberedSetSize previousFutureSurvivorStart |
  	self assert: futureSurvivorStart = futureSpace start. "future space should be empty at the start"
+ 
  	weakList := ephemeronList := nil.
+ 	numRememberedEphemerons := 0.
  	firstTime := true.
  	previousRememberedSetSize := 0.
  	previousFutureSurvivorStart := futureSurvivorStart.
+ 
  	[self scavengeRememberedSetStartingAt: previousRememberedSetSize.
  	 previousRememberedSetSize := rememberedSetSize.
  	 firstTime ifTrue:
  		[coInterpreter mapInterpreterOops.
  		 firstTime := false].
+ 	 "if nothing more copied and forwarded (or remembered by mapInterpreterOops)
+ 	  to scavenge, and no ephemerons to process, scavenge is done."
- 	 "nothing more copied and forwarded (or remembered by mapInterpreterOops)
- 	  to scavenge so scavenge is done."
  	 (previousRememberedSetSize = rememberedSetSize
  	  and: [previousFutureSurvivorStart = futureSurvivorStart
+ 	  and: [numRememberedEphemerons = 0
+ 	  and: [ephemeronList isNil]]]) ifTrue:
- 	  and: [ephemeronList isNil]]) ifTrue:
  		[^self].
  
  	 self scavengeFutureSurvivorSpaceStartingAt: previousFutureSurvivorStart.
+ 	 "if no more roots created to scavenge, and no ephemerons to process, scavenge is done."
- 	 "no more roots created to scavenge, so scavenge is done."
  	 (previousRememberedSetSize = rememberedSetSize
+ 	  and: [numRememberedEphemerons = 0
+ 	  and: [ephemeronList isNil]]) ifTrue:
- 	  and: [ephemeronList isNil]) ifTrue:
  		[^self].
  
  	 previousFutureSurvivorStart := futureSurvivorStart.
+ 	 (numRememberedEphemerons > 0
+ 	  or: [ephemeronList notNil]) ifTrue:
+ 		[self processEphemerons]] repeat!
- 	 ephemeronList notNil ifTrue:
- 		[self processEphemeronList]] repeat!

Item was changed:
  ----- Method: SpurGenerationScavenger>>scavengeReferentsOf: (in category 'scavenger') -----
  scavengeReferentsOf: referrer
  	"scavengeReferentsOf: referrer inspects all the pointers in referrer.
  	 If any are new objects, it has them moved to FutureSurvivorSpace,
  	 and answers truth. If there are no new referents, it answers falsity.
  	 To handle weak arrays only scavenge string slots and answer true
  	 if the referrer is weak, so that it won't be removed from the
  	 remembered set until later."
  	| foundNewReferent |
  	"forwarding objects should be followed by callers,
  	 unless the forwarder is a root in the remembered table."
  	self assert: ((manager isForwarded: referrer) not
  				or: [manager isRemembered: referrer]).
+ 	"unscanned ephemerons should be scanned later."
+ 	self assert: ((manager isEphemeron: referrer) not
+ 				or: [| key |
+ 					key := manager keyOfEphemeron: referrer.
+ 					(manager isForwarded: key) ifTrue:
+ 						[key := manager followForwarded: key].
+ 					self isScavengeSurvivor: key]).
  	foundNewReferent := false.
  	0 to: (manager numStrongSlotsOf: referrer) - 1 do:
  		[:i| | referent newLocation |
  		referent := manager fetchPointer: i ofMaybeForwardedObject: referrer.
  		(manager isNonImmediate: referent) ifTrue:
  			["a forwarding pointer could be because of become: or scavenging."
  			 referent := (manager isForwarded: referent)
  								ifTrue: [manager followForwarded: referent]
  								ifFalse: [referent].
  			 (manager isYoung: referent)
  				ifTrue:
  					["if target is already in future space forwarding pointer was due to a become:."
  					 (manager isInFutureSpace: referent)
  						ifTrue: [newLocation := referent]
  						ifFalse:
  							[(manager isForwarded: referent)
  								ifTrue: [self halt. "can this even happen?"
  									newLocation := manager followForwarded: referent]
  								ifFalse: [newLocation := self copyAndForward: referent]].
  					 (manager isYoung: newLocation) ifTrue:
  						[foundNewReferent := true].
  					 manager storePointerUnchecked: i ofMaybeForwardedObject: referrer withValue: newLocation]
  				ifFalse:
  					[manager storePointerUnchecked: i ofMaybeForwardedObject: referrer withValue: referent]]].
  	^foundNewReferent or: [manager isWeakNonImm: referrer]!

Item was changed:
  ----- Method: SpurGenerationScavenger>>scavengeRememberedSetStartingAt: (in category 'scavenger') -----
  scavengeRememberedSetStartingAt: n
  	"scavengeRememberedSetStartingAt: n traverses objects in the remembered
  	 set starting at the nth one.  If the object does not refer to any new objects, it
+ 	 is removed from the set.  Otherwise, its new referents are scavenged.  Defer
+ 	 scavenging ephemerons until after a complete scavenge has been performed,
+ 	 so that triggered ephemerons can be fired.  Move them to the front of the set
+ 	 and count them in numRememberedEphemerons for later scanning."
+ 	| destIndex sourceIndex referrer |
- 	 is removed from the set. Otherwise, its new referents are scavenged."
- 	| destIndex sourceIndex |
  	sourceIndex := destIndex := n.
  	[sourceIndex < rememberedSetSize] whileTrue:
+ 		["*Don't* follow forwarding pointers here. oldSpace objects may refer
+ 		  to these roots, and so they can't be removed in the scavenge."
+ 		referrer := rememberedSet at: sourceIndex.
+ 		"Any potential firing ephemerons should not be scanned yet.
+ 		 Move any to the front of the set to save time in later scanning."
+ 		((manager isEphemeron: referrer)
+ 		 and: [(self isScavengeSurvivor: ((manager keyOfEphemeron: referrer))) not])
- 		[| referree |
- 		"*Don't* follow forwarding pointers here. oldSpace objects may refer
- 		 to these roots, and so they can't be removed in the scavenge."
- 		referree := rememberedSet at: sourceIndex.
- 		(self scavengeReferentsOf: referree)
  			ifTrue:
+ 				[self assert: destIndex >= numRememberedEphemerons.
+ 				 rememberedSet
+ 					at: destIndex put: (rememberedSet at: numRememberedEphemerons);
+ 					at: numRememberedEphemerons put: referrer.
+ 				 numRememberedEphemerons := numRememberedEphemerons + 1.
- 				[rememberedSet at: destIndex put: referree.
  				 destIndex := destIndex + 1]
  			ifFalse:
+ 				[(self scavengeReferentsOf: referrer)
+ 					ifTrue:
+ 						[rememberedSet at: destIndex put: referrer.
+ 						 destIndex := destIndex + 1]
+ 					ifFalse:
+ 						[manager setIsRememberedOf: referrer to: false]].
- 				[manager setIsRememberedOf: referree to: false].
  		 sourceIndex := sourceIndex + 1].
+ 	rememberedSetSize := destIndex.
+ 	self assert: self noUnfiredEphemeronsAtEndOfRememberedSet!
- 	rememberedSetSize := destIndex!

Item was added:
+ ----- Method: SpurGenerationScavenger>>scavengeUnfiredEphemeronsInRememberedSet (in category 'weakness and ephemerality') -----
+ scavengeUnfiredEphemeronsInRememberedSet
+ 	"There are ephemerons to be scavenged in the remembered set.
+ 	 Scavenge any with unfired (live) keys, removing them from the
+ 	 unscavenged ephemerons, and from the set if they no longer refer
+ 	 to new objects, and answer if any with unfired keys were found."
+ 	| unfiredEphemeronsScavenged i referrer key hasNewReferents |
+ 	unfiredEphemeronsScavenged := false.
+ 	i := 0.
+ 	[i < numRememberedEphemerons] whileTrue:
+ 		[referrer := rememberedSet at: i.
+ 		 self assert: (manager isEphemeron: referrer).
+ 		 key := manager keyOfEphemeron: referrer.
+ 		 (manager isOopForwarded: key) ifTrue:
+ 			[key := manager followForwarded: key].
+ 		 (self isScavengeSurvivor: key)
+ 			ifTrue:
+ 				[unfiredEphemeronsScavenged := true.
+ 				 hasNewReferents := self scavengeReferentsOf: referrer.
+ 				 "remove from unscanned ephemerons in set by swapping with last ephemeron"
+ 				 numRememberedEphemerons := numRememberedEphemerons - 1.
+ 				 rememberedSet
+ 					at: i
+ 					put: (rememberedSet at: numRememberedEphemerons).
+ 				 hasNewReferents
+ 					ifTrue: "keep in set"
+ 						[rememberedSet
+ 							at: numRememberedEphemerons
+ 							put: referrer]
+ 					ifFalse: "remove from set by overwriting with next-to-be scanned"
+ 						[previousRememberedSetSize := previousRememberedSetSize - 1.
+ 						 rememberedSetSize := rememberedSetSize - 1.
+ 						 rememberedSet
+ 							at: numRememberedEphemerons
+ 								put: (rememberedSet at: previousRememberedSetSize);
+ 							at: previousRememberedSetSize
+ 								put: (rememberedSet at: rememberedSetSize).
+ 						 manager setIsRememberedOf: referrer to: false]]
+ 				ifFalse:
+ 					[i := i + 1]].
+ 	^unfiredEphemeronsScavenged!

Item was added:
+ ----- Method: SpurGenerationScavenger>>scavengeUnfiredEphemeronsOnEphemeronList (in category 'weakness and ephemerality') -----
+ scavengeUnfiredEphemeronsOnEphemeronList
+ 	"There may be ephemerons to be scavenged on the ephemeronList.
+ 	 Scavenge any with unfired (live) keys, removing them from the
+ 	 list, and answer if any with unfired keys were found."
+ 	| unfiredEphemeronsScavenged corpseOffset previousCorpse |
+ 	ephemeronList ifNil:
+ 		[^false].
+ 	unfiredEphemeronsScavenged := false.
+ 	corpseOffset := ephemeronList.
+ 	[corpseOffset ~= 0] whileTrue:
+ 		[| ephemeronCorpse ephemeron nextCorpseOffset key |
+ 		 ephemeronCorpse := self corpseForCorpseOffset: corpseOffset.
+ 		 self assert: (manager isForwarded: ephemeronCorpse).
+ 		 ephemeron := manager followForwarded: ephemeronCorpse.
+ 		 nextCorpseOffset := self nextCorpseOffset: ephemeronCorpse.
+ 		 key := manager keyOfEphemeron: ephemeron.
+ 		 (manager isOopForwarded: key) ifTrue:
+ 			[key := manager followForwarded: key].
+ 		 (self isScavengeSurvivor: key)
+ 			ifTrue:
+ 				[corpseOffset = ephemeronList
+ 					ifTrue: [ephemeronList := nextCorpseOffset ~= 0 ifTrue: [nextCorpseOffset]]
+ 					ifFalse: [self setCorpseOffsetOf: previousCorpse to: nextCorpseOffset].
+ 				 unfiredEphemeronsScavenged := true.
+ 				 self cCoerceSimple: (self scavengeReferentsOf: ephemeron) to: #void]
+ 			ifFalse:
+ 				[previousCorpse := ephemeronCorpse].
+ 		 corpseOffset := nextCorpseOffset].
+ 	^unfiredEphemeronsScavenged!

Item was added:
+ ----- Method: SpurGenerationScavenger>>setCorpseOffsetOf:to: (in category 'weakness and ephemerality') -----
+ setCorpseOffsetOf: corpse to: offset
+ 	"Set the offset of the corpse's next corpse to offset.  Use the identityHash
+ 	 and format fields to construct a 27 bit offset through non-future newSpace and
+ 	 use this to implement the list. 27 bits is 2 ^ 27 slots, or at least 0.5Gb, big enough
+ 	 for any newSpace size for the near future."
+ 	manager
+ 		setHashBitsOf: corpse
+ 			to: offset >> manager formatFieldWidthShift;
+ 		setFormatOf: corpse
+ 			to: (offset bitAnd: manager formatMask)!

Item was added:
+ ----- Method: SpurMemoryManager>>isEphemeron: (in category 'object testing') -----
+ isEphemeron: objOop
+ 	self assert: (self isNonImmediate: objOop).
+ 	^(self formatOf: objOop) = self ephemeronFormat!

Item was added:
+ ----- Method: SpurMemoryManager>>keyOfEphemeron: (in category 'object access') -----
+ keyOfEphemeron: objOop
+ 	"Answer the object the ephemeron guards.  This is its first element."
+ 	self assert: ((self isNonImmediate: objOop) and: [self isEphemeron: objOop]).
+ 	^self fetchPointer: 0 ofObject: objOop!

Item was added:
+ ----- Method: StackInterpreter>>fireEphemeron: (in category 'finalization') -----
+ fireEphemeron: ephemeron
+ 	self shouldBeImplemented!



More information about the Vm-dev mailing list