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