1 /* 2 * Copyright (c) 2010, 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 package test.java.lang.invoke.lib; 25 26 import java.lang.constant.ClassDesc; 27 import java.lang.constant.ConstantDesc; 28 import java.lang.constant.ConstantDescs; 29 import java.lang.constant.DirectMethodHandleDesc; 30 import java.lang.constant.DynamicCallSiteDesc; 31 import java.lang.constant.DynamicConstantDesc; 32 import java.lang.constant.MethodHandleDesc; 33 import java.lang.constant.MethodTypeDesc; 34 import java.lang.invoke.MethodHandle; 35 import java.lang.invoke.MethodHandles; 36 import java.lang.invoke.MethodType; 37 import static java.lang.invoke.MethodType.fromMethodDescriptorString; 38 import java.util.concurrent.atomic.AtomicInteger; 39 import java.util.function.Consumer; 40 41 import jdk.internal.classfile.ClassBuilder; 42 import jdk.internal.classfile.Classfile; 43 import jdk.internal.classfile.CodeBuilder; 44 import jdk.internal.classfile.TypeKind; 45 46 public class InstructionHelper { 47 48 static final AtomicInteger COUNT = new AtomicInteger(); 49 50 private static void commonBuild(ClassBuilder classBuilder) { 51 classBuilder 52 .withVersion(55, 0) 53 .withSuperclass(ConstantDescs.CD_Object) 54 .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC, 55 methodBuilder -> methodBuilder 56 .withCode(codeBuilder -> codeBuilder 57 .aload(0) 58 .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, 59 ConstantDescs.MTD_void, false) 60 .return_())); 61 } 62 63 public static MethodHandle invokedynamic(MethodHandles.Lookup l, String name, MethodType type, String bsmMethodName, 64 MethodType bsmType, ConstantDesc... boostrapArgs) throws Exception { 65 ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement()); 66 byte[] byteArray = Classfile.of().build(genClassDesc, classBuilder -> { 67 commonBuild(classBuilder); 68 classBuilder 69 .withMethod("m", MethodTypeDesc.ofDescriptor(type.toMethodDescriptorString()), 70 Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder 71 .withCode(codeBuilder -> { 72 for (int i = 0; i < type.parameterCount(); i++) { 73 codeBuilder.loadInstruction(TypeKind.from(type.parameterType(i)), i); 74 } 75 codeBuilder.invokedynamic(DynamicCallSiteDesc.of( 76 MethodHandleDesc.ofMethod( 77 DirectMethodHandleDesc.Kind.STATIC, 78 classDesc(l.lookupClass()), 79 bsmMethodName, 80 MethodTypeDesc.ofDescriptor( 81 bsmType.toMethodDescriptorString())), 82 name, 83 MethodTypeDesc.ofDescriptor(type.toMethodDescriptorString()), 84 boostrapArgs)); 85 codeBuilder.returnInstruction(TypeKind.from(type.returnType())); 86 })); 87 }); 88 Class<?> gc = l.defineClass(byteArray); 89 return l.findStatic(gc, "m", type); 90 } 91 92 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, Class<?> type, String bsmMethodName, 93 MethodType bsmType, ConstantDesc... bootstrapArgs) throws Exception { 94 return ldcDynamicConstant(l, name, type, l.lookupClass(), bsmMethodName, bsmType, bootstrapArgs); 95 } 96 97 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, Class<?> type, Class<?> bsmClass, 98 String bsmMethodName, MethodType bsmType, ConstantDesc... bootstrapArgs) throws Exception { 99 return ldcDynamicConstant(l, name, type.descriptorString(), bsmClass.descriptorString(), bsmMethodName, 100 bsmType.descriptorString(), bootstrapArgs); 101 } 102 103 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, String type, String bsmMethodName, 104 String bsmType, ConstantDesc... bootstrapArgs) throws Exception { 105 return ldcDynamicConstant(l, name, type, l.lookupClass().descriptorString(), bsmMethodName, bsmType, bootstrapArgs); 106 } 107 108 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, String type, String bsmClass, 109 String bsmMethodName, String bsmType, ConstantDesc... bootstrapArgs) 110 throws IllegalAccessException, NoSuchMethodException { 111 String methodType = "()" + type; 112 ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement()); 113 byte[] bytes = Classfile.of().build(genClassDesc, classBuilder -> { 114 commonBuild(classBuilder); 115 classBuilder.withMethod("m", MethodTypeDesc.of(ClassDesc.ofDescriptor(type)), 116 Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder 117 .withCode(codeBuilder -> codeBuilder 118 .ldc(DynamicConstantDesc.ofNamed( 119 MethodHandleDesc.ofMethod( 120 DirectMethodHandleDesc.Kind.STATIC, 121 ClassDesc.ofDescriptor(bsmClass), 122 bsmMethodName, 123 MethodTypeDesc.ofDescriptor(bsmType)), 124 name, 125 ClassDesc.ofDescriptor(type), 126 bootstrapArgs)) 127 .returnInstruction(TypeKind.fromDescriptor(type)))); 128 }); 129 Class<?> gc = l.defineClass(bytes); 130 return l.findStatic(gc, "m", fromMethodDescriptorString(methodType, l.lookupClass().getClassLoader())); 131 } 132 133 public static String csym(Class<?> c) { 134 return c.getCanonicalName().replace('.', '/'); 135 } 136 137 public static ClassDesc classDesc(Class<?> c) { 138 return ClassDesc.ofDescriptor(c.descriptorString()); 139 } 140 141 public static ClassDesc classDesc(Class<?> c, String suffix) { 142 StringBuilder sb = new StringBuilder(c.descriptorString()); 143 String classDescStr = sb.insert(sb.length() - 1, suffix).toString(); 144 return ClassDesc.ofDescriptor(classDescStr); 145 } 146 147 148 public static MethodHandle buildMethodHandle(MethodHandles.Lookup l, String methodName, MethodType methodType, Consumer<? super CodeBuilder> builder) { 149 ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement()); 150 return buildMethodHandle(l, genClassDesc, methodName, methodType, builder); 151 } 152 153 public static MethodHandle buildMethodHandle(MethodHandles.Lookup l, ClassDesc classDesc, String methodName, MethodType methodType, Consumer<? super CodeBuilder> builder) { 154 try { 155 byte[] bytes = Classfile.of().build(classDesc, classBuilder -> { 156 classBuilder.withMethod(methodName, 157 MethodTypeDesc.ofDescriptor(methodType.toMethodDescriptorString()), 158 Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, 159 methodBuilder -> methodBuilder.withCode(builder)); 160 }); 161 Class<?> clazz = l.defineClass(bytes); 162 return l.findStatic(clazz, methodName, methodType); 163 } catch (Throwable t) { 164 t.printStackTrace(); 165 throw new RuntimeException("Failed to buildMethodHandle: " + methodName + " type " + methodType); 166 } 167 } 168 169 }