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 jdk.experimental.bytecode.BasicClassBuilder;
  27 import jdk.experimental.bytecode.BasicTypeHelper;
  28 import jdk.experimental.bytecode.Flag;
  29 import jdk.experimental.bytecode.PoolHelper;
  30 import jdk.experimental.bytecode.TypedCodeBuilder;
  31 
  32 import java.io.FileOutputStream;
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import java.util.concurrent.atomic.AtomicInteger;
  37 import java.util.function.Consumer;
  38 import java.util.function.Function;
  39 
  40 import static java.lang.invoke.MethodType.fromMethodDescriptorString;
  41 import static java.lang.invoke.MethodType.methodType;
  42 
  43 public class InstructionHelper {
  44 
  45     static final BasicTypeHelper BTH = new BasicTypeHelper();
  46 
  47     static final AtomicInteger COUNT = new AtomicInteger();
  48 
  49     static BasicClassBuilder classBuilder(MethodHandles.Lookup l) {
  50         String className = l.lookupClass().getCanonicalName().replace('.', '/') + "$Code_" + COUNT.getAndIncrement();
  51         return new BasicClassBuilder(className, 53, 0)
  52                 .withSuperclass("java/lang/Object")
  53                 .withMethod("<init>", "()V", M ->
  54                         M.withFlags(Flag.ACC_PUBLIC)
  55                                 .withCode(TypedCodeBuilder::new, C ->
  56                                         C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
  57                                 ));
  58     }
  59 
  60     public static MethodHandle invokedynamic(MethodHandles.Lookup l,
  61                                       String name, MethodType type,
  62                                       String bsmMethodName, MethodType bsmType,
  63                                       Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
  64         byte[] byteArray = classBuilder(l)
  65                 .withMethod("m", type.toMethodDescriptorString(), M ->
  66                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
  67                                 .withCode(TypedCodeBuilder::new,
  68                                           C -> {
  69                                               for (int i = 0; i < type.parameterCount(); i++) {
  70                                                   C.load(BTH.tag(cref(type.parameterType(i))), i);
  71                                               }
  72                                               C.invokedynamic(name, type.toMethodDescriptorString(),
  73                                                               csym(l.lookupClass()), bsmMethodName, bsmType.toMethodDescriptorString(),
  74                                                               staticArgs);
  75                                               C.return_(BTH.tag(cref(type.returnType())));
  76                                           }
  77                                 ))
  78                 .build();
  79         Class<?> gc = l.defineClass(byteArray);
  80         return l.findStatic(gc, "m", type);
  81     }
  82 
  83     public static MethodHandle ldcMethodHandle(MethodHandles.Lookup l,
  84                                         int refKind, Class<?> owner, String name, MethodType type) throws Exception {
  85         return ldc(l, MethodHandle.class,
  86                    P -> P.putHandle(refKind, csym(owner), name, type.toMethodDescriptorString()));
  87     }
  88 
  89     public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l,
  90                                                   String name, Class<?> type,
  91                                                   String bsmMethodName, MethodType bsmType,
  92                                                   Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
  93         return ldcDynamicConstant(l, name, cref(type), bsmMethodName, bsmType.toMethodDescriptorString(), staticArgs);
  94     }
  95 
  96     public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l,
  97                                                   String name, String type,
  98                                                   String bsmMethodName, String bsmType,
  99                                                   Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
 100         return ldc(l, type,
 101                    P -> P.putDynamicConstant(name, type,
 102                                              csym(l.lookupClass()), bsmMethodName, bsmType,
 103                                              staticArgs));
 104     }
 105 
 106     public static MethodHandle ldc(MethodHandles.Lookup l,
 107                             Class<?> type,
 108                             Function<PoolHelper<String, String, byte[]>, Integer> poolFunc) throws Exception {
 109         return ldc(l, cref(type), poolFunc);
 110     }
 111 
 112     public static MethodHandle ldc(MethodHandles.Lookup l,
 113                                    String type,
 114                                    Function<PoolHelper<String, String, byte[]>, Integer> poolFunc) throws Exception {
 115         String methodType = "()" + type;
 116         byte[] byteArray = classBuilder(l)
 117                 .withMethod("m", "()" + type, M ->
 118                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
 119                                 .withCode(TypedCodeBuilder::new,
 120                                           C -> {
 121                                               C.ldc(null, (P, v) -> poolFunc.apply(P));
 122                                               C.return_(BTH.tag(type));
 123                                           }
 124                                 ))
 125                 .build();
 126         Class<?> gc = l.defineClass(byteArray);
 127         return l.findStatic(gc, "m", fromMethodDescriptorString(methodType, l.lookupClass().getClassLoader()));
 128     }
 129 
 130     public static String csym(Class<?> c) {
 131         return c.getCanonicalName().replace('.', '/');
 132     }
 133 
 134     public static String cref(Class<?> c) {
 135         return methodType(c).toMethodDescriptorString().substring(2);
 136     }
 137 }