7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 package org.graalvm.compiler.hotspot.test;
26
27 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
28 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset;
29
30 import java.lang.ref.WeakReference;
31
32 import org.graalvm.compiler.debug.DebugContext;
33 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
34 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
35 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
36 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
37 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
38 import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
39 import org.graalvm.compiler.nodes.StructuredGraph;
40 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
41 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
42 import org.graalvm.compiler.nodes.memory.ReadNode;
43 import org.graalvm.compiler.nodes.memory.WriteNode;
44 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
45 import org.graalvm.compiler.nodes.spi.LoweringTool;
46 import org.graalvm.compiler.phases.OptimisticOptimizations;
47 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
48 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
49 import org.graalvm.compiler.phases.common.LoweringPhase;
50 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
51 import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
52 import org.graalvm.compiler.phases.tiers.HighTierContext;
53 import org.graalvm.compiler.phases.tiers.MidTierContext;
54 import org.junit.Assert;
55 import org.junit.Test;
56
57 import jdk.vm.ci.hotspot.HotSpotInstalledCode;
58 import jdk.vm.ci.meta.JavaConstant;
59 import jdk.vm.ci.meta.ResolvedJavaMethod;
60 import sun.misc.Unsafe;
61
62 /**
63 * The following unit tests assert the presence of write barriers for both Serial and G1 GCs.
64 * Normally, the tests check for compile time inserted barriers. However, there are the cases of
65 * unsafe loads of the java.lang.ref.Reference.referent field where runtime checks have to be
66 * performed also. For those cases, the unit tests check the presence of the compile-time inserted
67 * barriers. Concerning the runtime checks, the results of variable inputs (object types and
68 * offsets) passed as input parameters can be checked against printed output from the G1 write
69 * barrier snippets. The runtime checks have been validated offline.
70 */
71 public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
72
73 private final GraalHotSpotVMConfig config = runtime().getVMConfig();
74 private static final long referentOffset = referentOffset();
75
76 public static class Container {
77
78 public Container a;
79 public Container b;
80 }
81
82 /**
83 * Expected 2 barriers for the Serial GC and 4 for G1 (2 pre + 2 post).
84 */
85 @Test
86 public void test1() throws Exception {
87 testHelper("test1Snippet", (config.useG1GC) ? 4 : 2);
88 }
89
90 public static void test1Snippet() {
91 Container main = new Container();
92 Container temp1 = new Container();
93 Container temp2 = new Container();
94 main.a = temp1;
150 }
151
152 public static Object test4Snippet() {
153 WeakReference<Object> weakRef = new WeakReference<>(new Object());
154 return weakRef.get();
155 }
156
157 static WeakReference<Object> wr = new WeakReference<>(new Object());
158 static Container con = new Container();
159
160 /**
161 * Expected 4 barriers for the Serial GC and 9 for G1 (1 ref + 4 pre + 4 post). In this test, we
162 * load the correct offset of the WeakReference object so naturally we assert the presence of
163 * the pre barrier.
164 */
165 @Test
166 public void test5() throws Exception {
167 testHelper("test5Snippet", config.useG1GC ? 1 : 0);
168 }
169
170 public static Object test5Snippet() throws Exception {
171 return UNSAFE.getObject(wr, config(null).useCompressedOops ? 12L : 16L);
172 }
173
174 /**
175 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
176 * load the java.lang.ref.Reference.referent field so the pre barier has to be executed.
177 */
178 @Test
179 public void test6() throws Exception {
180 test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(referentOffset), null);
181 }
182
183 /**
184 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
185 * load a matching offset of a wrong object so the pre barier must not be executed.
186 */
187 @Test
188 public void test7() throws Exception {
189 test2("testUnsafeLoad", UNSAFE, con, Long.valueOf(referentOffset), null);
190 }
191
192 /**
193 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
194 * load a non-matching offset field of the java.lang.ref.Reference object so the pre barier must
195 * not be executed.
196 */
197 @Test
198 public void test8() throws Exception {
199 test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 20 : 32), null);
200 }
201
202 /**
203 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
204 * load a matching offset+disp field of the java.lang.ref.Reference object so the pre barier
205 * must be executed.
206 */
207 @Test
208 public void test10() throws Exception {
209 test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 6 : 8), Integer.valueOf(config.useCompressedOops ? 6 : 8));
282 for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
283 if (config.useG1GC) {
284 if (write.getBarrierType() != BarrierType.NONE) {
285 Assert.assertEquals(1, write.successors().count());
286 Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
287 Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
288 }
289 } else {
290 if (write.getBarrierType() != BarrierType.NONE) {
291 Assert.assertEquals(1, write.successors().count());
292 Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
293 }
294 }
295 }
296
297 for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
298 if (read.getBarrierType() != BarrierType.NONE) {
299 Assert.assertTrue(read.getAddress() instanceof OffsetAddressNode);
300 JavaConstant constDisp = ((OffsetAddressNode) read.getAddress()).getOffset().asJavaConstant();
301 Assert.assertNotNull(constDisp);
302 Assert.assertEquals(referentOffset, constDisp.asLong());
303 Assert.assertTrue(config.useG1GC);
304 Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType());
305 Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
306 }
307 }
308 } catch (Throwable e) {
309 throw debug.handle(e);
310 }
311 }
312
313 private void test2(final String snippet, Object... args) throws Exception {
314 HotSpotInstalledCode code = getInstalledCode(snippet, args[0] instanceof Unsafe);
315 code.executeVarargs(args);
316 }
317 }
|
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 package org.graalvm.compiler.hotspot.test;
26
27 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset;
28
29 import java.lang.ref.WeakReference;
30
31 import org.graalvm.compiler.api.replacements.Fold;
32 import org.graalvm.compiler.debug.DebugContext;
33 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
34 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase;
35 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
36 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
37 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
38 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
39 import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
40 import org.graalvm.compiler.nodes.StructuredGraph;
41 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
42 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
43 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
44 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
45 import org.graalvm.compiler.nodes.memory.ReadNode;
46 import org.graalvm.compiler.nodes.memory.WriteNode;
47 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
48 import org.graalvm.compiler.nodes.spi.LoweringTool;
49 import org.graalvm.compiler.phases.OptimisticOptimizations;
50 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
51 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
52 import org.graalvm.compiler.phases.common.LoweringPhase;
53 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
54 import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
55 import org.graalvm.compiler.phases.tiers.HighTierContext;
56 import org.graalvm.compiler.phases.tiers.MidTierContext;
57 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
58 import org.junit.Assert;
59 import org.junit.Test;
60
61 import jdk.vm.ci.hotspot.HotSpotInstalledCode;
62 import jdk.vm.ci.meta.JavaConstant;
63 import jdk.vm.ci.meta.ResolvedJavaMethod;
64 import sun.misc.Unsafe;
65
66 /**
67 * The following unit tests assert the presence of write barriers for both Serial and G1 GCs.
68 * Normally, the tests check for compile time inserted barriers. However, there are the cases of
69 * unsafe loads of the java.lang.ref.Reference.referent field where runtime checks have to be
70 * performed also. For those cases, the unit tests check the presence of the compile-time inserted
71 * barriers. Concerning the runtime checks, the results of variable inputs (object types and
72 * offsets) passed as input parameters can be checked against printed output from the G1 write
73 * barrier snippets. The runtime checks have been validated offline.
74 */
75 public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
76
77 private final GraalHotSpotVMConfig config = runtime().getVMConfig();
78
79 public static class Container {
80
81 public Container a;
82 public Container b;
83 }
84
85 /**
86 * Expected 2 barriers for the Serial GC and 4 for G1 (2 pre + 2 post).
87 */
88 @Test
89 public void test1() throws Exception {
90 testHelper("test1Snippet", (config.useG1GC) ? 4 : 2);
91 }
92
93 public static void test1Snippet() {
94 Container main = new Container();
95 Container temp1 = new Container();
96 Container temp2 = new Container();
97 main.a = temp1;
153 }
154
155 public static Object test4Snippet() {
156 WeakReference<Object> weakRef = new WeakReference<>(new Object());
157 return weakRef.get();
158 }
159
160 static WeakReference<Object> wr = new WeakReference<>(new Object());
161 static Container con = new Container();
162
163 /**
164 * Expected 4 barriers for the Serial GC and 9 for G1 (1 ref + 4 pre + 4 post). In this test, we
165 * load the correct offset of the WeakReference object so naturally we assert the presence of
166 * the pre barrier.
167 */
168 @Test
169 public void test5() throws Exception {
170 testHelper("test5Snippet", config.useG1GC ? 1 : 0);
171 }
172
173 @Override
174 protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
175 NodeIntrinsicPluginFactory.InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
176 new PluginFactory_WriteBarrierAdditionTest().registerPlugins(invocationPlugins, injection);
177 super.registerInvocationPlugins(invocationPlugins);
178 }
179
180 @Fold
181 public static boolean useCompressedOops(@Fold.InjectedParameter GraalHotSpotVMConfig config) {
182 return config.useCompressedOops;
183 }
184
185 public static Object test5Snippet() throws Exception {
186 return UNSAFE.getObject(wr, useCompressedOops(GraalHotSpotVMConfigBase.INJECTED_VMCONFIG) ? 12L : 16L);
187 }
188
189 /**
190 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
191 * load the java.lang.ref.Reference.referent field so the pre barier has to be executed.
192 */
193 @Test
194 public void test6() throws Exception {
195 test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(referentOffset(getMetaAccess())), null);
196 }
197
198 /**
199 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
200 * load a matching offset of a wrong object so the pre barier must not be executed.
201 */
202 @Test
203 public void test7() throws Exception {
204 test2("testUnsafeLoad", UNSAFE, con, Long.valueOf(referentOffset(getMetaAccess())), null);
205 }
206
207 /**
208 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
209 * load a non-matching offset field of the java.lang.ref.Reference object so the pre barier must
210 * not be executed.
211 */
212 @Test
213 public void test8() throws Exception {
214 test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 20 : 32), null);
215 }
216
217 /**
218 * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
219 * load a matching offset+disp field of the java.lang.ref.Reference object so the pre barier
220 * must be executed.
221 */
222 @Test
223 public void test10() throws Exception {
224 test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 6 : 8), Integer.valueOf(config.useCompressedOops ? 6 : 8));
297 for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
298 if (config.useG1GC) {
299 if (write.getBarrierType() != BarrierType.NONE) {
300 Assert.assertEquals(1, write.successors().count());
301 Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
302 Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
303 }
304 } else {
305 if (write.getBarrierType() != BarrierType.NONE) {
306 Assert.assertEquals(1, write.successors().count());
307 Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
308 }
309 }
310 }
311
312 for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
313 if (read.getBarrierType() != BarrierType.NONE) {
314 Assert.assertTrue(read.getAddress() instanceof OffsetAddressNode);
315 JavaConstant constDisp = ((OffsetAddressNode) read.getAddress()).getOffset().asJavaConstant();
316 Assert.assertNotNull(constDisp);
317 Assert.assertEquals(referentOffset(getMetaAccess()), constDisp.asLong());
318 Assert.assertTrue(config.useG1GC);
319 Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType());
320 Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
321 }
322 }
323 } catch (Throwable e) {
324 throw debug.handle(e);
325 }
326 }
327
328 private void test2(final String snippet, Object... args) throws Exception {
329 HotSpotInstalledCode code = getInstalledCode(snippet, args[0] instanceof Unsafe);
330 code.executeVarargs(args);
331 }
332 }
|