blob: bb020b9b9f6bda1724e478202aabd6c29d3d0ce2 [file] [log] [blame]
Aart Bik0e54c012016-03-04 12:08:31 -08001/*
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
17import java.lang.reflect.Field;
18
19import sun.misc.Unsafe;
20
21/**
22 * Checker test on the 1.8 unsafe operations. Note, this is by no means an
23 * exhaustive unit test for these CAS (compare-and-swap) and fence operations.
24 * Instead, this test ensures the methods are recognized as intrinsic and behave
25 * as expected.
26 */
27public class Main {
28
29 private static final Unsafe unsafe = getUnsafe();
30
31 private static Thread[] sThreads = new Thread[10];
32
33 //
34 // Fields accessed by setters and adders.
35 //
36
37 public int i = 0;
38 public long l = 0;
39 public Object o = null;
40
41 //
42 // Setters.
43 //
44
45 /// CHECK-START: int Main.set32(java.lang.Object, long, int) intrinsics_recognition (after)
46 /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetInt
47 /// CHECK-DAG: Return [<<Result>>]
48 private static int set32(Object o, long offset, int newValue) {
49 return unsafe.getAndSetInt(o, offset, newValue);
50 }
51
52 /// CHECK-START: long Main.set64(java.lang.Object, long, long) intrinsics_recognition (after)
53 /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetLong
54 /// CHECK-DAG: Return [<<Result>>]
55 private static long set64(Object o, long offset, long newValue) {
56 return unsafe.getAndSetLong(o, offset, newValue);
57 }
58
59 /// CHECK-START: java.lang.Object Main.setObj(java.lang.Object, long, java.lang.Object) intrinsics_recognition (after)
60 /// CHECK-DAG: <<Result:l\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetObject
61 /// CHECK-DAG: Return [<<Result>>]
62 private static Object setObj(Object o, long offset, Object newValue) {
63 return unsafe.getAndSetObject(o, offset, newValue);
64 }
65
66 //
67 // Adders.
68 //
69
70 /// CHECK-START: int Main.add32(java.lang.Object, long, int) intrinsics_recognition (after)
71 /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddInt
72 /// CHECK-DAG: Return [<<Result>>]
73 private static int add32(Object o, long offset, int delta) {
74 return unsafe.getAndAddInt(o, offset, delta);
75 }
76
77 /// CHECK-START: long Main.add64(java.lang.Object, long, long) intrinsics_recognition (after)
78 /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddLong
79 /// CHECK-DAG: Return [<<Result>>]
80 private static long add64(Object o, long offset, long delta) {
81 return unsafe.getAndAddLong(o, offset, delta);
82 }
83
84 //
85 // Fences (native).
86 //
87
88 /// CHECK-START: void Main.load() intrinsics_recognition (after)
89 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeLoadFence
Aart Bik11932592016-03-08 12:42:25 -080090 //
91 /// CHECK-START: void Main.load() instruction_simplifier (after)
92 /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeLoadFence
93 //
94 /// CHECK-START: void Main.load() instruction_simplifier (after)
95 /// CHECK-DAG: MemoryBarrier kind:LoadAny
Aart Bik0e54c012016-03-04 12:08:31 -080096 private static void load() {
97 unsafe.loadFence();
98 }
99
100 /// CHECK-START: void Main.store() intrinsics_recognition (after)
101 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeStoreFence
Aart Bik11932592016-03-08 12:42:25 -0800102 //
103 /// CHECK-START: void Main.store() instruction_simplifier (after)
104 /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeStoreFence
105 //
106 /// CHECK-START: void Main.store() instruction_simplifier (after)
107 /// CHECK-DAG: MemoryBarrier kind:AnyStore
Aart Bik0e54c012016-03-04 12:08:31 -0800108 private static void store() {
109 unsafe.storeFence();
110 }
111
112 /// CHECK-START: void Main.full() intrinsics_recognition (after)
113 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeFullFence
Aart Bik11932592016-03-08 12:42:25 -0800114 //
115 /// CHECK-START: void Main.full() instruction_simplifier (after)
116 /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeFullFence
117 //
118 /// CHECK-START: void Main.full() instruction_simplifier (after)
119 /// CHECK-DAG: MemoryBarrier kind:AnyAny
Aart Bik0e54c012016-03-04 12:08:31 -0800120 private static void full() {
121 unsafe.fullFence();
122 }
123
124 //
125 // Thread fork/join.
126 //
127
128 private static void fork(Runnable r) {
129 for (int i = 0; i < 10; i++) {
130 sThreads[i] = new Thread(r);
131 sThreads[i].start();
132 }
133 }
134
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
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 sanity within same thread.
171
172 set32(m, intOffset, 3);
173 expectEquals32(3, m.i);
174
175 set64(m, longOffset, 7L);
176 expectEquals64(7L, m.l);
177
178 setObj(m, objOffset, m);
179 expectEqualsObj(m, m.o);
180
181 add32(m, intOffset, 11);
182 expectEquals32(14, m.i);
183
184 add64(m, longOffset, 13L);
185 expectEquals64(20L, m.l);
186
187 // Some sanity 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 expectEquals32(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 expectEquals64(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 expectEqualsObj(sThreads[9], m.o); // one thread's last value wins
215
216 // Some sanity 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 expectEquals32(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 expectEquals64(659L, m.l); // all values accounted for
235
236 // TODO: the fences
237
238 System.out.println("passed");
239 }
240
241 // Use reflection to implement "Unsafe.getUnsafe()";
242 private static Unsafe getUnsafe() {
243 try {
244 Class<?> unsafeClass = Unsafe.class;
245 Field f = unsafeClass.getDeclaredField("theUnsafe");
246 f.setAccessible(true);
247 return (Unsafe) f.get(null);
248 } catch (Exception e) {
249 throw new Error("Cannot get Unsafe instance");
250 }
251 }
252
253 private static void expectEquals32(int expected, int result) {
254 if (expected != result) {
255 throw new Error("Expected: " + expected + ", found: " + result);
256 }
257 }
258
259 private static void expectEquals64(long expected, long result) {
260 if (expected != result) {
261 throw new Error("Expected: " + expected + ", found: " + result);
262 }
263 }
264
265 private static void expectEqualsObj(Object expected, Object result) {
266 if (expected != result) {
267 throw new Error("Expected: " + expected + ", found: " + result);
268 }
269 }
270}