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 }