1 /*
  2  * Copyright (c) 2017, 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
 26  * @bug 8186046
 27  * @summary Test bootstrap methods throwing an exception
 28  * @library /java/lang/invoke/common
 29  * @build test.java.lang.invoke.lib.InstructionHelper
 30  * @enablePreview
 31  * @run testng CondyBSMException
 32  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMException
 33  */
 34 
 35 import org.testng.Assert;
 36 import org.testng.annotations.Test;
 37 import test.java.lang.invoke.lib.InstructionHelper;
 38 
 39 import java.lang.invoke.MethodHandle;
 40 import java.lang.invoke.MethodHandles;
 41 import java.lang.reflect.Constructor;
 42 
 43 import static java.lang.invoke.MethodType.methodType;
 44 
 45 public class CondyBSMException {
 46 
 47     @Test
 48     public void testThrowable() {
 49         test("Throwable", BootstrapMethodError.class, Throwable.class);
 50     }
 51 
 52     @Test
 53     public void testError() {
 54         test("Error", Error.class);
 55     }
 56 
 57     @Test
 58     public void testBootstrapMethodError() {
 59         test("BootstrapMethodError", BootstrapMethodError.class);
 60     }
 61 
 62     @Test
 63     public void testRuntimeException() {
 64         test("RuntimeException", BootstrapMethodError.class, RuntimeException.class);
 65     }
 66 
 67     @Test
 68     public void testException() {
 69         test("Exception", BootstrapMethodError.class, Exception.class);
 70     }
 71 
 72     static void test(String message, Class<? extends Throwable>... ts) {
 73         MethodHandle mh = thrower(message, ts[ts.length - 1]);
 74         Throwable caught = null;
 75         try {
 76             mh.invoke();
 77         } catch (Throwable t) {
 78             caught = t;
 79         }
 80 
 81         if (caught == null) {
 82             Assert.fail("Throwable expected");
 83         }
 84 
 85         String actualMessage = null;
 86         for (int i = 0; i < ts.length; i++) {
 87             actualMessage = caught.getMessage();
 88             Assert.assertNotNull(caught);
 89             Assert.assertTrue(ts[i].isAssignableFrom(caught.getClass()));
 90             caught = caught.getCause();
 91         }
 92 
 93         Assert.assertEquals(actualMessage, message);
 94     }
 95 
 96     static Throwable throwingBsm(MethodHandles.Lookup l, String name, Class<Throwable> type) throws Throwable {
 97         Throwable t;
 98         try {
 99             Constructor<Throwable> c = type.getDeclaredConstructor(String.class);
100             t = c.newInstance(name);
101         } catch (Exception e) {
102             throw new InternalError();
103         }
104         throw t;
105     }
106 
107     static MethodHandle thrower(String message, Class<? extends Throwable> t) {
108         try {
109             return InstructionHelper.ldcDynamicConstant(
110                     MethodHandles.lookup(),
111                     message, t,
112                     "throwingBsm",
113                     methodType(Throwable.class, MethodHandles.Lookup.class, String.class, Class.class)
114             );
115         } catch (Exception e) {
116             throw new Error(e);
117         }
118     }
119 }