Skip to content

Commit d37573f

Browse files
committed
[GR-63609] SVM: Optimize Serial GC write barriers of stores on newly created objects
PullRequest: graal/20330
2 parents 4c2718e + 8d06a31 commit d37573f

File tree

3 files changed

+78
-19
lines changed

3 files changed

+78
-19
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/SerialWriteBarrierNode.java

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -35,22 +35,71 @@
3535
public class SerialWriteBarrierNode extends ObjectWriteBarrierNode {
3636
public static final NodeClass<SerialWriteBarrierNode> TYPE = NodeClass.create(SerialWriteBarrierNode.class);
3737

38-
protected boolean verifyOnly;
38+
/**
39+
* Denote the status of the object that is the destination of the write corresponding to a
40+
* {@code SerialWriteBarrierNode}. During barrier expansion, we can take advantage of this
41+
* information to elide or emit a more efficient sequence for a {@code SerialWriteBarrierNode}.
42+
*/
43+
public enum BaseStatus {
44+
/**
45+
* There is no extra information for this base, the code should be emitted taking all
46+
* possibilities into consideration.
47+
*/
48+
DEFAULT,
49+
50+
/**
51+
* The object is created inside this compilation unit and there is no loop or call between
52+
* the allocation and the barrier. Therefore, the base object is likely young and the
53+
* backend can outline the path in which the object is in the old generation for better code
54+
* size and performance.
55+
*/
56+
NO_LOOP_OR_CALL,
57+
58+
/**
59+
* The object is created inside this compilation unit and there is no loop or safepoint
60+
* between the allocation and the barrier. Therefore, if the backend can ensure that a newly
61+
* allocated object is always young or the remember cards corresponding to it are all
62+
* dirtied, the object still has that property at the write barrier and the barrier can be
63+
* elided completely.
64+
*/
65+
NO_LOOP_OR_SAFEPOINT;
66+
67+
/**
68+
* Whether this base is likely young. This corresponds to NO_LOOP_OR_CALL or
69+
* NO_LOOP_OR_SAFEPOINT above.
70+
*/
71+
public boolean likelyYoung() {
72+
return this != DEFAULT;
73+
}
74+
}
75+
76+
private boolean eliminated;
77+
78+
private BaseStatus baseStatus;
3979

4080
public SerialWriteBarrierNode(AddressNode address, boolean precise) {
4181
this(TYPE, address, precise);
4282
}
4383

4484
protected SerialWriteBarrierNode(NodeClass<? extends SerialWriteBarrierNode> c, AddressNode address, boolean precise) {
4585
super(c, address, null, precise);
86+
this.baseStatus = BaseStatus.DEFAULT;
87+
}
88+
89+
public void setEliminated() {
90+
eliminated = true;
91+
}
92+
93+
public boolean isEliminated() {
94+
return eliminated;
4695
}
4796

48-
public void setVerifyOnly(boolean value) {
49-
this.verifyOnly = value;
97+
public void setBaseStatus(BaseStatus status) {
98+
baseStatus = status;
5099
}
51100

52-
public boolean getVerifyOnly() {
53-
return verifyOnly;
101+
public BaseStatus getBaseStatus() {
102+
return baseStatus;
54103
}
55104

56105
@Override

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/gc/SerialWriteBarrierSnippets.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -126,7 +126,7 @@ public void lower(SnippetTemplate.AbstractTemplates templates, SnippetTemplate.S
126126
args.add("object", address.getBase());
127127
}
128128
args.add("counters", counters);
129-
args.add("verifyOnly", barrier.getVerifyOnly());
129+
args.add("verifyOnly", barrier.isEliminated());
130130

131131
templates.template(tool, barrier, args).instantiate(tool.getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
132132
}

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

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -113,12 +113,17 @@ public static void postWriteBarrierStub(Object object) {
113113
private static native void callPostWriteBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
114114

115115
@Snippet
116-
public static void postWriteBarrierSnippet(Object object, @ConstantParameter boolean shouldOutline, @ConstantParameter boolean alwaysAlignedChunk, @ConstantParameter boolean verifyOnly) {
116+
public static void postWriteBarrierSnippet(Object object, @ConstantParameter boolean shouldOutline, @ConstantParameter boolean alwaysAlignedChunk, @ConstantParameter boolean eliminated) {
117+
boolean shouldVerify = SerialGCOptions.VerifyWriteBarriers.getValue();
118+
if (!shouldVerify && eliminated) {
119+
return;
120+
}
121+
117122
Object fixedObject = FixedValueAnchorNode.getObject(object);
118123
ObjectHeader oh = Heap.getHeap().getObjectHeader();
119124
UnsignedWord objectHeader = oh.readHeaderFromObject(fixedObject);
120125

121-
if (SerialGCOptions.VerifyWriteBarriers.getValue() && alwaysAlignedChunk) {
126+
if (shouldVerify && alwaysAlignedChunk) {
122127
/*
123128
* To increase verification coverage, we do the verification before checking if a
124129
* barrier is needed at all.
@@ -136,20 +141,20 @@ public static void postWriteBarrierSnippet(Object object, @ConstantParameter boo
136141
return;
137142
}
138143

139-
if (shouldOutline && !verifyOnly) {
144+
if (shouldOutline && !eliminated) {
140145
callPostWriteBarrierStub(POST_WRITE_BARRIER, fixedObject);
141146
return;
142147
}
143148

144149
if (!alwaysAlignedChunk) {
145150
boolean unaligned = ObjectHeaderImpl.isUnalignedHeader(objectHeader);
146151
if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, unaligned)) {
147-
RememberedSet.get().dirtyCardForUnalignedObject(fixedObject, verifyOnly);
152+
RememberedSet.get().dirtyCardForUnalignedObject(fixedObject, eliminated);
148153
return;
149154
}
150155
}
151156

152-
RememberedSet.get().dirtyCardForAlignedObject(fixedObject, verifyOnly);
157+
RememberedSet.get().dirtyCardForAlignedObject(fixedObject, eliminated);
153158
}
154159

155160
private class PostWriteBarrierLowering implements NodeLoweringProvider<WriteBarrierNode> {
@@ -179,7 +184,7 @@ public void lower(WriteBarrierNode barrier, LoweringTool tool) {
179184
args.add("object", address.getBase());
180185
args.add("shouldOutline", shouldOutline(barrier));
181186
args.add("alwaysAlignedChunk", alwaysAlignedChunk);
182-
args.add("verifyOnly", getVerifyOnly(barrier));
187+
args.add("eliminated", tryEliminate(barrier));
183188

184189
template(tool, barrier, args).instantiate(tool.getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
185190
}
@@ -188,12 +193,17 @@ private static boolean shouldOutline(WriteBarrierNode barrier) {
188193
if (SerialGCOptions.OutlineWriteBarriers.getValue() != null) {
189194
return SerialGCOptions.OutlineWriteBarriers.getValue();
190195
}
191-
return GraalOptions.ReduceCodeSize.getValue(barrier.getOptions());
196+
if (GraalOptions.ReduceCodeSize.getValue(barrier.getOptions())) {
197+
return true;
198+
}
199+
// Newly allocated objects are likely young, so we can outline the execution after
200+
// checking hasRememberedSet
201+
return barrier instanceof SerialWriteBarrierNode serialBarrier && serialBarrier.getBaseStatus().likelyYoung();
192202
}
193203

194-
private static boolean getVerifyOnly(WriteBarrierNode barrier) {
195-
if (barrier instanceof SerialWriteBarrierNode) {
196-
return ((SerialWriteBarrierNode) barrier).getVerifyOnly();
204+
private static boolean tryEliminate(WriteBarrierNode barrier) {
205+
if (barrier instanceof SerialWriteBarrierNode serialBarrier) {
206+
return serialBarrier.isEliminated() || serialBarrier.getBaseStatus() == SerialWriteBarrierNode.BaseStatus.NO_LOOP_OR_SAFEPOINT;
197207
}
198208
return false;
199209
}

0 commit comments

Comments
 (0)