1 /*
  2  * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2021, Arm Limited. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  */
 24 
 25 package compiler.valhalla.inlinetypes;
 26 
 27 /**
 28  * @test TestBufferTearingC1
 29  * @key randomness
 30  * @summary Tests for C1 missing barriers when buffering value classes.
 31  * @enablePreview
 32  * @modules java.base/jdk.internal.value
 33  *          java.base/jdk.internal.vm.annotation
 34  * @run main/othervm -XX:InlineFieldMaxFlatSize=-1 -XX:FlatArrayElementMaxSize=-1
 35  *                   compiler.valhalla.inlinetypes.TestBufferTearingC1
 36  * @run main/othervm -XX:InlineFieldMaxFlatSize=-1 -XX:FlatArrayElementMaxSize=-1
 37  *                   -XX:TieredStopAtLevel=1
 38  *                   compiler.valhalla.inlinetypes.TestBufferTearingC1
 39  */
 40 
 41 import jdk.internal.value.ValueClass;
 42 import jdk.internal.vm.annotation.ImplicitlyConstructible;
 43 import jdk.internal.vm.annotation.LooselyConsistentValue;
 44 import jdk.internal.vm.annotation.NullRestricted;
 45 
 46 @ImplicitlyConstructible
 47 @LooselyConsistentValue
 48 value class Point {
 49     public int x, y;
 50 
 51     public Point(int x, int y) {
 52         this.x = x;
 53         this.y = y;
 54     }
 55 }
 56 
 57 @ImplicitlyConstructible
 58 @LooselyConsistentValue
 59 value class Rect {
 60     public Point a, b;
 61 
 62     public Rect(Point a, Point b) {
 63         this.a = a;
 64         this.b = b;
 65     }
 66 }
 67 
 68 public class TestBufferTearingC1 {
 69 
 70     public static Point[] points = (Point[])ValueClass.newNullRestrictedArray(Point.class, 1);
 71     public static Rect rect = new Rect(new Point(1, 1), new Point(2, 2));
 72     public static Rect[] rects = (Rect[])ValueClass.newNullRestrictedArray(Rect.class, 1);
 73 
 74     static {
 75         points[0] = new Point(1, 1);
 76         rects[0] = rect;
 77     }
 78 
 79     public static Object ref1 = points[0];
 80     public static Object ref2 = rect.a;
 81     public static Object ref3 = rects[0].a;
 82 
 83     static volatile boolean running = true;
 84 
 85     public static void writeRefs(int iter) {
 86         ref1 = points[0];    // Indexed load of flattened array
 87         ref2 = rect.a;       // Load from flattened field
 88         ref3 = rects[0].a;   // Indexed load (delayed) followed by flattened field access
 89 
 90         points[0] = new Point(iter, iter);
 91         rect = new Rect(new Point(iter, iter), new Point(iter + 1, iter + 1));
 92         rects[0] = rect;
 93     }
 94 
 95     private static void checkMissingBarrier() {
 96         while (running) {
 97             // Each refN holds a "buffered" reference created when reading a
 98             // flattened field or array element.  It should not be possible to
 99             // read through this reference and see the intermediate
100             // zero-initialised state of the object (i.e. there should be a
101             // store-store barrier after copying the flattened field contents
102             // before the store that publishes it).
103 
104             if (((Point)ref1).x == 0 || ((Point)ref1).y == 0) {
105                 throw new IllegalStateException();
106             }
107 
108             if (((Point)ref2).x == 0 || ((Point)ref2).y == 0) {
109                 throw new IllegalStateException();
110             }
111 
112             if (((Point)ref3).x == 0 || ((Point)ref3).y == 0) {
113                 throw new IllegalStateException();
114             }
115         }
116     }
117 
118     public static void main(String[] args) throws InterruptedException {
119         Thread[] threads = new Thread[10];
120         for (int i = 0; i < 10; i++) {
121             threads[i] = new Thread(TestBufferTearingC1::checkMissingBarrier);
122             threads[i].start();
123         }
124 
125         for (int i = 1; i < 1_000_000; i++) {
126             writeRefs(i);
127         }
128 
129         running = false;
130 
131         for (int i = 0; i < 10; i++) {
132             threads[i].join();
133         }
134     }
135 }