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 }