Skip to content

Commit d00bd3e

Browse files
committed
Improvements and minor fixes.
1 parent 34f2556 commit d00bd3e

22 files changed

+381
-301
lines changed

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,14 @@
5252
* Most allocation within a AlignedHeapChunk is via fast-path allocation snippets, but a slow-path
5353
* allocation method is available.
5454
* <p>
55-
* Objects in a AlignedHeapChunk have to be promoted by copying from their current HeapChunk to a
56-
* destination HeapChunk.
57-
* <p>
58-
* An AlignedHeapChunk is laid out:
55+
* An AlignedHeapChunk is laid out as follows:
5956
*
6057
* <pre>
61-
* +===============+-------+--------+----------------------+
62-
* | AlignedHeader | Card | First | Object ... |
63-
* | Fields | Table | Object | |
64-
* | | | Table | |
65-
* +===============+-------+--------+----------------------+
58+
* +===============+-------+--------+-----------------+-----------------+
59+
* | AlignedHeader | Card | First | Initial Object | Object ... |
60+
* | Fields | Table | Object | Move Info (only | |
61+
* | | | Table | Compacting GC) | |
62+
* +===============+-------+--------+-----------------+-----------------+
6663
* </pre>
6764
*
6865
* The size of both the CardTable and the FirstObjectTable depends on the used {@link RememberedSet}
@@ -107,6 +104,10 @@ public static Pointer getObjectsEnd(AlignedHeader that) {
107104
return HeapChunk.getEndPointer(that);
108105
}
109106

