Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java
41149 views
1
/*
2
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test id=z
26
* @key randomness
27
* @bug 8059022
28
* @modules java.base/jdk.internal.misc:+open
29
* @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet)
30
* @requires vm.gc.Z
31
* @library /test/lib
32
* @run main/othervm -XX:+UseZGC
33
* -XX:+UnlockDiagnosticVMOptions
34
* -XX:+ZVerifyViews -XX:ZCollectionInterval=1
35
* -XX:-CreateCoredumpOnCrash
36
* -XX:CompileCommand=dontinline,*::mergeImpl*
37
* compiler.gcbarriers.UnsafeIntrinsicsTest
38
*/
39
40
/*
41
* @test id=shenandoah
42
* @key randomness
43
* @bug 8255401 8251944
44
* @modules java.base/jdk.internal.misc:+open
45
* @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet)
46
* @requires vm.gc.Shenandoah
47
* @library /test/lib
48
* @run main/othervm -XX:+UseShenandoahGC
49
* -XX:+UnlockDiagnosticVMOptions
50
* -XX:-CreateCoredumpOnCrash
51
* -XX:+ShenandoahVerify
52
* -XX:+IgnoreUnrecognizedVMOptions -XX:+ShenandoahVerifyOptoBarriers
53
* -XX:CompileCommand=dontinline,*::mergeImpl*
54
* compiler.gcbarriers.UnsafeIntrinsicsTest
55
*/
56
57
package compiler.gcbarriers;
58
59
import java.lang.reflect.Field;
60
import java.util.ArrayList;
61
import java.util.Random;
62
import jdk.test.lib.Utils;
63
import sun.misc.Unsafe;
64
65
public class UnsafeIntrinsicsTest {
66
67
/*
68
* This test triggers the loadbarriers by allocating a lot, keeping the objects alive and then
69
* letting them die in a way that maximizes fragmentation.
70
*
71
* All subtests (OperationType's) could run in parallel.
72
*/
73
74
static int node_count = 133700;
75
static int thread_count = 4;
76
static int time = Integer.getInteger("time", 4); // seconds per subtest
77
78
static Runner r = new Runner(null, 1, 1, Runner.OperationType.CAS);
79
80
static Node first_node;
81
int epoch = 0;
82
83
public static void main(String[] args) {
84
UnsafeIntrinsicsTest t = new UnsafeIntrinsicsTest();
85
86
t.testWithLocalData(Runner.OperationType.CAS);
87
t.testWithLocalData(Runner.OperationType.Weak_CAS);
88
t.testWithLocalData(Runner.OperationType.CMPX);
89
90
t.testWithSharedData(Runner.OperationType.Swap);
91
t.testWithSharedData(Runner.OperationType.Load);
92
}
93
94
public UnsafeIntrinsicsTest() {
95
96
}
97
98
public void testWithLocalData(Runner.OperationType optype) {
99
System.out.println("Testing " + optype.name() + " with " + thread_count +" thread and " + node_count + " nodes");
100
101
// start mutator threads
102
ArrayList<Thread> thread_list = new ArrayList<Thread>();
103
Random r = Utils.getRandomInstance();
104
for (int i = 0; i < thread_count; i++) {
105
106
setup(); // each thread has its own circle of nodes
107
Thread t = new Thread(new Runner(first_node, time, r.nextLong(), optype));
108
t.start();
109
thread_list.add(t);
110
}
111
112
waitForCompletion(thread_list);
113
countNodes();
114
}
115
116
public void testWithSharedData(Runner.OperationType optype) {
117
System.out.println("Testing " + optype.name() + " with " + thread_count +" thread and " + node_count + " nodes");
118
119
setup(); // All nodes are shared between threads
120
ArrayList<Thread> thread_list = new ArrayList<Thread>();
121
Random r = Utils.getRandomInstance();
122
for (int i = 0; i < thread_count; i++) {
123
Thread t = new Thread(new Runner(first_node, time, r.nextLong(), optype));
124
t.start();
125
thread_list.add(t);
126
}
127
128
waitForCompletion(thread_list);
129
countNodes();
130
}
131
132
public void waitForCompletion(ArrayList<Thread> thread_list) {
133
// do some waiting
134
try {
135
Thread.sleep(time*1000);
136
} catch (InterruptedException e) {
137
e.printStackTrace();
138
}
139
140
// wait for all thread to terminate
141
for (int i = 0; i < thread_count; i++) {
142
try {
143
thread_list.get(i).join();
144
} catch (InterruptedException e) {
145
e.printStackTrace();
146
}
147
}
148
}
149
150
void countNodes() {
151
epoch++;
152
int count = 0;
153
Node node = first_node;
154
while (node.number() < epoch) {
155
node.setNumber(epoch);
156
count++;
157
node = node.next();
158
}
159
System.out.println("Program end, found " + count + " nodes");
160
}
161
162
// Create a circular linked list
163
public void setup() {
164
first_node = new Node();
165
Node last_node = first_node;
166
for (int i = 0; i < node_count; i++) {
167
last_node = new Node(last_node);
168
}
169
first_node.setNext(last_node);
170
}
171
}
172
173
class Runner implements Runnable {
174
175
OperationType type;
176
Node current;
177
Random r;
178
long time;
179
long seed;
180
181
long milage = 0;
182
long created = 0;
183
long skipped = 0;
184
int iterations = 0;
185
186
static final jdk.internal.misc.Unsafe UNSAFE;
187
static final long offset;
188
189
public enum OperationType {
190
Load("Load"),
191
Swap("Swap"),
192
CAS("CAS"),
193
Weak_CAS("Weak-CAS"),
194
CMPX("CMPX");
195
196
private String name;
197
private OperationType(String name) { this.name = name; }
198
}
199
200
static {
201
try {
202
Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
203
f.setAccessible(true);
204
UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
205
offset = UNSAFE.objectFieldOffset(Node.class.getDeclaredField("next"));
206
} catch (Exception e) {
207
throw new RuntimeException("Unable to get Unsafe instance.", e);
208
}
209
}
210
211
public Runner(Node start, int testtime, long seed, OperationType type) {
212
current = start;
213
time = testtime*1000000000L;
214
r = new Random(seed);
215
this.type = type;
216
}
217
218
@Override
219
public void run() {
220
long starttime = System.nanoTime();
221
while((System.nanoTime() - starttime) < time) {
222
iterations++;
223
// Run a bit
224
int run_length = r.nextInt() & 0xfff;
225
for (int i = 0; i < run_length; i++) {
226
current = current.next();
227
milage++;
228
}
229
// find a start node
230
Node startNode = current;
231
Node expectedNext = startNode.next;
232
233
// Run a bit more
234
int skip_length = (r.nextInt() & 0xff) + 1;
235
for (int i = 0; i < skip_length; i++) {
236
current = current.next();
237
skipped++;
238
}
239
240
// create a branch
241
int branch_length = (r.nextInt() & 0xff) + 1;
242
created += branch_length;
243
Node head = makeBranch(current, branch_length);
244
245
// complete circle, but continue to run on old path
246
boolean test_fail = ((iterations & 0x1) == 0);
247
Node current = merge(startNode, expectedNext, head, test_fail);
248
}
249
System.out.println("Milage: " + milage + " Skipped: " + skipped + " Created: " + created + " iterations: " + iterations);
250
}
251
252
/*
253
* The reason for the duplicated code that is wrapping the unsafe operations is that we want
254
* to test the operations individually. They must not interfere with each other - checking a field
255
* will heal that reference and no operation after can trigger the barrier.
256
*
257
* All mergeImpl*-method are prevented from being inlined.
258
*/
259
260
private Node merge(Node startNode, Node expectedNext, Node head, boolean test_fail) {
261
switch (type) {
262
case Load:
263
return mergeImplLoad(startNode, expectedNext, head);
264
case Swap:
265
return mergeImplSwap(startNode, expectedNext, head);
266
case CAS:
267
if (test_fail) {
268
return mergeImplCASFail(startNode, expectedNext, head);
269
} else {
270
return mergeImplCAS(startNode, expectedNext, head);
271
}
272
case Weak_CAS:
273
if (test_fail) {
274
return mergeImplWeakCASFail(startNode, expectedNext, head);
275
} else {
276
return mergeImplWeakCAS(startNode, expectedNext, head);
277
}
278
case CMPX:
279
if (test_fail) {
280
return mergeImplCMPXFail(startNode, expectedNext, head);
281
} else {
282
return mergeImplCMPX(startNode, expectedNext, head);
283
}
284
default:
285
throw new Error("Unimplemented");
286
}
287
}
288
289
private Node mergeImplLoad(Node startNode, Node expectedNext, Node head) {
290
// Atomic load version
291
Node temp = (Node) UNSAFE.getReference(startNode, offset);
292
startNode.setNext(head);
293
return temp;
294
}
295
296
private Node mergeImplSwap(Node startNode, Node expectedNext, Node head) {
297
// Swap version
298
return (Node) UNSAFE.getAndSetReference(startNode, offset, head);
299
}
300
301
private Node mergeImplCAS(Node startNode, Node expectedNext, Node head) {
302
// CAS - should always be true within a single thread - no other thread can have overwritten
303
if (!UNSAFE.compareAndSetReference(startNode, offset, expectedNext, head)) {
304
throw new Error("CAS should always succeed on thread local objects, check you barrier implementation");
305
}
306
return expectedNext; // continue on old circle
307
}
308
309
private Node mergeImplCASFail(Node startNode, Node expectedNext, Node head) {
310
// Force a fail
311
if (UNSAFE.compareAndSetReference(startNode, offset, "fail", head)) {
312
throw new Error("This CAS should always fail, check you barrier implementation");
313
}
314
if (startNode.next() != expectedNext) {
315
throw new Error("Shouldn't have changed");
316
}
317
return current;
318
}
319
320
private Node mergeImplWeakCAS(Node startNode, Node expectedNext, Node head) {
321
// Weak CAS - should always be true within a single thread - no other thread can have overwritten
322
if (!UNSAFE.weakCompareAndSetReference(startNode, offset, expectedNext, head)) {
323
throw new Error("Weak CAS should always succeed on thread local objects, check you barrier implementation");
324
}
325
return expectedNext; // continue on old circle
326
}
327
328
private Node mergeImplWeakCASFail(Node startNode, Node expectedNext, Node head) {
329
// Force a fail
330
if (UNSAFE.weakCompareAndSetReference(startNode, offset, "fail", head)) {
331
throw new Error("This weak CAS should always fail, check you barrier implementation");
332
}
333
if (startNode.next() != expectedNext) {
334
throw new Error("Shouldn't have changed");
335
}
336
return current;
337
}
338
339
private Node mergeImplCMPX(Node startNode, Node expectedNext, Node head) {
340
// CmpX - should always be true within a single thread - no other thread can have overwritten
341
Object res = UNSAFE.compareAndExchangeReference(startNode, offset, expectedNext, head);
342
if (!res.equals(expectedNext)) {
343
throw new Error("Fail CmpX should always succeed on thread local objects, check you barrier implementation");
344
}
345
return expectedNext; // continue on old circle
346
}
347
348
private Node mergeImplCMPXFail(Node startNode, Node expectedNext, Node head) {
349
Object res = UNSAFE.compareAndExchangeReference(startNode, offset, head, head);
350
if (startNode.next() != expectedNext) {
351
throw new Error("Shouldn't have changed");
352
}
353
if (head == expectedNext) {
354
throw new Error("Test malfunction");
355
}
356
if (!res.equals(expectedNext)) {
357
throw new Error("This CmpX should have returned 'expectedNext' when it failed");
358
}
359
if (res.equals(head)) {
360
throw new Error("This CmpX shouldn't have returned head when it failed. count: "+ iterations);
361
}
362
363
return current;
364
}
365
366
// Create a new branch that will replace a part of the circle
367
public Node makeBranch(Node end_node, int count) {
368
Node head = end_node;
369
for (int i = 0; i < count; i++) {
370
head = new Node(head);
371
}
372
return head;
373
}
374
}
375
376
class Node {
377
Node next;
378
int number = 0;
379
380
public int number() {
381
return number;
382
}
383
384
public void setNumber(int v) {
385
number = v;
386
}
387
388
public Node() {
389
}
390
391
public Node(Node link) {
392
next = link;
393
}
394
395
public void setNext(Node next) {
396
this.next = next;
397
}
398
public Node next() {
399
return next;
400
}
401
}
402
403