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