1 /* 2 * Copyright (c) 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 /* @test 25 * @summary unit tests for java.lang.invoke.MethodHandles 26 * @library /test/lib /java/lang/invoke/common 27 * @compile MethodHandlesTest.java MethodHandlesCastFailureTest.java remote/RemoteExample.java 28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions 29 * -XX:-VerifyDependencies 30 * -esa 31 * test.java.lang.invoke.MethodHandlesCastFailureTest 32 */ 33 34 package test.java.lang.invoke; 35 36 import org.junit.*; 37 import test.java.lang.invoke.lib.CodeCacheOverflowProcessor; 38 39 import java.lang.invoke.MethodHandle; 40 import java.lang.invoke.MethodHandles; 41 import java.lang.invoke.MethodType; 42 43 import static org.junit.Assert.*; 44 45 public class MethodHandlesCastFailureTest extends MethodHandlesTest { 46 47 @Test // SLOW testCastFailure()48 public void testCastFailure() throws Throwable { 49 CodeCacheOverflowProcessor.runMHTest(this::testCastFailure0); 50 } 51 testCastFailure0()52 public void testCastFailure0() throws Throwable { 53 if (CAN_SKIP_WORKING) return; 54 startTest("testCastFailure"); 55 testCastFailure("cast/argument", 11000); 56 if (CAN_TEST_LIGHTLY) return; 57 testCastFailure("unbox/argument", 11000); 58 testCastFailure("cast/return", 11000); 59 testCastFailure("unbox/return", 11000); 60 } 61 62 static class Surprise { asMethodHandle()63 public MethodHandle asMethodHandle() { 64 return VALUE.bindTo(this); 65 } value(Object x)66 Object value(Object x) { 67 trace("value", x); 68 if (boo != null) return boo; 69 return x; 70 } 71 Object boo; boo(Object x)72 void boo(Object x) { boo = x; } 73 trace(String x, Object y)74 static void trace(String x, Object y) { 75 if (verbosity > 8) System.out.println(x+"="+y); 76 } refIdentity(Object x)77 static Object refIdentity(Object x) { trace("ref.x", x); return x; } boxIdentity(Integer x)78 static Integer boxIdentity(Integer x) { trace("box.x", x); return x; } intIdentity(int x)79 static int intIdentity(int x) { trace("int.x", x); return x; } 80 static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY; 81 static { 82 try { 83 VALUE = PRIVATE.findVirtual( 84 Surprise.class, "value", 85 MethodType.methodType(Object.class, Object.class)); 86 REF_IDENTITY = PRIVATE.findStatic( 87 Surprise.class, "refIdentity", 88 MethodType.methodType(Object.class, Object.class)); 89 BOX_IDENTITY = PRIVATE.findStatic( 90 Surprise.class, "boxIdentity", 91 MethodType.methodType(Integer.class, Integer.class)); 92 INT_IDENTITY = PRIVATE.findStatic( 93 Surprise.class, "intIdentity", 94 MethodType.methodType(int.class, int.class)); 95 } catch (NoSuchMethodException | IllegalAccessException ex) { 96 throw new RuntimeException(ex); 97 } 98 } 99 } 100 101 @SuppressWarnings("ConvertToStringSwitch") testCastFailure(String mode, int okCount)102 void testCastFailure(String mode, int okCount) throws Throwable { 103 countTest(false); 104 if (verbosity > 2) System.out.println("mode="+mode); 105 Surprise boo = new Surprise(); 106 MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0; 107 if (mode.endsWith("/return")) { 108 if (mode.equals("unbox/return")) { 109 // fail on return to ((Integer)surprise).intValue 110 surprise = surprise.asType(MethodType.methodType(int.class, Object.class)); 111 identity = identity.asType(MethodType.methodType(int.class, Object.class)); 112 } else if (mode.equals("cast/return")) { 113 // fail on return to (Integer)surprise 114 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class)); 115 identity = identity.asType(MethodType.methodType(Integer.class, Object.class)); 116 } 117 } else if (mode.endsWith("/argument")) { 118 MethodHandle callee = null; 119 if (mode.equals("unbox/argument")) { 120 // fail on handing surprise to int argument 121 callee = Surprise.INT_IDENTITY; 122 } else if (mode.equals("cast/argument")) { 123 // fail on handing surprise to Integer argument 124 callee = Surprise.BOX_IDENTITY; 125 } 126 if (callee != null) { 127 callee = callee.asType(MethodType.genericMethodType(1)); 128 surprise = MethodHandles.filterArguments(callee, 0, surprise); 129 identity = MethodHandles.filterArguments(callee, 0, identity); 130 } 131 } 132 assertNotSame(mode, surprise, surprise0); 133 identity = identity.asType(MethodType.genericMethodType(1)); 134 surprise = surprise.asType(MethodType.genericMethodType(1)); 135 Object x = 42; 136 for (int i = 0; i < okCount; i++) { 137 Object y = identity.invokeExact(x); 138 assertEquals(x, y); 139 Object z = surprise.invokeExact(x); 140 assertEquals(x, z); 141 } 142 boo.boo("Boo!"); 143 Object y = identity.invokeExact(x); 144 assertEquals(x, y); 145 try { 146 Object z = surprise.invokeExact(x); 147 System.out.println("Failed to throw; got z="+z); 148 assertTrue(false); 149 } catch (ClassCastException ex) { 150 if (verbosity > 2) 151 System.out.println("caught "+ex); 152 if (verbosity > 3) 153 ex.printStackTrace(System.out); 154 assertTrue(true); // all is well 155 } 156 } 157 } 158