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) intrinsics_recognition (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) intrinsics_recognition (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) intrinsics_recognition (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) intrinsics_recognition (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) intrinsics_recognition (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() intrinsics_recognition (after) 94 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeLoadFence 95 // 96 /// CHECK-START: void Main.load() instruction_simplifier (after) 97 /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeLoadFence 98 // 99 /// CHECK-START: void Main.load() instruction_simplifier (after) 100 /// CHECK-DAG: MemoryBarrier kind:LoadAny load()101 private static void load() { 102 unsafe.loadFence(); 103 } 104 105 /// CHECK-START: void Main.store() intrinsics_recognition (after) 106 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeStoreFence 107 // 108 /// CHECK-START: void Main.store() instruction_simplifier (after) 109 /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeStoreFence 110 // 111 /// CHECK-START: void Main.store() instruction_simplifier (after) 112 /// CHECK-DAG: MemoryBarrier kind:AnyStore store()113 private static void store() { 114 unsafe.storeFence(); 115 } 116 117 /// CHECK-START: void Main.full() intrinsics_recognition (after) 118 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeFullFence 119 // 120 /// CHECK-START: void Main.full() instruction_simplifier (after) 121 /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeFullFence 122 // 123 /// CHECK-START: void Main.full() instruction_simplifier (after) 124 /// CHECK-DAG: MemoryBarrier kind:AnyAny full()125 private static void full() { 126 unsafe.fullFence(); 127 } 128 129 // 130 // Thread fork/join. 131 // 132 fork(Runnable r)133 private static void fork(Runnable r) { 134 for (int i = 0; i < 10; i++) { 135 sThreads[i] = new Thread(r); 136 } 137 // Start the threads only after the full array has been written with new threads, 138 // because one test relies on the contents of this array to be consistent. 139 for (int i = 0; i < 10; i++) { 140 sThreads[i].start(); 141 } 142 } 143 join()144 private static void join() { 145 try { 146 for (int i = 0; i < 10; i++) { 147 sThreads[i].join(); 148 } 149 } catch (InterruptedException e) { 150 throw new Error("Failed join: " + e); 151 } 152 } 153 154 // 155 // Driver. 156 // 157 main(String[] args)158 public static void main(String[] args) { 159 System.out.println("starting"); 160 161 final Main m = new Main(); 162 163 // Get the offsets. 164 165 final long intOffset, longOffset, objOffset; 166 try { 167 Field intField = Main.class.getDeclaredField("i"); 168 Field longField = Main.class.getDeclaredField("l"); 169 Field objField = Main.class.getDeclaredField("o"); 170 171 intOffset = unsafe.objectFieldOffset(intField); 172 longOffset = unsafe.objectFieldOffset(longField); 173 objOffset = unsafe.objectFieldOffset(objField); 174 175 } catch (NoSuchFieldException e) { 176 throw new Error("No offset: " + e); 177 } 178 179 // Some sanity on setters and adders within same thread. 180 181 set32(m, intOffset, 3); 182 expectEqual32(3, m.i); 183 184 set64(m, longOffset, 7L); 185 expectEqual64(7L, m.l); 186 187 setObj(m, objOffset, m); 188 expectEqualObj(m, m.o); 189 190 add32(m, intOffset, 11); 191 expectEqual32(14, m.i); 192 193 add64(m, longOffset, 13L); 194 expectEqual64(20L, m.l); 195 196 // Some sanity on setters within different threads. 197 198 fork(new Runnable() { 199 public void run() { 200 for (int i = 0; i < 10; i++) 201 set32(m, intOffset, i); 202 } 203 }); 204 join(); 205 expectEqual32(9, m.i); // one thread's last value wins 206 207 fork(new Runnable() { 208 public void run() { 209 for (int i = 0; i < 10; i++) 210 set64(m, longOffset, (long) (100 + i)); 211 } 212 }); 213 join(); 214 expectEqual64(109L, m.l); // one thread's last value wins 215 216 fork(new Runnable() { 217 public void run() { 218 for (int i = 0; i < 10; i++) 219 setObj(m, objOffset, sThreads[i]); 220 } 221 }); 222 join(); 223 expectEqualObj(sThreads[9], m.o); // one thread's last value wins 224 225 // Some sanity on adders within different threads. 226 227 fork(new Runnable() { 228 public void run() { 229 for (int i = 0; i < 10; i++) 230 add32(m, intOffset, i + 1); 231 } 232 }); 233 join(); 234 expectEqual32(559, m.i); // all values accounted for 235 236 fork(new Runnable() { 237 public void run() { 238 for (int i = 0; i < 10; i++) 239 add64(m, longOffset, (long) (i + 1)); 240 } 241 }); 242 join(); 243 expectEqual64(659L, m.l); // all values accounted for 244 245 // Some sanity on fences within same thread. Note that memory fences within one 246 // thread make little sense, but the sanity check ensures nothing bad happens. 247 248 m.i = -1; 249 m.l = -2L; 250 m.o = null; 251 252 load(); 253 store(); 254 full(); 255 256 expectEqual32(-1, m.i); 257 expectEqual64(-2L, m.l); 258 expectEqualObj(null, m.o); 259 260 // Some sanity on full fence within different threads. We write the non-volatile m.l after 261 // the fork(), which means there is no happens-before relation in the Java memory model 262 // with respect to the read in the threads. This relation is enforced by the memory fences 263 // and the weak-set() -> get() guard. Note that the guard semantics used here are actually 264 // too strong and already enforce total memory visibility, but this test illustrates what 265 // should still happen if Java had a true relaxed memory guard. 266 267 final AtomicBoolean guard1 = new AtomicBoolean(); 268 m.l = 0L; 269 270 fork(new Runnable() { 271 public void run() { 272 while (!guard1.get()); // busy-waiting 273 full(); 274 expectEqual64(-123456789L, m.l); 275 } 276 }); 277 278 m.l = -123456789L; 279 full(); 280 while (!guard1.weakCompareAndSet(false, true)); // relaxed memory order 281 join(); 282 283 // Some sanity on release/acquire fences within different threads. We write the non-volatile 284 // m.l after the fork(), which means there is no happens-before relation in the Java memory 285 // model with respect to the read in the threads. This relation is enforced by the memory fences 286 // and the weak-set() -> get() guard. Note that the guard semantics used here are actually 287 // too strong and already enforce total memory visibility, but this test illustrates what 288 // should still happen if Java had a true relaxed memory guard. 289 290 final AtomicBoolean guard2 = new AtomicBoolean(); 291 m.l = 0L; 292 293 fork(new Runnable() { 294 public void run() { 295 while (!guard2.get()); // busy-waiting 296 load(); 297 expectEqual64(-987654321L, m.l); 298 } 299 }); 300 301 m.l = -987654321L; 302 store(); 303 while (!guard2.weakCompareAndSet(false, true)); // relaxed memory order 304 join(); 305 306 // Some sanity on release/acquire fences within different threads using a test suggested by 307 // Hans Boehm. Even this test remains with the realm of sanity only, since having the threads 308 // read the same value consistently would be a valid outcome. 309 310 m.x_value = -1; 311 m.y_value = -1; 312 m.running = true; 313 314 fork(new Runnable() { 315 public void run() { 316 while (m.running) { 317 for (int few_times = 0; few_times < 1000; few_times++) { 318 // Read y first, then load fence, then read x. 319 // They should appear in order, if seen at all. 320 int local_y = m.y_value; 321 load(); 322 int local_x = m.x_value; 323 expectLessThanOrEqual32(local_y, local_x); 324 } 325 } 326 } 327 }); 328 329 for (int many_times = 0; many_times < 100000; many_times++) { 330 m.x_value = many_times; 331 store(); 332 m.y_value = many_times; 333 } 334 m.running = false; 335 join(); 336 337 // All done! 338 339 System.out.println("passed"); 340 } 341 342 // Use reflection to implement "Unsafe.getUnsafe()"; getUnsafe()343 private static Unsafe getUnsafe() { 344 try { 345 Class<?> unsafeClass = Unsafe.class; 346 Field f = unsafeClass.getDeclaredField("theUnsafe"); 347 f.setAccessible(true); 348 return (Unsafe) f.get(null); 349 } catch (Exception e) { 350 throw new Error("Cannot get Unsafe instance"); 351 } 352 } 353 expectEqual32(int expected, int result)354 private static void expectEqual32(int expected, int result) { 355 if (expected != result) { 356 throw new Error("Expected: " + expected + ", found: " + result); 357 } 358 } 359 expectLessThanOrEqual32(int val1, int val2)360 private static void expectLessThanOrEqual32(int val1, int val2) { 361 if (val1 > val2) { 362 throw new Error("Expected: " + val1 + " <= " + val2); 363 } 364 } 365 expectEqual64(long expected, long result)366 private static void expectEqual64(long expected, long result) { 367 if (expected != result) { 368 throw new Error("Expected: " + expected + ", found: " + result); 369 } 370 } 371 expectEqualObj(Object expected, Object result)372 private static void expectEqualObj(Object expected, Object result) { 373 if (expected != result) { 374 throw new Error("Expected: " + expected + ", found: " + result); 375 } 376 } 377 } 378