xref: /aosp_15_r20/art/test/2235-JdkUnsafeTest/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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