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 /* 25 * @test 26 * @bug 8200261 27 * @summary Tests an anonymous class that implements interfaces with default methods. 28 * @library /testlibrary 29 * @modules java.base/jdk.internal.org.objectweb.asm 30 * java.management 31 * @compile -XDignore.symbol.file=true UnsafeDefMeths.java 32 * @run main UnsafeDefMeths 33 */ 34 35 import jdk.internal.org.objectweb.asm.ClassWriter; 36 import jdk.internal.org.objectweb.asm.MethodVisitor; 37 import jdk.internal.org.objectweb.asm.Type; 38 import sun.misc.Unsafe; 39 40 import java.lang.invoke.MethodType; 41 import java.lang.reflect.Field; 42 import java.lang.reflect.Method; 43 import java.util.stream.Collectors; 44 import java.util.stream.Stream; 45 46 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; 47 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 48 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; 49 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 50 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 51 import static jdk.internal.org.objectweb.asm.Opcodes.DUP; 52 import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD; 53 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; 54 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; 55 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 56 import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; 57 58 public class UnsafeDefMeths { 59 60 static final Unsafe UNSAFE; 61 62 static { 63 try { 64 Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 65 unsafeField.setAccessible(true); 66 UNSAFE = (Unsafe) unsafeField.get(null); 67 } 68 catch (Exception e) { 69 throw new InternalError(e); 70 } 71 } 72 73 interface Resource { 74 Pointer ptr(); 75 } 76 77 interface Struct extends Resource { 78 StructPointer ptr(); 79 } 80 81 interface Pointer { } 82 83 interface StructPointer extends Pointer { } 84 85 interface I extends Struct { 86 void m(); 87 } 88 89 static String IMPL_PREFIX = "$$impl"; 90 static String PTR_FIELD_NAME = "ptr"; 91 92 public static void main(String[] args) throws Throwable { 93 byte[] bytes = new UnsafeDefMeths().generate(I.class); 94 Class<?> cl = UNSAFE.defineAnonymousClass(I.class, bytes, new Object[0]); 95 I i = (I)cl.getConstructors()[0].newInstance(new Object[] { null }); //exception here! 96 } 97 98 // Generate a class similar to: 99 // 100 // public class UnsafeDefMeths$I$$impl implements UnsafeDefMeths$I, UnsafeDefMeths$Struct { 101 // 102 // public UnsafeDefMeths$StructPointer ptr; 103 // 104 // public UnsafeDefMeths$I$$impl(UnsafeDefMeths$StructPointer p) { 105 // ptr = p; 106 // } 107 // 108 // public UnsafeDefMeths$StructPointer ptr() { 109 // return ptr; 110 // } 111 // } 112 // 113 byte[] generate(Class<?> iface) { 114 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 115 116 String ifaceTypeName = Type.getInternalName(iface); 117 String proxyClassName = ifaceTypeName + IMPL_PREFIX; 118 // class definition 119 cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, proxyClassName, 120 desc(Object.class) + desc(ifaceTypeName) + desc(Struct.class), 121 name(Object.class), 122 new String[] { ifaceTypeName, name(Struct.class) }); 123 124 cw.visitField(ACC_PUBLIC, PTR_FIELD_NAME, desc(StructPointer.class), desc(StructPointer.class), null); 125 cw.visitEnd(); 126 127 // constructor 128 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", 129 meth(desc(void.class), desc(StructPointer.class)), 130 meth(desc(void.class), desc(StructPointer.class)), null); 131 mv.visitCode(); 132 mv.visitVarInsn(ALOAD, 0); 133 mv.visitInsn(DUP); 134 mv.visitMethodInsn(INVOKESPECIAL, name(Object.class), "<init>", meth(desc(void.class)), false); 135 mv.visitVarInsn(ALOAD, 1); 136 mv.visitFieldInsn(PUTFIELD, proxyClassName, PTR_FIELD_NAME, desc(StructPointer.class)); 137 mv.visitInsn(RETURN); 138 mv.visitMaxs(0, 0); 139 mv.visitEnd(); 140 141 // ptr() impl 142 mv = cw.visitMethod(ACC_PUBLIC, PTR_FIELD_NAME, meth(desc(StructPointer.class)), 143 meth(desc(StructPointer.class)), null); 144 mv.visitCode(); 145 mv.visitVarInsn(ALOAD, 0); 146 mv.visitFieldInsn(GETFIELD, proxyClassName, PTR_FIELD_NAME, desc(StructPointer.class)); 147 mv.visitInsn(ARETURN); 148 mv.visitMaxs(0, 0); 149 mv.visitEnd(); 150 151 return cw.toByteArray(); 152 } 153 154 String name(Class<?> clazz) { 155 if (clazz.isPrimitive()) { 156 throw new IllegalStateException(); 157 } else if (clazz.isArray()) { 158 return desc(clazz); 159 } else { 160 return clazz.getName().replaceAll("\\.", "/"); 161 } 162 } 163 164 String desc(Class<?> clazz) { 165 String mdesc = MethodType.methodType(clazz).toMethodDescriptorString(); 166 return mdesc.substring(mdesc.indexOf(')') + 1); 167 } 168 169 String desc(String clazzName) { 170 return "L" + clazzName + ";"; 171 } 172 173 String gen(String clazz, String... typeargs) { 174 return clazz.substring(0, clazz.length() - 1) + Stream.of(typeargs).collect(Collectors.joining("", "<", ">")) + ";"; 175 } 176 177 String meth(String restype, String... argtypes) { 178 return Stream.of(argtypes).collect(Collectors.joining("", "(", ")")) + restype; 179 } 180 181 String meth(Method m) { 182 return MethodType.methodType(m.getReturnType(), m.getParameterTypes()).toMethodDescriptorString(); 183 } 184 }