Skip to content

Commit

Permalink
Add ephemeron tests with ephemeron list
Browse files Browse the repository at this point in the history
  • Loading branch information
guillep committed Aug 7, 2023
1 parent 2007a60 commit a8c3f6b
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 5 deletions.
22 changes: 17 additions & 5 deletions smalltalksrc/VMMaker/SpurGenerationScavenger.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -1290,11 +1290,17 @@ SpurGenerationScavenger >> 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 |
| unfiredEphemeronsScavenged corpseOffset previousCorpse previousList |
ephemeronList ifNil:
[^false].
unfiredEphemeronsScavenged := false.
corpseOffset := ephemeronList.

"New ephemerons get added to a new list. We work on the previous one.
Finally, we concatenate both if necessary"
previousList := ephemeronList.
ephemeronList := nil.

[corpseOffset ~= 0] whileTrue:
[| ephemeronCorpse ephemeron nextCorpseOffset |
ephemeronCorpse := self corpseForCorpseOffset: corpseOffset.
Expand All @@ -1303,14 +1309,20 @@ SpurGenerationScavenger >> scavengeUnfiredEphemeronsOnEphemeronList [
nextCorpseOffset := self nextCorpseOffset: ephemeronCorpse.
(self isScavengeSurvivor: (manager keyOfEphemeron: ephemeron))
ifTrue:
[corpseOffset = ephemeronList
ifTrue: [ephemeronList := nextCorpseOffset ~= 0 ifTrue: [nextCorpseOffset]]
[corpseOffset = previousList
ifTrue: [previousList := nextCorpseOffset ]
ifFalse: [self setCorpseOffsetOf: previousCorpse to: nextCorpseOffset].
unfiredEphemeronsScavenged := true.
self cCoerceSimple: (self scavengeReferentsOfFromOldSpace: ephemeron) to: #void]
ifFalse:
[previousCorpse := ephemeronCorpse].
ifFalse: [
previousCorpse := ephemeronCorpse].
corpseOffset := nextCorpseOffset].

"If we have a previous corpse, it is an ephemeron that did not yet survive.
Chain it to the current list that was appended from tracing the list"
previousCorpse ifNotNil: [
self setCorpseOffsetOf: previousCorpse to: (ephemeronList ifNil: 0).
ephemeronList := previousList].
^unfiredEphemeronsScavenged
]

Expand Down
86 changes: 86 additions & 0 deletions smalltalksrc/VMMakerTests/VMSpurScavengeEphemeronTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ Class {
#category : #'VMMakerTests-MemoryTests'
}

{ #category : #'tests-ephemerons-globals' }
VMSpurScavengeEphemeronTest >> pushRoot: anObject [

| link |
link := self newArrayWithSlots: 2.
memory
storePointer: 0 "Value"
ofObject: link
withValue: anObject.
memory
storePointer: 1 "Next"
ofObject: link
withValue: self keptObjectInVMVariable1.
self keepObjectInVMVariable1: link.
]

{ #category : #initialization }
VMSpurScavengeEphemeronTest >> setUp [

Expand Down Expand Up @@ -32,6 +48,76 @@ VMSpurScavengeEphemeronTest >> testDequeueMournerWithOnlyOneEphemeronShouldEmpty
self assert: memory dequeueMourner equals: nil
]

{ #category : #'tests-ephemerons-globals' }
VMSpurScavengeEphemeronTest >> testEphemeronDiscoveredDuringEphemeronListIteration [

| ephemeronObjectOop1 ephemeronObjectOop2 dicoveredEphemeron nonSurvivingKey key1 key2 |
ephemeronObjectOop1 := self newEphemeronObject.
ephemeronObjectOop2 := self newEphemeronObject.
dicoveredEphemeron := self newEphemeronObject.
key1 := self newObjectWithSlots: 0.
key2 := self newObjectWithSlots: 0.
nonSurvivingKey := self newObjectWithSlots: 0.
memory
storePointer: 0
ofObject: ephemeronObjectOop1
withValue: key1.
memory
storePointer: 0
ofObject: ephemeronObjectOop2
withValue: key2.
memory
storePointer: 0
ofObject: dicoveredEphemeron
withValue: nonSurvivingKey.
memory
storePointer: 1
ofObject: ephemeronObjectOop1
withValue: dicoveredEphemeron.

"Order is important here. The surviving key should be traced AFTER the ephemerons.
This way they are added to the ephemeron list to be traced later."
self pushRoot: key1.
self pushRoot: key2.

"Both these ephemerons must survive.
When iterating the ephemeron list, if the head survives, the head gets rewritten and the ephemeron gets traced.
If, when tracing the ephemeron a new ephemeron is discovered, it gets added at the head of the list"
self pushRoot: ephemeronObjectOop1.

"Then, when iterating the second ephemeron in the list, the head has changed!
This should be properly handled"
self pushRoot: ephemeronObjectOop2.

memory doScavenge: 1 "TenureByAge".

"Weak assertion: check the heap is in correct state"
memory setCheckForLeaks: -1.
memory runLeakCheckerFor: GCModeIncremental
]

{ #category : #'tests-ephemerons-globals' }
VMSpurScavengeEphemeronTest >> testEphemeronDiscoveredTwiceInRememberedSet [

| ephemeronObjectOop oldEphemeronObjectOop1 oldEphemeronObjectOop2 |
ephemeronObjectOop := self newEphemeronObject.
oldEphemeronObjectOop1 := self newOldEphemeronObject.
oldEphemeronObjectOop2 := self newOldEphemeronObject.
memory
storePointer: 0
ofObject: oldEphemeronObjectOop1
withValue: ephemeronObjectOop.
memory
storePointer: 0
ofObject: oldEphemeronObjectOop2
withValue: ephemeronObjectOop.

memory doScavenge: 1 "TenureByAge".

memory setCheckForLeaks: -1.
memory runLeakCheckerFor: GCModeIncremental
]

{ #category : #'tests-ephemerons-globals' }
VMSpurScavengeEphemeronTest >> testFireManyEphemeronWithSameKey [

Expand Down

0 comments on commit a8c3f6b

Please sign in to comment.