1 /*
  2  * Copyright (c) 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 package org.openjdk.bench.valhalla.array.read;
 24 
 25 import java.util.concurrent.TimeUnit;
 26 import jdk.internal.value.ValueClass;
 27 import org.openjdk.jmh.annotations.*;
 28 
 29 @BenchmarkMode(Mode.AverageTime)
 30 @OutputTimeUnit(TimeUnit.NANOSECONDS)
 31 @State(Scope.Thread)
 32 @Warmup(iterations = 5, time = 1)
 33 @Measurement(iterations = 5, time = 1)
 34 @Fork(3)
 35 public class HoistArrayChecks {
 36     private static final int SIZE = 1_000_000;
 37 
 38     value record Point(byte x, byte y) {
 39         static final Point DEFAULT = new Point((byte) 0, (byte) 0);
 40     }
 41 
 42     Point[] nonAtomicFlatArray = (Point[]) ValueClass.newNullRestrictedNonAtomicArray(Point.class, SIZE, Point.DEFAULT);
 43     Point[] atomicFlatArray = (Point[]) ValueClass.newNullRestrictedAtomicArray(Point.class, SIZE, Point.DEFAULT);
 44     Point[] nullableFlatArray = (Point[]) ValueClass.newNullableAtomicArray(Point.class, SIZE);
 45 
 46     @Setup
 47     public void setup() {
 48         for (int i = 0; i < SIZE; i++) {
 49             nullableFlatArray[i] = Point.DEFAULT;
 50         }
 51     }
 52 
 53     @Benchmark
 54     public int nonAtomicNaive() {
 55         int sum = 0;
 56         for (int i = 0; i < SIZE; i++) {
 57             Point p = nonAtomicFlatArray[i];
 58             sum += p.x + p.y;
 59         }
 60         return sum;
 61     }
 62 
 63     @Benchmark
 64     public int nonAtomicHoisted() {
 65         Point[] array = nonAtomicFlatArray;
 66         int sum = 0;
 67         for (int i = 0; i < SIZE; i++) {
 68             Point p = array[i];
 69             sum += p.x + p.y;
 70         }
 71         return sum;
 72     }
 73 
 74     @Benchmark
 75     public int atomicNaive() {
 76         int sum = 0;
 77         for (int i = 0; i < SIZE; i++) {
 78             Point p = atomicFlatArray[i];
 79             sum += p.x + p.y;
 80         }
 81         return sum;
 82     }
 83 
 84     @Benchmark
 85     public int atomicHoisted() {
 86         Point[] array = atomicFlatArray;
 87         int sum = 0;
 88         for (int i = 0; i < SIZE; i++) {
 89             Point p = array[i];
 90             sum += p.x + p.y;
 91         }
 92         return sum;
 93     }
 94 
 95     @Benchmark
 96     public int nullableNaive() {
 97         int sum = 0;
 98         for (int i = 0; i < SIZE; i++) {
 99             Point p = nullableFlatArray[i];
100             sum += p.x + p.y;
101         }
102         return sum;
103     }
104 
105     @Benchmark
106     public int nullableHoisted() {
107         Point[] array = nullableFlatArray;
108         int sum = 0;
109         for (int i = 0; i < SIZE; i++) {
110             Point p = array[i];
111             sum += p.x + p.y;
112         }
113         return sum;
114     }
115 }