Skip to content

Commit 4db000e

Browse files
author
Christian Wimmer
committed
Optimize serial GC write barrier for non-array stores
1 parent 5b743d4 commit 4db000e

File tree

1 file changed

+45
-8
lines changed
  • substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal

1 file changed

+45
-8
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
3535
import org.graalvm.compiler.debug.DebugHandlersFactory;
3636
import org.graalvm.compiler.graph.Node;
37+
import org.graalvm.compiler.nodes.BreakpointNode;
3738
import org.graalvm.compiler.nodes.NamedLocationIdentity;
3839
import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
3940
import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
@@ -42,6 +43,7 @@
4243
import org.graalvm.compiler.nodes.gc.WriteBarrier;
4344
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
4445
import org.graalvm.compiler.nodes.spi.LoweringTool;
46+
import org.graalvm.compiler.nodes.type.StampTool;
4547
import org.graalvm.compiler.options.Option;
4648
import org.graalvm.compiler.options.OptionValues;
4749
import org.graalvm.compiler.phases.util.Providers;
@@ -64,13 +66,18 @@
6466
import com.oracle.svm.core.util.Counter;
6567
import com.oracle.svm.core.util.CounterFeature;
6668

69+
import jdk.vm.ci.meta.ResolvedJavaType;
70+
6771
public class BarrierSnippets extends SubstrateTemplates implements Snippets {
6872
/** A LocationIdentity to distinguish card locations from other locations. */
6973
public static final LocationIdentity CARD_REMEMBERED_SET_LOCATION = NamedLocationIdentity.mutable("CardRememberedSet");
7074

7175
public static class Options {
7276
@Option(help = "Instrument write barriers with counters")//
7377
public static final HostedOptionKey<Boolean> CountWriteBarriers = new HostedOptionKey<>(false);
78+
79+
@Option(help = "Verify write barriers")//
80+
public static final HostedOptionKey<Boolean> VerifyWriteBarriers = new HostedOptionKey<>(true);
7481
}
7582

7683
@Fold
@@ -90,23 +97,40 @@ public void registerLowerings(Map<Class<? extends Node>, NodeLoweringProvider<?>
9097
}
9198

9299
@Snippet
93-
public static void postWriteBarrierSnippet(Object object, @ConstantParameter boolean verifyOnly) {
100+
public static void postWriteBarrierSnippet(Object object, @ConstantParameter boolean alwaysAlignedChunk, @ConstantParameter boolean verifyOnly) {
94101
counters().postWriteBarrier.inc();
95102

96103
Object fixedObject = FixedValueAnchorNode.getObject(object);
97104
UnsignedWord objectHeader = ObjectHeaderImpl.readHeaderFromObject(fixedObject);
105+
106+
if (Options.VerifyWriteBarriers.getValue() && alwaysAlignedChunk) {
107+
/*
108+
* To increase verification coverage, we do the verification before checking if a
109+
* barrier is needed at all. And in addition to verifying that the object is in an
110+
* aligned chunk, we also verify that it is not an array at all because most arrays are
111+
* small and therefore in an aligned chunk.
112+
*/
113+
if (ObjectHeaderImpl.isUnalignedHeader(objectHeader) || object == null || object.getClass().isArray()) {
114+
BreakpointNode.breakpoint();
115+
}
116+
}
117+
98118
boolean needsBarrier = RememberedSet.get().hasRememberedSet(objectHeader);
99119
if (BranchProbabilityNode.probability(BranchProbabilityNode.FREQUENT_PROBABILITY, !needsBarrier)) {
100120
return;
101121
}
102-
boolean aligned = ObjectHeaderImpl.isAlignedHeader(objectHeader);
103-
if (BranchProbabilityNode.probability(BranchProbabilityNode.LIKELY_PROBABILITY, aligned)) {
104-
counters().postWriteBarrierAligned.inc();
105-
RememberedSet.get().dirtyCardForAlignedObject(fixedObject, verifyOnly);
106-
return;
122+
123+
if (!alwaysAlignedChunk) {
124+
boolean unaligned = ObjectHeaderImpl.isUnalignedHeader(objectHeader);
125+
if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, unaligned)) {
126+
counters().postWriteBarrierUnaligned.inc();
127+
RememberedSet.get().dirtyCardForUnalignedObject(fixedObject, verifyOnly);
128+
return;
129+
}
107130
}
108-
counters().postWriteBarrierUnaligned.inc();
109-
RememberedSet.get().dirtyCardForUnalignedObject(fixedObject, verifyOnly);
131+
132+
counters().postWriteBarrierAligned.inc();
133+
RememberedSet.get().dirtyCardForAlignedObject(fixedObject, verifyOnly);
110134
}
111135

112136
private class PostWriteBarrierLowering implements NodeLoweringProvider<WriteBarrier> {
@@ -116,7 +140,20 @@ private class PostWriteBarrierLowering implements NodeLoweringProvider<WriteBarr
116140
public void lower(WriteBarrier barrier, LoweringTool tool) {
117141
Arguments args = new Arguments(postWriteBarrierSnippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
118142
OffsetAddressNode address = (OffsetAddressNode) barrier.getAddress();
143+
144+
/*
145+
* We know that instances (in contrast to arrays) are always in aligned chunks. There is
146+
* no code anywhere that would allocate an instance into an unaligned chunk.
147+
*
148+
* Note that arrays can be assigned to values that have the type java.lang.Object, so
149+
* that case is excluded. Arrays can also implement some interfaces, like Serializable.
150+
* For simplicity, we exclude all interface types.
151+
*/
152+
ResolvedJavaType baseType = StampTool.typeOrNull(address.getBase());
153+
boolean alwaysAlignedChunk = baseType != null && !baseType.isArray() && !baseType.isJavaLangObject() && !baseType.isInterface();
154+
119155
args.add("object", address.getBase());
156+
args.addConst("alwaysAlignedChunk", alwaysAlignedChunk);
120157
args.addConst("verifyOnly", getVerifyOnly(barrier));
121158

122159
template(barrier, args).instantiate(providers.getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);

0 commit comments

Comments
 (0)