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