1 /*
  2  * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  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 package compiler.gcbarriers;
 25 
 26 import compiler.lib.ir_framework.*;
 27 import java.lang.invoke.VarHandle;
 28 import java.lang.invoke.MethodHandles;
 29 import java.lang.ref.Reference;
 30 import java.lang.ref.ReferenceQueue;
 31 import java.lang.ref.SoftReference;
 32 import java.lang.ref.WeakReference;
 33 import java.util.concurrent.ThreadLocalRandom;
 34 import jdk.test.lib.Asserts;
 35 
 36 /**
 37  * @test
 38  * @summary Test that G1 barriers are generated and optimized as expected.
 39  * @library /test/lib /
 40  * @requires vm.gc.G1
 41  * @run driver compiler.gcbarriers.TestG1BarrierGeneration
 42  */
 43 
 44 public class TestG1BarrierGeneration {
 45     static final String PRE_ONLY = "pre";
 46     static final String POST_ONLY = "post";
 47     static final String POST_ONLY_NOT_NULL = "post notnull";
 48     static final String PRE_AND_POST = "pre post";
 49     static final String PRE_AND_POST_NOT_NULL = "pre post notnull";
 50     static final String ANY = ".*";
 51 
 52     static class Outer {
 53         Object f;
 54     }
 55 
 56     static class OuterWithVolatileField {
 57         volatile Object f;
 58     }
 59 
 60     static class OuterWithFewFields implements Cloneable {
 61         Object f1;
 62         Object f2;
 63         public Object clone() throws CloneNotSupportedException {
 64             return super.clone();
 65         }
 66     }
 67 
 68     static class OuterWithManyFields implements Cloneable {
 69         Object f1;
 70         Object f2;
 71         Object f3;
 72         Object f4;
 73         Object f5;
 74         Object f6;
 75         Object f7;
 76         Object f8;
 77         Object f9;
 78         Object f10;
 79         public Object clone() throws CloneNotSupportedException {
 80             return super.clone();
 81         }
 82     }
 83 
 84     static final VarHandle fVarHandle;
 85     static {
 86         MethodHandles.Lookup l = MethodHandles.lookup();
 87         try {
 88             fVarHandle = l.findVarHandle(Outer.class, "f", Object.class);
 89         } catch (Exception e) {
 90             throw new Error(e);
 91         }
 92     }
 93 
 94     @DontInline
 95     static void nonInlinedMethod() {}
 96 
 97     public static void main(String[] args) {
 98         TestFramework framework = new TestFramework();
 99         Scenario[] scenarios = new Scenario[2*2];
100         int scenarioIndex = 0;
101         for (int i = 0; i < 2; i++) {
102             for (int j = 0; j < 2; j++) {
103                 scenarios[scenarioIndex] =
104                     new Scenario(scenarioIndex,
105                                  "-XX:CompileCommand=inline,java.lang.ref.*::*",
106                                  "-XX:" + (i == 0 ? "-" : "+") + "UseCompressedOops",
107                                  "-XX:" + (j == 0 ? "-" : "+") + "ReduceInitialCardMarks");
108                 scenarioIndex++;
109             }
110         }
111         framework.addScenarios(scenarios);
112         framework.start();
113     }
114 
115     @Test
116     @IR(applyIf = {"UseCompressedOops", "false"},
117         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
118         phase = CompilePhase.FINAL_CODE)
119     @IR(applyIf = {"UseCompressedOops", "true"},
120         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
121         phase = CompilePhase.FINAL_CODE)
122     public static void testStore(Outer o, Object o1) {
123         o.f = o1;
124     }
125 
126     @Test
127     @IR(applyIf = {"UseCompressedOops", "false"},
128         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
129         phase = CompilePhase.FINAL_CODE)
130     @IR(applyIf = {"UseCompressedOops", "true"},
131         counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
132         phase = CompilePhase.FINAL_CODE)
133     public static void testStoreNull(Outer o) {
134         o.f = null;
135     }
136 
137     @Test
138     @IR(applyIf = {"UseCompressedOops", "false"},
139         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
140         phase = CompilePhase.FINAL_CODE)
141     @IR(applyIf = {"UseCompressedOops", "true"},
142         counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
143         phase = CompilePhase.FINAL_CODE)
144     public static void testStoreObfuscatedNull(Outer o, Object o1) {
145         Object o2 = o1;
146         for (int i = 0; i < 4; i++) {
147             if ((i % 2) == 0) {
148                 o2 = null;
149             }
150         }
151         // o2 is null here, but this is only known to C2 after applying some
152         // optimizations (loop unrolling, IGVN).
153         o.f = o2;
154     }
155 
156     @Test
157     @IR(applyIf = {"UseCompressedOops", "false"},
158         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"},
159         phase = CompilePhase.FINAL_CODE)
160     @IR(applyIf = {"UseCompressedOops", "true"},
161         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"},
162         phase = CompilePhase.FINAL_CODE)
163     public static void testStoreNotNull(Outer o, Object o1) {
164         if (o1.hashCode() == 42) {
165             return;
166         }
167         o.f = o1;
168     }
169 
170     @Test
171     @IR(applyIf = {"UseCompressedOops", "false"},
172         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "2"},
173         phase = CompilePhase.FINAL_CODE)
174     @IR(applyIf = {"UseCompressedOops", "true"},
175         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "2"},
176         phase = CompilePhase.FINAL_CODE)
177     public static void testStoreTwice(Outer o, Outer p, Object o1) {
178         o.f = o1;
179         p.f = o1;
180     }
181 
182     @Test
183     @IR(applyIf = {"UseCompressedOops", "false"},
184         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
185         phase = CompilePhase.FINAL_CODE)
186     @IR(applyIf = {"UseCompressedOops", "true"},
187         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
188         phase = CompilePhase.FINAL_CODE)
189     public static void testStoreVolatile(OuterWithVolatileField o, Object o1) {
190         o.f = o1;
191     }
192 
193     @Test
194     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
195         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
196         phase = CompilePhase.FINAL_CODE)
197     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
198         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
199         phase = CompilePhase.FINAL_CODE)
200     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
201         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
202         phase = CompilePhase.FINAL_CODE)
203     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
204         failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY,
205                   IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
206         phase = CompilePhase.FINAL_CODE)
207     public static Outer testStoreOnNewObject(Object o1) {
208         Outer o = new Outer();
209         o.f = o1;
210         return o;
211     }
212 
213     @Test
214     @IR(failOn = {IRNode.STORE_P, IRNode.STORE_N},
215         phase = CompilePhase.BEFORE_MACRO_EXPANSION)
216     public static Outer testStoreNullOnNewObject() {
217         Outer o = new Outer();
218         o.f = null;
219         return o;
220     }
221 
222     @Test
223     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
224         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"},
225         phase = CompilePhase.FINAL_CODE)
226     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
227         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"},
228         phase = CompilePhase.FINAL_CODE)
229     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
230         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
231         phase = CompilePhase.FINAL_CODE)
232     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
233         failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY,
234                   IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
235         phase = CompilePhase.FINAL_CODE)
236     public static Outer testStoreNotNullOnNewObject(Object o1) {
237         if (o1.hashCode() == 42) {
238             return null;
239         }
240         Outer o = new Outer();
241         o.f = o1;
242         return o;
243     }
244 
245     @Test
246     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
247         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"},
248         phase = CompilePhase.FINAL_CODE)
249     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
250         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"},
251         phase = CompilePhase.FINAL_CODE)
252     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
253         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
254         phase = CompilePhase.FINAL_CODE)
255     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
256         failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY,
257                   IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
258         phase = CompilePhase.FINAL_CODE)
259     public static Outer testStoreOnNewObjectInTwoPaths(Object o1, boolean c) {
260         Outer o;
261         if (c) {
262             o = new Outer();
263             o.f = o1;
264         } else {
265             o = new Outer();
266             o.f = o1;
267         }
268         return o;
269     }
270 
271     @Test
272     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
273         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
274         phase = CompilePhase.FINAL_CODE)
275     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
276         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
277         phase = CompilePhase.FINAL_CODE)
278     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
279         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
280         phase = CompilePhase.FINAL_CODE)
281     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
282         failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
283         phase = CompilePhase.FINAL_CODE)
284     public static Outer testStoreConditionallyOnNewObject(Object o1, boolean c) {
285         Outer o = new Outer();
286         if (c) {
287             o.f = o1;
288         }
289         return o;
290     }
291 
292     @Test
293     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
294         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
295         phase = CompilePhase.FINAL_CODE)
296     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
297         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
298         phase = CompilePhase.FINAL_CODE)
299     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
300         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
301         phase = CompilePhase.FINAL_CODE)
302     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
303         failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
304         phase = CompilePhase.FINAL_CODE)
305     public static Outer testStoreOnNewObjectAfterException(Object o1, boolean c) throws Exception {
306         Outer o = new Outer();
307         if (c) {
308             throw new Exception("");
309         }
310         o.f = o1;
311         return o;
312     }
313 
314     @Test
315     @IR(applyIf = {"UseCompressedOops", "false"},
316         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
317         phase = CompilePhase.FINAL_CODE)
318     @IR(applyIf = {"UseCompressedOops", "true"},
319         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
320         phase = CompilePhase.FINAL_CODE)
321     public static Outer testStoreOnNewObjectAfterCall(Object o1) {
322         Outer o = new Outer();
323         nonInlinedMethod();
324         o.f = o1;
325         return o;
326     }
327 
328     @Run(test = {"testStore",
329                  "testStoreNull",
330                  "testStoreObfuscatedNull",
331                  "testStoreNotNull",
332                  "testStoreTwice",
333                  "testStoreVolatile",
334                  "testStoreOnNewObject",
335                  "testStoreNullOnNewObject",
336                  "testStoreNotNullOnNewObject",
337                  "testStoreOnNewObjectInTwoPaths",
338                  "testStoreConditionallyOnNewObject",
339                  "testStoreOnNewObjectAfterException",
340                  "testStoreOnNewObjectAfterCall"})
341     public void runStoreTests() {
342         {
343             Outer o = new Outer();
344             Object o1 = new Object();
345             testStore(o, o1);
346             Asserts.assertEquals(o1, o.f);
347         }
348         {
349             Outer o = new Outer();
350             testStoreNull(o);
351             Asserts.assertNull(o.f);
352         }
353         {
354             Outer o = new Outer();
355             Object o1 = new Object();
356             testStoreObfuscatedNull(o, o1);
357             Asserts.assertNull(o.f);
358         }
359         {
360             Outer o = new Outer();
361             Object o1 = new Object();
362             testStoreNotNull(o, o1);
363             Asserts.assertEquals(o1, o.f);
364         }
365         {
366             Outer o = new Outer();
367             Outer p = new Outer();
368             Object o1 = new Object();
369             testStoreTwice(o, p, o1);
370             Asserts.assertEquals(o1, o.f);
371             Asserts.assertEquals(o1, p.f);
372         }
373         {
374             OuterWithVolatileField o = new OuterWithVolatileField();
375             Object o1 = new Object();
376             testStoreVolatile(o, o1);
377             Asserts.assertEquals(o1, o.f);
378         }
379         {
380             Object o1 = new Object();
381             Outer o = testStoreOnNewObject(o1);
382             Asserts.assertEquals(o1, o.f);
383         }
384         {
385             Outer o = testStoreNullOnNewObject();
386             Asserts.assertNull(o.f);
387         }
388         {
389             Object o1 = new Object();
390             Outer o = testStoreNotNullOnNewObject(o1);
391             Asserts.assertEquals(o1, o.f);
392         }
393         {
394             Object o1 = new Object();
395             Outer o = testStoreOnNewObjectInTwoPaths(o1, ThreadLocalRandom.current().nextBoolean());
396             Asserts.assertEquals(o1, o.f);
397         }
398         {
399             Object o1 = new Object();
400             boolean c = ThreadLocalRandom.current().nextBoolean();
401             Outer o = testStoreConditionallyOnNewObject(o1, c);
402             Asserts.assertTrue(o.f == (c ? o1 : null));
403         }
404         {
405             Object o1 = new Object();
406             boolean c = ThreadLocalRandom.current().nextBoolean();
407             try {
408                 Outer o = testStoreOnNewObjectAfterException(o1, c);
409             } catch (Exception e) {}
410         }
411         {
412             Object o1 = new Object();
413             Outer o = testStoreOnNewObjectAfterCall(o1);
414             Asserts.assertEquals(o1, o.f);
415         }
416     }
417 
418     @Test
419     @IR(applyIf = {"UseCompressedOops", "false"},
420         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
421         phase = CompilePhase.FINAL_CODE)
422     @IR(applyIf = {"UseCompressedOops", "true"},
423         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
424         phase = CompilePhase.FINAL_CODE)
425     public static void testArrayStore(Object[] a, int index, Object o1) {
426         a[index] = o1;
427     }
428 
429     @Test
430     @IR(applyIf = {"UseCompressedOops", "false"},
431         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
432         phase = CompilePhase.FINAL_CODE)
433     @IR(applyIf = {"UseCompressedOops", "true"},
434         counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
435         phase = CompilePhase.FINAL_CODE)
436     public static void testArrayStoreNull(Object[] a, int index) {
437         a[index] = null;
438     }
439 
440     @Test
441     @IR(applyIf = {"UseCompressedOops", "false"},
442         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"},
443         phase = CompilePhase.FINAL_CODE)
444     @IR(applyIf = {"UseCompressedOops", "true"},
445         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"},
446         phase = CompilePhase.FINAL_CODE)
447     public static void testArrayStoreNotNull(Object[] a, int index, Object o1) {
448         if (o1.hashCode() == 42) {
449             return;
450         }
451         a[index] = o1;
452     }
453 
454     @Test
455     @IR(applyIf = {"UseCompressedOops", "false"},
456         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "2"},
457         phase = CompilePhase.FINAL_CODE)
458     @IR(applyIf = {"UseCompressedOops", "true"},
459         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "2"},
460         phase = CompilePhase.FINAL_CODE)
461     public static void testArrayStoreTwice(Object[] a, Object[] b, int index, Object o1) {
462         a[index] = o1;
463         b[index] = o1;
464     }
465 
466     @Test
467     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
468         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
469         phase = CompilePhase.FINAL_CODE)
470     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
471         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
472         phase = CompilePhase.FINAL_CODE)
473     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
474         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
475         phase = CompilePhase.FINAL_CODE)
476     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
477         failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY,
478                   IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
479         phase = CompilePhase.FINAL_CODE)
480     public static Object[] testStoreOnNewArrayAtKnownIndex(Object o1) {
481         Object[] a = new Object[10];
482         a[4] = o1;
483         return a;
484     }
485 
486     @Test
487     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
488         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
489         phase = CompilePhase.FINAL_CODE)
490     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
491         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
492         phase = CompilePhase.FINAL_CODE)
493     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
494         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
495         phase = CompilePhase.FINAL_CODE)
496     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
497         failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY,
498                   IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
499         phase = CompilePhase.FINAL_CODE)
500     public static Object[] testStoreOnNewArrayAtUnknownIndex(Object o1, int index) {
501         Object[] a = new Object[10];
502         a[index] = o1;
503         return a;
504     }
505 
506     @Test
507     @IR(failOn = IRNode.SAFEPOINT)
508     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
509         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
510         phase = CompilePhase.FINAL_CODE)
511     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
512         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
513         phase = CompilePhase.FINAL_CODE)
514     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
515         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY},
516         phase = CompilePhase.FINAL_CODE)
517     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
518         failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
519         phase = CompilePhase.FINAL_CODE)
520     public static Object[] testStoreAllOnNewSmallArray(Object o1) {
521         Object[] a = new Object[64];
522         for (int i = 0; i < a.length; i++) {
523             a[i] = o1;
524         }
525         return a;
526     }
527 
528     @Test
529     @IR(counts = {IRNode.SAFEPOINT, "1"})
530     @IR(applyIf = {"UseCompressedOops", "false"},
531         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
532         phase = CompilePhase.FINAL_CODE)
533     @IR(applyIf = {"UseCompressedOops", "true"},
534         counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
535         phase = CompilePhase.FINAL_CODE)
536     public static Object[] testStoreAllOnNewLargeArray(Object o1) {
537         Object[] a = new Object[1024];
538         for (int i = 0; i < a.length; i++) {
539             a[i] = o1;
540         }
541         return a;
542     }
543 
544     @Run(test = {"testArrayStore",
545                  "testArrayStoreNull",
546                  "testArrayStoreNotNull",
547                  "testArrayStoreTwice",
548                  "testStoreOnNewArrayAtKnownIndex",
549                  "testStoreOnNewArrayAtUnknownIndex",
550                  "testStoreAllOnNewSmallArray",
551                  "testStoreAllOnNewLargeArray"})
552     public void runArrayStoreTests() {
553         {
554             Object[] a = new Object[10];
555             Object o1 = new Object();
556             testArrayStore(a, 4, o1);
557             Asserts.assertEquals(o1, a[4]);
558         }
559         {
560             Object[] a = new Object[10];
561             testArrayStoreNull(a, 4);
562             Asserts.assertNull(a[4]);
563         }
564         {
565             Object[] a = new Object[10];
566             Object o1 = new Object();
567             testArrayStoreNotNull(a, 4, o1);
568             Asserts.assertEquals(o1, a[4]);
569         }
570         {
571             Object[] a = new Object[10];
572             Object[] b = new Object[10];
573             Object o1 = new Object();
574             testArrayStoreTwice(a, b, 4, o1);
575             Asserts.assertEquals(o1, a[4]);
576             Asserts.assertEquals(o1, b[4]);
577         }
578         {
579             Object o1 = new Object();
580             Object[] a = testStoreOnNewArrayAtKnownIndex(o1);
581             Asserts.assertEquals(o1, a[4]);
582         }
583         {
584             Object o1 = new Object();
585             Object[] a = testStoreOnNewArrayAtUnknownIndex(o1, 5);
586             Asserts.assertEquals(o1, a[5]);
587         }
588         {
589             Object o1 = new Object();
590             Object[] a = testStoreAllOnNewSmallArray(o1);
591             for (int i = 0; i < a.length; i++) {
592                 Asserts.assertEquals(o1, a[i]);
593             }
594         }
595         {
596             Object o1 = new Object();
597             Object[] a = testStoreAllOnNewLargeArray(o1);
598             for (int i = 0; i < a.length; i++) {
599                 Asserts.assertEquals(o1, a[i]);
600             }
601         }
602     }
603 
604     @Test
605     public static Object[] testCloneArrayOfObjects(Object[] a) {
606         Object[] a1 = null;
607         try {
608             a1 = a.clone();
609         } catch (Exception e) {}
610         return a1;
611     }
612 
613     @Test
614     @IR(applyIf = {"ReduceInitialCardMarks", "true"},
615         failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY,
616                   IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY,
617                   IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY},
618         phase = CompilePhase.FINAL_CODE)
619     @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "false"},
620         counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"},
621         phase = CompilePhase.FINAL_CODE)
622     @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "true"},
623         counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"},
624         phase = CompilePhase.FINAL_CODE)
625     public static OuterWithFewFields testCloneObjectWithFewFields(OuterWithFewFields o) {
626         Object o1 = null;
627         try {
628             o1 = o.clone();
629         } catch (Exception e) {}
630         return (OuterWithFewFields)o1;
631     }
632 
633     @Test
634     @IR(applyIf = {"ReduceInitialCardMarks", "true"},
635         counts = {IRNode.CALL_OF, "jlong_disjoint_arraycopy", "1"})
636     @IR(applyIf = {"ReduceInitialCardMarks", "false"},
637         counts = {IRNode.CALL_OF, "G1BarrierSetRuntime::clone", "1"})
638     public static OuterWithManyFields testCloneObjectWithManyFields(OuterWithManyFields o) {
639         Object o1 = null;
640         try {
641             o1 = o.clone();
642         } catch (Exception e) {}
643         return (OuterWithManyFields)o1;
644     }
645 
646     @Run(test = {"testCloneArrayOfObjects",
647                  "testCloneObjectWithFewFields",
648                  "testCloneObjectWithManyFields"})
649     public void runCloneTests() {
650         {
651             Object o1 = new Object();
652             Object[] a = new Object[4];
653             for (int i = 0; i < 4; i++) {
654                 a[i] = o1;
655             }
656             Object[] a1 = testCloneArrayOfObjects(a);
657             for (int i = 0; i < 4; i++) {
658                 Asserts.assertEquals(o1, a1[i]);
659             }
660         }
661         {
662             Object a = new Object();
663             Object b = new Object();
664             OuterWithFewFields o = new OuterWithFewFields();
665             o.f1 = a;
666             o.f2 = b;
667             OuterWithFewFields o1 = testCloneObjectWithFewFields(o);
668             Asserts.assertEquals(a, o1.f1);
669             Asserts.assertEquals(b, o1.f2);
670         }
671         {
672             Object a = new Object();
673             Object b = new Object();
674             Object c = new Object();
675             Object d = new Object();
676             Object e = new Object();
677             Object f = new Object();
678             Object g = new Object();
679             Object h = new Object();
680             Object i = new Object();
681             Object j = new Object();
682             OuterWithManyFields o = new OuterWithManyFields();
683             o.f1 = a;
684             o.f2 = b;
685             o.f3 = c;
686             o.f4 = d;
687             o.f5 = e;
688             o.f6 = f;
689             o.f7 = g;
690             o.f8 = h;
691             o.f9 = i;
692             o.f10 = j;
693             OuterWithManyFields o1 = testCloneObjectWithManyFields(o);
694             Asserts.assertEquals(a, o1.f1);
695             Asserts.assertEquals(b, o1.f2);
696             Asserts.assertEquals(c, o1.f3);
697             Asserts.assertEquals(d, o1.f4);
698             Asserts.assertEquals(e, o1.f5);
699             Asserts.assertEquals(f, o1.f6);
700             Asserts.assertEquals(g, o1.f7);
701             Asserts.assertEquals(h, o1.f8);
702             Asserts.assertEquals(i, o1.f9);
703             Asserts.assertEquals(j, o1.f10);
704         }
705     }
706 
707     @Test
708     @IR(applyIf = {"UseCompressedOops", "false"},
709         counts = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
710         phase = CompilePhase.FINAL_CODE)
711     @IR(applyIf = {"UseCompressedOops", "true"},
712         counts = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
713         phase = CompilePhase.FINAL_CODE)
714     static Object testCompareAndExchange(Outer o, Object oldVal, Object newVal) {
715         return fVarHandle.compareAndExchange(o, oldVal, newVal);
716     }
717 
718     @Test
719     @IR(applyIf = {"UseCompressedOops", "false"},
720         counts = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
721         phase = CompilePhase.FINAL_CODE)
722     @IR(applyIf = {"UseCompressedOops", "true"},
723         counts = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
724         phase = CompilePhase.FINAL_CODE)
725     static boolean testCompareAndSwap(Outer o, Object oldVal, Object newVal) {
726         return fVarHandle.compareAndSet(o, oldVal, newVal);
727     }
728 
729     @Test
730     @IR(applyIf = {"UseCompressedOops", "false"},
731         counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
732         phase = CompilePhase.FINAL_CODE)
733     @IR(applyIf = {"UseCompressedOops", "true"},
734         counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
735         phase = CompilePhase.FINAL_CODE)
736     static Object testGetAndSet(Outer o, Object newVal) {
737         return fVarHandle.getAndSet(o, newVal);
738     }
739 
740     // IR checks are disabled for s390 because barriers are not elided (to be investigated).
741     @Test
742     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
743         applyIfPlatform = {"s390", "false"},
744         counts = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
745         phase = CompilePhase.FINAL_CODE)
746     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
747         applyIfPlatform = {"s390", "false"},
748         counts = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
749         phase = CompilePhase.FINAL_CODE)
750     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
751         applyIfPlatform = {"s390", "false"},
752         failOn = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, ANY},
753         phase = CompilePhase.FINAL_CODE)
754     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
755         applyIfPlatform = {"s390", "false"},
756         failOn = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, ANY},
757         phase = CompilePhase.FINAL_CODE)
758     static Object testCompareAndExchangeOnNewObject(Object oldVal, Object newVal) {
759         Outer o = new Outer();
760         o.f = oldVal;
761         return fVarHandle.compareAndExchange(o, oldVal, newVal);
762     }
763 
764     // IR checks are disabled for s390 when OOPs compression is disabled
765     // because barriers are not elided in this configuration (to be investigated).
766     @Test
767     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
768         applyIfPlatform = {"s390", "false"},
769         counts = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
770         phase = CompilePhase.FINAL_CODE)
771     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
772         counts = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
773         phase = CompilePhase.FINAL_CODE)
774     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
775         applyIfPlatform = {"s390", "false"},
776         failOn = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, ANY},
777         phase = CompilePhase.FINAL_CODE)
778     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
779         failOn = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, ANY},
780         phase = CompilePhase.FINAL_CODE)
781     static boolean testCompareAndSwapOnNewObject(Object oldVal, Object newVal) {
782         Outer o = new Outer();
783         o.f = oldVal;
784         return fVarHandle.compareAndSet(o, oldVal, newVal);
785     }
786 
787     @Test
788     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
789         counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
790         phase = CompilePhase.FINAL_CODE)
791     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
792         counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
793         phase = CompilePhase.FINAL_CODE)
794     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
795         failOn = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, ANY},
796         phase = CompilePhase.FINAL_CODE)
797     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
798         failOn = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, ANY},
799         phase = CompilePhase.FINAL_CODE)
800     static Object testGetAndSetOnNewObject(Object oldVal, Object newVal) {
801         Outer o = new Outer();
802         o.f = oldVal;
803         return fVarHandle.getAndSet(o, newVal);
804     }
805 
806     @Test
807     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
808         counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
809         phase = CompilePhase.FINAL_CODE)
810     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
811         counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
812         phase = CompilePhase.FINAL_CODE)
813     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
814         failOn = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, ANY},
815         phase = CompilePhase.FINAL_CODE)
816     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
817         failOn = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, ANY},
818         phase = CompilePhase.FINAL_CODE)
819     static Object testGetAndSetConditionallyOnNewObject(Object oldVal, Object newVal, boolean c) {
820         Outer o = new Outer();
821         o.f = oldVal;
822         if (c) {
823             return fVarHandle.getAndSet(o, newVal);
824         }
825         return oldVal;
826     }
827 
828     @Test
829     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"},
830         counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, POST_ONLY, "1"},
831         phase = CompilePhase.FINAL_CODE)
832     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"},
833         counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, POST_ONLY, "1"},
834         phase = CompilePhase.FINAL_CODE)
835     @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"},
836         failOn = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, ANY},
837         phase = CompilePhase.FINAL_CODE)
838     @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"},
839         failOn = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, ANY},
840         phase = CompilePhase.FINAL_CODE)
841     static Object testGetAndSetOnNewObjectAfterException(Object oldVal, Object newVal, boolean c) throws Exception {
842         Outer o = new Outer();
843         if (c) {
844             throw new Exception("");
845         }
846         o.f = oldVal;
847         return fVarHandle.getAndSet(o, newVal);
848     }
849 
850     @Test
851     @IR(applyIf = {"UseCompressedOops", "false"},
852         counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
853         phase = CompilePhase.FINAL_CODE)
854     @IR(applyIf = {"UseCompressedOops", "true"},
855         counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"},
856         phase = CompilePhase.FINAL_CODE)
857     static Object testGetAndSetOnNewObjectAfterCall(Object oldVal, Object newVal) {
858         Outer o = new Outer();
859         nonInlinedMethod();
860         o.f = oldVal;
861         return fVarHandle.getAndSet(o, newVal);
862     }
863 
864     @Run(test = {"testCompareAndExchange",
865                  "testCompareAndSwap",
866                  "testGetAndSet",
867                  "testCompareAndExchangeOnNewObject",
868                  "testCompareAndSwapOnNewObject",
869                  "testGetAndSetOnNewObject",
870                  "testGetAndSetConditionallyOnNewObject",
871                  "testGetAndSetOnNewObjectAfterException",
872                  "testGetAndSetOnNewObjectAfterCall"})
873     public void runAtomicTests() {
874         {
875             Outer o = new Outer();
876             Object oldVal = new Object();
877             o.f = oldVal;
878             Object newVal = new Object();
879             Object oldVal2 = testCompareAndExchange(o, oldVal, newVal);
880             Asserts.assertEquals(oldVal, oldVal2);
881             Asserts.assertEquals(o.f, newVal);
882         }
883         {
884             Outer o = new Outer();
885             Object oldVal = new Object();
886             o.f = oldVal;
887             Object newVal = new Object();
888             boolean b = testCompareAndSwap(o, oldVal, newVal);
889             Asserts.assertTrue(b);
890             Asserts.assertEquals(o.f, newVal);
891         }
892         {
893             Outer o = new Outer();
894             Object oldVal = new Object();
895             o.f = oldVal;
896             Object newVal = new Object();
897             Object oldVal2 = testGetAndSet(o, newVal);
898             Asserts.assertEquals(oldVal, oldVal2);
899             Asserts.assertEquals(o.f, newVal);
900         }
901         {
902             Object oldVal = new Object();
903             Object newVal = new Object();
904             Object oldVal2 = testCompareAndExchangeOnNewObject(oldVal, newVal);
905             Asserts.assertEquals(oldVal, oldVal2);
906         }
907         {
908             Object oldVal = new Object();
909             Object newVal = new Object();
910             boolean b = testCompareAndSwapOnNewObject(oldVal, newVal);
911             Asserts.assertTrue(b);
912         }
913         {
914             Object oldVal = new Object();
915             Object newVal = new Object();
916             Object oldVal2 = testGetAndSetOnNewObject(oldVal, newVal);
917             Asserts.assertEquals(oldVal, oldVal2);
918         }
919         {
920             Object oldVal = new Object();
921             Object newVal = new Object();
922             boolean c = ThreadLocalRandom.current().nextBoolean();
923             Object oldVal2 = testGetAndSetConditionallyOnNewObject(oldVal, newVal, c);
924             Asserts.assertEquals(oldVal, oldVal2);
925         }
926         {
927             Object oldVal = new Object();
928             Object newVal = new Object();
929             boolean c = ThreadLocalRandom.current().nextBoolean();
930             try {
931                 Object oldVal2 = testGetAndSetOnNewObjectAfterException(oldVal, newVal, c);
932             } catch (Exception e) {}
933         }
934         {
935             Object oldVal = new Object();
936             Object newVal = new Object();
937             Object oldVal2 = testGetAndSetOnNewObjectAfterCall(oldVal, newVal);
938             Asserts.assertEquals(oldVal, oldVal2);
939         }
940     }
941 
942     @Test
943     @IR(applyIf = {"UseCompressedOops", "false"},
944         counts = {IRNode.G1_LOAD_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
945         phase = CompilePhase.FINAL_CODE)
946     @IR(applyIf = {"UseCompressedOops", "true"},
947         counts = {IRNode.G1_LOAD_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
948         phase = CompilePhase.FINAL_CODE)
949     static Object testLoadSoftReference(SoftReference<Object> ref) {
950         return ref.get();
951     }
952 
953     @Test
954     @IR(applyIf = {"UseCompressedOops", "false"},
955         counts = {IRNode.G1_LOAD_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
956         phase = CompilePhase.FINAL_CODE)
957     @IR(applyIf = {"UseCompressedOops", "true"},
958         counts = {IRNode.G1_LOAD_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"},
959         phase = CompilePhase.FINAL_CODE)
960     static Object testLoadWeakReference(WeakReference<Object> ref) {
961         return ref.get();
962     }
963 
964     @Run(test = {"testLoadSoftReference",
965                  "testLoadWeakReference"})
966     public void runReferenceTests() {
967         {
968             Object o1 = new Object();
969             SoftReference<Object> sref = new SoftReference<Object>(o1);
970             Object o2 = testLoadSoftReference(sref);
971             Asserts.assertTrue(o2 == o1 || o2 == null);
972         }
973         {
974             Object o1 = new Object();
975             WeakReference<Object> wref = new WeakReference<Object>(o1);
976             Object o2 = testLoadWeakReference(wref);
977             Asserts.assertTrue(o2 == o1 || o2 == null);
978         }
979     }
980 }