1 /* 2 * Copyright (C) 2021 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 jdk.internal.misc.Unsafe; 19 20 public class Main { check(boolean actual, boolean expected, String msg)21 private static void check(boolean actual, boolean expected, String msg) { 22 if (actual != expected) { 23 System.out.println(msg + " : " + actual + " != " + expected); 24 System.exit(1); 25 } 26 } 27 check(byte actual, byte expected, String msg)28 private static void check(byte actual, byte expected, String msg) { 29 if (actual != expected) { 30 System.out.println(msg + " : " + actual + " != " + expected); 31 System.exit(1); 32 } 33 } 34 check(char actual, char expected, String msg)35 private static void check(char actual, char expected, String msg) { 36 if (actual != expected) { 37 System.out.println(msg + " : " + actual + " != " + expected); 38 System.exit(1); 39 } 40 } 41 check(short actual, short expected, String msg)42 private static void check(short actual, short expected, String msg) { 43 if (actual != expected) { 44 System.out.println(msg + " : " + actual + " != " + expected); 45 System.exit(1); 46 } 47 } 48 check(int actual, int expected, String msg)49 private static void check(int actual, int expected, String msg) { 50 if (actual != expected) { 51 System.out.println(msg + " : " + actual + " != " + expected); 52 System.exit(1); 53 } 54 } 55 check(long actual, long expected, String msg)56 private static void check(long actual, long expected, String msg) { 57 if (actual != expected) { 58 System.out.println(msg + " : " + actual + " != " + expected); 59 System.exit(1); 60 } 61 } 62 check(float actual, float expected, String msg)63 private static void check(float actual, float expected, String msg) { 64 if (actual != expected) { 65 System.out.println(msg + " : " + actual + " != " + expected); 66 System.exit(1); 67 } 68 } 69 check(double actual, double expected, String msg)70 private static void check(double actual, double expected, String msg) { 71 if (actual != expected) { 72 System.out.println(msg + " : " + actual + " != " + expected); 73 System.exit(1); 74 } 75 } 76 check(Object actual, Object expected, String msg)77 private static void check(Object actual, Object expected, String msg) { 78 if (actual != expected) { 79 System.out.println(msg + " : " + actual + " != " + expected); 80 System.exit(1); 81 } 82 } 83 expectThrow(Class<?> exceptionClass, String msg)84 private static void expectThrow(Class<?> exceptionClass, String msg) { 85 System.out.println(msg + " : expected " + exceptionClass.getName()); 86 System.exit(1); 87 } 88 getUnsafe()89 private static Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException { 90 Class<?> unsafeClass = Unsafe.class; 91 Field f = unsafeClass.getDeclaredField("theUnsafe"); 92 f.setAccessible(true); 93 return (Unsafe) f.get(null); 94 } 95 main(String[] args)96 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { 97 System.loadLibrary(args[0]); 98 Unsafe unsafe = getUnsafe(); 99 100 testArrayBaseOffset(unsafe); 101 testArrayIndexScale(unsafe); 102 testGetAndPutAndCAS(unsafe); 103 testCompareAndSet(unsafe); 104 testGetAndPutVolatile(unsafe); 105 testGetAcquireAndPutRelease(unsafe); 106 testCopyMemory(unsafe); 107 } 108 testArrayBaseOffset(Unsafe unsafe)109 private static void testArrayBaseOffset(Unsafe unsafe) { 110 check(unsafe.arrayBaseOffset(boolean[].class), vmJdkArrayBaseOffset(boolean[].class), 111 "Unsafe.arrayBaseOffset(boolean[])"); 112 check(unsafe.arrayBaseOffset(byte[].class), vmJdkArrayBaseOffset(byte[].class), 113 "Unsafe.arrayBaseOffset(byte[])"); 114 check(unsafe.arrayBaseOffset(char[].class), vmJdkArrayBaseOffset(char[].class), 115 "Unsafe.arrayBaseOffset(char[])"); 116 check(unsafe.arrayBaseOffset(double[].class), vmJdkArrayBaseOffset(double[].class), 117 "Unsafe.arrayBaseOffset(double[])"); 118 check(unsafe.arrayBaseOffset(float[].class), vmJdkArrayBaseOffset(float[].class), 119 "Unsafe.arrayBaseOffset(float[])"); 120 check(unsafe.arrayBaseOffset(int[].class), vmJdkArrayBaseOffset(int[].class), 121 "Unsafe.arrayBaseOffset(int[])"); 122 check(unsafe.arrayBaseOffset(long[].class), vmJdkArrayBaseOffset(long[].class), 123 "Unsafe.arrayBaseOffset(long[])"); 124 check(unsafe.arrayBaseOffset(Object[].class), vmJdkArrayBaseOffset(Object[].class), 125 "Unsafe.arrayBaseOffset(Object[])"); 126 } 127 testArrayIndexScale(Unsafe unsafe)128 private static void testArrayIndexScale(Unsafe unsafe) { 129 check(unsafe.arrayIndexScale(boolean[].class), vmJdkArrayIndexScale(boolean[].class), 130 "Unsafe.arrayIndexScale(boolean[])"); 131 check(unsafe.arrayIndexScale(byte[].class), vmJdkArrayIndexScale(byte[].class), 132 "Unsafe.arrayIndexScale(byte[])"); 133 check(unsafe.arrayIndexScale(char[].class), vmJdkArrayIndexScale(char[].class), 134 "Unsafe.arrayIndexScale(char[])"); 135 check(unsafe.arrayIndexScale(double[].class), vmJdkArrayIndexScale(double[].class), 136 "Unsafe.arrayIndexScale(double[])"); 137 check(unsafe.arrayIndexScale(float[].class), vmJdkArrayIndexScale(float[].class), 138 "Unsafe.arrayIndexScale(float[])"); 139 check(unsafe.arrayIndexScale(int[].class), vmJdkArrayIndexScale(int[].class), 140 "Unsafe.arrayIndexScale(int[])"); 141 check(unsafe.arrayIndexScale(long[].class), vmJdkArrayIndexScale(long[].class), 142 "Unsafe.arrayIndexScale(long[])"); 143 check(unsafe.arrayIndexScale(Object[].class), vmJdkArrayIndexScale(Object[].class), 144 "Unsafe.arrayIndexScale(Object[])"); 145 } 146 testGetAndPutAndCAS(Unsafe unsafe)147 private static void testGetAndPutAndCAS(Unsafe unsafe) throws NoSuchFieldException { 148 TestClass t = new TestClass(); 149 150 int intValue = 12345678; 151 Field intField = TestClass.class.getDeclaredField("intVar"); 152 long intOffset = unsafe.objectFieldOffset(intField); 153 check(unsafe.getInt(t, intOffset), 0, "Unsafe.getInt(Object, long) - initial"); 154 unsafe.putInt(t, intOffset, intValue); 155 check(t.intVar, intValue, "Unsafe.putInt(Object, long, int)"); 156 check(unsafe.getInt(t, intOffset), intValue, "Unsafe.getInt(Object, long)"); 157 158 long longValue = 1234567887654321L; 159 Field longField = TestClass.class.getDeclaredField("longVar"); 160 long longOffset = unsafe.objectFieldOffset(longField); 161 check(unsafe.getLong(t, longOffset), 0, "Unsafe.getLong(Object, long) - initial"); 162 unsafe.putLong(t, longOffset, longValue); 163 check(t.longVar, longValue, "Unsafe.putLong(Object, long, long)"); 164 check(unsafe.getLong(t, longOffset), longValue, "Unsafe.getLong(Object, long)"); 165 166 Object objectValue = new Object(); 167 Field objectField = TestClass.class.getDeclaredField("objectVar"); 168 long objectOffset = unsafe.objectFieldOffset(objectField); 169 check(unsafe.getObject(t, objectOffset), null, "Unsafe.getObject(Object, long) - initial"); 170 unsafe.putObject(t, objectOffset, objectValue); 171 check(t.objectVar, objectValue, "Unsafe.putObject(Object, long, Object)"); 172 check(unsafe.getObject(t, objectOffset), objectValue, "Unsafe.getObject(Object, long)"); 173 174 if (unsafe.compareAndSwapInt(t, intOffset, 0, 1)) { 175 System.out.println("Unexpectedly succeeding compareAndSwapInt(t, intOffset, 0, 1)"); 176 } 177 if (!unsafe.compareAndSwapInt(t, intOffset, intValue, 0)) { 178 System.out.println( 179 "Unexpectedly not succeeding compareAndSwapInt(t, intOffset, intValue, 0)"); 180 } 181 if (!unsafe.compareAndSwapInt(t, intOffset, 0, 1)) { 182 System.out.println("Unexpectedly not succeeding compareAndSwapInt(t, intOffset, 0, 1)"); 183 } 184 // Exercise jdk.internal.misc.Unsafe.compareAndSwapInt using the same 185 // integer (1) for the `expectedValue` and `newValue` arguments. 186 if (!unsafe.compareAndSwapInt(t, intOffset, 1, 1)) { 187 System.out.println("Unexpectedly not succeeding compareAndSwapInt(t, intOffset, 1, 1)"); 188 } 189 190 if (unsafe.compareAndSwapLong(t, longOffset, 0, 1)) { 191 System.out.println("Unexpectedly succeeding compareAndSwapLong(t, longOffset, 0, 1)"); 192 } 193 if (!unsafe.compareAndSwapLong(t, longOffset, longValue, 0)) { 194 System.out.println( 195 "Unexpectedly not succeeding compareAndSwapLong(t, longOffset, longValue, 0)"); 196 } 197 if (!unsafe.compareAndSwapLong(t, longOffset, 0, 1)) { 198 System.out.println("Unexpectedly not succeeding compareAndSwapLong(t, longOffset, 0, 1)"); 199 } 200 // Exercise jdk.internal.misc.Unsafe.compareAndSwapLong using the same 201 // integer (1) for the `expectedValue` and `newValue` arguments. 202 if (!unsafe.compareAndSwapLong(t, longOffset, 1, 1)) { 203 System.out.println("Unexpectedly not succeeding compareAndSwapLong(t, longOffset, 1, 1)"); 204 } 205 206 // We do not use `null` as argument to jdk.internal.misc.Unsafe.compareAndSwapObject 207 // in those tests, as this value is not affected by heap poisoning 208 // (which uses address negation to poison and unpoison heap object 209 // references). This way, when heap poisoning is enabled, we can 210 // better exercise its implementation within that method. 211 if (unsafe.compareAndSwapObject(t, objectOffset, new Object(), new Object())) { 212 System.out.println("Unexpectedly succeeding " + 213 "compareAndSwapObject(t, objectOffset, new Object(), new Object())"); 214 } 215 Object objectValue2 = new Object(); 216 if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue, objectValue2)) { 217 System.out.println("Unexpectedly not succeeding " + 218 "compareAndSwapObject(t, objectOffset, objectValue, objectValue2)"); 219 } 220 Object objectValue3 = new Object(); 221 if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue2, objectValue3)) { 222 System.out.println("Unexpectedly not succeeding " + 223 "compareAndSwapObject(t, objectOffset, objectValue2, objectValue3)"); 224 } 225 // Exercise jdk.internal.misc.Unsafe.compareAndSwapObject using the same 226 // object (`objectValue3`) for the `expectedValue` and `newValue` arguments. 227 if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue3, objectValue3)) { 228 System.out.println("Unexpectedly not succeeding " + 229 "compareAndSwapObject(t, objectOffset, objectValue3, objectValue3)"); 230 } 231 // Exercise jdk.internal.misc.Unsafe.compareAndSwapObject using the same 232 // object (`t`) for the `obj` and `newValue` arguments. 233 if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue3, t)) { 234 System.out.println( 235 "Unexpectedly not succeeding compareAndSwapObject(t, objectOffset, objectValue3, t)"); 236 } 237 // Exercise jdk.internal.misc.Unsafe.compareAndSwapObject using the same 238 // object (`t`) for the `obj`, `expectedValue` and `newValue` arguments. 239 if (!unsafe.compareAndSwapObject(t, objectOffset, t, t)) { 240 System.out.println("Unexpectedly not succeeding compareAndSwapObject(t, objectOffset, t, t)"); 241 } 242 // Exercise jdk.internal.misc.Unsafe.compareAndSwapObject using the same 243 // object (`t`) for the `obj` and `expectedValue` arguments. 244 if (!unsafe.compareAndSwapObject(t, objectOffset, t, new Object())) { 245 System.out.println( 246 "Unexpectedly not succeeding compareAndSwapObject(t, objectOffset, t, new Object())"); 247 } 248 } 249 testCompareAndSet(Unsafe unsafe)250 private static void testCompareAndSet(Unsafe unsafe) throws NoSuchFieldException { 251 TestClass t = new TestClass(); 252 253 int intValue = 12345678; 254 Field intField = TestClass.class.getDeclaredField("intVar"); 255 long intOffset = unsafe.objectFieldOffset(intField); 256 unsafe.putInt(t, intOffset, intValue); 257 258 long longValue = 1234567887654321L; 259 Field longField = TestClass.class.getDeclaredField("longVar"); 260 long longOffset = unsafe.objectFieldOffset(longField); 261 unsafe.putLong(t, longOffset, longValue); 262 263 Object objectValue = new Object(); 264 Field objectField = TestClass.class.getDeclaredField("objectVar"); 265 long objectOffset = unsafe.objectFieldOffset(objectField); 266 unsafe.putObject(t, objectOffset, objectValue); 267 268 if (unsafe.compareAndSetInt(t, intOffset, 0, 1)) { 269 System.out.println("Unexpectedly succeeding compareAndSetInt(t, intOffset, 0, 1)"); 270 } 271 check(t.intVar, intValue, "Unsafe.compareAndSetInt(Object, long, int, int) - not set"); 272 if (!unsafe.compareAndSetInt(t, intOffset, intValue, 0)) { 273 System.out.println( 274 "Unexpectedly not succeeding compareAndSetInt(t, intOffset, intValue, 0)"); 275 } 276 check(t.intVar, 0, "Unsafe.compareAndSetInt(Object, long, int, int) - gets set"); 277 if (!unsafe.compareAndSetInt(t, intOffset, 0, 1)) { 278 System.out.println("Unexpectedly not succeeding compareAndSetInt(t, intOffset, 0, 1)"); 279 } 280 check(t.intVar, 1, "Unsafe.compareAndSetInt(Object, long, int, int) - gets re-set"); 281 // Exercise jdk.internal.misc.Unsafe.compareAndSetInt using the same 282 // integer (1) for the `expectedValue` and `newValue` arguments. 283 if (!unsafe.compareAndSetInt(t, intOffset, 1, 1)) { 284 System.out.println("Unexpectedly not succeeding compareAndSetInt(t, intOffset, 1, 1)"); 285 } 286 check(t.intVar, 1, "Unsafe.compareAndSetInt(Object, long, int, int) - gets set to same"); 287 288 if (unsafe.compareAndSetLong(t, longOffset, 0, 1)) { 289 System.out.println("Unexpectedly succeeding compareAndSetLong(t, longOffset, 0, 1)"); 290 } 291 check(t.longVar, longValue, "Unsafe.compareAndSetLong(Object, long, long, long) - not set"); 292 if (!unsafe.compareAndSetLong(t, longOffset, longValue, 0)) { 293 System.out.println( 294 "Unexpectedly not succeeding compareAndSetLong(t, longOffset, longValue, 0)"); 295 } 296 check(t.longVar, 0, "Unsafe.compareAndSetLong(Object, long, long, long) - gets set"); 297 if (!unsafe.compareAndSetLong(t, longOffset, 0, 1)) { 298 System.out.println("Unexpectedly not succeeding compareAndSetLong(t, longOffset, 0, 1)"); 299 } 300 check(t.longVar, 1, "Unsafe.compareAndSetLong(Object, long, long, long) - gets re-set"); 301 // Exercise jdk.internal.misc.Unsafe.compareAndSetLong using the same 302 // integer (1) for the `expectedValue` and `newValue` arguments. 303 if (!unsafe.compareAndSetLong(t, longOffset, 1, 1)) { 304 System.out.println("Unexpectedly not succeeding compareAndSetLong(t, longOffset, 1, 1)"); 305 } 306 check(t.longVar, 1, "Unsafe.compareAndSetLong(Object, long, long, long) - gets set to same"); 307 308 // We do not use `null` as argument to jdk.internal.misc.Unsafe.compareAndSwapObject 309 // in those tests, as this value is not affected by heap poisoning 310 // (which uses address negation to poison and unpoison heap object 311 // references). This way, when heap poisoning is enabled, we can 312 // better exercise its implementation within that method. 313 if (unsafe.compareAndSetObject(t, objectOffset, new Object(), new Object())) { 314 System.out.println("Unexpectedly succeeding compareAndSetObject(t, objectOffset, 0, 1)"); 315 } 316 check(t.objectVar, objectValue, "Unsafe.compareAndSetObject(Object, long, Object, Object) - not set"); 317 Object objectValue2 = new Object(); 318 if (!unsafe.compareAndSetObject(t, objectOffset, objectValue, objectValue2)) { 319 System.out.println( 320 "Unexpectedly not succeeding compareAndSetObject(t, objectOffset, objectValue, 0)"); 321 } 322 check(t.objectVar, objectValue2, "Unsafe.compareAndSetObject(Object, long, Object, Object) - gets set"); 323 Object objectValue3 = new Object(); 324 if (!unsafe.compareAndSetObject(t, objectOffset, objectValue2, objectValue3)) { 325 System.out.println("Unexpectedly not succeeding compareAndSetObject(t, objectOffset, 0, 1)"); 326 } 327 check(t.objectVar, objectValue3, "Unsafe.compareAndSetObject(Object, long, Object, Object) - gets re-set"); 328 // Exercise jdk.internal.misc.Unsafe.compareAndSetObject using the same 329 // object for the `expectedValue` and `newValue` arguments. 330 if (!unsafe.compareAndSetObject(t, objectOffset, objectValue3, objectValue3)) { 331 System.out.println("Unexpectedly not succeeding compareAndSetObject(t, objectOffset, 1, 1)"); 332 } 333 check(t.objectVar, objectValue3, "Unsafe.compareAndSetObject(Object, long, Object, Object) - gets set to same"); 334 335 // Reset and now try with `compareAndSetReference` which replaced `compareAndSetObject`. 336 unsafe.putObject(t, objectOffset, objectValue); 337 338 if (unsafe.compareAndSetReference(t, objectOffset, new Object(), new Object())) { 339 System.out.println("Unexpectedly succeeding compareAndSetReference(t, objectOffset, 0, 1)"); 340 } 341 check(t.objectVar, objectValue, "Unsafe.compareAndSetReference(Object, long, Object, Object) - not set"); 342 objectValue2 = new Object(); 343 if (!unsafe.compareAndSetReference(t, objectOffset, objectValue, objectValue2)) { 344 System.out.println( 345 "Unexpectedly not succeeding compareAndSetReference(t, objectOffset, objectValue, 0)"); 346 } 347 check(t.objectVar, objectValue2, "Unsafe.compareAndSetReference(Object, long, Object, Object) - gets set"); 348 objectValue3 = new Object(); 349 if (!unsafe.compareAndSetReference(t, objectOffset, objectValue2, objectValue3)) { 350 System.out.println("Unexpectedly not succeeding compareAndSetReference(t, objectOffset, 0, 1)"); 351 } 352 check(t.objectVar, objectValue3, "Unsafe.compareAndSetReference(Object, long, Object, Object) - gets re-set"); 353 // Exercise jdk.internal.misc.Unsafe.compareAndSetReference using the same 354 // object for the `expectedValue` and `newValue` arguments. 355 if (!unsafe.compareAndSetReference(t, objectOffset, objectValue3, objectValue3)) { 356 System.out.println("Unexpectedly not succeeding compareAndSetReference(t, objectOffset, 1, 1)"); 357 } 358 check(t.objectVar, objectValue3, "Unsafe.compareAndSetReference(Object, long, Object, Object) - gets set to same"); 359 } 360 testGetAndPutVolatile(Unsafe unsafe)361 private static void testGetAndPutVolatile(Unsafe unsafe) throws NoSuchFieldException { 362 TestVolatileClass tv = new TestVolatileClass(); 363 364 int intValue = 12345678; 365 Field volatileIntField = TestVolatileClass.class.getDeclaredField("volatileIntVar"); 366 long volatileIntOffset = unsafe.objectFieldOffset(volatileIntField); 367 check(unsafe.getIntVolatile(tv, volatileIntOffset), 368 0, 369 "Unsafe.getIntVolatile(Object, long) - initial"); 370 unsafe.putIntVolatile(tv, volatileIntOffset, intValue); 371 check(tv.volatileIntVar, intValue, "Unsafe.putIntVolatile(Object, long, int)"); 372 check(unsafe.getIntVolatile(tv, volatileIntOffset), 373 intValue, 374 "Unsafe.getIntVolatile(Object, long)"); 375 376 boolean booleanValue = true; 377 Field volatileBooleanField = TestVolatileClass.class.getDeclaredField("volatileBooleanVar"); 378 long volatileBooleanOffset = unsafe.objectFieldOffset(volatileBooleanField); 379 check(unsafe.getBooleanVolatile(tv, volatileBooleanOffset), 380 false, 381 "Unsafe.getBooleanVolatile(Object, long) - initial"); 382 unsafe.putBooleanVolatile(tv, volatileBooleanOffset, booleanValue); 383 check(tv.volatileBooleanVar, booleanValue, "Unsafe.putBooleanVolatile(Object, long, boolean)"); 384 check(unsafe.getBooleanVolatile(tv, volatileBooleanOffset), 385 booleanValue, 386 "Unsafe.getBooleanVolatile(Object, long)"); 387 388 byte byteValue = 125; 389 Field volatileByteField = TestVolatileClass.class.getDeclaredField("volatileByteVar"); 390 long volatileByteOffset = unsafe.objectFieldOffset(volatileByteField); 391 check(unsafe.getByteVolatile(tv, volatileByteOffset), 392 0, 393 "Unsafe.getByteVolatile(Object, long) - initial"); 394 unsafe.putByteVolatile(tv, volatileByteOffset, byteValue); 395 check(tv.volatileByteVar, byteValue, "Unsafe.putByteVolatile(Object, long, byte)"); 396 check(unsafe.getByteVolatile(tv, volatileByteOffset), 397 byteValue, 398 "Unsafe.getByteVolatile(Object, long)"); 399 400 char charValue = 'X'; 401 Field volatileCharField = TestVolatileClass.class.getDeclaredField("volatileCharVar"); 402 long volatileCharOffset = unsafe.objectFieldOffset(volatileCharField); 403 check(unsafe.getCharVolatile(tv, volatileCharOffset), 404 '\0', 405 "Unsafe.getCharVolatile(Object, long) - initial"); 406 unsafe.putCharVolatile(tv, volatileCharOffset, charValue); 407 check(tv.volatileCharVar, charValue, "Unsafe.putCharVolatile(Object, long, char)"); 408 check(unsafe.getCharVolatile(tv, volatileCharOffset), 409 charValue, 410 "Unsafe.getCharVolatile(Object, long)"); 411 412 short shortValue = 32523; 413 Field volatileShortField = TestVolatileClass.class.getDeclaredField("volatileShortVar"); 414 long volatileShortOffset = unsafe.objectFieldOffset(volatileShortField); 415 check(unsafe.getShortVolatile(tv, volatileShortOffset), 416 0, 417 "Unsafe.getShortVolatile(Object, long) - initial"); 418 unsafe.putShortVolatile(tv, volatileShortOffset, shortValue); 419 check(tv.volatileShortVar, shortValue, "Unsafe.putShortVolatile(Object, long, short)"); 420 check(unsafe.getShortVolatile(tv, volatileShortOffset), 421 shortValue, 422 "Unsafe.getShortVolatile(Object, long)"); 423 424 long longValue = 1234567887654321L; 425 Field volatileLongField = TestVolatileClass.class.getDeclaredField("volatileLongVar"); 426 long volatileLongOffset = unsafe.objectFieldOffset(volatileLongField); 427 check(unsafe.getLongVolatile(tv, volatileLongOffset), 428 0, 429 "Unsafe.getLongVolatile(Object, long) - initial"); 430 unsafe.putLongVolatile(tv, volatileLongOffset, longValue); 431 check(tv.volatileLongVar, longValue, "Unsafe.putLongVolatile(Object, long, long)"); 432 check(unsafe.getLongVolatile(tv, volatileLongOffset), 433 longValue, 434 "Unsafe.getLongVolatile(Object, long)"); 435 436 float floatValue = 123456.7890123f; 437 Field volatileFloatField = TestVolatileClass.class.getDeclaredField("volatileFloatVar"); 438 long volatileFloatOffset = unsafe.objectFieldOffset(volatileFloatField); 439 check(unsafe.getFloatVolatile(tv, volatileFloatOffset), 440 0.0f, 441 "Unsafe.getFloatVolatile(Object, long) - initial"); 442 unsafe.putFloatVolatile(tv, volatileFloatOffset, floatValue); 443 check(tv.volatileFloatVar, floatValue, "Unsafe.putFloatVolatile(Object, long, float)"); 444 check(unsafe.getFloatVolatile(tv, volatileFloatOffset), 445 floatValue, 446 "Unsafe.getFloatVolatile(Object, long)"); 447 448 double doubleValue = 654321.7890123d; 449 Field volatileDoubleField = TestVolatileClass.class.getDeclaredField("volatileDoubleVar"); 450 long volatileDoubleOffset = unsafe.objectFieldOffset(volatileDoubleField); 451 check(unsafe.getDoubleVolatile(tv, volatileDoubleOffset), 452 0.0d, 453 "Unsafe.getDoubleVolatile(Object, double) - initial"); 454 unsafe.putDoubleVolatile(tv, volatileDoubleOffset, doubleValue); 455 check(tv.volatileDoubleVar, doubleValue, "Unsafe.putDoubleVolatile(Object, long, double)"); 456 check(unsafe.getDoubleVolatile(tv, volatileDoubleOffset), 457 doubleValue, 458 "Unsafe.getDoubleVolatile(Object, long)"); 459 460 Object objectValue = new Object(); 461 Field volatileObjectField = TestVolatileClass.class.getDeclaredField("volatileObjectVar"); 462 long volatileObjectOffset = unsafe.objectFieldOffset(volatileObjectField); 463 check(unsafe.getReferenceVolatile(tv, volatileObjectOffset), 464 null, 465 "Unsafe.getReferenceVolatile(Object, long) - initial"); 466 unsafe.putReferenceVolatile(tv, volatileObjectOffset, objectValue); 467 check(tv.volatileObjectVar, objectValue, "Unsafe.putReferenceVolatile(Object, long, Object)"); 468 check(unsafe.getReferenceVolatile(tv, volatileObjectOffset), 469 objectValue, 470 "Unsafe.getReferenceVolatile(Object, long)"); 471 } 472 testGetAcquireAndPutRelease(Unsafe unsafe)473 private static void testGetAcquireAndPutRelease(Unsafe unsafe) throws NoSuchFieldException { 474 TestVolatileClass tv = new TestVolatileClass(); 475 476 int intValue = 12345678; 477 Field volatileIntField = TestVolatileClass.class.getDeclaredField("volatileIntVar"); 478 long volatileIntOffset = unsafe.objectFieldOffset(volatileIntField); 479 check(unsafe.getIntAcquire(tv, volatileIntOffset), 480 0, 481 "Unsafe.getIntAcquire(Object, long) - initial"); 482 unsafe.putIntRelease(tv, volatileIntOffset, intValue); 483 check(tv.volatileIntVar, intValue, "Unsafe.putIntRelease(Object, long, int)"); 484 check(unsafe.getIntAcquire(tv, volatileIntOffset), 485 intValue, 486 "Unsafe.getIntAcquire(Object, long)"); 487 488 long longValue = 1234567887654321L; 489 Field volatileLongField = TestVolatileClass.class.getDeclaredField("volatileLongVar"); 490 long volatileLongOffset = unsafe.objectFieldOffset(volatileLongField); 491 check(unsafe.getLongAcquire(tv, volatileLongOffset), 492 0, 493 "Unsafe.getLongAcquire(Object, long) - initial"); 494 unsafe.putLongRelease(tv, volatileLongOffset, longValue); 495 check(tv.volatileLongVar, longValue, "Unsafe.putLongRelease(Object, long, long)"); 496 check(unsafe.getLongAcquire(tv, volatileLongOffset), 497 longValue, 498 "Unsafe.getLongAcquire(Object, long)"); 499 500 Object objectValue = new Object(); 501 Field volatileObjectField = TestVolatileClass.class.getDeclaredField("volatileObjectVar"); 502 long volatileObjectOffset = unsafe.objectFieldOffset(volatileObjectField); 503 check(unsafe.getObjectAcquire(tv, volatileObjectOffset), 504 null, 505 "Unsafe.getObjectAcquire(Object, long) - initial"); 506 unsafe.putObjectRelease(tv, volatileObjectOffset, objectValue); 507 check(tv.volatileObjectVar, objectValue, "Unsafe.putObjectRelease(Object, long, Object)"); 508 check(unsafe.getObjectAcquire(tv, volatileObjectOffset), 509 objectValue, 510 "Unsafe.getObjectAcquire(Object, long)"); 511 } 512 testCopyMemory(Unsafe unsafe)513 private static void testCopyMemory(Unsafe unsafe) { 514 final int size = 4 * 1024; 515 516 final int intSize = 4; 517 int[] inputInts = new int[size / intSize]; 518 for (int i = 0; i != inputInts.length; ++i) { 519 inputInts[i] = ((int)i) + 1; 520 } 521 int[] outputInts = new int[size / intSize]; 522 unsafe.copyMemory(inputInts, Unsafe.ARRAY_INT_BASE_OFFSET, 523 outputInts, Unsafe.ARRAY_INT_BASE_OFFSET, 524 size); 525 for (int i = 0; i != inputInts.length; ++i) { 526 check(inputInts[i], outputInts[i], "unsafe.copyMemory/int"); 527 } 528 529 final int longSize = 8; 530 long[] inputLongs = new long[size / longSize]; 531 for (int i = 0; i != inputLongs.length; ++i) { 532 inputLongs[i] = ((long)i) + 1L; 533 } 534 long[] outputLongs = new long[size / longSize]; 535 unsafe.copyMemory(inputLongs, 0, outputLongs, 0, size); 536 unsafe.copyMemory(inputLongs, Unsafe.ARRAY_LONG_BASE_OFFSET, 537 outputLongs, Unsafe.ARRAY_LONG_BASE_OFFSET, 538 size); 539 for (int i = 0; i != inputLongs.length; ++i) { 540 check(inputLongs[i], outputLongs[i], "unsafe.copyMemory/long"); 541 } 542 543 final int floatSize = 4; 544 float[] inputFloats = new float[size / floatSize]; 545 for (int i = 0; i != inputFloats.length; ++i) { 546 inputFloats[i] = ((float)i) + 0.5f; 547 } 548 float[] outputFloats = new float[size / floatSize]; 549 unsafe.copyMemory(inputFloats, 0, outputFloats, 0, size); 550 unsafe.copyMemory(inputFloats, Unsafe.ARRAY_FLOAT_BASE_OFFSET, 551 outputFloats, Unsafe.ARRAY_FLOAT_BASE_OFFSET, 552 size); 553 for (int i = 0; i != inputFloats.length; ++i) { 554 check(inputFloats[i], outputFloats[i], "unsafe.copyMemory/float"); 555 } 556 557 final int doubleSize = 8; 558 double[] inputDoubles = new double[size / doubleSize]; 559 for (int i = 0; i != inputDoubles.length; ++i) { 560 inputDoubles[i] = ((double)i) + 0.5; 561 } 562 double[] outputDoubles = new double[size / doubleSize]; 563 unsafe.copyMemory(inputDoubles, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, 564 outputDoubles, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, 565 size); 566 for (int i = 0; i != inputDoubles.length; ++i) { 567 check(inputDoubles[i], outputDoubles[i], "unsafe.copyMemory/double"); 568 } 569 570 // check the version that works with memory pointers 571 try (TestMemoryPtr srcPtr = new TestMemoryPtr(size); 572 TestMemoryPtr dstPtr = new TestMemoryPtr(size)) { 573 // use the integer array to fill the source 574 unsafe.copyMemory(inputInts, Unsafe.ARRAY_INT_BASE_OFFSET, 575 null, srcPtr.get(), 576 size); 577 578 unsafe.copyMemory(srcPtr.get(), dstPtr.get(), size); 579 for (int i = 0; i != size; ++i) { 580 check(unsafe.getByte(srcPtr.get() + i), 581 unsafe.getByte(dstPtr.get() + i), 582 "unsafe.copyMemory/memoryAddress"); 583 } 584 } 585 586 try { 587 TestClass srcObj = new TestClass(); 588 srcObj.intVar = 12345678; 589 int[] dstArray = new int[1]; 590 unsafe.copyMemory(srcObj, unsafe.objectFieldOffset(TestClass.class, "intVar"), 591 dstArray, Unsafe.ARRAY_INT_BASE_OFFSET, 592 4); 593 expectThrow(RuntimeException.class, "unsafe.copyMemory/non-array-src"); 594 } catch (RuntimeException expected) { 595 } 596 597 try { 598 int[] srcArray = { 12345678 }; 599 TestClass dstObj = new TestClass(); 600 unsafe.copyMemory(srcArray, Unsafe.ARRAY_INT_BASE_OFFSET, 601 dstObj, unsafe.objectFieldOffset(TestClass.class, "intVar"), 602 4); 603 expectThrow(RuntimeException.class, "unsafe.copyMemory/non-array-dst"); 604 } catch (RuntimeException expected) { 605 } 606 } 607 608 private static class TestClass { 609 public int intVar = 0; 610 public long longVar = 0; 611 public Object objectVar = null; 612 } 613 614 private static class TestVolatileClass { 615 public volatile int volatileIntVar = 0; 616 public volatile boolean volatileBooleanVar = false; 617 public volatile byte volatileByteVar = 0; 618 public volatile short volatileShortVar = 0; 619 public volatile char volatileCharVar = 0; 620 public volatile long volatileLongVar = 0; 621 public volatile float volatileFloatVar = 0.0f; 622 public volatile double volatileDoubleVar = 0.0d; 623 public volatile Object volatileObjectVar = null; 624 } 625 626 private static class TestMemoryPtr implements AutoCloseable { 627 private long ptr = 0; 628 TestMemoryPtr(int size)629 public TestMemoryPtr(int size) { 630 ptr = jdkUnsafeTestMalloc(size); 631 } 632 get()633 public long get() { 634 return ptr; 635 } 636 637 @Override close()638 public void close() { 639 if (ptr != 0) { 640 jdkUnsafeTestFree(ptr); 641 ptr = 0; 642 } 643 } 644 } 645 vmJdkArrayBaseOffset(Class<?> clazz)646 private static native int vmJdkArrayBaseOffset(Class<?> clazz); vmJdkArrayIndexScale(Class<?> clazz)647 private static native int vmJdkArrayIndexScale(Class<?> clazz); jdkUnsafeTestMalloc(long size)648 private static native long jdkUnsafeTestMalloc(long size); jdkUnsafeTestFree(long memory)649 private static native void jdkUnsafeTestFree(long memory); 650 } 651