JavaAdapterBytecodeGenerator.java revision 1692:bb6cf30cf892
1/* 2 * Copyright (c) 2010, 2013, 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 26package jdk.nashorn.internal.runtime.linker; 27 28import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 29import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; 30import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 31import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 32import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; 33import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; 34import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 35import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; 36import static jdk.internal.org.objectweb.asm.Opcodes.D2F; 37import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 38import static jdk.internal.org.objectweb.asm.Opcodes.I2B; 39import static jdk.internal.org.objectweb.asm.Opcodes.I2S; 40import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 41import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; 42import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; 43import static jdk.nashorn.internal.lookup.Lookup.MH; 44import static jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome.ERROR_NO_ACCESSIBLE_CONSTRUCTOR; 45 46import java.lang.invoke.CallSite; 47import java.lang.invoke.MethodHandle; 48import java.lang.invoke.MethodHandles.Lookup; 49import java.lang.invoke.MethodType; 50import java.lang.reflect.AccessibleObject; 51import java.lang.reflect.Constructor; 52import java.lang.reflect.Method; 53import java.lang.reflect.Modifier; 54import java.lang.reflect.Module; 55import java.security.AccessControlContext; 56import java.security.AccessController; 57import java.security.PrivilegedAction; 58import java.util.Arrays; 59import java.util.Collection; 60import java.util.HashSet; 61import java.util.Iterator; 62import java.util.List; 63import java.util.Set; 64import jdk.internal.org.objectweb.asm.ClassWriter; 65import jdk.internal.org.objectweb.asm.Handle; 66import jdk.internal.org.objectweb.asm.Label; 67import jdk.internal.org.objectweb.asm.Opcodes; 68import jdk.internal.org.objectweb.asm.Type; 69import jdk.internal.org.objectweb.asm.commons.InstructionAdapter; 70import jdk.nashorn.api.scripting.ScriptUtils; 71import jdk.nashorn.internal.codegen.CompilerConstants.Call; 72import jdk.nashorn.internal.runtime.ScriptFunction; 73import jdk.nashorn.internal.runtime.ScriptObject; 74import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome; 75import jdk.internal.reflect.CallerSensitive; 76 77/** 78 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}. 79 * </p><p> 80 * For every protected or public constructor in the extended class, the adapter class will have either one or two 81 * public constructors (visibility of protected constructors in the extended class is promoted to public). 82 * <li> 83 * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded 84 * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the 85 * passed ScriptObject's member functions are used to implement and/or override methods on the original class, 86 * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the 87 * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed 88 * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its 89 * functions) will be reflected in the adapter instance as it is live dispatching to its members on every method invocation. 90 * {@code java.lang.Object} methods {@code equals}, {@code hashCode}, and {@code toString} can also be overridden. The 91 * only restriction is that since every JavaScript object already has a {@code toString} function through the 92 * {@code Object.prototype}, the {@code toString} in the adapter is only overridden if the passed ScriptObject has a 93 * {@code toString} function as its own property, and not inherited from a prototype. All other adapter methods can be 94 * implemented or overridden through a prototype-inherited function of the ScriptObject passed to the constructor too. 95 * </li> 96 * <li> 97 * If the original types collectively have only one abstract method, or have several of them, but all share the 98 * same name, an additional constructor for instance-level override adapter is provided for every original constructor; 99 * this one takes a ScriptFunction as its last argument preceded by original constructor arguments. This constructor 100 * will use the passed function as the implementation for all abstract methods. For consistency, any concrete methods 101 * sharing the single abstract method name will also be overridden by the function. When methods on the adapter instance 102 * are invoked, the ScriptFunction is invoked with UNDEFINED or Global as its "this" depending whether the function is 103 * strict or not. 104 * </li> 105 * <li> 106 * If the adapter being generated has class-level overrides, constructors taking same arguments as the superclass 107 * constructors are created. These constructors simply delegate to the superclass constructor. They are simply used to 108 * create instances of the adapter class, with no instance-level overrides, as they don't have them. If the original 109 * class' constructor was variable arity, the adapter constructor will also be variable arity. Protected constructors 110 * are exposed as public. 111 * </li> 112 * </ul> 113 * </p><p> 114 * For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect 115 * to coerce the JavaScript function return value to the expected Java return type. 116 * </p><p> 117 * Since we are adding a trailing argument to the generated constructors in the adapter class with instance-level overrides, they will never be 118 * declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The 119 * reason we are passing the additional argument at the end of the argument list instead at the front is that the 120 * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses 121 * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>. 122 * </p><p> 123 * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can 124 * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked 125 * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and 126 * the passed script object will be used as the implementations for its methods, just as in the above case of the 127 * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on 128 * every invocation, and the implementation object is bound to the class, not to any instance. All created instances 129 * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the 130 * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to 131 * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to 132 * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are 133 * defined with a protection domain of their creator code, and an adapter class that has both class and instance level 134 * overrides would need to have two potentially different protection domains: one for class-based behavior and one for 135 * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be 136 * implemented securely. 137 */ 138final class JavaAdapterBytecodeGenerator { 139 // Field names in adapters 140 private static final String GLOBAL_FIELD_NAME = "global"; 141 private static final String DELEGATE_FIELD_NAME = "delegate"; 142 private static final String IS_FUNCTION_FIELD_NAME = "isFunction"; 143 private static final String CALL_THIS_FIELD_NAME = "callThis"; 144 145 // Initializer names 146 private static final String INIT = "<init>"; 147 private static final String CLASS_INIT = "<clinit>"; 148 149 // Types often used in generated bytecode 150 private static final Type OBJECT_TYPE = Type.getType(Object.class); 151 private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class); 152 private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class); 153 154 // JavaAdapterServices methods used in generated bytecode 155 private static final Call CHECK_FUNCTION = lookupServiceMethod("checkFunction", ScriptFunction.class, Object.class, String.class); 156 private static final Call EXPORT_RETURN_VALUE = lookupServiceMethod("exportReturnValue", Object.class, Object.class); 157 private static final Call GET_CALL_THIS = lookupServiceMethod("getCallThis", Object.class, ScriptFunction.class, Object.class); 158 private static final Call GET_CLASS_OVERRIDES = lookupServiceMethod("getClassOverrides", ScriptObject.class); 159 private static final Call GET_NON_NULL_GLOBAL = lookupServiceMethod("getNonNullGlobal", ScriptObject.class); 160 private static final Call HAS_OWN_TO_STRING = lookupServiceMethod("hasOwnToString", boolean.class, ScriptObject.class); 161 private static final Call INVOKE_NO_PERMISSIONS = lookupServiceMethod("invokeNoPermissions", void.class, MethodHandle.class, Object.class); 162 private static final Call NOT_AN_OBJECT = lookupServiceMethod("notAnObject", void.class, Object.class); 163 private static final Call SET_GLOBAL = lookupServiceMethod("setGlobal", Runnable.class, ScriptObject.class); 164 private static final Call TO_CHAR_PRIMITIVE = lookupServiceMethod("toCharPrimitive", char.class, Object.class); 165 private static final Call UNSUPPORTED = lookupServiceMethod("unsupported", UnsupportedOperationException.class); 166 private static final Call WRAP_THROWABLE = lookupServiceMethod("wrapThrowable", RuntimeException.class, Throwable.class); 167 168 // Other methods invoked by the generated bytecode 169 private static final Call UNWRAP = staticCallNoLookup(ScriptUtils.class, "unwrap", Object.class, Object.class); 170 private static final Call CHAR_VALUE_OF = staticCallNoLookup(Character.class, "valueOf", Character.class, char.class); 171 private static final Call DOUBLE_VALUE_OF = staticCallNoLookup(Double.class, "valueOf", Double.class, double.class); 172 private static final Call LONG_VALUE_OF = staticCallNoLookup(Long.class, "valueOf", Long.class, long.class); 173 private static final Call RUN = interfaceCallNoLookup(Runnable.class, "run", void.class); 174 175 // ASM handle to the bootstrap method 176 @SuppressWarnings("deprecation") 177 private static final Handle BOOTSTRAP_HANDLE = new Handle(H_INVOKESTATIC, 178 Type.getInternalName(JavaAdapterServices.class), "bootstrap", 179 MethodType.methodType(CallSite.class, Lookup.class, String.class, 180 MethodType.class, int.class).toMethodDescriptorString()); 181 182 // ASM handle to the bootstrap method for array populator 183 @SuppressWarnings("deprecation") 184 private static final Handle CREATE_ARRAY_BOOTSTRAP_HANDLE = new Handle(H_INVOKESTATIC, 185 Type.getInternalName(JavaAdapterServices.class), "createArrayBootstrap", 186 MethodType.methodType(CallSite.class, Lookup.class, String.class, 187 MethodType.class).toMethodDescriptorString()); 188 189 // Field type names used in the generated bytecode 190 private static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor(); 191 private static final String OBJECT_TYPE_DESCRIPTOR = OBJECT_TYPE.getDescriptor(); 192 private static final String BOOLEAN_TYPE_DESCRIPTOR = Type.BOOLEAN_TYPE.getDescriptor(); 193 194 // Throwable names used in the generated bytecode 195 private static final String RUNTIME_EXCEPTION_TYPE_NAME = Type.getInternalName(RuntimeException.class); 196 private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class); 197 private static final String THROWABLE_TYPE_NAME = Type.getInternalName(Throwable.class); 198 199 // Some more frequently used method descriptors 200 private static final String GET_METHOD_PROPERTY_METHOD_DESCRIPTOR = Type.getMethodDescriptor(OBJECT_TYPE, SCRIPT_OBJECT_TYPE); 201 private static final String VOID_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE); 202 203 static final String ADAPTER_PACKAGE_INTERNAL = "jdk/nashorn/javaadapters/"; 204 static final String ADAPTER_PACKAGE = "jdk.nashorn.javaadapters"; 205 private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255; 206 207 // Method name prefix for invoking super-methods 208 static final String SUPER_PREFIX = "super$"; 209 210 // Method name and type for the no-privilege finalizer delegate 211 private static final String FINALIZER_DELEGATE_NAME = "$$nashornFinalizerDelegate"; 212 private static final String FINALIZER_DELEGATE_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE); 213 214 /** 215 * Collection of methods we never override: Object.clone(), Object.finalize(). 216 */ 217 private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods(); 218 219 // This is the superclass for our generated adapter. 220 private final Class<?> superClass; 221 // Interfaces implemented by our generated adapter. 222 private final List<Class<?>> interfaces; 223 // Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class 224 // loader that has the visibility of all original types (class to extend and interfaces to implement) and of the 225 // Nashorn classes. 226 private final ClassLoader commonLoader; 227 // Is this a generator for the version of the class that can have overrides on the class level? 228 private final boolean classOverride; 229 // Binary name of the superClass 230 private final String superClassName; 231 // Binary name of the generated class. 232 private final String generatedClassName; 233 private final Set<String> abstractMethodNames = new HashSet<>(); 234 private final String samName; 235 private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED); 236 private final Set<MethodInfo> methodInfos = new HashSet<>(); 237 private final boolean autoConvertibleFromFunction; 238 private boolean hasExplicitFinalizer = false; 239 private final Set<Module> accessedModules = new HashSet<>(); 240 241 private final ClassWriter cw; 242 243 /** 244 * Creates a generator for the bytecode for the adapter for the specified superclass and interfaces. 245 * @param superClass the superclass the adapter will extend. 246 * @param interfaces the interfaces the adapter will implement. 247 * @param commonLoader the class loader that can see all of superClass, interfaces, and Nashorn classes. 248 * @param classOverride true to generate the bytecode for the adapter that has class-level overrides, false to 249 * generate the bytecode for the adapter that has instance-level overrides. 250 * @throws AdaptationException if the adapter can not be generated for some reason. 251 */ 252 JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces, 253 final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException { 254 assert superClass != null && !superClass.isInterface(); 255 assert interfaces != null; 256 257 this.superClass = superClass; 258 this.interfaces = interfaces; 259 this.classOverride = classOverride; 260 this.commonLoader = commonLoader; 261 cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { 262 @Override 263 protected String getCommonSuperClass(final String type1, final String type2) { 264 // We need to override ClassWriter.getCommonSuperClass to use this factory's commonLoader as a class 265 // loader to find the common superclass of two types when needed. 266 return JavaAdapterBytecodeGenerator.this.getCommonSuperClass(type1, type2); 267 } 268 }; 269 superClassName = Type.getInternalName(superClass); 270 generatedClassName = getGeneratedClassName(superClass, interfaces); 271 272 cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER, generatedClassName, null, superClassName, getInternalTypeNames(interfaces)); 273 generateField(GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 274 generateField(DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 275 276 gatherMethods(superClass); 277 gatherMethods(interfaces); 278 if (abstractMethodNames.size() == 1) { 279 samName = abstractMethodNames.iterator().next(); 280 generateField(CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR); 281 generateField(IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR); 282 } else { 283 samName = null; 284 } 285 if(classOverride) { 286 generateClassInit(); 287 } 288 autoConvertibleFromFunction = generateConstructors(); 289 generateMethods(); 290 generateSuperMethods(); 291 if (hasExplicitFinalizer) { 292 generateFinalizerMethods(); 293 } 294 // } 295 cw.visitEnd(); 296 } 297 298 private void generateField(final String name, final String fieldDesc) { 299 cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), name, fieldDesc, null, null).visitEnd(); 300 } 301 302 JavaAdapterClassLoader createAdapterClassLoader() { 303 return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray(), accessedModules); 304 } 305 306 boolean isAutoConvertibleFromFunction() { 307 return autoConvertibleFromFunction; 308 } 309 310 private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) { 311 // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're 312 // just implementing interfaces or extending Object), then the first implemented interface or Object. 313 final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType; 314 final Package pkg = namingType.getPackage(); 315 final String namingTypeName = Type.getInternalName(namingType); 316 final StringBuilder buf = new StringBuilder(); 317 buf.append(ADAPTER_PACKAGE_INTERNAL).append(namingTypeName.replace('/', '_')); 318 final Iterator<Class<?>> it = interfaces.iterator(); 319 if(superType == Object.class && it.hasNext()) { 320 it.next(); // Skip first interface, it was used to primarily name the adapter 321 } 322 // Append interface names to the adapter name 323 while(it.hasNext()) { 324 buf.append("$$").append(it.next().getSimpleName()); 325 } 326 return buf.toString().substring(0, Math.min(MAX_GENERATED_TYPE_NAME_LENGTH, buf.length())); 327 } 328 329 /** 330 * Given a list of class objects, return an array with their binary names. Used to generate the array of interface 331 * names to implement. 332 * @param classes the classes 333 * @return an array of names 334 */ 335 private static String[] getInternalTypeNames(final List<Class<?>> classes) { 336 final int interfaceCount = classes.size(); 337 final String[] interfaceNames = new String[interfaceCount]; 338 for(int i = 0; i < interfaceCount; ++i) { 339 interfaceNames[i] = Type.getInternalName(classes.get(i)); 340 } 341 return interfaceNames; 342 } 343 344 private void generateClassInit() { 345 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT, 346 VOID_METHOD_DESCRIPTOR, null, null)); 347 348 // Assign "global = Context.getGlobal()" 349 GET_NON_NULL_GLOBAL.invoke(mv); 350 mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 351 352 GET_CLASS_OVERRIDES.invoke(mv); 353 if(samName != null) { 354 // If the class is a SAM, allow having ScriptFunction passed as class overrides 355 mv.dup(); 356 mv.instanceOf(SCRIPT_FUNCTION_TYPE); 357 mv.dup(); 358 mv.putstatic(generatedClassName, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR); 359 final Label notFunction = new Label(); 360 mv.ifeq(notFunction); 361 mv.dup(); 362 mv.checkcast(SCRIPT_FUNCTION_TYPE); 363 emitInitCallThis(mv); 364 mv.visitLabel(notFunction); 365 } 366 mv.putstatic(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 367 368 endInitMethod(mv); 369 } 370 371 /** 372 * Emit bytecode for initializing the "callThis" field. 373 */ 374 private void emitInitCallThis(final InstructionAdapter mv) { 375 loadField(mv, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 376 GET_CALL_THIS.invoke(mv); 377 if(classOverride) { 378 mv.putstatic(generatedClassName, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR); 379 } else { 380 // It is presumed ALOAD 0 was already executed 381 mv.putfield(generatedClassName, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR); 382 } 383 } 384 385 private boolean generateConstructors() throws AdaptationException { 386 boolean gotCtor = false; 387 boolean canBeAutoConverted = false; 388 for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) { 389 final int modifier = ctor.getModifiers(); 390 if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) { 391 canBeAutoConverted = generateConstructors(ctor) | canBeAutoConverted; 392 gotCtor = true; 393 } 394 } 395 if(!gotCtor) { 396 throw new AdaptationException(ERROR_NO_ACCESSIBLE_CONSTRUCTOR, superClass.getCanonicalName()); 397 } 398 return canBeAutoConverted; 399 } 400 401 private boolean generateConstructors(final Constructor<?> ctor) { 402 for (final Class<?> pt : ctor.getParameterTypes()) { 403 if (pt.isPrimitive()) continue; 404 final Module ptMod = pt.getModule(); 405 if (ptMod != null) { 406 accessedModules.add(ptMod); 407 } 408 } 409 410 if(classOverride) { 411 // Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want 412 // to create instances without further per-instance overrides. 413 generateDelegatingConstructor(ctor); 414 return false; 415 } 416 417 // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the 418 // beginning of its parameter list. 419 generateOverridingConstructor(ctor, false); 420 421 if (samName == null) { 422 return false; 423 } 424 // If all our abstract methods have a single name, generate an additional constructor, one that takes a 425 // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods. 426 generateOverridingConstructor(ctor, true); 427 // If the original type only has a single abstract method name, as well as a default ctor, then it can 428 // be automatically converted from JS function. 429 return ctor.getParameterTypes().length == 0; 430 } 431 432 private void generateDelegatingConstructor(final Constructor<?> ctor) { 433 final Type originalCtorType = Type.getType(ctor); 434 final Type[] argTypes = originalCtorType.getArgumentTypes(); 435 436 // All constructors must be public, even if in the superclass they were protected. 437 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC | 438 (ctor.isVarArgs() ? ACC_VARARGS : 0), INIT, 439 Type.getMethodDescriptor(originalCtorType.getReturnType(), argTypes), null, null)); 440 441 mv.visitCode(); 442 emitSuperConstructorCall(mv, originalCtorType.getDescriptor()); 443 444 endInitMethod(mv); 445 } 446 447 /** 448 * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype 449 * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of 450 * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize 451 * all the method handle fields of the adapter instance with functions from the script object (or the script 452 * function itself, if that's what's passed). There is one method handle field in the adapter class for every method 453 * that can be implemented or overridden; the name of every field is same as the name of the method, with a number 454 * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke 455 * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType, 456 * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity 457 * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}. 458 * The constructor that takes a script function will only initialize the methods with the same name as the single 459 * abstract method. The constructor will also store the Nashorn global that was current at the constructor 460 * invocation time in a field named "global". The generated constructor will be public, regardless of whether the 461 * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the 462 * supertype constructor was. 463 * @param ctor the supertype constructor that is serving as the base for the generated constructor. 464 * @param fromFunction true if we're generating a constructor that initializes SAM types from a single 465 * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a 466 * ScriptObject passed to it. 467 */ 468 private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) { 469 final Type originalCtorType = Type.getType(ctor); 470 final Type[] originalArgTypes = originalCtorType.getArgumentTypes(); 471 final int argLen = originalArgTypes.length; 472 final Type[] newArgTypes = new Type[argLen + 1]; 473 474 // Insert ScriptFunction|ScriptObject as the last argument to the constructor 475 final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE; 476 newArgTypes[argLen] = extraArgumentType; 477 System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen); 478 479 // All constructors must be public, even if in the superclass they were protected. 480 // Existing super constructor <init>(this, args...) triggers generating <init>(this, args..., delegate). 481 // Any variable arity constructors become fixed-arity with explicit array arguments. 482 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, 483 Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null)); 484 485 mv.visitCode(); 486 // First, invoke super constructor with original arguments. 487 final int extraArgOffset = emitSuperConstructorCall(mv, originalCtorType.getDescriptor()); 488 489 // Assign "this.global = Context.getGlobal()" 490 mv.visitVarInsn(ALOAD, 0); 491 GET_NON_NULL_GLOBAL.invoke(mv); 492 mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 493 494 // Assign "this.delegate = delegate" 495 mv.visitVarInsn(ALOAD, 0); 496 mv.visitVarInsn(ALOAD, extraArgOffset); 497 mv.putfield(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 498 499 if (fromFunction) { 500 // Assign "isFunction = true" 501 mv.visitVarInsn(ALOAD, 0); 502 mv.iconst(1); 503 mv.putfield(generatedClassName, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR); 504 505 mv.visitVarInsn(ALOAD, 0); 506 mv.visitVarInsn(ALOAD, extraArgOffset); 507 emitInitCallThis(mv); 508 } 509 510 endInitMethod(mv); 511 512 if (! fromFunction) { 513 newArgTypes[argLen] = OBJECT_TYPE; 514 final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, 515 Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null)); 516 generateOverridingConstructorWithObjectParam(mv2, originalCtorType.getDescriptor()); 517 } 518 } 519 520 // Object additional param accepting constructor - generated to handle null and undefined value 521 // for script adapters. This is effectively to throw TypeError on such script adapters. See 522 // JavaAdapterServices.getHandle as well. 523 private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final String ctorDescriptor) { 524 mv.visitCode(); 525 final int extraArgOffset = emitSuperConstructorCall(mv, ctorDescriptor); 526 mv.visitVarInsn(ALOAD, extraArgOffset); 527 NOT_AN_OBJECT.invoke(mv); 528 endInitMethod(mv); 529 } 530 531 private static void endInitMethod(final InstructionAdapter mv) { 532 mv.visitInsn(RETURN); 533 endMethod(mv); 534 } 535 536 private static void endMethod(final InstructionAdapter mv) { 537 mv.visitMaxs(0, 0); 538 mv.visitEnd(); 539 } 540 541 /** 542 * Encapsulation of the information used to generate methods in the adapter classes. Basically, a wrapper around the 543 * reflective Method object, a cached MethodType, and the name of the field in the adapter class that will hold the 544 * method handle serving as the implementation of this method in adapter instances. 545 * 546 */ 547 private static class MethodInfo { 548 private final Method method; 549 private final MethodType type; 550 551 private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException { 552 this(clazz.getDeclaredMethod(name, argTypes)); 553 } 554 555 private MethodInfo(final Method method) { 556 this.method = method; 557 this.type = MH.type(method.getReturnType(), method.getParameterTypes()); 558 } 559 560 @Override 561 public boolean equals(final Object obj) { 562 return obj instanceof MethodInfo && equals((MethodInfo)obj); 563 } 564 565 private boolean equals(final MethodInfo other) { 566 // Only method name and type are used for comparison; method handle field name is not. 567 return getName().equals(other.getName()) && type.equals(other.type); 568 } 569 570 String getName() { 571 return method.getName(); 572 } 573 574 @Override 575 public int hashCode() { 576 return getName().hashCode() ^ type.hashCode(); 577 } 578 } 579 580 private void generateMethods() { 581 for(final MethodInfo mi: methodInfos) { 582 generateMethod(mi); 583 } 584 } 585 586 /** 587 * Generates a method in the adapter class that adapts a method from the 588 * original class. The generated method will either invoke the delegate 589 * using a CALL dynamic operation call site (if it is a SAM method and the 590 * delegate is a ScriptFunction), or invoke GET_METHOD_PROPERTY dynamic 591 * operation with the method name as the argument and then invoke the 592 * returned ScriptFunction using the CALL dynamic operation. If 593 * GET_METHOD_PROPERTY returns null or undefined (that is, the JS object 594 * doesn't provide an implementation for the method) then the method will 595 * either do a super invocation to base class, or if the method is abstract, 596 * throw an {@link UnsupportedOperationException}. Finally, if 597 * GET_METHOD_PROPERTY returns something other than a ScriptFunction, null, 598 * or undefined, a TypeError is thrown. The current Global is checked before 599 * the dynamic operations, and if it is different than the Global used to 600 * create the adapter, the creating Global is set to be the current Global. 601 * In this case, the previously current Global is restored after the 602 * invocation. If CALL results in a Throwable that is not one of the 603 * method's declared exceptions, and is not an unchecked throwable, then it 604 * is wrapped into a {@link RuntimeException} and the runtime exception is 605 * thrown. 606 * @param mi the method info describing the method to be generated. 607 */ 608 private void generateMethod(final MethodInfo mi) { 609 final Method method = mi.method; 610 final Class<?>[] exceptions = method.getExceptionTypes(); 611 final String[] exceptionNames = getExceptionNames(exceptions); 612 final MethodType type = mi.type; 613 final String methodDesc = type.toMethodDescriptorString(); 614 final String name = mi.getName(); 615 616 final Type asmType = Type.getMethodType(methodDesc); 617 final Type[] asmArgTypes = asmType.getArgumentTypes(); 618 619 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name, 620 methodDesc, null, exceptionNames)); 621 mv.visitCode(); 622 623 final Class<?> returnType = type.returnType(); 624 final Type asmReturnType = Type.getType(returnType); 625 626 // Determine the first index for a local variable 627 int nextLocalVar = 1; // "this" is at 0 628 for(final Type t: asmArgTypes) { 629 nextLocalVar += t.getSize(); 630 } 631 // Set our local variable index 632 final int globalRestoringRunnableVar = nextLocalVar++; 633 634 // Load the creatingGlobal object 635 loadField(mv, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 636 637 // stack: [creatingGlobal] 638 SET_GLOBAL.invoke(mv); 639 // stack: [runnable] 640 mv.visitVarInsn(ASTORE, globalRestoringRunnableVar); 641 // stack: [] 642 643 final Label tryBlockStart = new Label(); 644 mv.visitLabel(tryBlockStart); 645 646 final Label callCallee = new Label(); 647 final Label defaultBehavior = new Label(); 648 // If this is a SAM type... 649 if (samName != null) { 650 // ...every method will be checking whether we're initialized with a 651 // function. 652 loadField(mv, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR); 653 // stack: [isFunction] 654 if (name.equals(samName)) { 655 final Label notFunction = new Label(); 656 mv.ifeq(notFunction); 657 // stack: [] 658 // If it's a SAM method, it'll load delegate as the "callee" and 659 // "callThis" as "this" for the call if delegate is a function. 660 loadField(mv, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 661 // NOTE: if we added "mv.checkcast(SCRIPT_FUNCTION_TYPE);" here 662 // we could emit the invokedynamic CALL instruction with signature 663 // (ScriptFunction, Object, ...) instead of (Object, Object, ...). 664 // We could combine this with an optimization in 665 // ScriptFunction.findCallMethod where it could link a call with a 666 // thinner guard when the call site statically guarantees that the 667 // callee argument is a ScriptFunction. Additionally, we could use 668 // a "ScriptFunction function" field in generated classes instead 669 // of a "boolean isFunction" field to avoid the checkcast. 670 loadField(mv, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR); 671 // stack: [callThis, delegate] 672 mv.goTo(callCallee); 673 mv.visitLabel(notFunction); 674 } else { 675 // If it's not a SAM method, and the delegate is a function, 676 // it'll fall back to default behavior 677 mv.ifne(defaultBehavior); 678 // stack: [] 679 } 680 } 681 682 // At this point, this is either not a SAM method or the delegate is 683 // not a ScriptFunction. We need to emit a GET_METHOD_PROPERTY Nashorn 684 // invokedynamic. 685 686 if(name.equals("toString")) { 687 // Since every JS Object has a toString, we only override 688 // "String toString()" it if it's explicitly specified on the object. 689 loadField(mv, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 690 // stack: [delegate] 691 HAS_OWN_TO_STRING.invoke(mv); 692 // stack: [hasOwnToString] 693 mv.ifeq(defaultBehavior); 694 } 695 696 loadField(mv, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 697 mv.dup(); 698 // stack: [delegate, delegate] 699 final String encodedName = NameCodec.encode(name); 700 mv.visitInvokeDynamicInsn(encodedName, 701 GET_METHOD_PROPERTY_METHOD_DESCRIPTOR, BOOTSTRAP_HANDLE, 702 NashornCallSiteDescriptor.GET_METHOD_PROPERTY); 703 // stack: [callee, delegate] 704 mv.visitLdcInsn(name); 705 // stack: [name, callee, delegate] 706 CHECK_FUNCTION.invoke(mv); 707 // stack: [fnCalleeOrNull, delegate] 708 final Label hasFunction = new Label(); 709 mv.dup(); 710 // stack: [fnCalleeOrNull, fnCalleeOrNull, delegate] 711 mv.ifnonnull(hasFunction); 712 // stack: [null, delegate] 713 // If it's null or undefined, clear stack and fall back to default 714 // behavior. 715 mv.pop2(); 716 // stack: [] 717 718 // We can also arrive here from check for "delegate instanceof ScriptFunction" 719 // in a non-SAM method as well as from a check for "hasOwnToString(delegate)" 720 // for a toString delegate. 721 mv.visitLabel(defaultBehavior); 722 final Runnable emitFinally = ()->emitFinally(mv, globalRestoringRunnableVar); 723 final Label normalFinally = new Label(); 724 if(Modifier.isAbstract(method.getModifiers())) { 725 // If the super method is abstract, throw UnsupportedOperationException 726 UNSUPPORTED.invoke(mv); 727 // NOTE: no need to invoke emitFinally.run() as we're inside the 728 // tryBlockStart/tryBlockEnd range, so throwing this exception will 729 // transfer control to the rethrow handler and the finally block in it 730 // will execute. 731 mv.athrow(); 732 } else { 733 // If the super method is not abstract, delegate to it. 734 emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); 735 mv.goTo(normalFinally); 736 } 737 738 mv.visitLabel(hasFunction); 739 // stack: [callee, delegate] 740 mv.swap(); 741 // stack [delegate, callee] 742 mv.visitLabel(callCallee); 743 744 745 // Load all parameters back on stack for dynamic invocation. 746 747 int varOffset = 1; 748 // If the param list length is more than 253 slots, we can't invoke it 749 // directly as with (callee, this) it'll exceed 255. 750 final boolean isVarArgCall = getParamListLengthInSlots(asmArgTypes) > 253; 751 for (final Type t : asmArgTypes) { 752 mv.load(varOffset, t); 753 convertParam(mv, t, isVarArgCall); 754 varOffset += t.getSize(); 755 } 756 // stack: [args..., callee, delegate] 757 758 // If the resulting parameter list length is too long... 759 if (isVarArgCall) { 760 // ... we pack the parameters (except callee and this) into an array 761 // and use Nashorn vararg invocation. 762 mv.visitInvokeDynamicInsn(NameCodec.EMPTY_NAME, 763 getArrayCreatorMethodType(type).toMethodDescriptorString(), 764 CREATE_ARRAY_BOOTSTRAP_HANDLE); 765 } 766 767 // Invoke the target method handle 768 mv.visitInvokeDynamicInsn(encodedName, 769 getCallMethodType(isVarArgCall, type).toMethodDescriptorString(), 770 BOOTSTRAP_HANDLE, NashornCallSiteDescriptor.CALL); 771 // stack: [returnValue] 772 convertReturnValue(mv, returnType); 773 mv.visitLabel(normalFinally); 774 emitFinally.run(); 775 mv.areturn(asmReturnType); 776 777 // If Throwable is not declared, we need an adapter from Throwable to RuntimeException 778 final boolean throwableDeclared = isThrowableDeclared(exceptions); 779 final Label throwableHandler; 780 if (!throwableDeclared) { 781 // Add "throw new RuntimeException(Throwable)" handler for Throwable 782 throwableHandler = new Label(); 783 mv.visitLabel(throwableHandler); 784 WRAP_THROWABLE.invoke(mv); 785 // Fall through to rethrow handler 786 } else { 787 throwableHandler = null; 788 } 789 final Label rethrowHandler = new Label(); 790 mv.visitLabel(rethrowHandler); 791 // Rethrow handler for RuntimeException, Error, and all declared exception types 792 emitFinally.run(); 793 mv.athrow(); 794 795 if(throwableDeclared) { 796 mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, THROWABLE_TYPE_NAME); 797 assert throwableHandler == null; 798 } else { 799 mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME); 800 mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, ERROR_TYPE_NAME); 801 for(final String excName: exceptionNames) { 802 mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, excName); 803 } 804 mv.visitTryCatchBlock(tryBlockStart, normalFinally, throwableHandler, THROWABLE_TYPE_NAME); 805 } 806 endMethod(mv); 807 } 808 809 private static MethodType getCallMethodType(final boolean isVarArgCall, final MethodType type) { 810 final Class<?>[] callParamTypes; 811 if (isVarArgCall) { 812 // Variable arity calls are always (Object callee, Object this, Object[] params) 813 callParamTypes = new Class<?>[] { Object.class, Object.class, Object[].class }; 814 } else { 815 // Adjust invocation type signature for conversions we instituted in 816 // convertParam; also, byte and short get passed as ints. 817 final Class<?>[] origParamTypes = type.parameterArray(); 818 callParamTypes = new Class<?>[origParamTypes.length + 2]; 819 callParamTypes[0] = Object.class; // callee; could be ScriptFunction.class ostensibly 820 callParamTypes[1] = Object.class; // this 821 for(int i = 0; i < origParamTypes.length; ++i) { 822 callParamTypes[i + 2] = getNashornParamType(origParamTypes[i], false); 823 } 824 } 825 return MethodType.methodType(getNashornReturnType(type.returnType()), callParamTypes); 826 } 827 828 private static MethodType getArrayCreatorMethodType(final MethodType type) { 829 final Class<?>[] callParamTypes = type.parameterArray(); 830 for(int i = 0; i < callParamTypes.length; ++i) { 831 callParamTypes[i] = getNashornParamType(callParamTypes[i], true); 832 } 833 return MethodType.methodType(Object[].class, callParamTypes); 834 } 835 836 private static Class<?> getNashornParamType(final Class<?> clazz, final boolean varArg) { 837 if (clazz == byte.class || clazz == short.class) { 838 return int.class; 839 } else if (clazz == float.class) { 840 // If using variable arity, we'll pass a Double instead of double 841 // so that floats don't extend the length of the parameter list. 842 // We return Object.class instead of Double.class though as the 843 // array collector will anyway operate on Object. 844 return varArg ? Object.class : double.class; 845 } else if (!clazz.isPrimitive() || clazz == long.class || clazz == char.class) { 846 return Object.class; 847 } 848 return clazz; 849 } 850 851 private static Class<?> getNashornReturnType(final Class<?> clazz) { 852 if (clazz == byte.class || clazz == short.class) { 853 return int.class; 854 } else if (clazz == float.class) { 855 return double.class; 856 } else if (clazz == void.class || clazz == char.class) { 857 return Object.class; 858 } 859 return clazz; 860 } 861 862 863 private void loadField(final InstructionAdapter mv, final String name, final String desc) { 864 if(classOverride) { 865 mv.getstatic(generatedClassName, name, desc); 866 } else { 867 mv.visitVarInsn(ALOAD, 0); 868 mv.getfield(generatedClassName, name, desc); 869 } 870 } 871 872 private static void convertReturnValue(final InstructionAdapter mv, final Class<?> origReturnType) { 873 if (origReturnType == void.class) { 874 mv.pop(); 875 } else if (origReturnType == Object.class) { 876 // Must hide ConsString (and potentially other internal Nashorn types) from callers 877 EXPORT_RETURN_VALUE.invoke(mv); 878 } else if (origReturnType == byte.class) { 879 mv.visitInsn(I2B); 880 } else if (origReturnType == short.class) { 881 mv.visitInsn(I2S); 882 } else if (origReturnType == float.class) { 883 mv.visitInsn(D2F); 884 } else if (origReturnType == char.class) { 885 TO_CHAR_PRIMITIVE.invoke(mv); 886 } 887 } 888 889 /** 890 * Emits instruction for converting a parameter on the top of the stack to 891 * a type that is understood by Nashorn. 892 * @param mv the current method visitor 893 * @param t the type on the top of the stack 894 * @param varArg if the invocation will be variable arity 895 */ 896 private static void convertParam(final InstructionAdapter mv, final Type t, final boolean varArg) { 897 // We perform conversions of some primitives to accommodate types that 898 // Nashorn can handle. 899 switch(t.getSort()) { 900 case Type.CHAR: 901 // Chars are boxed, as we don't know if the JS code wants to treat 902 // them as an effective "unsigned short" or as a single-char string. 903 CHAR_VALUE_OF.invoke(mv); 904 break; 905 case Type.FLOAT: 906 // Floats are widened to double. 907 mv.visitInsn(Opcodes.F2D); 908 if (varArg) { 909 // We'll be boxing everything anyway for the vararg invocation, 910 // so we might as well do it proactively here and thus not cause 911 // a widening in the number of slots, as that could even make 912 // the array creation invocation go over 255 param slots. 913 DOUBLE_VALUE_OF.invoke(mv); 914 } 915 break; 916 case Type.LONG: 917 // Longs are boxed as Nashorn can't represent them precisely as a 918 // primitive number. 919 LONG_VALUE_OF.invoke(mv); 920 break; 921 case Type.OBJECT: 922 if(t.equals(OBJECT_TYPE)) { 923 // Object can carry a ScriptObjectMirror and needs to be unwrapped 924 // before passing into a Nashorn function. 925 UNWRAP.invoke(mv); 926 } 927 break; 928 } 929 } 930 931 private static int getParamListLengthInSlots(final Type[] paramTypes) { 932 int len = paramTypes.length; 933 for(final Type t: paramTypes) { 934 final int sort = t.getSort(); 935 if (sort == Type.FLOAT || sort == Type.DOUBLE) { 936 // Floats are widened to double, so they'll take up two slots. 937 // Longs on the other hand are always boxed, so their width 938 // becomes 1 and thus they don't contribute an extra slot here. 939 ++len; 940 } 941 } 942 return len; 943 } 944 /** 945 * Emit code to restore the previous Nashorn Context when needed. 946 * @param mv the instruction adapter 947 * @param globalRestoringRunnableVar index of the local variable holding the reference to the global restoring Runnable 948 */ 949 private static void emitFinally(final InstructionAdapter mv, final int globalRestoringRunnableVar) { 950 mv.visitVarInsn(ALOAD, globalRestoringRunnableVar); 951 RUN.invoke(mv); 952 } 953 954 private static boolean isThrowableDeclared(final Class<?>[] exceptions) { 955 for (final Class<?> exception : exceptions) { 956 if (exception == Throwable.class) { 957 return true; 958 } 959 } 960 return false; 961 } 962 963 private void generateSuperMethods() { 964 for(final MethodInfo mi: methodInfos) { 965 if(!Modifier.isAbstract(mi.method.getModifiers())) { 966 generateSuperMethod(mi); 967 } 968 } 969 } 970 971 private void generateSuperMethod(final MethodInfo mi) { 972 final Method method = mi.method; 973 974 final String methodDesc = mi.type.toMethodDescriptorString(); 975 final String name = mi.getName(); 976 977 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), 978 SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); 979 mv.visitCode(); 980 981 emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); 982 mv.areturn(Type.getType(mi.type.returnType())); 983 endMethod(mv); 984 } 985 986 // find the appropriate super type to use for invokespecial on the given interface 987 private Class<?> findInvokespecialOwnerFor(final Class<?> cl) { 988 assert Modifier.isInterface(cl.getModifiers()) : cl + " is not an interface"; 989 990 if (cl.isAssignableFrom(superClass)) { 991 return superClass; 992 } 993 994 for (final Class<?> iface : interfaces) { 995 if (cl.isAssignableFrom(iface)) { 996 return iface; 997 } 998 } 999 1000 // we better that interface that extends the given interface! 1001 throw new AssertionError("can't find the class/interface that extends " + cl); 1002 } 1003 1004 private int emitSuperConstructorCall(final InstructionAdapter mv, final String methodDesc) { 1005 return emitSuperCall(mv, null, INIT, methodDesc, true); 1006 } 1007 1008 private int emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) { 1009 return emitSuperCall(mv, owner, name, methodDesc, false); 1010 } 1011 1012 private int emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc, final boolean constructor) { 1013 mv.visitVarInsn(ALOAD, 0); 1014 int nextParam = 1; 1015 final Type methodType = Type.getMethodType(methodDesc); 1016 for(final Type t: methodType.getArgumentTypes()) { 1017 mv.load(nextParam, t); 1018 nextParam += t.getSize(); 1019 } 1020 1021 // default method - non-abstract, interface method 1022 if (!constructor && Modifier.isInterface(owner.getModifiers())) { 1023 // we should call default method on the immediate "super" type - not on (possibly) 1024 // the indirectly inherited interface class! 1025 mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false); 1026 } else { 1027 mv.invokespecial(superClassName, name, methodDesc, false); 1028 } 1029 return nextParam; 1030 } 1031 1032 private void generateFinalizerMethods() { 1033 generateFinalizerDelegate(); 1034 generateFinalizerOverride(); 1035 } 1036 1037 private void generateFinalizerDelegate() { 1038 // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll 1039 // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see 1040 // generateFinalizerOverride()). 1041 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC, 1042 FINALIZER_DELEGATE_NAME, FINALIZER_DELEGATE_METHOD_DESCRIPTOR, null, null)); 1043 1044 // Simply invoke super.finalize() 1045 mv.visitVarInsn(ALOAD, 0); 1046 mv.checkcast(Type.getType(generatedClassName)); 1047 mv.invokespecial(superClassName, "finalize", VOID_METHOD_DESCRIPTOR, false); 1048 1049 mv.visitInsn(RETURN); 1050 endMethod(mv); 1051 } 1052 1053 @SuppressWarnings("deprecation") 1054 private void generateFinalizerOverride() { 1055 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, "finalize", 1056 VOID_METHOD_DESCRIPTOR, null, null)); 1057 // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ... 1058 mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, FINALIZER_DELEGATE_NAME, 1059 FINALIZER_DELEGATE_METHOD_DESCRIPTOR)); 1060 mv.visitVarInsn(ALOAD, 0); 1061 // ...and invoke it through JavaAdapterServices.invokeNoPermissions 1062 INVOKE_NO_PERMISSIONS.invoke(mv); 1063 mv.visitInsn(RETURN); 1064 endMethod(mv); 1065 } 1066 1067 private static String[] getExceptionNames(final Class<?>[] exceptions) { 1068 final String[] exceptionNames = new String[exceptions.length]; 1069 for (int i = 0; i < exceptions.length; ++i) { 1070 exceptionNames[i] = Type.getInternalName(exceptions[i]); 1071 } 1072 return exceptionNames; 1073 } 1074 1075 private static int getAccessModifiers(final Method method) { 1076 return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0); 1077 } 1078 1079 /** 1080 * Gathers methods that can be implemented or overridden from the specified type into this factory's 1081 * {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from 1082 * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its 1083 * superclass and the interfaces it implements, and add further methods that were not directly declared on the 1084 * class. 1085 * @param type the type defining the methods. 1086 */ 1087 private void gatherMethods(final Class<?> type) throws AdaptationException { 1088 if (Modifier.isPublic(type.getModifiers())) { 1089 final Module module = type.getModule(); 1090 if (module != null) { 1091 accessedModules.add(module); 1092 } 1093 1094 final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods(); 1095 1096 for (final Method typeMethod: typeMethods) { 1097 final String name = typeMethod.getName(); 1098 if(name.startsWith(SUPER_PREFIX)) { 1099 continue; 1100 } 1101 final int m = typeMethod.getModifiers(); 1102 if (Modifier.isStatic(m)) { 1103 continue; 1104 } 1105 if (Modifier.isPublic(m) || Modifier.isProtected(m)) { 1106 // Is it a "finalize()"? 1107 if(name.equals("finalize") && typeMethod.getParameterCount() == 0) { 1108 if(type != Object.class) { 1109 hasExplicitFinalizer = true; 1110 if(Modifier.isFinal(m)) { 1111 // Must be able to override an explicit finalizer 1112 throw new AdaptationException(Outcome.ERROR_FINAL_FINALIZER, type.getCanonicalName()); 1113 } 1114 } 1115 continue; 1116 } 1117 1118 for (final Class<?> pt : typeMethod.getParameterTypes()) { 1119 if (pt.isPrimitive()) continue; 1120 final Module ptMod = pt.getModule(); 1121 if (ptMod != null) { 1122 accessedModules.add(ptMod); 1123 } 1124 } 1125 1126 final Class<?> rt = typeMethod.getReturnType(); 1127 if (!rt.isPrimitive()) { 1128 final Module rtMod = rt.getModule(); 1129 if (rtMod != null) accessedModules.add(rtMod); 1130 } 1131 1132 final MethodInfo mi = new MethodInfo(typeMethod); 1133 if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) { 1134 finalMethods.add(mi); 1135 } else if (!finalMethods.contains(mi) && methodInfos.add(mi) && Modifier.isAbstract(m)) { 1136 abstractMethodNames.add(mi.getName()); 1137 } 1138 } 1139 } 1140 } 1141 // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done. 1142 // Needing to invoke the method recursively for a non-interface Class object is the consequence of needing to 1143 // see all declared protected methods, and Class.getDeclaredMethods() doesn't provide those declared in a 1144 // superclass. For interfaces, we used Class.getMethods(), as we're only interested in public ones there, and 1145 // getMethods() does provide those declared in a superinterface. 1146 if (!type.isInterface()) { 1147 final Class<?> superType = type.getSuperclass(); 1148 if (superType != null) { 1149 gatherMethods(superType); 1150 } 1151 for (final Class<?> itf: type.getInterfaces()) { 1152 gatherMethods(itf); 1153 } 1154 } 1155 } 1156 1157 private void gatherMethods(final List<Class<?>> classes) throws AdaptationException { 1158 for(final Class<?> c: classes) { 1159 gatherMethods(c); 1160 } 1161 } 1162 1163 private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers"); 1164 1165 /** 1166 * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters, 1167 * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and 1168 * {@code Object.clone()}. 1169 * @return a collection of method infos representing those methods that we never override in adapter classes. 1170 */ 1171 private static Collection<MethodInfo> getExcludedMethods() { 1172 return AccessController.doPrivileged(new PrivilegedAction<Collection<MethodInfo>>() { 1173 @Override 1174 public Collection<MethodInfo> run() { 1175 try { 1176 return Arrays.asList( 1177 new MethodInfo(Object.class, "finalize"), 1178 new MethodInfo(Object.class, "clone")); 1179 } catch (final NoSuchMethodException e) { 1180 throw new AssertionError(e); 1181 } 1182 } 1183 }, GET_DECLARED_MEMBERS_ACC_CTXT); 1184 } 1185 1186 private String getCommonSuperClass(final String type1, final String type2) { 1187 try { 1188 final Class<?> c1 = Class.forName(type1.replace('/', '.'), false, commonLoader); 1189 final Class<?> c2 = Class.forName(type2.replace('/', '.'), false, commonLoader); 1190 if (c1.isAssignableFrom(c2)) { 1191 return type1; 1192 } 1193 if (c2.isAssignableFrom(c1)) { 1194 return type2; 1195 } 1196 if (c1.isInterface() || c2.isInterface()) { 1197 return OBJECT_TYPE.getInternalName(); 1198 } 1199 return assignableSuperClass(c1, c2).getName().replace('.', '/'); 1200 } catch(final ClassNotFoundException e) { 1201 throw new RuntimeException(e); 1202 } 1203 } 1204 1205 private static Class<?> assignableSuperClass(final Class<?> c1, final Class<?> c2) { 1206 final Class<?> superClass = c1.getSuperclass(); 1207 return superClass.isAssignableFrom(c2) ? superClass : assignableSuperClass(superClass, c2); 1208 } 1209 1210 private static boolean isCallerSensitive(final AccessibleObject e) { 1211 return e.isAnnotationPresent(CallerSensitive.class); 1212 } 1213 1214 private static final Call lookupServiceMethod(final String name, final Class<?> rtype, final Class<?>... ptypes) { 1215 return staticCallNoLookup(JavaAdapterServices.class, name, rtype, ptypes); 1216 } 1217} 1218