3131import org .graalvm .compiler .api .replacements .Fold ;
3232import org .graalvm .compiler .api .replacements .Snippet ;
3333import org .graalvm .compiler .api .replacements .Snippet .ConstantParameter ;
34+ import org .graalvm .compiler .api .replacements .Snippet .NonNullParameter ;
3435import org .graalvm .compiler .api .replacements .SnippetReflectionProvider ;
3536import org .graalvm .compiler .debug .DebugHandlersFactory ;
3637import org .graalvm .compiler .graph .Node ;
38+ import org .graalvm .compiler .nodes .BreakpointNode ;
3739import org .graalvm .compiler .nodes .NamedLocationIdentity ;
3840import org .graalvm .compiler .nodes .extended .BranchProbabilityNode ;
3941import org .graalvm .compiler .nodes .extended .FixedValueAnchorNode ;
4244import org .graalvm .compiler .nodes .gc .WriteBarrier ;
4345import org .graalvm .compiler .nodes .memory .address .OffsetAddressNode ;
4446import org .graalvm .compiler .nodes .spi .LoweringTool ;
47+ import org .graalvm .compiler .nodes .type .StampTool ;
4548import org .graalvm .compiler .options .Option ;
4649import org .graalvm .compiler .options .OptionValues ;
4750import org .graalvm .compiler .phases .util .Providers ;
6467import com .oracle .svm .core .util .Counter ;
6568import com .oracle .svm .core .util .CounterFeature ;
6669
70+ import jdk .vm .ci .meta .ResolvedJavaType ;
71+
6772public class BarrierSnippets extends SubstrateTemplates implements Snippets {
6873 /** A LocationIdentity to distinguish card locations from other locations. */
6974 public static final LocationIdentity CARD_REMEMBERED_SET_LOCATION = NamedLocationIdentity .mutable ("CardRememberedSet" );
7075
7176 public static class Options {
7277 @ Option (help = "Instrument write barriers with counters" )//
7378 public static final HostedOptionKey <Boolean > CountWriteBarriers = new HostedOptionKey <>(false );
79+
80+ @ Option (help = "Verify write barriers" )//
81+ public static final HostedOptionKey <Boolean > VerifyWriteBarriers = new HostedOptionKey <>(true );
7482 }
7583
7684 @ Fold
@@ -90,23 +98,40 @@ public void registerLowerings(Map<Class<? extends Node>, NodeLoweringProvider<?>
9098 }
9199
92100 @ Snippet
93- public static void postWriteBarrierSnippet (Object object , @ ConstantParameter boolean verifyOnly ) {
101+ public static void postWriteBarrierSnippet (@ NonNullParameter Object object , @ ConstantParameter boolean alwaysAlignedChunk , @ ConstantParameter boolean verifyOnly ) {
94102 counters ().postWriteBarrier .inc ();
95103
96104 Object fixedObject = FixedValueAnchorNode .getObject (object );
97105 UnsignedWord objectHeader = ObjectHeaderImpl .readHeaderFromObject (fixedObject );
106+
107+ if (Options .VerifyWriteBarriers .getValue () && alwaysAlignedChunk ) {
108+ /*
109+ * In addition to verifying that the object is in an aligned chunk, we also verify that
110+ * it is not an array at all. Since most arrays are small and therefore in an aligned
111+ * chunk, this greatly increases the verification coverage. To increase verification
112+ * coverage, we also do the verification before checking if a barrier is needed at all.
113+ */
114+ if (ObjectHeaderImpl .isUnalignedHeader (objectHeader ) || object .getClass ().isArray ()) {
115+ BreakpointNode .breakpoint ();
116+ }
117+ }
118+
98119 boolean needsBarrier = RememberedSet .get ().hasRememberedSet (objectHeader );
99120 if (BranchProbabilityNode .probability (BranchProbabilityNode .FREQUENT_PROBABILITY , !needsBarrier )) {
100121 return ;
101122 }
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 ;
123+
124+ if (!alwaysAlignedChunk ) {
125+ boolean unaligned = ObjectHeaderImpl .isUnalignedHeader (objectHeader );
126+ if (BranchProbabilityNode .probability (BranchProbabilityNode .NOT_LIKELY_PROBABILITY , unaligned )) {
127+ counters ().postWriteBarrierUnaligned .inc ();
128+ RememberedSet .get ().dirtyCardForUnalignedObject (fixedObject , verifyOnly );
129+ return ;
130+ }
107131 }
108- counters ().postWriteBarrierUnaligned .inc ();
109- RememberedSet .get ().dirtyCardForUnalignedObject (fixedObject , verifyOnly );
132+
133+ counters ().postWriteBarrierAligned .inc ();
134+ RememberedSet .get ().dirtyCardForAlignedObject (fixedObject , verifyOnly );
110135 }
111136
112137 private class PostWriteBarrierLowering implements NodeLoweringProvider <WriteBarrier > {
@@ -116,7 +141,20 @@ private class PostWriteBarrierLowering implements NodeLoweringProvider<WriteBarr
116141 public void lower (WriteBarrier barrier , LoweringTool tool ) {
117142 Arguments args = new Arguments (postWriteBarrierSnippet , barrier .graph ().getGuardsStage (), tool .getLoweringStage ());
118143 OffsetAddressNode address = (OffsetAddressNode ) barrier .getAddress ();
144+
145+ /*
146+ * We know that instances (in contrast to arrays) are always in aligned chunks. There is
147+ * no code anywhere that would allocate an instance into an unaligned chunk.
148+ *
149+ * Note that arrays can be assigned to values that have the type java.lang.Object, so
150+ * that case is excluded. Arrays can also implement some interfaces, like Serializable.
151+ * For simplicity, we exclude all interface types.
152+ */
153+ ResolvedJavaType baseType = StampTool .typeOrNull (address .getBase ());
154+ boolean alwaysAlignedChunk = baseType != null && !baseType .isArray () && !baseType .isJavaLangObject () && !baseType .isInterface ();
155+
119156 args .add ("object" , address .getBase ());
157+ args .addConst ("alwaysAlignedChunk" , alwaysAlignedChunk );
120158 args .addConst ("verifyOnly" , getVerifyOnly (barrier ));
121159
122160 template (barrier , args ).instantiate (providers .getMetaAccess (), barrier , SnippetTemplate .DEFAULT_REPLACER , args );
0 commit comments