3434import org .graalvm .compiler .api .replacements .SnippetReflectionProvider ;
3535import org .graalvm .compiler .debug .DebugHandlersFactory ;
3636import org .graalvm .compiler .graph .Node ;
37+ import org .graalvm .compiler .nodes .BreakpointNode ;
3738import org .graalvm .compiler .nodes .NamedLocationIdentity ;
3839import org .graalvm .compiler .nodes .extended .BranchProbabilityNode ;
3940import org .graalvm .compiler .nodes .extended .FixedValueAnchorNode ;
4243import org .graalvm .compiler .nodes .gc .WriteBarrier ;
4344import org .graalvm .compiler .nodes .memory .address .OffsetAddressNode ;
4445import org .graalvm .compiler .nodes .spi .LoweringTool ;
46+ import org .graalvm .compiler .nodes .type .StampTool ;
4547import org .graalvm .compiler .options .Option ;
4648import org .graalvm .compiler .options .OptionValues ;
4749import org .graalvm .compiler .phases .util .Providers ;
6466import com .oracle .svm .core .util .Counter ;
6567import com .oracle .svm .core .util .CounterFeature ;
6668
69+ import jdk .vm .ci .meta .ResolvedJavaType ;
70+
6771public 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