10e54c0160c84894696c05af6cad9eae3690f9496Aart Bik/*
20e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * Copyright (C) 2016 The Android Open Source Project
30e54c0160c84894696c05af6cad9eae3690f9496Aart Bik *
40e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * Licensed under the Apache License, Version 2.0 (the "License");
50e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * you may not use this file except in compliance with the License.
60e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * You may obtain a copy of the License at
70e54c0160c84894696c05af6cad9eae3690f9496Aart Bik *
80e54c0160c84894696c05af6cad9eae3690f9496Aart Bik *      http://www.apache.org/licenses/LICENSE-2.0
90e54c0160c84894696c05af6cad9eae3690f9496Aart Bik *
100e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * Unless required by applicable law or agreed to in writing, software
110e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * distributed under the License is distributed on an "AS IS" BASIS,
120e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * See the License for the specific language governing permissions and
140e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * limitations under the License.
150e54c0160c84894696c05af6cad9eae3690f9496Aart Bik */
160e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
170e54c0160c84894696c05af6cad9eae3690f9496Aart Bikimport java.lang.reflect.Field;
18700ae4071cc297e2c567322661704d5eb5af76aeAart Bikimport java.util.concurrent.atomic.AtomicBoolean;
190e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
200e54c0160c84894696c05af6cad9eae3690f9496Aart Bikimport sun.misc.Unsafe;
210e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
220e54c0160c84894696c05af6cad9eae3690f9496Aart Bik/**
230e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * Checker test on the 1.8 unsafe operations. Note, this is by no means an
240e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * exhaustive unit test for these CAS (compare-and-swap) and fence operations.
250e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * Instead, this test ensures the methods are recognized as intrinsic and behave
260e54c0160c84894696c05af6cad9eae3690f9496Aart Bik * as expected.
270e54c0160c84894696c05af6cad9eae3690f9496Aart Bik */
280e54c0160c84894696c05af6cad9eae3690f9496Aart Bikpublic class Main {
290e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
300e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static final Unsafe unsafe = getUnsafe();
310e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
320e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static Thread[] sThreads = new Thread[10];
330e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
340e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
35700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  // Fields accessed by setters and adders, and by memory fence tests.
360e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
370e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
380e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  public int i = 0;
390e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  public long l = 0;
400e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  public Object o = null;
410e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
42700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  public int x_value;
43700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  public int y_value;
44700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  public volatile boolean running;
45700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
460e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
470e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  // Setters.
480e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
490e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
500e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: int Main.set32(java.lang.Object, long, int) intrinsics_recognition (after)
510e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetInt
520e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG:                 Return [<<Result>>]
530e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static int set32(Object o, long offset, int newValue) {
540e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    return unsafe.getAndSetInt(o, offset, newValue);
550e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
560e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
570e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: long Main.set64(java.lang.Object, long, long) intrinsics_recognition (after)
580e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetLong
590e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG:                 Return [<<Result>>]
600e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static long set64(Object o, long offset, long newValue) {
610e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    return unsafe.getAndSetLong(o, offset, newValue);
620e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
630e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
640e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: java.lang.Object Main.setObj(java.lang.Object, long, java.lang.Object) intrinsics_recognition (after)
650e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: <<Result:l\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetObject
660e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG:                 Return [<<Result>>]
670e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static Object setObj(Object o, long offset, Object newValue) {
680e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    return unsafe.getAndSetObject(o, offset, newValue);
690e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
700e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
710e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
720e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  // Adders.
730e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
740e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
750e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: int Main.add32(java.lang.Object, long, int) intrinsics_recognition (after)
760e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddInt
770e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG:                 Return [<<Result>>]
780e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static int add32(Object o, long offset, int delta) {
790e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    return unsafe.getAndAddInt(o, offset, delta);
800e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
810e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
820e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: long Main.add64(java.lang.Object, long, long) intrinsics_recognition (after)
830e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddLong
840e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG:                 Return [<<Result>>]
850e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static long add64(Object o, long offset, long delta) {
860e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    return unsafe.getAndAddLong(o, offset, delta);
870e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
880e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
890e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
900e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  // Fences (native).
910e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
920e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
930e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: void Main.load() intrinsics_recognition (after)
940e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeLoadFence
951193259cb37c9763a111825aa04718a409d07145Aart Bik  //
961193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-START: void Main.load() instruction_simplifier (after)
971193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeLoadFence
981193259cb37c9763a111825aa04718a409d07145Aart Bik  //
991193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-START: void Main.load() instruction_simplifier (after)
1001193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-DAG: MemoryBarrier kind:LoadAny
1010e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static void load() {
1020e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    unsafe.loadFence();
1030e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
1040e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1050e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: void Main.store() intrinsics_recognition (after)
1060e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeStoreFence
1071193259cb37c9763a111825aa04718a409d07145Aart Bik  //
1081193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-START: void Main.store() instruction_simplifier (after)
1091193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeStoreFence
1101193259cb37c9763a111825aa04718a409d07145Aart Bik  //
1111193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-START: void Main.store() instruction_simplifier (after)
1121193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-DAG: MemoryBarrier kind:AnyStore
1130e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static void store() {
1140e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    unsafe.storeFence();
1150e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
1160e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1170e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-START: void Main.full() intrinsics_recognition (after)
1180e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeFullFence
1191193259cb37c9763a111825aa04718a409d07145Aart Bik  //
1201193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-START: void Main.full() instruction_simplifier (after)
1211193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeFullFence
1221193259cb37c9763a111825aa04718a409d07145Aart Bik  //
1231193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-START: void Main.full() instruction_simplifier (after)
1241193259cb37c9763a111825aa04718a409d07145Aart Bik  /// CHECK-DAG: MemoryBarrier kind:AnyAny
1250e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static void full() {
1260e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    unsafe.fullFence();
1270e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
1280e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1290e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
1300e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  // Thread fork/join.
1310e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
1320e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1330e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static void fork(Runnable r) {
1340e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    for (int i = 0; i < 10; i++) {
1350e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      sThreads[i] = new Thread(r);
136d07453889fd9f314849df8c172afadb477e46d64Aart Bik    }
137d07453889fd9f314849df8c172afadb477e46d64Aart Bik    // Start the threads only after the full array has been written with new threads,
138d07453889fd9f314849df8c172afadb477e46d64Aart Bik    // because one test relies on the contents of this array to be consistent.
139d07453889fd9f314849df8c172afadb477e46d64Aart Bik    for (int i = 0; i < 10; i++) {
1400e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      sThreads[i].start();
1410e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
1420e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
1430e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1440e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static void join() {
1450e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    try {
1460e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      for (int i = 0; i < 10; i++) {
1470e54c0160c84894696c05af6cad9eae3690f9496Aart Bik        sThreads[i].join();
1480e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      }
1490e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    } catch (InterruptedException e) {
1500e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      throw new Error("Failed join: " + e);
1510e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
1520e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
1530e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1540e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
1550e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  // Driver.
1560e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  //
1570e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1580e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  public static void main(String[] args) {
1590e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    System.out.println("starting");
1600e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1610e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    final Main m = new Main();
1620e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1630e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    // Get the offsets.
1640e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1650e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    final long intOffset, longOffset, objOffset;
1660e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    try {
1670e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      Field intField = Main.class.getDeclaredField("i");
1680e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      Field longField = Main.class.getDeclaredField("l");
1690e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      Field objField = Main.class.getDeclaredField("o");
1700e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1710e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      intOffset = unsafe.objectFieldOffset(intField);
1720e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      longOffset = unsafe.objectFieldOffset(longField);
1730e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      objOffset = unsafe.objectFieldOffset(objField);
1740e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1750e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    } catch (NoSuchFieldException e) {
1760e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      throw new Error("No offset: " + e);
1770e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
1780e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
179700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // Some sanity on setters and adders within same thread.
1800e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1810e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    set32(m, intOffset, 3);
182700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual32(3, m.i);
1830e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1840e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    set64(m, longOffset, 7L);
185700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual64(7L, m.l);
1860e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1870e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    setObj(m, objOffset, m);
188700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqualObj(m, m.o);
1890e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1900e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    add32(m, intOffset, 11);
191700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual32(14, m.i);
1920e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1930e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    add64(m, longOffset, 13L);
194700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual64(20L, m.l);
1950e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1960e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    // Some sanity on setters within different threads.
1970e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
1980e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    fork(new Runnable() {
1990e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      public void run() {
2000e54c0160c84894696c05af6cad9eae3690f9496Aart Bik        for (int i = 0; i < 10; i++)
2010e54c0160c84894696c05af6cad9eae3690f9496Aart Bik          set32(m, intOffset, i);
2020e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      }
2030e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    });
2040e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    join();
205700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual32(9, m.i);  // one thread's last value wins
2060e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
2070e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    fork(new Runnable() {
2080e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      public void run() {
2090e54c0160c84894696c05af6cad9eae3690f9496Aart Bik        for (int i = 0; i < 10; i++)
2100e54c0160c84894696c05af6cad9eae3690f9496Aart Bik          set64(m, longOffset, (long) (100 + i));
2110e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      }
2120e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    });
2130e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    join();
214700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual64(109L, m.l);  // one thread's last value wins
2150e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
2160e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    fork(new Runnable() {
2170e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      public void run() {
2180e54c0160c84894696c05af6cad9eae3690f9496Aart Bik        for (int i = 0; i < 10; i++)
2190e54c0160c84894696c05af6cad9eae3690f9496Aart Bik          setObj(m, objOffset, sThreads[i]);
2200e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      }
2210e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    });
2220e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    join();
223700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqualObj(sThreads[9], m.o);  // one thread's last value wins
2240e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
2250e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    // Some sanity on adders within different threads.
2260e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
2270e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    fork(new Runnable() {
2280e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      public void run() {
2290e54c0160c84894696c05af6cad9eae3690f9496Aart Bik        for (int i = 0; i < 10; i++)
2300e54c0160c84894696c05af6cad9eae3690f9496Aart Bik          add32(m, intOffset, i + 1);
2310e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      }
2320e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    });
2330e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    join();
234700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual32(559, m.i);  // all values accounted for
2350e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
2360e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    fork(new Runnable() {
2370e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      public void run() {
2380e54c0160c84894696c05af6cad9eae3690f9496Aart Bik        for (int i = 0; i < 10; i++)
2390e54c0160c84894696c05af6cad9eae3690f9496Aart Bik          add64(m, longOffset, (long) (i + 1));
2400e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      }
2410e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    });
2420e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    join();
243700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual64(659L, m.l);  // all values accounted for
244700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
245700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // Some sanity on fences within same thread. Note that memory fences within one
246700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // thread make little sense, but the sanity check ensures nothing bad happens.
247700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
248700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.i = -1;
249700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.l = -2L;
250700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.o = null;
251700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
252700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    load();
253700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    store();
254700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    full();
255700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
256700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual32(-1, m.i);
257700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqual64(-2L, m.l);
258700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    expectEqualObj(null, m.o);
259700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
260700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // Some sanity on full fence within different threads. We write the non-volatile m.l after
261700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // the fork(), which means there is no happens-before relation in the Java memory model
262700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // with respect to the read in the threads. This relation is enforced by the memory fences
263700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // and the weak-set() -> get() guard. Note that the guard semantics used here are actually
264700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // too strong and already enforce total memory visibility, but this test illustrates what
265700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // should still happen if Java had a true relaxed memory guard.
266700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
267700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    final AtomicBoolean guard1 = new AtomicBoolean();
268700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.l = 0L;
269700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
270700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    fork(new Runnable() {
271700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      public void run() {
272700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        while (!guard1.get());  // busy-waiting
273700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        full();
274700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        expectEqual64(-123456789L, m.l);
275700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      }
276700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    });
277700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
278700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.l = -123456789L;
279700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    full();
280700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    while (!guard1.weakCompareAndSet(false, true));  // relaxed memory order
281700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    join();
282700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
283700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // Some sanity on release/acquire fences within different threads. We write the non-volatile
284700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // m.l after the fork(), which means there is no happens-before relation in the Java memory
285700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // model with respect to the read in the threads. This relation is enforced by the memory fences
286700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // and the weak-set() -> get() guard. Note that the guard semantics used here are actually
287700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // too strong and already enforce total memory visibility, but this test illustrates what
288700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // should still happen if Java had a true relaxed memory guard.
289700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
290700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    final AtomicBoolean guard2 = new AtomicBoolean();
291700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.l = 0L;
292700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
293700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    fork(new Runnable() {
294700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      public void run() {
295700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        while (!guard2.get());  // busy-waiting
296700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        load();
297700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        expectEqual64(-987654321L, m.l);
298700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      }
299700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    });
300700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
301700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.l = -987654321L;
302700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    store();
303700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    while (!guard2.weakCompareAndSet(false, true));  // relaxed memory order
304700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    join();
305700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
306700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // Some sanity on release/acquire fences within different threads using a test suggested by
307700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // Hans Boehm. Even this test remains with the realm of sanity only, since having the threads
308700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // read the same value consistently would be a valid outcome.
309700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
310700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.x_value = -1;
311700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.y_value = -1;
312700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.running = true;
313700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
314700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    fork(new Runnable() {
315700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      public void run() {
316700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        while (m.running) {
317700ae4071cc297e2c567322661704d5eb5af76aeAart Bik          for (int few_times = 0; few_times < 1000; few_times++) {
318700ae4071cc297e2c567322661704d5eb5af76aeAart Bik            // Read y first, then load fence, then read x.
319700ae4071cc297e2c567322661704d5eb5af76aeAart Bik            // They should appear in order, if seen at all.
320700ae4071cc297e2c567322661704d5eb5af76aeAart Bik            int local_y = m.y_value;
321700ae4071cc297e2c567322661704d5eb5af76aeAart Bik            load();
322700ae4071cc297e2c567322661704d5eb5af76aeAart Bik            int local_x = m.x_value;
323700ae4071cc297e2c567322661704d5eb5af76aeAart Bik            expectLessThanOrEqual32(local_y, local_x);
324700ae4071cc297e2c567322661704d5eb5af76aeAart Bik          }
325700ae4071cc297e2c567322661704d5eb5af76aeAart Bik        }
326700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      }
327700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    });
328700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
329700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    for (int many_times = 0; many_times < 100000; many_times++) {
330700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      m.x_value = many_times;
331700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      store();
332700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      m.y_value = many_times;
333700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    }
334700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    m.running = false;
335700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    join();
3360e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
337700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    // All done!
3380e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
3390e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    System.out.println("passed");
3400e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
3410e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
3420e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  // Use reflection to implement "Unsafe.getUnsafe()";
3430e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  private static Unsafe getUnsafe() {
3440e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    try {
3450e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      Class<?> unsafeClass = Unsafe.class;
3460e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      Field f = unsafeClass.getDeclaredField("theUnsafe");
3470e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      f.setAccessible(true);
3480e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      return (Unsafe) f.get(null);
3490e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    } catch (Exception e) {
3500e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      throw new Error("Cannot get Unsafe instance");
3510e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
3520e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
3530e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
354700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  private static void expectEqual32(int expected, int result) {
3550e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    if (expected != result) {
3560e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      throw new Error("Expected: " + expected + ", found: " + result);
3570e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
3580e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
3590e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
360700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  private static void expectLessThanOrEqual32(int val1, int val2) {
361700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    if (val1 > val2) {
362700ae4071cc297e2c567322661704d5eb5af76aeAart Bik      throw new Error("Expected: " + val1 + " <= " + val2);
363700ae4071cc297e2c567322661704d5eb5af76aeAart Bik    }
364700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  }
365700ae4071cc297e2c567322661704d5eb5af76aeAart Bik
366700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  private static void expectEqual64(long expected, long result) {
3670e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    if (expected != result) {
3680e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      throw new Error("Expected: " + expected + ", found: " + result);
3690e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
3700e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
3710e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
372700ae4071cc297e2c567322661704d5eb5af76aeAart Bik  private static void expectEqualObj(Object expected, Object result) {
3730e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    if (expected != result) {
3740e54c0160c84894696c05af6cad9eae3690f9496Aart Bik      throw new Error("Expected: " + expected + ", found: " + result);
3750e54c0160c84894696c05af6cad9eae3690f9496Aart Bik    }
3760e54c0160c84894696c05af6cad9eae3690f9496Aart Bik  }
3770e54c0160c84894696c05af6cad9eae3690f9496Aart Bik}
378