1 /* 2 * Copyright (c) 2014, 2016, 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 * @bug 8046903 26 * @summary VM anonymous class members can't be statically invocable 27 * @modules java.base/jdk.internal.misc java.base/jdk.internal.org.objectweb.asm 28 * @run junit test.java.lang.invoke.VMAnonymousClass 29 */ 30 package test.java.lang.invoke; 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.MethodType; 35 import org.junit.Test; 36 import jdk.internal.misc.Unsafe; 37 import jdk.internal.org.objectweb.asm.*; 38 import static jdk.internal.org.objectweb.asm.Opcodes.*; 39 40 public class VMAnonymousClass { main(String[] args)41 public static void main(String[] args) throws Throwable { 42 VMAnonymousClass test = new VMAnonymousClass(); 43 test.testJavaLang(); 44 test.testJavaUtil(); 45 test.testJdkInternalMisc(); 46 test.testJavaLangInvoke(); 47 test.testProhibitedJavaPkg(); 48 System.out.println("TEST PASSED"); 49 } 50 51 // Test VM anonymous classes from different packages 52 // (see j.l.i.InvokerBytecodeGenerator::isStaticallyInvocable). testJavaLang()53 @Test public void testJavaLang() throws Throwable { test("java/lang"); } testJavaUtil()54 @Test public void testJavaUtil() throws Throwable { test("java/util"); } testJdkInternalMisc()55 @Test public void testJdkInternalMisc() throws Throwable { test("jdk/internal/misc"); } testJavaLangInvoke()56 @Test public void testJavaLangInvoke() throws Throwable { test("java/lang/invoke"); } testProhibitedJavaPkg()57 @Test public void testProhibitedJavaPkg() throws Throwable { 58 try { 59 test("java/prohibited"); 60 } catch (IllegalArgumentException e) { 61 return; 62 } 63 throw new RuntimeException("Expected SecurityException"); 64 } 65 66 private static Unsafe unsafe = Unsafe.getUnsafe(); 67 test(String pkg)68 private static void test(String pkg) throws Throwable { 69 byte[] bytes = dumpClass(pkg); 70 Class host_class; 71 if (pkg.equals("java/prohibited")) { 72 VMAnonymousClass sampleclass = new VMAnonymousClass(); 73 host_class = (Class)sampleclass.getClass(); 74 } else if (pkg.equals("java/lang")) { 75 host_class = Object.class; 76 } else if (pkg.equals("java/util")) { 77 host_class = java.util.ArrayList.class; 78 } else if (pkg.equals("jdk/internal/misc")) { 79 host_class = jdk.internal.misc.Signal.class; 80 } else if (pkg.equals("java/lang/invoke")) { 81 host_class = java.lang.invoke.CallSite.class; 82 } else { 83 throw new RuntimeException("Unexpected pkg: " + pkg); 84 } 85 // Define VM anonymous class 86 Class anonClass = unsafe.defineAnonymousClass(host_class, bytes, null); 87 88 MethodType t = MethodType.methodType(Object.class, int.class); 89 MethodHandle target = MethodHandles.lookup().findStatic(anonClass, "get", t); 90 91 // Wrap target into LF (convert) to get "target" referenced from LF 92 MethodHandle wrappedMH = target.asType(MethodType.methodType(Object.class, Integer.class)); 93 94 // Invoke enough times to provoke LF compilation to bytecode. 95 for (int i = 0; i<100; i++) { 96 Object r = wrappedMH.invokeExact((Integer)1); 97 } 98 } 99 100 /* 101 * Constructs bytecode for the following class: 102 * public class pkg.MyClass { 103 * MyClass() {} 104 * public Object get(int i) { return null; } 105 * } 106 */ dumpClass(String pkg)107 public static byte[] dumpClass(String pkg) { 108 ClassWriter cw = new ClassWriter(0); 109 MethodVisitor mv; 110 111 cw.visit(52, ACC_SUPER | ACC_PUBLIC, pkg+"/MyClass", null, "java/lang/Object", null); 112 { 113 mv = cw.visitMethod(0, "<init>", "()V", null, null); 114 mv.visitCode(); 115 mv.visitVarInsn(ALOAD, 0); 116 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 117 mv.visitInsn(RETURN); 118 mv.visitMaxs(1, 1); 119 mv.visitEnd(); 120 } 121 { 122 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "get", "(I)Ljava/lang/Object;", null, null); 123 mv.visitCode(); 124 mv.visitInsn(ACONST_NULL); 125 mv.visitInsn(ARETURN); 126 mv.visitMaxs(1, 1); 127 mv.visitEnd(); 128 } 129 cw.visitEnd(); 130 return cw.toByteArray(); 131 } 132 } 133