1 /*
   2  * Copyright (c) 2016, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.experimental.value;
  27 
  28 import jdk.experimental.bytecode.BasicClassBuilder.BasicPoolHelper;
  29 import jdk.experimental.bytecode.BasicClassBuilder.BasicTypeHelper;
  30 import jdk.experimental.bytecode.ClassBuilder;
  31 import jdk.experimental.bytecode.Flag;
  32 import jdk.experimental.bytecode.PoolHelper;
  33 import jdk.experimental.bytecode.TypeHelper;
  34 import jdk.experimental.bytecode.TypeTag;
  35 import jdk.experimental.bytecode.TypedCodeBuilder;
  36 import jdk.internal.misc.Unsafe;
  37 import sun.security.action.GetPropertyAction;
  38 import valhalla.shady.MinimalValueTypes_1_0;
  39 
  40 import java.lang.invoke.MethodHandle;
  41 import java.lang.invoke.MethodHandles.Lookup;
  42 import java.lang.invoke.MethodType;
  43 import java.lang.invoke.ProxyClassesDumper;
  44 import java.security.AccessController;
  45 import java.util.Iterator;
  46 import java.util.PropertyPermission;
  47 import java.util.function.Consumer;
  48 
  49 /**
  50  * Utility class for building method handles.
  51  */
  52 public class MethodHandleBuilder {
  53 
  54     static final Unsafe UNSAFE = Unsafe.getUnsafe();
  55 
  56     public static MethodHandle loadCode(Lookup lookup, String name, MethodType type, Consumer<? super TypedCodeBuilder<Class<?>, String, byte[], ?>> builder) {
  57             return loadCode(lookup, name, type.toMethodDescriptorString(), builder);
  58     }
  59 
  60     public static MethodHandle loadCode(Lookup lookup, String name, String type, Consumer<? super TypedCodeBuilder<Class<?>, String, byte[], ?>> builder) {
  61         IsolatedMethodBuilder isolatedMethodBuilder = new IsolatedMethodBuilder();
  62         isolatedMethodBuilder
  63                 .withSuperclass(Object.class)
  64                 .withMajorVersion(52)
  65                 .withMinorVersion(0)
  66                 .withFlags(Flag.ACC_PUBLIC)
  67                 .withMethod(name, type, M ->
  68                     M.withFlags(Flag.ACC_STATIC, Flag.ACC_PUBLIC)
  69                      .withCode(TypedCodeBuilder::new, builder));
  70 
  71         try {
  72             byte[] barr = isolatedMethodBuilder.build();
  73             ProxyClassesDumper dumper = dumper();
  74             if (dumper != null) {
  75                 dumper.dumpClass(name, barr.clone());
  76             }
  77             Class<?> clazz = UNSAFE.defineAnonymousClass(lookup.lookupClass(), barr, null);
  78             return lookup.findStatic(clazz, name, MethodType.fromMethodDescriptorString(type, lookup.lookupClass().getClassLoader()));
  79         } catch (ReflectiveOperationException e) {
  80             throw new IllegalStateException(e);
  81         }
  82     }
  83 
  84     static class IsolatedMethodBuilder extends ClassBuilder<Class<?>, String, IsolatedMethodBuilder> {
  85 
  86         IsolatedMethodBuilder() {
  87             super(new IsolatedMethodPoolHelper(), new IsolatedMethodTypeHelper());
  88             withThisClass(new Object() { }.getClass());
  89         }
  90 
  91         static class IsolatedMethodTypeHelper implements TypeHelper<Class<?>, String> {
  92 
  93             BasicTypeHelper basicTypeHelper = new BasicTypeHelper();
  94 
  95             @Override
  96             public String elemtype(String s) {
  97                 return basicTypeHelper.elemtype(s);
  98             }
  99 
 100             @Override
 101             public String arrayOf(String s) {
 102                 return basicTypeHelper.arrayOf(s);
 103             }
 104 
 105             @Override
 106             public Iterator<String> parameterTypes(String s) {
 107                 return basicTypeHelper.parameterTypes(s);
 108             }
 109 
 110             @Override
 111             public String fromTag(TypeTag tag) {
 112                 return basicTypeHelper.fromTag(tag);
 113             }
 114 
 115             @Override
 116             public String returnType(String s) {
 117                 return basicTypeHelper.returnType(s);
 118             }
 119 
 120             @Override
 121             public String type(Class<?> aClass) {
 122                 if (aClass.isArray()) {
 123                     return aClass.getName().replaceAll("\\.", "/");
 124                 } else {
 125                     return MinimalValueTypes_1_0.isValueType(aClass) ?
 126                             "Q" + aClass.getName().replaceAll("\\.", "/") + ";" :
 127                             "L" + aClass.getName().replaceAll("\\.", "/") + ";";
 128                 }
 129             }
 130 
 131             @Override
 132             public Class<?> symbol(String type) {
 133                 try {
 134                     return basicTypeHelper.from(type);
 135                 } catch (ReflectiveOperationException ex) {
 136                     throw new AssertionError(ex);
 137                 }
 138             }
 139 
 140             @Override
 141             public TypeTag tag(String s) {
 142                 return basicTypeHelper.tag(s);
 143             }
 144 
 145             @Override
 146             public Class<?> symbolFrom(String s) {
 147                 return symbol(s);
 148             }
 149 
 150             @Override
 151             public String commonSupertype(String t1, String t2) {
 152                 return basicTypeHelper.commonSupertype(t1, t2);
 153             }
 154 
 155             @Override
 156             public String nullType() {
 157                 return basicTypeHelper.nullType();
 158             }
 159         }
 160 
 161         static class IsolatedMethodPoolHelper implements PoolHelper<Class<?>, String, byte[]> {
 162             BasicPoolHelper basicPoolHelper = new BasicPoolHelper();
 163 
 164             String from(Class<?> c) {
 165                 return c.getName().replaceAll("\\.", "/");
 166             }
 167 
 168             @Override
 169             public int putClass(Class<?> symbol) {
 170                 return basicPoolHelper.putClass(from(symbol));
 171             }
 172 
 173             @Override
 174             public int putFieldRef(Class<?> owner, CharSequence name, String type) {
 175                 return basicPoolHelper.putFieldRef(from(owner), name, type);
 176             }
 177 
 178             @Override
 179             public int putMethodRef(Class<?> owner, CharSequence name, String type, boolean isInterface) {
 180                 return basicPoolHelper.putMethodRef(from(owner), name, type, isInterface);
 181             }
 182 
 183             @Override
 184             public int putUtf8(CharSequence s) {
 185                 return basicPoolHelper.putUtf8(s);
 186             }
 187 
 188             @Override
 189             public int putType(String s) {
 190                 return basicPoolHelper.putType(s);
 191             }
 192 
 193             @Override
 194             public int putValue(Object v) {
 195                 return basicPoolHelper.putValue(v);
 196             }
 197 
 198             @Override
 199             public int putMethodType(String s) {
 200                 return basicPoolHelper.putMethodType(s);
 201             }
 202 
 203             @Override
 204             public int putHandle(int refKind, Class<?> owner, CharSequence name, String type) {
 205                 return basicPoolHelper.putHandle(refKind, from(owner), name, type);
 206             }
 207 
 208             @Override
 209             public int putInvokeDynamic(CharSequence invokedName, String invokedType, int bskKind, Class<?> bsmClass, CharSequence bsmName, String bsmType, Object... staticArgs) {
 210                 return basicPoolHelper.putInvokeDynamic(invokedName, invokedType, bskKind, from(bsmClass), bsmName, bsmType, staticArgs);
 211             }
 212 
 213             @Override
 214             public int size() {
 215                 return basicPoolHelper.size();
 216             }
 217 
 218             @Override
 219             public byte[] entries() {
 220                 return basicPoolHelper.entries();
 221             }
 222         }
 223 
 224         @Override
 225         public byte[] build() {
 226             return super.build();
 227         }
 228     }
 229 
 230     private static ProxyClassesDumper dumper() {
 231         final String key = "valhalla.dumpIsolatedMethodClasses";
 232         String path = AccessController.doPrivileged(
 233                 new GetPropertyAction(key), null,
 234                 new PropertyPermission(key, "read"));
 235         return (null == path) ? null : ProxyClassesDumper.getInstance(path);
 236     }
 237 }