Skip to content

Commit 1c31464

Browse files
committed
Populate first object table during fix-up instead.
1 parent 762ce84 commit 1c31464

File tree

5 files changed

+65
-66
lines changed

5 files changed

+65
-66
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java

+3-9
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ private void fixupReferencesBeforeCompaction(ChunkReleaser chunkReleaser, Timers
284284
try {
285285
AlignedHeapChunk.AlignedHeader aChunk = space.getFirstAlignedHeapChunk();
286286
while (aChunk.isNonNull()) {
287-
ObjectMoveInfo.walkObjects(aChunk, fixupVisitor);
287+
ObjectMoveInfo.walkObjectsForFixup(aChunk, fixupVisitor);
288288
aChunk = HeapChunk.getNext(aChunk);
289289
}
290290
} finally {
@@ -396,16 +396,10 @@ private void compact(Timers timers) {
396396

397397
Timer oldCompactionRememberedSetsTimer = timers.oldCompactionRememberedSets.open();
398398
try {
399+
// Clear the card tables (which currently contain brick tables).
400+
// The first-object tables have already been populated.
399401
chunk = space.getFirstAlignedHeapChunk();
400402
while (chunk.isNonNull()) {
401-
/*
402-
* Clears the card table (which currently contains the brick table) and updates the
403-
* first object table.
404-
*
405-
* GR-54022: we should be able to avoid this pass and build the first object tables
406-
* during planning and reset card tables once we detect that we are finished with a
407-
* chunk during compaction. The remembered set bits are already set after planning.
408-
*/
409403
if (!AlignedHeapChunk.isEmpty(chunk)) {
410404
RememberedSet.get().clearRememberedSet(chunk);
411405
} // empty chunks will be freed or reset before reuse, no need to reinitialize here

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ private Object copyAlignedObject(Object originalObj) {
449449
if (SerialGCOptions.useCompactingOldGen() && GCImpl.getGCImpl().isCompleteCollection()) {
450450
/*
451451
* In a compacting complete collection, the remembered set bit is set already during
452-
* marking and the first object table is built during planning.
452+
* marking and the first object table is built later during fix-up.
453453
*/
454454
} else {
455455
/*

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/ObjectMoveInfo.java

+34-7
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626

2727
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
2828

29-
import com.oracle.svm.core.util.VMError;
30-
import jdk.graal.compiler.word.Word;
3129
import org.graalvm.word.Pointer;
3230
import org.graalvm.word.UnsignedWord;
3331

@@ -37,10 +35,14 @@
3735
import com.oracle.svm.core.genscavenge.AlignedHeapChunk;
3836
import com.oracle.svm.core.genscavenge.HeapChunk;
3937
import com.oracle.svm.core.genscavenge.ObjectHeaderImpl;
38+
import com.oracle.svm.core.genscavenge.remset.AlignedChunkRememberedSet;
4039
import com.oracle.svm.core.genscavenge.remset.BrickTable;
40+
import com.oracle.svm.core.genscavenge.remset.FirstObjectTable;
4141
import com.oracle.svm.core.hub.LayoutEncoding;
42+
import com.oracle.svm.core.util.VMError;
4243

4344
import jdk.graal.compiler.api.replacements.Fold;
45+
import jdk.graal.compiler.word.Word;
4446

4547
/**
4648
* {@link PlanningVisitor} decides where objects will be moved and uses the methods of this class to
@@ -165,21 +167,46 @@ static boolean useCompressedLayout() {
165167
* @see AlignedHeapChunk#walkObjects
166168
*/
167169
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
168-
public static void walkObjects(AlignedHeapChunk.AlignedHeader chunkHeader, ObjectFixupVisitor visitor) {
169-
Pointer p = AlignedHeapChunk.getObjectsStart(chunkHeader);
170+
public static void walkObjectsForFixup(AlignedHeapChunk.AlignedHeader chunk, ObjectFixupVisitor visitor) {
171+
FirstObjectTable.initializeTable(AlignedChunkRememberedSet.getFirstObjectTableStart(chunk), AlignedChunkRememberedSet.getFirstObjectTableSize());
172+
173+
Pointer p = AlignedHeapChunk.getObjectsStart(chunk);
170174
do {
171-
Pointer nextObjSeq = getNextObjectSeqAddress(p);
172-
Pointer objSeqEnd = p.add(getObjectSeqSize(p));
173-
assert objSeqEnd.belowOrEqual(HeapChunk.getTopPointer(chunkHeader));
175+
Pointer objSeq = p;
176+
Pointer nextObjSeq = getNextObjectSeqAddress(objSeq);
177+
Pointer objSeqNewAddress = getNewAddress(objSeq);
178+
AlignedHeapChunk.AlignedHeader objSeqNewChunk = AlignedHeapChunk.getEnclosingChunkFromObjectPointer(objSeqNewAddress);
179+
Pointer objSeqEnd = objSeq.add(getObjectSeqSize(objSeq));
180+
assert objSeqEnd.belowOrEqual(HeapChunk.getTopPointer(chunk));
174181
while (p.notEqual(objSeqEnd)) {
175182
assert p.belowThan(objSeqEnd);
176183
Object obj = p.toObject();
177184
UnsignedWord objSize = LayoutEncoding.getSizeFromObjectInlineInGC(obj);
185+
186+
/*
187+
* Add the object's new location to the first object table of the target chunk. Note
188+
* that we have already encountered that chunk and initialized its table earlier.
189+
*
190+
* Rebuilding the table is also required for swept chunks, where dead objects can
191+
* mean that another object is now the first object in a range.
192+
*/
193+
Pointer newAddress = objSeqNewAddress.add(p.subtract(objSeq));
194+
UnsignedWord offset = newAddress.subtract(AlignedHeapChunk.getObjectsStart(objSeqNewChunk));
195+
FirstObjectTable.setTableForObject(AlignedChunkRememberedSet.getFirstObjectTableStart(objSeqNewChunk), offset, offset.add(objSize));
196+
178197
if (!visitor.visitObjectInline(obj)) {
179198
throw VMError.shouldNotReachHereAtRuntime();
180199
}
200+
181201
p = p.add(objSize);
182202
}
203+
if (nextObjSeq.isNonNull() && chunk.getShouldSweepInsteadOfCompact()) {
204+
// We will write a filler object here, add the location to the first object table.
205+
assert p.belowThan(nextObjSeq);
206+
UnsignedWord offset = p.subtract(AlignedHeapChunk.getObjectsStart(chunk));
207+
UnsignedWord size = nextObjSeq.subtract(p);
208+
FirstObjectTable.setTableForObject(AlignedChunkRememberedSet.getFirstObjectTableStart(chunk), offset, offset.add(size));
209+
}
183210
p = nextObjSeq;
184211
} while (p.isNonNull());
185212
}

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/PlanningVisitor.java

+18-45
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@
3434
import com.oracle.svm.core.genscavenge.HeapChunk;
3535
import com.oracle.svm.core.genscavenge.ObjectHeaderImpl;
3636
import com.oracle.svm.core.genscavenge.Space;
37-
import com.oracle.svm.core.genscavenge.remset.AlignedChunkRememberedSet;
3837
import com.oracle.svm.core.genscavenge.remset.BrickTable;
39-
import com.oracle.svm.core.genscavenge.remset.FirstObjectTable;
4038
import com.oracle.svm.core.hub.LayoutEncoding;
4139

4240
import jdk.graal.compiler.word.Word;
@@ -58,9 +56,6 @@ public PlanningVisitor() {
5856
public void init(Space space) {
5957
allocChunk = space.getFirstAlignedHeapChunk();
6058
allocPointer = AlignedHeapChunk.getObjectsStart(allocChunk);
61-
if (!allocChunk.getShouldSweepInsteadOfCompact()) {
62-
FirstObjectTable.initializeTable(AlignedChunkRememberedSet.getFirstObjectTableStart(allocChunk), AlignedChunkRememberedSet.getFirstObjectTableSize());
63-
}
6459
}
6560

6661
@Override
@@ -120,43 +115,12 @@ public boolean visitChunk(AlignedHeapChunk.AlignedHeader chunk) {
120115
}
121116

122117
objSeqSize = objSeqSize.add(objSize);
123-
if (!sweeping) {
124-
if (allocPointer.add(objSeqSize).aboveThan(AlignedHeapChunk.getObjectsEnd(allocChunk))) {
125-
/* Out of space, move to the start of the next chunk. */
126-
allocChunk = HeapChunk.getNext(allocChunk);
127-
assert allocChunk.isNonNull();
128-
assert !allocChunk.getShouldSweepInsteadOfCompact();
129-
allocPointer = AlignedHeapChunk.getObjectsStart(allocChunk);
130-
131-
/*
132-
* TODO: we should reset the FOT entries we already wrote in the last chunk
133-
* (but they should not be accessed, not even by heap verification)
134-
*/
135-
136-
/* Visit previous objects in sequence again to write new FOT entries. */
137-
FirstObjectTable.initializeTable(AlignedChunkRememberedSet.getFirstObjectTableStart(allocChunk), AlignedChunkRememberedSet.getFirstObjectTableSize());
138-
Pointer q = objSeq;
139-
while (q.notEqual(p)) {
140-
UnsignedWord offset = q.subtract(objSeq);
141-
UnsignedWord size = LayoutEncoding.getSizeFromObjectInlineInGC(q.toObject());
142-
FirstObjectTable.setTableForObject(AlignedChunkRememberedSet.getFirstObjectTableStart(allocChunk), offset, offset.add(size));
143-
q = q.add(size);
144-
}
145-
}
146-
147-
Pointer allocEndOffset = allocPointer.add(objSeqSize).subtract(AlignedHeapChunk.getObjectsStart(allocChunk));
148-
FirstObjectTable.setTableForObject(AlignedChunkRememberedSet.getFirstObjectTableStart(allocChunk), allocEndOffset.subtract(objSize), allocEndOffset);
149-
}
150118

151119
} else { // not marked, i.e. not alive and start of a gap of yet unknown size
152120
if (objSeqSize.notEqual(0)) { // end of an object sequence
121+
Pointer newAddress = sweeping ? objSeq : allocate(objSeqSize);
122+
ObjectMoveInfo.setNewAddress(objSeq, newAddress);
153123
ObjectMoveInfo.setObjectSeqSize(objSeq, objSeqSize);
154-
if (sweeping) {
155-
ObjectMoveInfo.setNewAddress(objSeq, objSeq);
156-
} else {
157-
ObjectMoveInfo.setNewAddress(objSeq, allocPointer);
158-
allocPointer = allocPointer.add(objSeqSize); // ensured enough memory above
159-
}
160124

161125
objSeqSize = Word.zero();
162126

@@ -175,15 +139,10 @@ public boolean visitChunk(AlignedHeapChunk.AlignedHeader chunk) {
175139

176140
if (gapSize.notEqual(0)) { // truncate gap at chunk end
177141
chunk.setTopOffset(chunk.getTopOffset().subtract(gapSize));
178-
179142
} else if (objSeqSize.notEqual(0)) {
143+
Pointer newAddress = sweeping ? objSeq : allocate(objSeqSize);
144+
ObjectMoveInfo.setNewAddress(objSeq, newAddress);
180145
ObjectMoveInfo.setObjectSeqSize(objSeq, objSeqSize);
181-
if (sweeping) {
182-
ObjectMoveInfo.setNewAddress(objSeq, objSeq);
183-
} else {
184-
ObjectMoveInfo.setNewAddress(objSeq, allocPointer);
185-
allocPointer = allocPointer.add(objSeqSize); // ensured enough memory above
186-
}
187146
}
188147

189148
if (sweeping) {
@@ -209,4 +168,18 @@ public boolean visitChunk(AlignedHeapChunk.AlignedHeader chunk) {
209168

210169
return true;
211170
}
171+
172+
private Pointer allocate(UnsignedWord size) {
173+
Pointer p = allocPointer;
174+
allocPointer = allocPointer.add(size);
175+
if (allocPointer.aboveThan(AlignedHeapChunk.getObjectsEnd(allocChunk))) {
176+
allocChunk = HeapChunk.getNext(allocChunk);
177+
assert allocChunk.isNonNull();
178+
assert !allocChunk.getShouldSweepInsteadOfCompact();
179+
180+
p = AlignedHeapChunk.getObjectsStart(allocChunk);
181+
allocPointer = p.add(size);
182+
}
183+
return p;
184+
}
212185
}

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/SweepingVisitor.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import org.graalvm.word.UnsignedWord;
3131

3232
import com.oracle.svm.core.config.ConfigurationValues;
33+
import com.oracle.svm.core.genscavenge.AlignedHeapChunk;
34+
import com.oracle.svm.core.genscavenge.HeapChunk;
3335
import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode;
3436
import com.oracle.svm.core.genscavenge.graal.nodes.FormatObjectNode;
3537
import com.oracle.svm.core.heap.FillerArray;
@@ -62,12 +64,15 @@ static int arrayBaseOffset() {
6264

6365
@Override
6466
public boolean visit(Pointer objSeq, UnsignedWord size, Pointer newAddress, Pointer nextObjSeq) {
67+
assert objSeq.equal(newAddress);
6568
if (nextObjSeq.isNonNull()) {
6669
Pointer gapStart = objSeq.add(size);
67-
assert gapStart.belowOrEqual(nextObjSeq);
68-
if (gapStart.notEqual(nextObjSeq)) {
69-
writeFillerObjectAt(gapStart, nextObjSeq.subtract(gapStart));
70-
}
70+
assert gapStart.belowThan(nextObjSeq);
71+
writeFillerObjectAt(gapStart, nextObjSeq.subtract(gapStart));
72+
// Note that we have already added first object table entries for fillers during fixup.
73+
} else {
74+
AlignedHeapChunk.AlignedHeader chunk = AlignedHeapChunk.getEnclosingChunkFromObjectPointer(objSeq);
75+
assert objSeq.add(size).equal(HeapChunk.getTopPointer(chunk));
7176
}
7277
return true;
7378
}

0 commit comments

Comments
 (0)