Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java
47791 views
/*1* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package test.java.lang.invoke.MethodHandles;2324import com.oracle.testlibrary.jsr292.Helper;25import com.oracle.testlibrary.jsr292.CodeCacheOverflowProcessor;26import jdk.testlibrary.Asserts;27import jdk.testlibrary.TimeLimitedRunner;28import jdk.testlibrary.Utils;2930import java.lang.invoke.MethodHandle;31import java.lang.invoke.MethodHandles;32import java.lang.invoke.MethodType;33import java.lang.reflect.Array;34import java.util.*;35import java.util.function.BiFunction;36import java.util.function.Function;37import java.util.function.Supplier;3839/* @test40* @library /lib/testlibrary/jsr292 /lib/testlibrary/41* @compile CatchExceptionTest.java42* @run main/othervm -esa test.java.lang.invoke.MethodHandles.CatchExceptionTest43* @key randomness44*/45public class CatchExceptionTest {4647private static final List<Class<?>> ARGS_CLASSES;48protected static final int MAX_ARITY = Helper.MAX_ARITY - 1;4950static {51Class<?> classes[] = {52Object.class,53long.class,54int.class,55byte.class,56Integer[].class,57double[].class,58String.class,59};60ARGS_CLASSES = Collections.unmodifiableList(61Helper.randomClasses(classes, MAX_ARITY));62}6364private final TestCase testCase;65private final int nargs;66private final int argsCount;67private final MethodHandle catcher;68private int dropped;69private MethodHandle thrower;7071public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount,72final int catchDrops) {73this.testCase = testCase;74this.dropped = catchDrops;75MethodHandle thrower = testCase.thrower;76int throwerLen = thrower.type().parameterCount();77List<Class<?>> classes;78int extra = Math.max(0, argsCount - throwerLen);79classes = getThrowerParams(isVararg, extra);80this.argsCount = throwerLen + classes.size();81thrower = Helper.addTrailingArgs(thrower, this.argsCount, classes);82if (isVararg && argsCount > throwerLen) {83MethodType mt = thrower.type();84Class<?> lastParam = mt.parameterType(mt.parameterCount() - 1);85thrower = thrower.asVarargsCollector(lastParam);86}87this.thrower = thrower;88this.dropped = Math.min(this.argsCount, catchDrops);89catcher = testCase.getCatcher(getCatcherParams());90nargs = Math.max(2, this.argsCount);91}9293public static void main(String[] args) throws Throwable {94CodeCacheOverflowProcessor.runMHTest(CatchExceptionTest::test);95}9697public static void test() throws Throwable {98System.out.println("classes = " + ARGS_CLASSES);99TestFactory factory = new TestFactory();100long timeout = Helper.IS_THOROUGH ? 0L : Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT);101// subtract vm init time and reserve time for vm exit102timeout *= 0.9;103TimeLimitedRunner runner = new TimeLimitedRunner(timeout, 2.0d,104() -> {105CatchExceptionTest test = factory.nextTest();106if (test != null) {107test.runTest();108return true;109}110return false;111});112for (CatchExceptionTest test : TestFactory.MANDATORY_TEST_CASES) {113test.runTest();114}115runner.call();116}117118private List<Class<?>> getThrowerParams(boolean isVararg, int argsCount) {119return Helper.getParams(ARGS_CLASSES, isVararg, argsCount);120}121122private List<Class<?>> getCatcherParams() {123int catchArgc = 1 + this.argsCount - dropped;124List<Class<?>> result = new ArrayList<>(125thrower.type().parameterList().subList(0, catchArgc - 1));126// prepend throwable127result.add(0, testCase.throwableClass);128return result;129}130131private void runTest() {132if (Helper.IS_VERBOSE) {133System.out.printf("CatchException(%s, isVararg=%b argsCount=%d "134+ "dropped=%d)%n",135testCase, thrower.isVarargsCollector(),136argsCount, dropped);137}138139Helper.clear();140141Object[] args = Helper.randomArgs(142argsCount, thrower.type().parameterArray());143Object arg0 = Helper.MISSING_ARG;144Object arg1 = testCase.thrown;145if (argsCount > 0) {146arg0 = args[0];147}148if (argsCount > 1) {149args[1] = arg1;150}151Asserts.assertEQ(nargs, thrower.type().parameterCount());152if (argsCount < nargs) {153Object[] appendArgs = {arg0, arg1};154appendArgs = Arrays.copyOfRange(appendArgs, argsCount, nargs);155thrower = MethodHandles.insertArguments(156thrower, argsCount, appendArgs);157}158Asserts.assertEQ(argsCount, thrower.type().parameterCount());159160MethodHandle target = MethodHandles.catchException(161testCase.filter(thrower), testCase.throwableClass,162testCase.filter(catcher));163164Asserts.assertEQ(thrower.type(), target.type());165Asserts.assertEQ(argsCount, target.type().parameterCount());166167Object returned;168try {169returned = target.invokeWithArguments(args);170} catch (Throwable ex) {171if (CodeCacheOverflowProcessor.isThrowableCausedByVME(ex)) {172// This error will be treated by CodeCacheOverflowProcessor173// to prevent the test from failing because of code cache overflow.174throw new Error(ex);175}176testCase.assertCatch(ex);177returned = ex;178}179180testCase.assertReturn(returned, arg0, arg1, dropped, args);181}182}183184class TestFactory {185public static final List<CatchExceptionTest> MANDATORY_TEST_CASES = new ArrayList<>();186187private static final int MIN_TESTED_ARITY = 10;188189static {190for (int[] args : new int[][]{191{0, 0},192{MIN_TESTED_ARITY, 0},193{MIN_TESTED_ARITY, MIN_TESTED_ARITY},194{CatchExceptionTest.MAX_ARITY, 0},195{CatchExceptionTest.MAX_ARITY, CatchExceptionTest.MAX_ARITY},196}) {197MANDATORY_TEST_CASES.addAll(createTests(args[0], args[1]));198}199}200201private int count;202private int args;203private int dropArgs;204private int currentMaxDrops;205private int maxArgs;206private int maxDrops;207private int constructor;208private int constructorSize;209private boolean isVararg;210211public TestFactory() {212if (Helper.IS_THOROUGH) {213maxArgs = maxDrops = CatchExceptionTest.MAX_ARITY;214} else {215maxArgs = MIN_TESTED_ARITY216+ Helper.RNG.nextInt(CatchExceptionTest.MAX_ARITY217- MIN_TESTED_ARITY)218+ 1;219maxDrops = MIN_TESTED_ARITY220+ Helper.RNG.nextInt(maxArgs - MIN_TESTED_ARITY)221+ 1;222args = 1;223}224225System.out.printf("maxArgs = %d%nmaxDrops = %d%n", maxArgs, maxDrops);226constructorSize = TestCase.CONSTRUCTORS.size();227}228229private static List<CatchExceptionTest> createTests(int argsCount,230int catchDrops) {231if (catchDrops > argsCount || argsCount < 0 || catchDrops < 0) {232throw new IllegalArgumentException("argsCount = " + argsCount233+ ", catchDrops = " + catchDrops234);235}236List<CatchExceptionTest> result = new ArrayList<>(237TestCase.CONSTRUCTORS.size());238for (Supplier<TestCase> constructor : TestCase.CONSTRUCTORS) {239result.add(new CatchExceptionTest(constructor.get(),240/* isVararg = */ true,241argsCount,242catchDrops));243result.add(new CatchExceptionTest(constructor.get(),244/* isVararg = */ false,245argsCount,246catchDrops));247}248return result;249}250251/**252* @return next test from test matrix: {varArgs, noVarArgs} x253* TestCase.rtypes x TestCase.THROWABLES x {1, .., maxArgs } x254* {0, .., maxDrops}255*/256public CatchExceptionTest nextTest() {257if (constructor < constructorSize) {258return createTest();259}260constructor = 0;261count++;262if (!Helper.IS_THOROUGH && count > Helper.TEST_LIMIT) {263System.out.println("test limit is exceeded");264return null;265}266if (dropArgs <= currentMaxDrops) {267if (dropArgs == 0) {268if (Helper.IS_THOROUGH || Helper.RNG.nextBoolean()) {269++dropArgs;270return createTest();271} else if (Helper.IS_VERBOSE) {272System.out.printf(273"argsCount=%d : \"drop\" scenarios are skipped%n",274args);275}276} else {277++dropArgs;278return createTest();279}280}281282if (args < maxArgs) {283dropArgs = 0;284currentMaxDrops = Math.min(args, maxDrops);285++args;286return createTest();287}288return null;289}290291private CatchExceptionTest createTest() {292if (!Helper.IS_THOROUGH) {293return new CatchExceptionTest(294TestCase.CONSTRUCTORS.get(constructor++).get(),295Helper.RNG.nextBoolean(), args, dropArgs);296} else {297if (isVararg) {298isVararg = false;299return new CatchExceptionTest(300TestCase.CONSTRUCTORS.get(constructor++).get(),301isVararg, args, dropArgs);302} else {303isVararg = true;304return new CatchExceptionTest(305TestCase.CONSTRUCTORS.get(constructor).get(),306isVararg, args, dropArgs);307}308}309}310}311312class TestCase<T> {313private static enum ThrowMode {314NOTHING,315CAUGHT,316UNCAUGHT,317ADAPTER318}319320@SuppressWarnings("unchecked")321public static final List<Supplier<TestCase>> CONSTRUCTORS;322private static final MethodHandle FAKE_IDENTITY;323private static final MethodHandle THROW_OR_RETURN;324private static final MethodHandle CATCHER;325326static {327try {328MethodHandles.Lookup lookup = MethodHandles.lookup();329THROW_OR_RETURN = lookup.findStatic(330TestCase.class,331"throwOrReturn",332MethodType.methodType(Object.class, Object.class,333Throwable.class)334);335CATCHER = lookup.findStatic(336TestCase.class,337"catcher",338MethodType.methodType(Object.class, Object.class));339FAKE_IDENTITY = lookup.findVirtual(340TestCase.class, "fakeIdentity",341MethodType.methodType(Object.class, Object.class));342343} catch (NoSuchMethodException | IllegalAccessException e) {344throw new Error(e);345}346PartialConstructor[] constructors = {347create(Object.class, Object.class::cast),348create(String.class, Objects::toString),349create(int[].class, x -> new int[]{Objects.hashCode(x)}),350create(long.class,351x -> Objects.hashCode(x) & (-1L >>> 32)),352create(void.class, TestCase::noop)};353Throwable[] throwables = {354new ClassCastException("testing"),355new java.io.IOException("testing"),356new LinkageError("testing")};357List<Supplier<TestCase>> list = new ArrayList<>(constructors.length *358throwables.length * ThrowMode.values().length);359//noinspection unchecked360for (PartialConstructor f : constructors) {361for (ThrowMode mode : ThrowMode.values()) {362for (Throwable t : throwables) {363list.add(f.apply(mode, t));364}365}366}367CONSTRUCTORS = Collections.unmodifiableList(list);368}369370public final Class<T> rtype;371public final ThrowMode throwMode;372public final Throwable thrown;373public final Class<? extends Throwable> throwableClass;374/**375* MH which takes 2 args (Object,Throwable), 1st is the return value,376* 2nd is the exception which will be thrown, if it's supposed in current377* {@link #throwMode}.378*/379public final MethodHandle thrower;380private final Function<Object, T> cast;381protected MethodHandle filter;382private int fakeIdentityCount;383384private TestCase(Class<T> rtype, Function<Object, T> cast,385ThrowMode throwMode, Throwable thrown)386throws NoSuchMethodException, IllegalAccessException {387this.cast = cast;388filter = MethodHandles.lookup().findVirtual(389Function.class,390"apply",391MethodType.methodType(Object.class, Object.class))392.bindTo(cast);393this.rtype = rtype;394this.throwMode = throwMode;395this.throwableClass = thrown.getClass();396switch (throwMode) {397case NOTHING:398this.thrown = null;399break;400case ADAPTER:401case UNCAUGHT:402this.thrown = new Error("do not catch this");403break;404default:405this.thrown = thrown;406}407408MethodHandle throwOrReturn = THROW_OR_RETURN;409if (throwMode == ThrowMode.ADAPTER) {410MethodHandle fakeIdentity = FAKE_IDENTITY.bindTo(this);411for (int i = 0; i < 10; ++i) {412throwOrReturn = MethodHandles.filterReturnValue(413throwOrReturn, fakeIdentity);414}415}416thrower = throwOrReturn.asType(MethodType.genericMethodType(2));417}418419private static Void noop(Object x) {420return null;421}422423private static <T2> PartialConstructor create(424Class<T2> rtype, Function<Object, T2> cast) {425return (t, u) -> () -> {426try {427return new TestCase<>(rtype, cast, t, u);428} catch (NoSuchMethodException | IllegalAccessException e) {429throw new Error(e);430}431};432}433434private static <T extends Throwable>435Object throwOrReturn(Object normal, T exception) throws T {436if (exception != null) {437Helper.called("throwOrReturn/throw", normal, exception);438throw exception;439}440Helper.called("throwOrReturn/normal", normal, exception);441return normal;442}443444private static <T extends Throwable> Object catcher(Object o) {445Helper.called("catcher", o);446return o;447}448449public MethodHandle filter(MethodHandle target) {450return MethodHandles.filterReturnValue(target, filter);451}452453public MethodHandle getCatcher(List<Class<?>> classes) {454return MethodHandles.filterReturnValue(Helper.AS_LIST.asType(455MethodType.methodType(Object.class, classes)),456CATCHER457);458}459460@Override461public String toString() {462return "TestCase{" +463"rtype=" + rtype +464", throwMode=" + throwMode +465", throwableClass=" + throwableClass +466'}';467}468469public String callName() {470return "throwOrReturn/" +471(throwMode == ThrowMode.NOTHING472? "normal"473: "throw");474}475476public void assertReturn(Object returned, Object arg0, Object arg1,477int catchDrops, Object... args) {478int lag = 0;479if (throwMode == ThrowMode.CAUGHT) {480lag = 1;481}482Helper.assertCalled(lag, callName(), arg0, arg1);483484if (throwMode == ThrowMode.NOTHING) {485assertEQ(cast.apply(arg0), returned);486} else if (throwMode == ThrowMode.CAUGHT) {487List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));488// catcher receives an initial subsequence of target arguments:489catchArgs.subList(args.length - catchDrops, args.length).clear();490// catcher also receives the exception, prepended:491catchArgs.add(0, thrown);492Helper.assertCalled("catcher", catchArgs);493assertEQ(cast.apply(catchArgs), returned);494}495Asserts.assertEQ(0, fakeIdentityCount);496}497498private void assertEQ(T t, Object returned) {499if (rtype.isArray()) {500Asserts.assertEQ(t.getClass(), returned.getClass());501int n = Array.getLength(t);502Asserts.assertEQ(n, Array.getLength(returned));503for (int i = 0; i < n; ++i) {504Asserts.assertEQ(Array.get(t, i), Array.get(returned, i));505}506} else {507Asserts.assertEQ(t, returned);508}509}510511private Object fakeIdentity(Object x) {512System.out.println("should throw through this!");513++fakeIdentityCount;514return x;515}516517public void assertCatch(Throwable ex) {518try {519Asserts.assertSame(thrown, ex,520"must get the out-of-band exception");521} catch (Throwable t) {522ex.printStackTrace();523}524}525526public interface PartialConstructor527extends BiFunction<ThrowMode, Throwable, Supplier<TestCase>> {528}529}530531532