Skip to content

Commit

Permalink
- Fixing GC for perm space
Browse files Browse the repository at this point in the history
- Writing tests
  • Loading branch information
tesonep committed Jun 21, 2022
1 parent 2228c3d commit 4796869
Show file tree
Hide file tree
Showing 18 changed files with 239 additions and 82 deletions.
1 change: 1 addition & 0 deletions smalltalksrc/Slang/CCodeGenerator.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4586,6 +4586,7 @@ CCodeGenerator >> sizeOfIntegralCType: anIntegralCType [ "<String>"
['pid_t'] -> [self bytesPerWord].
"Standard C types"
['int64_t'] -> [8].
['uint64_t'] -> [8].
['uint32_t'] -> [4].
['uint16_t'] -> [2].
Expand Down
2 changes: 1 addition & 1 deletion smalltalksrc/VMMaker/CoInterpreter.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ CoInterpreter >> ceCheckAndMaybeRetryPrimitive: primIndex [
<api>
<option: #SpurObjectMemory>
| retried |

cogit recordPrimTrace ifTrue:
[self fastLogPrim: TracePrimitiveFailure].
retried := self retryPrimitiveOnFailure.
Expand Down
2 changes: 1 addition & 1 deletion smalltalksrc/VMMaker/CogVMSimulator.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -2643,7 +2643,7 @@ CogVMSimulator >> saneFunctionPointerForFailureOfPrimIndex: primIndex [
primitiveFunctionPointer is an invalid address proxy for a primitive."
| basePrimitive |

((self isOnRumpCStack: instructionPointer)
(((self isOnRumpCStack: instructionPointer) or: [self isMachineCodeIP: instructionPointer])
and: [primitiveFunctionPointer isInteger
and: [self isPrimitiveFunctionPointerAnIndex not
and: [primIndex ~= PrimNumberExternalCall
Expand Down
2 changes: 2 additions & 0 deletions smalltalksrc/VMMaker/ComposedImageReader.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ ComposedImageReader >> readImageNamed: imageName [

| aHeader |

objectMemory ensureAuxiliarStructures.

aHeader := self readHeaderFromImage: imageName.

self loadHeaderToMemory: aHeader.
Expand Down
1 change: 1 addition & 0 deletions smalltalksrc/VMMaker/SimpleStackBasedCogit.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ SimpleStackBasedCogit class >> initializeBytecodeTableForSistaV1 [
"SimpleStackBasedCogit initializeBytecodeTableForSistaV1"

BytecodeSetHasDirectedSuperSend := true.
BytecodeSetHasExtensions := true.
FirstSpecialSelector := 96.
NumSpecialSelectors := 32.
self flag:
Expand Down
57 changes: 43 additions & 14 deletions smalltalksrc/VMMaker/SpurGenerationScavenger.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,10 @@ SpurGenerationScavenger >> fireEphemeronsInRememberedSet [
ofObject: ephemeron
withValue: (self copyAndForward: key)].
"Fired ephemerons should have had their format changed."
self deny: ((self isScavengeSurvivor: key) and: [manager isEphemeron: ephemeron]).

self simulationOnly: [
self deny: ((self isScavengeSurvivor: key) and: [manager isEphemeron: ephemeron])].

(self scavengeReferentsOfFromOldSpace: ephemeron)
ifTrue: "keep in set"
[i := i + 1]
Expand Down Expand Up @@ -513,7 +516,11 @@ SpurGenerationScavenger >> fireEphemeronsOnEphemeronList [
oldList := ephemeronList.
ephemeronList := nil.
[ephemeronCorpse notNil] whileTrue:
[self assert: ((manager isYoung: ephemeronCorpse) and: [manager isForwarded: ephemeronCorpse]).
[
self simulationOnly: [
self assert: ((manager isYoung: ephemeronCorpse)
and: [manager isForwarded: ephemeronCorpse])].

ephemeron := manager followForwarded: ephemeronCorpse.
key := manager keyOfMaybeFiredEphemeron: ephemeron.
(self isScavengeSurvivor: key) ifFalse:
Expand Down Expand Up @@ -708,6 +715,8 @@ SpurGenerationScavenger >> mapOopsFromPermSpace [

| destIndex sourceIndex referrer |

<inline: #never>

sourceIndex := destIndex := 0.

"I iterate all the remembered set from the perm space to scavenge the references to new objects.
Expand All @@ -721,7 +730,7 @@ SpurGenerationScavenger >> mapOopsFromPermSpace [
self deny: (manager isEphemeron: referrer).
self deny: (manager isWeakNonImm: referrer).

(self scavengeReferentsOf: referrer additionalShouldKeepReferrerTestingBlock: [:aReferrer :referent | (manager isPermanent: referent) not])
(self scavengeReferentsOfFromPermSpace: referrer)
ifTrue:
[manager getFromPermSpaceRememberedSet save: referrer at: destIndex.
destIndex := destIndex + 1]
Expand Down Expand Up @@ -752,8 +761,10 @@ SpurGenerationScavenger >> newSpaceStart: startAddress newSpaceBytes: totalBytes
pastSpace start: startAddress; limit: startAddress + survivorBytes.
futureSpace start: pastSpace limit; limit: pastSpace limit + survivorBytes.
eden start: futureSpace limit; limit: startAddress + totalBytes.

manager getFromOldSpaceRememberedSet fudge: self rememberedSetFudge.

manager getFromPermSpaceRememberedSet fudge: self rememberedSetFudge.

self assert: self futureSpace limit <= (startAddress + totalBytes).
self assert: self eden start \\ manager allocationUnit
+ (self eden limit \\ manager allocationUnit) = 0.
Expand Down Expand Up @@ -1095,17 +1106,22 @@ SpurGenerationScavenger >> scavengeReferentsOf: referrer additionalShouldKeepRef

| fmt foundNewReferentOrIsWeakling numSlots |

"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: [(self isScavengeSurvivor: (manager keyOfEphemeron: referrer))
or: [self is: referrer onWeaklingList: ephemeronList]]).
self simulationOnly: [
"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: [(self isScavengeSurvivor: (manager keyOfEphemeron: referrer))
or: [self is: referrer onWeaklingList: ephemeronList]]) ].

fmt := manager formatOf: referrer.
foundNewReferentOrIsWeakling := manager isWeakFormat: fmt.

numSlots := manager numStrongSlotsOf: referrer format: fmt ephemeronInactiveIf: #isScavengeSurvivor:.

foundNewReferentOrIsWeakling := manager isWeakFormat: fmt.

0 to: numSlots - 1 do:
[:i| | referent newLocation |
referent := manager fetchPointer: i ofMaybeForwardedObject: referrer.
Expand All @@ -1132,9 +1148,19 @@ SpurGenerationScavenger >> scavengeReferentsOf: referrer additionalShouldKeepRef
{ #category : #scavenger }
SpurGenerationScavenger >> scavengeReferentsOfFromOldSpace: referrer [

<inline: #never>

^ self scavengeReferentsOf: referrer additionalShouldKeepReferrerTestingBlock: [ :aReferrer :aReferent | false ].
]

{ #category : #scavenger }
SpurGenerationScavenger >> scavengeReferentsOfFromPermSpace: referrer [

<inline: #never>

^ self scavengeReferentsOf: referrer additionalShouldKeepReferrerTestingBlock: [:aReferrer :referent | (manager isPermanent: referent) not].
]

{ #category : #scavenger }
SpurGenerationScavenger >> scavengeRememberedSetStartingAt: n [
"scavengeRememberedSetStartingAt: n traverses objects in the remembered
Expand All @@ -1143,7 +1169,10 @@ SpurGenerationScavenger >> scavengeRememberedSetStartingAt: n [
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."

<inline: false>
<returnTypeC: #void>

| destIndex sourceIndex referrer |
sourceIndex := destIndex := n.
[sourceIndex < manager getFromOldSpaceRememberedSet rememberedSetSize] whileTrue:
Expand All @@ -1167,7 +1196,7 @@ SpurGenerationScavenger >> scavengeRememberedSetStartingAt: n [
[manager setIsRememberedOf: referrer to: false]].
sourceIndex := sourceIndex + 1].
manager getFromOldSpaceRememberedSet rememberedSetSize: destIndex.
self assert: self noUnfiredEphemeronsAtEndOfRememberedSet
self assert: self noUnfiredEphemeronsAtEndOfRememberedSet.
]

{ #category : #'weakness and ephemerality' }
Expand Down
3 changes: 3 additions & 0 deletions smalltalksrc/VMMaker/SpurImageReader.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ SpurImageReader >> readImageNamed: imageName [
<api>

| file |

objectMemory ensureAuxiliarStructures.

file := self sqImageFile: imageName Open: 'rb'.
file ifNil: [
self logError: 'Image file cannot be read: %s' _: imageName.
Expand Down
68 changes: 45 additions & 23 deletions smalltalksrc/VMMaker/SpurMemoryManager.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -1367,9 +1367,10 @@ SpurMemoryManager >> addressCouldBeObj: address [
<inline: false>
^(address bitAnd: self baseHeaderSize - 1) = 0
and: [(self isInOldSpace: address)
or: [(self isInPermSpace: address)
or: [(self isInEden: address)
or: [(self isInPastSpace: address)
or: [self scavengeInProgress and: [self isInFutureSpace: address]]]]]
or: [self scavengeInProgress and: [self isInFutureSpace: address]]]]]]
]
{ #category : #'debug support' }
Expand Down Expand Up @@ -1875,7 +1876,7 @@ SpurMemoryManager >> allPermSpaceObjectsDo: aBlockClosure [
[ currentObject = permSpaceFreeStart ]
whileFalse: [
aBlockClosure value: currentObject.
currentObject := self objectAfter: currentObject limit: memoryMap permSpaceEnd ].
currentObject := self objectAfter: currentObject limit: permSpaceFreeStart ].
]
{ #category : #'weakness and ephemerality' }
Expand Down Expand Up @@ -3296,7 +3297,7 @@ SpurMemoryManager >> checkHeapIntegrity: excludeUnmarkedObjs classIndicesShouldB
[containsYoung := false.
(self isRemembered: obj) ifTrue:
[numRememberedObjectsInHeap := numRememberedObjectsInHeap + 1.
(scavenger isInRememberedSet: obj) ifFalse:
(fromOldSpaceRememberedSet isInRememberedSet: obj) ifFalse:
[coInterpreter print: 'remembered object '; printHex: obj; print: ' is not in remembered table'; cr.
self eek.
ok := false]].
Expand Down Expand Up @@ -3344,7 +3345,7 @@ SpurMemoryManager >> checkHeapIntegrity: excludeUnmarkedObjs classIndicesShouldB
"But the system copes with overflow..."
self flag: 'no support for remembered set overflow yet'.
"ok := rootTableOverflowed and: [needGCFlag]"].
scavenger rememberedSetWithIndexDo:
fromOldSpaceRememberedSet rememberedSetWithIndexDo:
[:obj :i|
(obj bitAnd: self wordSize - 1) ~= 0
ifTrue:
Expand Down Expand Up @@ -3466,7 +3467,8 @@ SpurMemoryManager >> checkOkayYoungReferrer: obj [
(self isRemembered: obj) ifFalse:
[ self print: 'remembered bit is not set in '; printHex: obj; cr. ^false ].
(scavenger isInRememberedSet: obj) ifTrue: [^true].
(self getFromOldSpaceRememberedSet isInRememberedSet: obj) ifTrue: [^true].
(self getFromPermSpaceRememberedSet isInRememberedSet: obj) ifTrue: [^true].
self printHex: obj; print: ' has remembered bit set but is not in remembered set'; cr.
Expand Down Expand Up @@ -4503,6 +4505,27 @@ SpurMemoryManager >> endianness [
self subclassResponsibility
]
{ #category : #initialization }
SpurMemoryManager >> ensureAuxiliarStructures [
self
cCode: [
fromOldSpaceRememberedSet isNil ifTrue: [
fromOldSpaceRememberedSet := self
cCoerce: (self malloc: (self sizeof: VMRememberedSet))
to: #'VMRememberedSet *'.
fromOldSpaceRememberedSet rootIndex: OldRememberedSetRootIndex].
fromPermSpaceRememberedSet isNil ifTrue: [
fromPermSpaceRememberedSet := self
cCoerce: (self malloc: (self sizeof: VMRememberedSet))
to: #'VMRememberedSet *'.
fromPermSpaceRememberedSet rootIndex: PermRememberedSetRootIndex]].
]
{ #category : #'class table' }
SpurMemoryManager >> ensureBehaviorHash: aBehavior [
| hash err |
Expand Down Expand Up @@ -5788,6 +5811,7 @@ SpurMemoryManager >> globalGarbageCollect [
self runLeakCheckerFor: GCModeFull
excludeUnmarkedObjs: true
classIndicesShouldBeValid: true.
compactionStartUsecs := coInterpreter ioUTCMicrosecondsNow.
segmentManager prepareForGlobalSweep. "for notePinned:"
compactor compact.
Expand Down Expand Up @@ -6536,20 +6560,6 @@ SpurMemoryManager >> initializeObjectMemory: bytesToShift [
self initializeOldSpaceFirstFree: freeOldSpaceStart. "initializes endOfMemory, freeStart, free space"
self initializeNewSpaceVariables.
self
cCode: [
fromOldSpaceRememberedSet := self
cCoerce: (self malloc: (self sizeof: VMRememberedSet))
to: #'VMRememberedSet *'.
fromOldSpaceRememberedSet rootIndex: OldRememberedSetRootIndex.
fromPermSpaceRememberedSet := self
cCoerce: (self malloc: (self sizeof: VMRememberedSet))
to: #'VMRememberedSet *'.
fromOldSpaceRememberedSet rootIndex: PermRememberedSetRootIndex].
fromOldSpaceRememberedSet initializeRememberedSet.
fromPermSpaceRememberedSet initializeRememberedSet.
Expand Down Expand Up @@ -7203,6 +7213,17 @@ SpurMemoryManager >> isInPastSpace: address [
andLessThan: pastSpaceStart
]
{ #category : #'object testing' }
SpurMemoryManager >> isInPermSpace: address [
<api>
^self
oop: address
isGreaterThanOrEqualTo: memoryMap permSpaceStart
andLessThan: memoryMap permSpaceEnd
]
{ #category : #immediates }
SpurMemoryManager >> isInRangeCharacterCode: characterCode [
^characterCode between: 0 and: (1 << 30) - 1
Expand Down Expand Up @@ -8323,6 +8344,7 @@ SpurMemoryManager >> markAndTraceObjStack: stackOrNil andContents: markAndTraceC
SpurMemoryManager >> markAndTraceRememberedSet: aRememberedSet [
| rememberedSetOop |
rememberedSetOop := aRememberedSet objectOop.
self setIsMarkedOf: rememberedSetOop to: true.
aRememberedSet rememberedSetWithIndexDo: [ :objOop :i |
Expand Down Expand Up @@ -8402,7 +8424,7 @@ SpurMemoryManager >> markLoopFrom: objOop [
[index > 0] whileTrue:
[index := index - 1.
field := self fetchPointer: index ofObject: objToScan.
(self isNonImmediate: field) ifTrue:
((self isNonImmediate: field) and: [(self isPermanent: field) not]) ifTrue:
[(self isForwarded: field) ifTrue: "fixFollowedField: is /not/ inlined"
[field := self fixFollowedField: index ofObject: objToScan withInitialValue: field].
(self markAndShouldScan: field) ifTrue:
Expand All @@ -8422,7 +8444,7 @@ SpurMemoryManager >> markLoopFrom: objOop [
[index > 0] whileTrue:
[index := index - 1.
field := self fetchPointer: index ofObject: objToScan.
(self isNonImmediate: field) ifTrue:
((self isNonImmediate: field) and: [(self isPermanent: field) not]) ifTrue:
[(self isForwarded: field) ifTrue: "fixFollowedField: is /not/ inlined"
[field := self fixFollowedField: index ofObject: objToScan withInitialValue: field].
(self markAndShouldScan: field) ifTrue:
Expand Down Expand Up @@ -10771,10 +10793,10 @@ SpurMemoryManager >> rememberObjInCorrectRememberedSet: objOop [
<api>
(self isOld: objOop) ifTrue: [
fromOldSpaceRememberedSet doRemember: objOop ].
^ fromOldSpaceRememberedSet doRemember: objOop ].
(self isPermanent: objOop) ifTrue: [
fromPermSpaceRememberedSet doRemember: objOop ].
^ fromPermSpaceRememberedSet doRemember: objOop ].
]
Expand Down
13 changes: 8 additions & 5 deletions smalltalksrc/VMMaker/SpurPlanningCompactor.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ SpurPlanningCompactor >> unpinRememberedSet [
<inline: true>
firstFieldOfRememberedSet := manager fetchPointer: 0 ofObject: manager oldRememberedSetObj.
manager setIsPinnedOf: manager oldRememberedSetObj to: false.
firstFieldOfPermRememberedSet := manager fetchPointer: 0 ofObject: manager permRememberedSetObj.
manager setIsPinnedOf: manager permRememberedSetObj to: false
]
Expand Down Expand Up @@ -909,10 +909,13 @@ SpurPlanningCompactor >> updatePointersInManagerHeapEntities [
[firstFieldOfRememberedSet := manager fetchPointer: 0 ofObject: firstFieldOfRememberedSet].
self relocateObjectsInHeapEntity: manager oldRememberedSetObj from: 1 to: manager getFromOldSpaceRememberedSet rememberedSetSize - 1.
(manager getFromPermSpaceRememberedSet rememberedSetSize > 0
and: [self isMobile: firstFieldOfPermRememberedSet]) ifTrue:
[firstFieldOfPermRememberedSet := manager fetchPointer: 0 ofObject: firstFieldOfPermRememberedSet].
self relocateObjectsInHeapEntity: manager permRememberedSetObj from: 1 to: manager getFromPermSpaceRememberedSet rememberedSetSize - 1
(manager getFromPermSpaceRememberedSet rememberedSetSize > 0) ifTrue:
[self updatePointersIn: firstFieldOfPermRememberedSet ].
manager getFromPermSpaceRememberedSet
rememberedSetWithIndexDo: [ :oop :index |
self updatePointersIn: oop ] startingAt: 1.
"Note that we /must not/ set the rememberedSetObj here since it is a slot in the hiddenRootsObj
and will be updated normally in updatePointersInInitialImmobileObjects. So do not do
Expand Down
4 changes: 3 additions & 1 deletion smalltalksrc/VMMaker/StackInterpreter.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -5224,7 +5224,9 @@ StackInterpreter >> encodeFrameFieldHasContext: hasContext "<Boolean>" isBlock:
{ #category : #simulation }
StackInterpreter >> encoderClassForHeader: headerInteger [
<doNotGenerate>
^Smalltalk classNamed: ((headerInteger < 0 or: [objectMemory headerIndicatesAlternateBytecodeSet: headerInteger])

^Smalltalk classNamed: ((MULTIPLEBYTECODESETS
and: [headerInteger < 0 or: [objectMemory headerIndicatesAlternateBytecodeSet: headerInteger]])
ifTrue: [AltBytecodeEncoderClassName]
ifFalse: [BytecodeEncoderClassName])
]
Expand Down
1 change: 1 addition & 0 deletions smalltalksrc/VMMaker/StackToRegisterMappingCogit.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ StackToRegisterMappingCogit class >> initializeBytecodeTableForSistaV1 [
numPushNilsFunction := #sistaV1:Num:Push:Nils:.
pushNilSizeFunction := #sistaV1PushNilSize:numInitialNils:.
BytecodeSetHasDirectedSuperSend := true.
BytecodeSetHasExtensions := true.
FirstSpecialSelector := 96.
NumSpecialSelectors := 32.
self flag:
Expand Down

0 comments on commit 4796869

Please sign in to comment.