Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/invoke/MethodHandles/CatchExceptionTest.java
41152 views
1
/*
2
* Copyright (c) 2014, 2018, 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
package test.java.lang.invoke.MethodHandles;
25
26
import jdk.test.lib.TimeLimitedRunner;
27
import jdk.test.lib.Asserts;
28
import jdk.test.lib.Utils;
29
import test.java.lang.invoke.lib.CodeCacheOverflowProcessor;
30
import test.java.lang.invoke.lib.Helper;
31
32
import java.lang.invoke.MethodHandle;
33
import java.lang.invoke.MethodHandles;
34
import java.lang.invoke.MethodType;
35
import java.lang.reflect.Array;
36
import java.util.ArrayList;
37
import java.util.Arrays;
38
import java.util.Collections;
39
import java.util.List;
40
import java.util.Objects;
41
import java.util.function.BiFunction;
42
import java.util.function.Function;
43
import java.util.function.Supplier;
44
45
/* @test
46
* @library /java/lang/invoke/common /test/lib
47
* @build jdk.test.lib.TimeLimitedRunner
48
* @compile CatchExceptionTest.java
49
* @run main/othervm -esa test.java.lang.invoke.MethodHandles.CatchExceptionTest
50
* @key intermittent randomness
51
*/
52
public class CatchExceptionTest {
53
private static final List<Class<?>> ARGS_CLASSES;
54
protected static final int MAX_ARITY = Helper.MAX_ARITY - 1;
55
56
static {
57
Class<?> classes[] = {
58
Object.class,
59
long.class,
60
int.class,
61
byte.class,
62
Integer[].class,
63
double[].class,
64
String.class,
65
};
66
ARGS_CLASSES = Collections.unmodifiableList(
67
Helper.randomClasses(classes, MAX_ARITY));
68
}
69
70
private final TestCase testCase;
71
private final int nargs;
72
private final int argsCount;
73
private final MethodHandle catcher;
74
private int dropped;
75
private MethodHandle thrower;
76
77
public CatchExceptionTest(TestCase testCase, final boolean isVararg,
78
final int argsCount, final int catchDrops) {
79
this.testCase = testCase;
80
this.dropped = catchDrops;
81
MethodHandle thrower = testCase.thrower;
82
int throwerLen = thrower.type().parameterCount();
83
List<Class<?>> classes;
84
int extra = Math.max(0, argsCount - throwerLen);
85
classes = getThrowerParams(isVararg, extra);
86
this.argsCount = throwerLen + classes.size();
87
thrower = Helper.addTrailingArgs(thrower, this.argsCount, classes);
88
if (isVararg && argsCount > throwerLen) {
89
MethodType mt = thrower.type();
90
Class<?> lastParam = mt.parameterType(mt.parameterCount() - 1);
91
thrower = thrower.asVarargsCollector(lastParam);
92
}
93
this.thrower = thrower;
94
this.dropped = Math.min(this.argsCount, catchDrops);
95
catcher = testCase.getCatcher(getCatcherParams());
96
nargs = Math.max(2, this.argsCount);
97
}
98
99
public static void main(String[] args) throws Throwable {
100
CodeCacheOverflowProcessor.runMHTest(CatchExceptionTest::test);
101
}
102
103
public static void test() throws Throwable {
104
System.out.println("classes = " + ARGS_CLASSES);
105
106
TestFactory factory = new TestFactory();
107
long timeout = Helper.IS_THOROUGH ? 0L : Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT);
108
// subtract vm init time and reserve time for vm exit
109
timeout *= 0.9;
110
TimeLimitedRunner runner = new TimeLimitedRunner(timeout, 2.0d,
111
() -> {
112
CatchExceptionTest test = factory.nextTest();
113
if (test != null) {
114
test.runTest();
115
return true;
116
}
117
return false;
118
});
119
for (CatchExceptionTest test : TestFactory.MANDATORY_TEST_CASES) {
120
test.runTest();
121
}
122
runner.call();
123
}
124
125
private List<Class<?>> getThrowerParams(boolean isVararg, int argsCount) {
126
return Helper.getParams(ARGS_CLASSES, isVararg, argsCount);
127
}
128
129
private List<Class<?>> getCatcherParams() {
130
int catchArgc = 1 + this.argsCount - dropped;
131
List<Class<?>> result = new ArrayList<>(
132
thrower.type().parameterList().subList(0, catchArgc - 1));
133
// prepend throwable
134
result.add(0, testCase.throwableClass);
135
return result;
136
}
137
138
private void runTest() {
139
if (Helper.IS_VERBOSE) {
140
System.out.printf("CatchException(%s, isVararg=%b argsCount=%d " +
141
"dropped=%d)%n",
142
testCase, thrower.isVarargsCollector(), argsCount, dropped);
143
}
144
145
Helper.clear();
146
147
Object[] args = Helper.randomArgs(
148
argsCount, thrower.type().parameterArray());
149
Object arg0 = Helper.MISSING_ARG;
150
Object arg1 = testCase.thrown;
151
if (argsCount > 0) {
152
arg0 = args[0];
153
}
154
if (argsCount > 1) {
155
args[1] = arg1;
156
}
157
Asserts.assertEQ(nargs, thrower.type().parameterCount());
158
if (argsCount < nargs) {
159
Object[] appendArgs = {arg0, arg1};
160
appendArgs = Arrays.copyOfRange(appendArgs, argsCount, nargs);
161
thrower = MethodHandles.insertArguments(
162
thrower, argsCount, appendArgs);
163
}
164
Asserts.assertEQ(argsCount, thrower.type().parameterCount());
165
166
MethodHandle target = MethodHandles.catchException(
167
testCase.filter(thrower), testCase.throwableClass,
168
testCase.filter(catcher));
169
170
Asserts.assertEQ(thrower.type(), target.type());
171
Asserts.assertEQ(argsCount, target.type().parameterCount());
172
173
Object returned;
174
try {
175
returned = target.invokeWithArguments(args);
176
} catch (Throwable ex) {
177
if (CodeCacheOverflowProcessor.isThrowableCausedByVME(ex)) {
178
// This error will be treated by CodeCacheOverflowProcessor
179
// to prevent the test from failing because of code cache overflow.
180
throw new Error(ex);
181
}
182
testCase.assertCatch(ex);
183
returned = ex;
184
}
185
186
testCase.assertReturn(returned, arg0, arg1, dropped, args);
187
}
188
}
189
190
class TestFactory {
191
public static final List<CatchExceptionTest> MANDATORY_TEST_CASES = new ArrayList<>();
192
193
private static final int MIN_TESTED_ARITY = 10;
194
195
static {
196
for (int[] args : new int[][]{
197
{0, 0},
198
{MIN_TESTED_ARITY, 0},
199
{MIN_TESTED_ARITY, MIN_TESTED_ARITY},
200
{CatchExceptionTest.MAX_ARITY, 0},
201
{CatchExceptionTest.MAX_ARITY, CatchExceptionTest.MAX_ARITY},
202
}) {
203
MANDATORY_TEST_CASES.addAll(createTests(args[0], args[1]));
204
}
205
}
206
207
private int count;
208
private int args;
209
private int dropArgs;
210
private int currentMaxDrops;
211
private int maxArgs;
212
private int maxDrops;
213
private int constructor;
214
private int constructorSize;
215
private boolean isVararg;
216
217
public TestFactory() {
218
if (Helper.IS_THOROUGH) {
219
maxArgs = maxDrops = CatchExceptionTest.MAX_ARITY;
220
} else {
221
maxArgs = MIN_TESTED_ARITY
222
+ Helper.RNG.nextInt(CatchExceptionTest.MAX_ARITY
223
- MIN_TESTED_ARITY)
224
+ 1;
225
maxDrops = MIN_TESTED_ARITY
226
+ Helper.RNG.nextInt(maxArgs - MIN_TESTED_ARITY)
227
+ 1;
228
args = 1;
229
}
230
231
System.out.printf("maxArgs = %d%nmaxDrops = %d%n", maxArgs, maxDrops);
232
constructorSize = TestCase.CONSTRUCTORS.size();
233
}
234
235
private static List<CatchExceptionTest> createTests(int argsCount,
236
int catchDrops) {
237
if (catchDrops > argsCount || argsCount < 0 || catchDrops < 0) {
238
throw new IllegalArgumentException("argsCount = " + argsCount
239
+ ", catchDrops = " + catchDrops
240
);
241
}
242
List<CatchExceptionTest> result = new ArrayList<>(
243
TestCase.CONSTRUCTORS.size());
244
for (Supplier<TestCase> constructor : TestCase.CONSTRUCTORS) {
245
result.add(new CatchExceptionTest(constructor.get(),
246
/* isVararg = */ true,
247
argsCount,
248
catchDrops));
249
result.add(new CatchExceptionTest(constructor.get(),
250
/* isVararg = */ false,
251
argsCount,
252
catchDrops));
253
}
254
return result;
255
}
256
257
/**
258
* @return next test from test matrix:
259
* {varArgs, noVarArgs} x TestCase.rtypes x TestCase.THROWABLES x {1, .., maxArgs } x {0, .., maxDrops}
260
*/
261
public CatchExceptionTest nextTest() {
262
if (constructor < constructorSize) {
263
return createTest();
264
}
265
constructor = 0;
266
count++;
267
if (!Helper.IS_THOROUGH && count > Helper.TEST_LIMIT) {
268
System.out.println("test limit is exceeded");
269
return null;
270
}
271
if (dropArgs <= currentMaxDrops) {
272
if (dropArgs == 0) {
273
if (Helper.IS_THOROUGH || Helper.RNG.nextBoolean()) {
274
++dropArgs;
275
return createTest();
276
} else if (Helper.IS_VERBOSE) {
277
System.out.printf(
278
"argsCount=%d : \"drop\" scenarios are skipped%n",
279
args);
280
}
281
} else {
282
++dropArgs;
283
return createTest();
284
}
285
}
286
287
if (args < maxArgs) {
288
dropArgs = 0;
289
currentMaxDrops = Math.min(args, maxDrops);
290
++args;
291
return createTest();
292
}
293
return null;
294
}
295
296
private CatchExceptionTest createTest() {
297
if (!Helper.IS_THOROUGH) {
298
return new CatchExceptionTest(
299
TestCase.CONSTRUCTORS.get(constructor++).get(),
300
Helper.RNG.nextBoolean(), args, dropArgs);
301
} else {
302
if (isVararg) {
303
isVararg = false;
304
return new CatchExceptionTest(
305
TestCase.CONSTRUCTORS.get(constructor++).get(),
306
isVararg, args, dropArgs);
307
} else {
308
isVararg = true;
309
return new CatchExceptionTest(
310
TestCase.CONSTRUCTORS.get(constructor).get(),
311
isVararg, args, dropArgs);
312
}
313
}
314
}
315
}
316
317
class TestCase<T> {
318
private static enum ThrowMode {
319
NOTHING,
320
CAUGHT,
321
UNCAUGHT,
322
ADAPTER
323
}
324
325
@SuppressWarnings("unchecked")
326
public static final List<Supplier<TestCase>> CONSTRUCTORS;
327
private static final MethodHandle FAKE_IDENTITY;
328
private static final MethodHandle THROW_OR_RETURN;
329
private static final MethodHandle CATCHER;
330
331
static {
332
try {
333
MethodHandles.Lookup lookup = MethodHandles.lookup();
334
THROW_OR_RETURN = lookup.findStatic(
335
TestCase.class,
336
"throwOrReturn",
337
MethodType.methodType(Object.class, Object.class,
338
Throwable.class)
339
);
340
CATCHER = lookup.findStatic(
341
TestCase.class,
342
"catcher",
343
MethodType.methodType(Object.class, Object.class));
344
FAKE_IDENTITY = lookup.findVirtual(
345
TestCase.class, "fakeIdentity",
346
MethodType.methodType(Object.class, Object.class));
347
348
} catch (NoSuchMethodException | IllegalAccessException e) {
349
throw new Error(e);
350
}
351
PartialConstructor[] constructors = {
352
create(Object.class, Object.class::cast),
353
create(String.class, Objects::toString),
354
create(int[].class, x -> new int[]{Objects.hashCode(x)}),
355
create(long.class,
356
x -> Objects.hashCode(x) & (-1L >>> 32)),
357
create(void.class, TestCase::noop)};
358
Throwable[] throwables = {
359
new ClassCastException("testing"),
360
new java.io.IOException("testing"),
361
new LinkageError("testing")};
362
List<Supplier<TestCase>> list = new ArrayList<>(constructors.length
363
* throwables.length * ThrowMode.values().length);
364
//noinspection unchecked
365
for (PartialConstructor f : constructors) {
366
for (ThrowMode mode : ThrowMode.values()) {
367
for (Throwable t : throwables) {
368
list.add(f.apply(mode, t));
369
}
370
}
371
}
372
CONSTRUCTORS = Collections.unmodifiableList(list);
373
}
374
375
public final Class<T> rtype;
376
public final ThrowMode throwMode;
377
public final Throwable thrown;
378
public final Class<? extends Throwable> throwableClass;
379
/**
380
* MH which takes 2 args (Object,Throwable), 1st is the return value,
381
* 2nd is the exception which will be thrown, if it's supposed in current
382
* {@link #throwMode}.
383
*/
384
public final MethodHandle thrower;
385
private final Function<Object, T> cast;
386
protected MethodHandle filter;
387
private int fakeIdentityCount;
388
389
private TestCase(Class<T> rtype, Function<Object, T> cast,
390
ThrowMode throwMode, Throwable thrown)
391
throws NoSuchMethodException, IllegalAccessException {
392
this.cast = cast;
393
filter = MethodHandles.lookup().findVirtual(
394
Function.class,
395
"apply",
396
MethodType.methodType(Object.class, Object.class))
397
.bindTo(cast);
398
this.rtype = rtype;
399
this.throwMode = throwMode;
400
this.throwableClass = thrown.getClass();
401
switch (throwMode) {
402
case NOTHING:
403
this.thrown = null;
404
break;
405
case ADAPTER:
406
case UNCAUGHT:
407
this.thrown = new Error("do not catch this");
408
break;
409
default:
410
this.thrown = thrown;
411
}
412
413
MethodHandle throwOrReturn = THROW_OR_RETURN;
414
if (throwMode == ThrowMode.ADAPTER) {
415
MethodHandle fakeIdentity = FAKE_IDENTITY.bindTo(this);
416
for (int i = 0; i < 10; ++i) {
417
throwOrReturn = MethodHandles.filterReturnValue(
418
throwOrReturn, fakeIdentity);
419
}
420
}
421
thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
422
}
423
424
private static Void noop(Object x) {
425
return null;
426
}
427
428
private static <T2> PartialConstructor create(
429
Class<T2> rtype, Function<Object, T2> cast) {
430
return (t, u) -> () -> {
431
try {
432
return new TestCase<>(rtype, cast, t, u);
433
} catch (NoSuchMethodException | IllegalAccessException e) {
434
throw new Error(e);
435
}
436
};
437
}
438
439
private static <T extends Throwable>
440
Object throwOrReturn(Object normal, T exception) throws T {
441
if (exception != null) {
442
Helper.called("throwOrReturn/throw", normal, exception);
443
throw exception;
444
}
445
Helper.called("throwOrReturn/normal", normal, exception);
446
return normal;
447
}
448
449
private static <T extends Throwable>
450
Object catcher(Object o) {
451
Helper.called("catcher", o);
452
return o;
453
}
454
455
public MethodHandle filter(MethodHandle target) {
456
return MethodHandles.filterReturnValue(target, filter);
457
}
458
459
public MethodHandle getCatcher(List<Class<?>> classes) {
460
return MethodHandles.filterReturnValue(Helper.AS_LIST.asType(
461
MethodType.methodType(Object.class, classes)),
462
CATCHER
463
);
464
}
465
466
@Override
467
public String toString() {
468
return "TestCase{" +
469
"rtype=" + rtype +
470
", throwMode=" + throwMode +
471
", throwableClass=" + throwableClass +
472
'}';
473
}
474
475
public String callName() {
476
return "throwOrReturn/" +
477
(throwMode == ThrowMode.NOTHING
478
? "normal"
479
: "throw");
480
}
481
482
public void assertReturn(Object returned, Object arg0, Object arg1,
483
int catchDrops, Object... args) {
484
int lag = 0;
485
if (throwMode == ThrowMode.CAUGHT) {
486
lag = 1;
487
}
488
Helper.assertCalled(lag, callName(), arg0, arg1);
489
490
if (throwMode == ThrowMode.NOTHING) {
491
assertEQ(cast.apply(arg0), returned);
492
} else if (throwMode == ThrowMode.CAUGHT) {
493
List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
494
// catcher receives an initial subsequence of target arguments:
495
catchArgs.subList(args.length - catchDrops, args.length).clear();
496
// catcher also receives the exception, prepended:
497
catchArgs.add(0, thrown);
498
Helper.assertCalled("catcher", catchArgs);
499
assertEQ(cast.apply(catchArgs), returned);
500
}
501
Asserts.assertEQ(0, fakeIdentityCount);
502
}
503
504
private void assertEQ(T t, Object returned) {
505
if (rtype.isArray()) {
506
Asserts.assertEQ(t.getClass(), returned.getClass());
507
int n = Array.getLength(t);
508
Asserts.assertEQ(n, Array.getLength(returned));
509
for (int i = 0; i < n; ++i) {
510
Asserts.assertEQ(Array.get(t, i), Array.get(returned, i));
511
}
512
} else {
513
Asserts.assertEQ(t, returned);
514
}
515
}
516
517
private Object fakeIdentity(Object x) {
518
System.out.println("should throw through this!");
519
++fakeIdentityCount;
520
return x;
521
}
522
523
public void assertCatch(Throwable ex) {
524
try {
525
Asserts.assertSame(thrown, ex,
526
"must get the out-of-band exception");
527
} catch (Throwable t) {
528
ex.printStackTrace();
529
}
530
}
531
532
public interface PartialConstructor
533
extends BiFunction<ThrowMode, Throwable, Supplier<TestCase>> {
534
}
535
}
536
537