107+
public static boolean isEmpty(AlignedHeader that) {
108+
return HeapChunk.getTopOffset(that).equal(getObjectsStartOffset());
109+
}
110+
110111
/** Allocate uninitialized memory within this AlignedHeapChunk. */
111112
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
112113
static Pointer allocateMemory(AlignedHeader that, UnsignedWord size) {

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

Lines changed: 166 additions & 119 deletions
Large diffs are not rendered by default.

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

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@
2424
*/
2525
package com.oracle.svm.core.genscavenge;
2626

27-
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.EXTREMELY_SLOW_PATH_PROBABILITY;
28-
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
29-
3027
import org.graalvm.nativeimage.Platform;
3128
import org.graalvm.nativeimage.Platforms;
3229
import org.graalvm.word.Pointer;
@@ -38,8 +35,6 @@
3835
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
3936
import com.oracle.svm.core.heap.ObjectVisitor;
4037
import com.oracle.svm.core.log.Log;
41-
import com.oracle.svm.core.thread.VMOperation;
42-
import com.oracle.svm.core.util.VMError;
4338

4439
/**
4540
* An OldGeneration has two Spaces, {@link #fromSpace} for existing objects, and {@link #toSpace}
@@ -109,7 +104,7 @@ void releaseSpaces(ChunkReleaser chunkReleaser) {
109104

110105
@Override
111106
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
112-
void beginPromotion(YoungGeneration youngGen, boolean incrementalGc) {
107+
void beginPromotion(boolean incrementalGc) {
113108
if (incrementalGc) {
114109
emptyFromSpaceIntoToSpace();
115110
}
@@ -161,9 +156,8 @@ void blackenDirtyCardRoots(GreyToBlackObjectVisitor visitor) {
161156
}
162157

163158
@Override
164-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
165159
boolean isInSpace(Pointer ptr) {
166-
return HeapImpl.findPointerInSpace(fromSpace, ptr) || HeapImpl.findPointerInSpace(toSpace, ptr);
160+
return fromSpace.contains(ptr) || toSpace.contains(ptr);
167161
}
168162

169163
@Override
@@ -216,18 +210,6 @@ UnsignedWord computeObjectBytes() {
216210
return fromSpace.computeObjectBytes().add(toSpace.computeObjectBytes());
217211
}
218212

219-
@Override
220-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
221-
AlignedHeapChunk.AlignedHeader requestAlignedChunk() {
222-
assert VMOperation.isGCInProgress() : "Should only be called from the collector.";
223-
AlignedHeapChunk.AlignedHeader chunk = HeapImpl.getChunkProvider().produceAlignedChunk();
224-
if (probability(EXTREMELY_SLOW_PATH_PROBABILITY, chunk.isNull())) {
225-
throw VMError.shouldNotReachHere("OldGeneration.requestAlignedChunk: failure to allocate aligned chunk");
226-
}
227-
RememberedSet.get().enableRememberedSetForChunk(chunk);
228-
return chunk;
229-
}
230-
231213
@Override
232214
void checkSanityBeforeCollection() {
233215
assert toSpace.isEmpty() : "toSpace should be empty before a collection.";

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ private void blackenDirtyCardRoots() {
999999
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
10001000
private static void beginPromotion(boolean isIncremental) {
10011001
HeapImpl heap = HeapImpl.getHeapImpl();
1002-
heap.getOldGeneration().beginPromotion(heap.getYoungGeneration(), isIncremental);
1002+
heap.getOldGeneration().beginPromotion(isIncremental);
10031003
if (isIncremental) {
10041004
heap.getYoungGeneration().beginPromotion();
10051005
}
@@ -1084,7 +1084,7 @@ private void promotePinnedObject(PinnedObjectImpl pinned) {
10841084
boolean isAligned = ObjectHeaderImpl.isAlignedObject(referent);
10851085
Header<?> originalChunk = getChunk(referent, isAligned);
10861086
Space originalSpace = HeapChunk.getSpace(originalChunk);
1087-
if (originalSpace.isFromSpace() || originalSpace.isCompactingOldSpace()) {
1087+
if (originalSpace.isFromSpace() || (originalSpace.isCompactingOldSpace() && completeCollection)) {
10881088
boolean promoted = false;
10891089
if (!completeCollection && originalSpace.getNextAgeForPromotion() < policy.getTenuringAge()) {
10901090
promoted = heap.getYoungGeneration().promotePinnedObject(referent, originalChunk, isAligned, originalSpace);

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

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -751,10 +751,10 @@ private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAcc
751751

752752
if (allowJavaHeapAccess) {
753753
// Accessing spaces and chunks is safe if we prevent a GC.
754-
if (isInYoungGen(ptr)) {
754+
if (youngGeneration.isInSpace(ptr)) {
755755
log.string("points into the young generation");
756756
return true;
757-
} else if (isInOldGen(ptr)) {
757+
} else if (oldGeneration.isInSpace(ptr)) {
758758
log.string("points into the old generation");
759759
return true;
760760
}
@@ -769,51 +769,7 @@ private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAcc
769769
}
770770

771771
boolean isInHeap(Pointer ptr) {
772-
return isInImageHeap(ptr) || isInYoungGen(ptr) || isInOldGen(ptr);
773-
}
774-
775-
@Uninterruptible(reason = "Prevent that chunks are freed.")
776-
private boolean isInYoungGen(Pointer ptr) {
777-
if (findPointerInSpace(youngGeneration.getEden(), ptr)) {
778-
return true;
779-
}
780-
781-
for (int i = 0; i < youngGeneration.getMaxSurvivorSpaces(); i++) {
782-
if (findPointerInSpace(youngGeneration.getSurvivorFromSpaceAt(i), ptr)) {
783-
return true;
784-
}
785-
if (findPointerInSpace(youngGeneration.getSurvivorToSpaceAt(i), ptr)) {
786-
return true;
787-
}
788-
}
789-
return false;
790-
}
791-
792-
@Uninterruptible(reason = "Prevent that chunks are freed.")
793-
private boolean isInOldGen(Pointer ptr) {
794-
return oldGeneration.isInSpace(ptr);
795-
}
796-
797-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
798-
static boolean findPointerInSpace(Space space, Pointer p) {
799-
AlignedHeapChunk.AlignedHeader aChunk = space.getFirstAlignedHeapChunk();
800-
while (aChunk.isNonNull()) {
801-
Pointer start = AlignedHeapChunk.getObjectsStart(aChunk);
802-
if (start.belowOrEqual(p) && p.belowThan(HeapChunk.getTopPointer(aChunk))) {
803-
return true;
804-
}
805-
aChunk = HeapChunk.getNext(aChunk);
806-
}
807-
808-
UnalignedHeapChunk.UnalignedHeader uChunk = space.getFirstUnalignedHeapChunk();
809-
while (uChunk.isNonNull()) {
810-
Pointer start = UnalignedHeapChunk.getObjectStart(uChunk);
811-
if (start.belowOrEqual(p) && p.belowThan(HeapChunk.getTopPointer(uChunk))) {
812-
return true;
813-
}
814-
uChunk = HeapChunk.getNext(uChunk);
815-
}
816-
return false;
772+
return isInImageHeap(ptr) || youngGeneration.isInSpace(ptr) || oldGeneration.isInSpace(ptr);
817773
}
818774

819775
private static boolean printTlabInfo(Log log, Pointer ptr) {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ private static boolean verifyAlignedChunks(Space space, AlignedHeader firstAlign
196196
success = false;
197197
}
198198

199+
if (aChunk.getShouldSweepInsteadOfCompact()) {
200+
Log.log().string("Aligned chunk ").zhex(aChunk).string(" is marked for sweeping while this should only be used during collections.").newline();
201+
success = false;
202+
}
203+
199204
OBJECT_VERIFIER.initialize(aChunk, WordFactory.nullPointer());
200205
AlignedHeapChunk.walkObjects(aChunk, OBJECT_VERIFIER);
201206
aChunk = HeapChunk.getNext(aChunk);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,14 +358,14 @@ public static boolean hasRememberedSet(UnsignedWord header) {
358358

359359
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
360360
public static void setMarked(Object o) {
361-
if (!SerialGCOptions.useCompactingOldGen()) {
361+
if (!SerialGCOptions.useCompactingOldGen()) { // not guarantee(): always folds, prevent call
362362
throw VMError.shouldNotReachHere("Only for compacting GC.");
363363
}
364364
UnsignedWord header = readHeaderFromObject(o);
365365
assert header.and(FORWARDED_OR_MARKED2_BIT).equal(0) : "forwarded or already marked";
366366
/*
367367
* The remembered bit is already set if the object was in the old generation before, or
368-
* unset if it was only just absorbed from the young generation.
368+
* unset if it was only just absorbed from the young generation, in which case we set it.
369369
*/
370370
writeHeaderToObject(o, header.or(MARKED_BITS));
371371
}
@@ -398,7 +398,7 @@ static boolean isPointerToForwardedObject(Pointer p) {
398398

399399
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
400400
public static boolean isForwardedHeader(UnsignedWord header) {
401-
return header.and(REMSET_OR_MARKED1_BIT.or(FORWARDED_OR_MARKED2_BIT)).equal(FORWARDED_OR_MARKED2_BIT);
401+
return header.and(MARKED_BITS).equal(FORWARDED_OR_MARKED2_BIT);
402402
}
403403

404404
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,32 @@
2424
*/
2525
package com.oracle.svm.core.genscavenge;
2626

27+
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.EXTREMELY_SLOW_PATH_PROBABILITY;
28+
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
29+
2730
import org.graalvm.word.Pointer;
2831
import org.graalvm.word.UnsignedWord;
2932

3033
import com.oracle.svm.core.Uninterruptible;
3134
import com.oracle.svm.core.genscavenge.GCImpl.ChunkReleaser;
35+
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
36+
import com.oracle.svm.core.thread.VMOperation;
37+
import com.oracle.svm.core.util.VMError;
3238

3339
public abstract class OldGeneration extends Generation {
3440
OldGeneration(String name) {
3541
super(name);
3642
}
3743

3844
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
39-
abstract void beginPromotion(YoungGeneration youngGen, boolean incrementalGc);
45+
abstract void beginPromotion(boolean incrementalGc);
4046

4147
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
4248
abstract void blackenDirtyCardRoots(GreyToBlackObjectVisitor visitor);
4349

4450
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
4551
abstract boolean scanGreyObjects(boolean incrementalGc);
4652

47-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
48-
abstract AlignedHeapChunk.AlignedHeader requestAlignedChunk();
49-
5053
abstract void sweepAndCompact(Timers timers, ChunkReleaser chunkReleaser);
5154

5255
abstract void releaseSpaces(ChunkReleaser chunkReleaser);
@@ -58,7 +61,6 @@ public abstract class OldGeneration extends Generation {
5861

5962
abstract UnsignedWord computeObjectBytes();
6063

61-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
6264
abstract boolean isInSpace(Pointer ptr);
6365

6466
abstract boolean verifyRememberedSets();
@@ -67,4 +69,15 @@ public abstract class OldGeneration extends Generation {
6769

6870
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
6971
abstract void tearDown();
72+
73+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
74+
AlignedHeapChunk.AlignedHeader requestAlignedChunk() {
75+
assert VMOperation.isGCInProgress() : "Should only be called from the collector.";
76+
AlignedHeapChunk.AlignedHeader chunk = HeapImpl.getChunkProvider().produceAlignedChunk();
77+
if (probability(EXTREMELY_SLOW_PATH_PROBABILITY, chunk.isNull())) {
78+
throw VMError.shouldNotReachHere("OldGeneration.requestAlignedChunk: failure to allocate aligned chunk");
79+
}
80+
RememberedSet.get().enableRememberedSetForChunk(chunk);
81+
return chunk;
82+
}
7083
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,9 @@ private static boolean willSurviveThisCollection(Object obj) {
250250
}
251251

252252
static void updateForwardedRefs() {
253-
Reference<?> current = rememberedRefsList;
253+
assert SerialGCOptions.useCompactingOldGen();
254254

255+
Reference<?> current = rememberedRefsList;
255256
while (current != null) {
256257
// Get the next node (the last node has a cyclic reference to self).
257258
Reference<?> next = ReferenceInternals.getNextDiscovered(current);

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public Integer getValue(OptionValues values) {
112112
/** Query these options only through an appropriate method. */
113113
public static class ConcealedOptions {
114114
@Option(help = "Collect old generation by compacting in-place instead of copying.", type = OptionType.Expert) //
115-
public static final HostedOptionKey<Boolean> CompactingOldGen = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
115+
public static final HostedOptionKey<Boolean> CompactingOldGen = new HostedOptionKey<>(true, SerialGCOptions::validateCompactingOldGen);
116116

117117
@Option(help = "Determines if a remembered set is used, which is necessary for collecting the young and old generation independently.", type = OptionType.Expert) //
118118
public static final HostedOptionKey<Boolean> UseRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
@@ -127,16 +127,11 @@ private static void serialGCOnly(OptionKey<?> optionKey) {
127127
}
128128
}
129129

130-
@Fold
131-
public static boolean useRememberedSet() {
132-
return !SubstrateOptions.UseEpsilonGC.getValue() && ConcealedOptions.UseRememberedSet.getValue();
133-
}
134-
135-
@Fold
136-
public static boolean useCompactingOldGen() {
137-
if (SubstrateOptions.UseEpsilonGC.getValue() || !ConcealedOptions.CompactingOldGen.getValue()) {
138-
return false;
130+
private static void validateCompactingOldGen(HostedOptionKey<Boolean> compactingOldGen) {
131+
if (!compactingOldGen.getValue()) {
132+
return;
139133
}
134+
serialGCOnly(compactingOldGen);
140135
if (!useRememberedSet()) {
141136
throw UserError.abort("%s requires %s.", SubstrateOptionsParser.commandArgument(ConcealedOptions.CompactingOldGen, "+"),
142137
SubstrateOptionsParser.commandArgument(ConcealedOptions.UseRememberedSet, "+"));
@@ -145,6 +140,15 @@ public static boolean useCompactingOldGen() {
145140
throw UserError.abort("%s requires %s.", SubstrateOptionsParser.commandArgument(ConcealedOptions.CompactingOldGen, "+"),
146141
SubstrateOptionsParser.commandArgument(SerialAndEpsilonGCOptions.AlignedHeapChunkSize, "<value below or equal to " + ObjectMoveInfo.MAX_CHUNK_SIZE + ">"));
147142
}
148-
return true;
143+
}
144+
145+
@Fold
146+
public static boolean useRememberedSet() {
147+
return !SubstrateOptions.UseEpsilonGC.getValue() && ConcealedOptions.UseRememberedSet.getValue();
148+
}
149+
150+
@Fold
151+
public static boolean useCompactingOldGen() {
152+
return !SubstrateOptions.UseEpsilonGC.getValue() && ConcealedOptions.CompactingOldGen.getValue();
149153
}
150154
}

0 commit comments

Comments
 (0)