blob: bb6de2ef289b5d0404ec8673e82eb17710f6157c [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
90 private static void load() {
91 unsafe.loadFence();
92 }
93
94 /// CHECK-START: void Main.store() intrinsics_recognition (after)
95 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeStoreFence
96 private static void store() {
97 unsafe.storeFence();
98 }
99
100 /// CHECK-START: void Main.full() intrinsics_recognition (after)
101 /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeFullFence
102 private static void full() {
103 unsafe.fullFence();
104 }
105
106 //
107 // Thread fork/join.
108 //
109
110 private static void fork(Runnable r) {
111 for (int i = 0; i < 10; i++) {
112 sThreads[i] = new Thread(r);
113 sThreads[i].start();
114 }
115 }
116
117 private static void join() {
118 try {
119 for (int i = 0; i < 10; i++) {
120 sThreads[i].join();
121 }
122 } catch (InterruptedException e) {
123 throw new Error("Failed join: " + e);
124 }
125 }
126
127 //
128 // Driver.
129 //
130
131 public static void main(String[] args) {
132 System.out.println("starting");
133
134 final Main m = new Main();
135
136 // Get the offsets.
137
138 final long intOffset, longOffset, objOffset;
139 try {
140 Field intField = Main.class.getDeclaredField("i");
141 Field longField = Main.class.getDeclaredField("l");
142 Field objField = Main.class.getDeclaredField("o");
143
144 intOffset = unsafe.objectFieldOffset(intField);
145 longOffset = unsafe.objectFieldOffset(longField);
146 objOffset = unsafe.objectFieldOffset(objField);
147
148 } catch (NoSuchFieldException e) {
149 throw new Error("No offset: " + e);
150 }
151
152 // Some sanity within same thread.
153
154 set32(m, intOffset, 3);
155 expectEquals32(3, m.i);
156
157 set64(m, longOffset, 7L);
158 expectEquals64(7L, m.l);
159
160 setObj(m, objOffset, m);
161 expectEqualsObj(m, m.o);
162
163 add32(m, intOffset, 11);
164 expectEquals32(14, m.i);
165
166 add64(m, longOffset, 13L);
167 expectEquals64(20L, m.l);
168
169 // Some sanity on setters within different threads.
170
171 fork(new Runnable() {
172 public void run() {
173 for (int i = 0; i < 10; i++)
174 set32(m, intOffset, i);
175 }
176 });
177 join();
178 expectEquals32(9, m.i); // one thread's last value wins
179
180 fork(new Runnable() {
181 public void run() {
182 for (int i = 0; i < 10; i++)
183 set64(m, longOffset, (long) (100 + i));
184 }
185 });
186 join();
187 expectEquals64(109L, m.l); // one thread's last value wins
188
189 fork(new Runnable() {
190 public void run() {
191 for (int i = 0; i < 10; i++)
192 setObj(m, objOffset, sThreads[i]);
193 }
194 });
195 join();
196 expectEqualsObj(sThreads[9], m.o); // one thread's last value wins
197
198 // Some sanity on adders within different threads.
199
200 fork(new Runnable() {
201 public void run() {
202 for (int i = 0; i < 10; i++)
203 add32(m, intOffset, i + 1);
204 }
205 });
206 join();
207 expectEquals32(559, m.i); // all values accounted for
208
209 fork(new Runnable() {
210 public void run() {
211 for (int i = 0; i < 10; i++)
212 add64(m, longOffset, (long) (i + 1));
213 }
214 });
215 join();
216 expectEquals64(659L, m.l); // all values accounted for
217
218 // TODO: the fences
219
220 System.out.println("passed");
221 }
222
223 // Use reflection to implement "Unsafe.getUnsafe()";
224 private static Unsafe getUnsafe() {
225 try {
226 Class<?> unsafeClass = Unsafe.class;
227 Field f = unsafeClass.getDeclaredField("theUnsafe");
228 f.setAccessible(true);
229 return (Unsafe) f.get(null);
230 } catch (Exception e) {
231 throw new Error("Cannot get Unsafe instance");
232 }
233 }
234
235 private static void expectEquals32(int expected, int result) {
236 if (expected != result) {
237 throw new Error("Expected: " + expected + ", found: " + result);
238 }
239 }
240
241 private static void expectEquals64(long expected, long result) {
242 if (expected != result) {
243 throw new Error("Expected: " + expected + ", found: " + result);
244 }
245 }
246
247 private static void expectEqualsObj(Object expected, Object result) {
248 if (expected != result) {
249 throw new Error("Expected: " + expected + ", found: " + result);
250 }
251 }
252}