34
34
import org .graalvm .compiler .api .replacements .SnippetReflectionProvider ;
35
35
import org .graalvm .compiler .debug .DebugHandlersFactory ;
36
36
import org .graalvm .compiler .graph .Node ;
37
+ import org .graalvm .compiler .nodes .BreakpointNode ;
37
38
import org .graalvm .compiler .nodes .NamedLocationIdentity ;
38
39
import org .graalvm .compiler .nodes .extended .BranchProbabilityNode ;
39
40
import org .graalvm .compiler .nodes .extended .FixedValueAnchorNode ;
42
43
import org .graalvm .compiler .nodes .gc .WriteBarrier ;
43
44
import org .graalvm .compiler .nodes .memory .address .OffsetAddressNode ;
44
45
import org .graalvm .compiler .nodes .spi .LoweringTool ;
46
+ import org .graalvm .compiler .nodes .type .StampTool ;
45
47
import org .graalvm .compiler .options .Option ;
46
48
import org .graalvm .compiler .options .OptionValues ;
47
49
import org .graalvm .compiler .phases .util .Providers ;
64
66
import com .oracle .svm .core .util .Counter ;
65
67
import com .oracle .svm .core .util .CounterFeature ;
66
68
69
+ import jdk .vm .ci .meta .ResolvedJavaType ;
70
+
67
71
public class BarrierSnippets extends SubstrateTemplates implements Snippets {
68
72
/** A LocationIdentity to distinguish card locations from other locations. */
69
73
public static final LocationIdentity CARD_REMEMBERED_SET_LOCATION = NamedLocationIdentity .mutable ("CardRememberedSet" );
70
74
71
75
public static class Options {
72
76
@ Option (help = "Instrument write barriers with counters" )//
73
77
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 );
74
81
}
75
82
76
83
@ Fold
@@ -90,23 +97,40 @@ public void registerLowerings(Map<Class<? extends Node>, NodeLoweringProvider<?>
90
97
}
91
98
92
99
@ Snippet
93
- public static void postWriteBarrierSnippet (Object object , @ ConstantParameter boolean verifyOnly ) {
100
+ public static void postWriteBarrierSnippet (Object object , @ ConstantParameter boolean alwaysAlignedChunk , @ ConstantParameter boolean verifyOnly ) {
94
101
counters ().postWriteBarrier .inc ();
95
102
96
103
Object fixedObject = FixedValueAnchorNode .getObject (object );
97
104
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
+
98
118
boolean needsBarrier = RememberedSet .get ().hasRememberedSet (objectHeader );
99
119
if (BranchProbabilityNode .probability (BranchProbabilityNode .FREQUENT_PROBABILITY , !needsBarrier )) {
100
120
return ;
101
121
}
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
+ }
107
130
}
108
- counters ().postWriteBarrierUnaligned .inc ();
109
- RememberedSet .get ().dirtyCardForUnalignedObject (fixedObject , verifyOnly );
131
+
132
+ counters ().postWriteBarrierAligned .inc ();
133
+ RememberedSet .get ().dirtyCardForAlignedObject (fixedObject , verifyOnly );
110
134
}
111
135
112
136
private class PostWriteBarrierLowering implements NodeLoweringProvider <WriteBarrier > {
@@ -116,7 +140,20 @@ private class PostWriteBarrierLowering implements NodeLoweringProvider<WriteBarr
116
140
public void lower (WriteBarrier barrier , LoweringTool tool ) {
117
141
Arguments args = new Arguments (postWriteBarrierSnippet , barrier .graph ().getGuardsStage (), tool .getLoweringStage ());
118
142
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
+
119
155
args .add ("object" , address .getBase ());
156
+ args .addConst ("alwaysAlignedChunk" , alwaysAlignedChunk );
120
157
args .addConst ("verifyOnly" , getVerifyOnly (barrier ));
121
158
122
159
template (barrier , args ).instantiate (providers .getMetaAccess (), barrier , SnippetTemplate .DEFAULT_REPLACER , args );
0 commit comments