1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.reflect.Field; 18 import java.util.concurrent.atomic.AtomicBoolean; 19 20 import sun.misc.Unsafe; 21 22 /** 23 * Checker test on the 1.8 unsafe operations. Note, this is by no means an 24 * exhaustive unit test for these CAS (compare-and-swap) and fence operations. 25 * Instead, this test ensures the methods are recognized as intrinsic and behave 26 * as expected. 27 */ 28 public class Main { 29 30 private static final Unsafe unsafe = getUnsafe(); 31 32 private static Thread[] sThreads = new Thread[10]; 33 34 // 35 // Fields accessed by setters and adders, and by memory fence tests. 36 // 37 38 public int i = 0; 39 public long l = 0; 40 public Object o = null; 41 42 public int x_value; 43 public int y_value; 44 public volatile boolean running; 45 46 // 47 // Setters. 48 // 49 50 /// CHECK-START: int Main.set32(java.lang.Object, long, int) builder (after) 51 /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetInt 52 /// CHECK-DAG: Return [<<Result>>] set32(Object o, long offset, int newValue)53 private static int set32(Object o, long offset, int newValue) { 54 return unsafe.getAndSetInt(o, offset, newValue); 55 } 56 57 /// CHECK-START: long Main.set64(java.lang.Object, long, long) builder (after) 58 /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetLong 59 /// CHECK-DAG: Return [<<Result>>] set64(Object o, long offset, long newValue)60 private static long set64(Object o, long offset, long newValue) { 61 return unsafe.getAndSetLong(o, offset, newValue); 62 } 63 64 /// CHECK-START: java.lang.Object Main.setObj(java.lang.Object, long, java.lang.Object) builder (after) 65 /// CHECK-DAG: <<Result:l\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetObject 66 /// CHECK-DAG: Return [<<Result>>] setObj(Object o, long offset, Object newValue)67 private static Object setObj(Object o, long offset, Object newValue) { 68 return unsafe.getAndSetObject(o, offset, newValue); 69 } 70 71 // 72 // Adders. 73 // 74 75 /// CHECK-START: int Main.add32(java.lang.Object, long, int) builder (after) 76 /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddInt 77 /// CHECK-DAG: Return [<<Result>>] add32(Object o, long offset, int delta)78 private static int add32(Object o, long offset, int delta) { 79 return unsafe.getAndAddInt(o, offset, delta); 80 } 81 82 /// CHECK-START: long Main.add64(java.lang.Object, long, long) builder (after) 83 /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddLong 84 /// CHECK-DAG: Return [<<Result>>] add64(Object o, long offset, long delta)85 private static long add64(Object o, long offset, long delta) { 86 return unsafe.getAndAddLong(o, offset, delta); 87 } 88 89 // 90 // Fences (native). 91 // 92 93 /// CHECK-START: void Main.load() builder (after) 94 /// CHECK-NOT: InvokeVirtual 95 // 96 /// CHECK-START: void Main.load() builder (after) 97 /// CHECK-DAG: MemoryBarrier kind:LoadAny load()98 private static void load() { 99 unsafe.loadFence(); 100 } 101 102 /// CHECK-START: void Main.store() builder (after) 103 /// CHECK-NOT: InvokeVirtual 104 // 105 /// CHECK-START: void Main.store() builder (after) 106 /// CHECK-DAG: MemoryBarrier kind:AnyStore store()107 private static void store() { 108 unsafe.storeFence(); 109 } 110 111 /// CHECK-START: void Main.full() builder (after) 112 /// CHECK-NOT: InvokeVirtual 113 // 114 /// CHECK-START: void Main.full() builder (after) 115 /// CHECK-DAG: MemoryBarrier kind:AnyAny full()116 private static void full() { 117 unsafe.fullFence(); 118 } 119 120 // 121 // Thread fork/join. 122 // 123 fork(Runnable r)124 private static void fork(Runnable r) { 125 for (int i = 0; i < 10; i++) { 126 sThreads[i] = new Thread(r); 127 } 128 // Start the threads only after the full array has been written with new threads, 129 // because one test relies on the contents of this array to be consistent. 130 for (int i = 0; i < 10; i++) { 131 sThreads[i].start(); 132 } 133 } 134 join()135 private static void join() { 136 try { 137 for (int i = 0; i < 10; i++) { 138 sThreads[i].join(); 139 } 140 } catch (InterruptedException e) { 141 throw new Error("Failed join: " + e); 142 } 143 } 144 145 // 146 // Driver. 147 // 148 main(String[] args)149 public static void main(String[] args) { 150 System.out.println("starting"); 151 152 final Main m = new Main(); 153 154 // Get the offsets. 155 156 final long intOffset, longOffset, objOffset; 157 try { 158 Field intField = Main.class.getDeclaredField("i"); 159 Field longField = Main.class.getDeclaredField("l"); 160 Field objField = Main.class.getDeclaredField("o"); 161 162 intOffset = unsafe.objectFieldOffset(intField); 163 longOffset = unsafe.objectFieldOffset(longField); 164 objOffset = unsafe.objectFieldOffset(objField); 165 166 } catch (NoSuchFieldException e) { 167 throw new Error("No offset: " + e); 168 } 169 170 // Some checks on setters and adders within same thread. 171 172 set32(m, intOffset, 3); 173 expectEqual32(3, m.i); 174 175 set64(m, longOffset, 7L); 176 expectEqual64(7L, m.l); 177 178 setObj(m, objOffset, m); 179 expectEqualObj(m, m.o); 180 181 add32(m, intOffset, 11); 182 expectEqual32(14, m.i); 183 184 add64(m, longOffset, 13L); 185 expectEqual64(20L, m.l); 186 187 // Some checks on setters within different threads. 188 189 fork(new Runnable() { 190 public void run() { 191 for (int i = 0; i < 10; i++) 192 set32(m, intOffset, i); 193 } 194 }); 195 join(); 196 expectEqual32(9, m.i); // one thread's last value wins 197 198 fork(new Runnable() { 199 public void run() { 200 for (int i = 0; i < 10; i++) 201 set64(m, longOffset, (long) (100 + i)); 202 } 203 }); 204 join(); 205 expectEqual64(109L, m.l); // one thread's last value wins 206 207 fork(new Runnable() { 208 public void run() { 209 for (int i = 0; i < 10; i++) 210 setObj(m, objOffset, sThreads[i]); 211 } 212 }); 213 join(); 214 expectEqualObj(sThreads[9], m.o); // one thread's last value wins 215 216 // Some checks on adders within different threads. 217 218 fork(new Runnable() { 219 public void run() { 220 for (int i = 0; i < 10; i++) 221 add32(m, intOffset, i + 1); 222 } 223 }); 224 join(); 225 expectEqual32(559, m.i); // all values accounted for 226 227 fork(new Runnable() { 228 public void run() { 229 for (int i = 0; i < 10; i++) 230 add64(m, longOffset, (long) (i + 1)); 231 } 232 }); 233 join(); 234 expectEqual64(659L, m.l); // all values accounted for 235 236 // Some checks on fences within same thread. Note that memory fences within one 237 // thread make little sense, but the assertion ensures nothing bad happens. 238 239 m.i = -1; 240 m.l = -2L; 241 m.o = null; 242 243 load(); 244 store(); 245 full(); 246 247 expectEqual32(-1, m.i); 248 expectEqual64(-2L, m.l); 249 expectEqualObj(null, m.o); 250 251 // Some checks on full fence within different threads. We write the non-volatile m.l after 252 // the fork(), which means there is no happens-before relation in the Java memory model 253 // with respect to the read in the threads. This relation is enforced by the memory fences 254 // and the weak-set() -> get() guard. Note that the guard semantics used here are actually 255 // too strong and already enforce total memory visibility, but this test illustrates what 256 // should still happen if Java had a true relaxed memory guard. 257 258 final AtomicBoolean guard1 = new AtomicBoolean(); 259 m.l = 0L; 260 261 fork(new Runnable() { 262 public void run() { 263 while (!guard1.get()); // busy-waiting 264 full(); 265 expectEqual64(-123456789L, m.l); 266 } 267 }); 268 269 m.l = -123456789L; 270 full(); 271 while (!guard1.weakCompareAndSet(false, true)); // relaxed memory order 272 join(); 273 274 // Some checks on release/acquire fences within different threads. We write the non-volatile 275 // m.l after the fork(), which means there is no happens-before relation in the Java memory 276 // model with respect to the read in the threads. This relation is enforced by the memory fences 277 // and the weak-set() -> get() guard. Note that the guard semantics used here are actually 278 // too strong and already enforce total memory visibility, but this test illustrates what 279 // should still happen if Java had a true relaxed memory guard. 280 281 final AtomicBoolean guard2 = new AtomicBoolean(); 282 m.l = 0L; 283 284 fork(new Runnable() { 285 public void run() { 286 while (!guard2.get()); // busy-waiting 287 load(); 288 expectEqual64(-987654321L, m.l); 289 } 290 }); 291 292 m.l = -987654321L; 293 store(); 294 while (!guard2.weakCompareAndSet(false, true)); // relaxed memory order 295 join(); 296 297 // Some checks on release/acquire fences within different threads using a test suggested by 298 // Hans Boehm. Even this test remains with the realm of soundness checking only, since having 299 // the threads read the same value consistently would be a valid outcome. 300 301 m.x_value = -1; 302 m.y_value = -1; 303 m.running = true; 304 305 fork(new Runnable() { 306 public void run() { 307 while (m.running) { 308 for (int few_times = 0; few_times < 1000; few_times++) { 309 // Read y first, then load fence, then read x. 310 // They should appear in order, if seen at all. 311 int local_y = m.y_value; 312 load(); 313 int local_x = m.x_value; 314 expectLessThanOrEqual32(local_y, local_x); 315 } 316 } 317 } 318 }); 319 320 for (int many_times = 0; many_times < 100000; many_times++) { 321 m.x_value = many_times; 322 store(); 323 m.y_value = many_times; 324 } 325 m.running = false; 326 join(); 327 328 // All done! 329 330 System.out.println("passed"); 331 } 332 333 // Use reflection to implement "Unsafe.getUnsafe()"; getUnsafe()334 private static Unsafe getUnsafe() { 335 try { 336 Class<?> unsafeClass = Unsafe.class; 337 Field f = unsafeClass.getDeclaredField("theUnsafe"); 338 f.setAccessible(true); 339 return (Unsafe) f.get(null); 340 } catch (Exception e) { 341 throw new Error("Cannot get Unsafe instance"); 342 } 343 } 344 expectEqual32(int expected, int result)345 private static void expectEqual32(int expected, int result) { 346 if (expected != result) { 347 throw new Error("Expected: " + expected + ", found: " + result); 348 } 349 } 350 expectLessThanOrEqual32(int val1, int val2)351 private static void expectLessThanOrEqual32(int val1, int val2) { 352 if (val1 > val2) { 353 throw new Error("Expected: " + val1 + " <= " + val2); 354 } 355 } 356 expectEqual64(long expected, long result)357 private static void expectEqual64(long expected, long result) { 358 if (expected != result) { 359 throw new Error("Expected: " + expected + ", found: " + result); 360 } 361 } 362 expectEqualObj(Object expected, Object result)363 private static void expectEqualObj(Object expected, Object result) { 364 if (expected != result) { 365 throw new Error("Expected: " + expected + ", found: " + result); 366 } 367 } 368 } 369