1 /* 2 * Copyright (c) 2010, 2022, 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.BytePoolHelper; 29 import jdk.experimental.bytecode.ClassBuilder; 30 import jdk.experimental.bytecode.CodeBuilder; 31 import jdk.experimental.bytecode.Flag; 32 import jdk.experimental.bytecode.MethodBuilder; 33 import jdk.experimental.bytecode.PoolHelper; 34 import jdk.experimental.bytecode.TypedCodeBuilder; 35 import jdk.experimental.bytecode.TypeHelper; 36 import jdk.experimental.bytecode.TypeTag; 37 38 import java.io.FileOutputStream; 39 import java.lang.invoke.MethodHandle; 40 import java.lang.invoke.MethodHandles; 41 import java.lang.invoke.MethodType; 42 import java.util.Iterator; 43 import java.util.concurrent.atomic.AtomicInteger; 44 import java.util.function.Consumer; 45 import java.util.function.Function; 46 47 import static java.lang.invoke.MethodType.fromMethodDescriptorString; 48 import static java.lang.invoke.MethodType.methodType; 49 50 /** 51 * 8308778: Temporarily keep the old bytecode API, but needs removing when Valhalla support is added to classfile API 52 */ 53 public class OldInstructionHelper { 54 55 static final BasicTypeHelper BTH = new BasicTypeHelper(); 56 57 static final AtomicInteger COUNT = new AtomicInteger(); 58 59 static String generateClassNameFromLookupClass(MethodHandles.Lookup l) { 60 return l.lookupClass().getCanonicalName().replace('.', '/') + "$Code_" + COUNT.getAndIncrement(); 61 } 62 63 static BasicClassBuilder classBuilder(MethodHandles.Lookup l) { 64 String className = generateClassNameFromLookupClass(l); 65 return new BasicClassBuilder(className, 55, 0) 66 .withSuperclass("java/lang/Object") 67 .withMethod("<init>", "()V", M -> 68 M.withFlags(Flag.ACC_PUBLIC) 69 .withCode(TypedCodeBuilder::new, C -> 70 C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() 71 )); 72 } 73 74 public static MethodHandle invokedynamic(MethodHandles.Lookup l, 75 String name, MethodType type, 76 String bsmMethodName, MethodType bsmType, 77 Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { 78 byte[] byteArray = classBuilder(l) 79 .withMethod("m", type.toMethodDescriptorString(), M -> 80 M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 81 .withCode(TypedCodeBuilder::new, 82 C -> { 83 for (int i = 0; i < type.parameterCount(); i++) { 84 C.load(BTH.tag(cref(type.parameterType(i))), i); 85 } 86 C.invokedynamic(name, type.toMethodDescriptorString(), 87 csym(l.lookupClass()), bsmMethodName, bsmType.toMethodDescriptorString(), 88 staticArgs); 89 C.return_(BTH.tag(cref(type.returnType()))); 90 } 91 )) 92 .build(); 93 Class<?> gc = l.defineClass(byteArray); 94 return l.findStatic(gc, "m", type); 95 } 96 97 public static MethodHandle ldcMethodHandle(MethodHandles.Lookup l, 98 int refKind, Class<?> owner, String name, MethodType type) throws Exception { 99 return ldc(l, MethodHandle.class, 100 P -> P.putHandle(refKind, csym(owner), name, type.toMethodDescriptorString())); 101 } 102 103 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, 104 String name, Class<?> type, 105 String bsmMethodName, MethodType bsmType, 106 Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { 107 return ldcDynamicConstant(l, name, type, l.lookupClass(), bsmMethodName, bsmType, staticArgs); 108 } 109 110 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, 111 String name, Class<?> type, 112 Class<?> bsmClass, String bsmMethodName, MethodType bsmType, 113 Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { 114 return ldcDynamicConstant(l, name, cref(type), csym(bsmClass), bsmMethodName, bsmType.toMethodDescriptorString(), staticArgs); 115 } 116 117 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, 118 String name, String type, 119 String bsmMethodName, String bsmType, 120 Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { 121 return ldcDynamicConstant(l, name, type, csym(l.lookupClass()), bsmMethodName, bsmType, staticArgs); 122 } 123 124 public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, 125 String name, String type, 126 String bsmClass, String bsmMethodName, String bsmType, 127 Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { 128 return ldc(l, type, 129 P -> P.putDynamicConstant(name, type, 130 bsmClass, bsmMethodName, bsmType, 131 staticArgs)); 132 } 133 134 public static MethodHandle ldc(MethodHandles.Lookup l, 135 Class<?> type, 136 Function<PoolHelper<String, String, byte[]>, Integer> poolFunc) throws Exception { 137 return ldc(l, cref(type), poolFunc); 138 } 139 140 public static MethodHandle ldc(MethodHandles.Lookup l, 141 String type, 142 Function<PoolHelper<String, String, byte[]>, Integer> poolFunc) throws Exception { 143 String methodType = "()" + type; 144 byte[] byteArray = classBuilder(l) 145 .withMethod("m", "()" + type, M -> 146 M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 147 .withCode(TypedCodeBuilder::new, 148 C -> { 149 C.ldc(null, (P, v) -> poolFunc.apply(P)); 150 C.return_(BTH.tag(type)); 151 } 152 )) 153 .build(); 154 Class<?> gc = l.defineClass(byteArray); 155 return l.findStatic(gc, "m", fromMethodDescriptorString(methodType, l.lookupClass().getClassLoader())); 156 } 157 158 public static String csym(Class<?> c) { 159 return c.getCanonicalName().replace('.', '/'); 160 } 161 162 public static String cref(Class<?> c) { 163 return methodType(c).toMethodDescriptorString().substring(2); 164 } 165 166 167 // loadCode(MethodHandles.Lookup, String, MethodType, Consumer<? super MethodHandleCodeBuilder<?>>) et al... 168 169 public static MethodHandle loadCode(MethodHandles.Lookup lookup, String methodName, MethodType type, Consumer<? super MethodHandleCodeBuilder<?>> builder) { 170 String className = generateClassNameFromLookupClass(lookup); 171 return loadCode(lookup, className, methodName, type, builder); 172 } 173 174 public static MethodHandle loadCode(MethodHandles.Lookup lookup, String className, String methodName, MethodType type, Consumer<? super MethodHandleCodeBuilder<?>> builder) { 175 String descriptor = type.toMethodDescriptorString(); 176 return loadCode(lookup, className, methodName, descriptor, MethodHandleCodeBuilder::new, 177 clazz -> { 178 try { 179 return lookup.findStatic(clazz, methodName, MethodType.fromMethodDescriptorString(descriptor, lookup.lookupClass().getClassLoader())); 180 } catch (ReflectiveOperationException ex) { 181 throw new IllegalStateException(ex); 182 } 183 }, 184 builder); 185 } 186 187 // Helper method to load code built with "buildCode()" 188 public static MethodHandle loadCodeBytes(MethodHandles.Lookup lookup, String methodName, MethodType type, byte[] byteCode) { 189 try { 190 Class<?> clazz = lookup.defineClass(byteCode); 191 return lookup.findStatic(clazz, methodName, type); 192 } catch (Throwable t) { 193 throw new RuntimeException("Failed to loadCodeBytes \"" + methodName + "\"", t); 194 } 195 } 196 197 198 private static <Z, C extends CodeBuilder<Class<?>, String, byte[], ?>> Z loadCode( 199 MethodHandles.Lookup lookup, String className, String methodName, String type, 200 Function<MethodBuilder<Class<?>, String, byte[]>, ? extends C> builderFunc, 201 Function<Class<?>, Z> resFunc, Consumer<? super C> builder) { 202 try { 203 byte[] byteArray = buildCode(lookup, className, methodName, type, builderFunc, builder); 204 Class<?> clazz = lookup.defineClass(byteArray); 205 return resFunc.apply(clazz); 206 } catch (Throwable e) { 207 throw new IllegalStateException(e); 208 } 209 } 210 211 public static byte[] buildCode(MethodHandles.Lookup lookup, String methodName, MethodType type, Consumer<? super MethodHandleCodeBuilder<?>> builder) { 212 String className = generateClassNameFromLookupClass(lookup); 213 return buildCode(lookup, className, methodName, type.toMethodDescriptorString(), MethodHandleCodeBuilder::new, builder); 214 } 215 216 public static <C extends CodeBuilder<Class<?>, String, byte[], ?>> byte[] buildCode( 217 MethodHandles.Lookup lookup, String className, String methodName, String type, 218 Function<MethodBuilder<Class<?>, String, byte[]>, ? extends C> builderFunc, 219 Consumer<? super C> builder) { 220 221 return new IsolatedMethodBuilder(className, lookup) 222 .withSuperclass(Object.class) 223 .withMajorVersion(66) 224 .withMinorVersion(0) 225 .withFlags(Flag.ACC_PUBLIC, Flag.ACC_IDENTITY) 226 .withMethod(methodName, type, M -> 227 M.withFlags(Flag.ACC_STATIC, Flag.ACC_PUBLIC) 228 .withCode(builderFunc, builder)).build(); 229 230 } 231 232 private static class IsolatedMethodBuilder extends ClassBuilder<Class<?>, String, IsolatedMethodBuilder> { 233 234 private static final Class<?> THIS_CLASS = new Object() { }.getClass(); 235 236 private IsolatedMethodBuilder(String clazz, MethodHandles.Lookup lookup) { 237 super(new IsolatedMethodPoolHelper(clazz), 238 new IsolatedMethodTypeHelper(lookup)); 239 withThisClass(THIS_CLASS); 240 } 241 242 public Class<?> thisClass() { 243 return THIS_CLASS; 244 } 245 246 static String classToInternalName(Class<?> c) { 247 if (c.isArray()) { 248 return c.descriptorString(); 249 } 250 return c.getName().replace('.', '/'); 251 } 252 253 private static class IsolatedMethodTypeHelper implements TypeHelper<Class<?>, String> { 254 255 BasicTypeHelper basicTypeHelper = new BasicTypeHelper(); 256 MethodHandles.Lookup lookup; 257 258 private IsolatedMethodTypeHelper(MethodHandles.Lookup lookup) { 259 this.lookup = lookup; 260 } 261 262 @Override 263 public String elemtype(String s) { 264 return basicTypeHelper.elemtype(s); 265 } 266 267 @Override 268 public String arrayOf(String s) { 269 return basicTypeHelper.arrayOf(s); 270 } 271 272 @Override 273 public Iterator<String> parameterTypes(String s) { 274 return basicTypeHelper.parameterTypes(s); 275 } 276 277 @Override 278 public String fromTag(TypeTag tag) { 279 return basicTypeHelper.fromTag(tag); 280 } 281 282 @Override 283 public String returnType(String s) { 284 return basicTypeHelper.returnType(s); 285 } 286 287 @Override 288 public String type(Class<?> aClass) { 289 return aClass.descriptorString(); 290 } 291 292 @Override 293 public Class<?> symbol(String desc) { 294 try { 295 if (desc.startsWith("[")) { 296 return Class.forName(desc.replaceAll("/", "."), true, lookup.lookupClass().getClassLoader()); 297 } else { 298 return Class.forName(basicTypeHelper.symbol(desc).replaceAll("/", "."), true, lookup.lookupClass().getClassLoader()); 299 } 300 } catch (ReflectiveOperationException ex) { 301 throw new AssertionError(ex); 302 } 303 } 304 305 @Override 306 public TypeTag tag(String s) { 307 return basicTypeHelper.tag(s); 308 } 309 310 @Override 311 public Class<?> symbolFrom(String s) { 312 return symbol(s); 313 } 314 315 @Override 316 public String commonSupertype(String t1, String t2) { 317 return basicTypeHelper.commonSupertype(t1, t2); 318 } 319 320 @Override 321 public String nullType() { 322 return basicTypeHelper.nullType(); 323 } 324 } 325 326 private static class IsolatedMethodPoolHelper extends BytePoolHelper<Class<?>, String> { 327 final String clazz; 328 329 private IsolatedMethodPoolHelper(String clazz) { 330 super(c -> from(c, clazz), s->s); 331 this.clazz = clazz; 332 } 333 334 static String from(Class<?> c, String clazz) { 335 return c == THIS_CLASS ? clazz.replace('.', '/') 336 : classToInternalName(c); 337 } 338 } 339 340 @Override 341 public byte[] build() { 342 return super.build(); 343 } 344 } 345 346 public static class MethodHandleCodeBuilder<T extends MethodHandleCodeBuilder<T>> extends TypedCodeBuilder<Class<?>, String, byte[], T> { 347 348 BasicTypeHelper basicTypeHelper = new BasicTypeHelper(); 349 350 public MethodHandleCodeBuilder(jdk.experimental.bytecode.MethodBuilder<Class<?>, String, byte[]> methodBuilder) { 351 super(methodBuilder); 352 } 353 354 TypeTag getTagType(String s) { 355 return basicTypeHelper.tag(s); 356 } 357 358 public T ifcmp(String s, CondKind cond, CharSequence label) { 359 return super.ifcmp(getTagType(s), cond, label); 360 } 361 362 public T return_(String s) { 363 return super.return_(getTagType(s)); 364 } 365 } 366 367 368 369 }