src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java

changeset 719
11b83c913cca
parent 609
34f7a699cdef
child 747
cfe1ce3a1067
child 802
2699ac6a6ccb
equal deleted inserted replaced
718:c59fb10cb0b5 719:11b83c913cca
57 import java.util.HashSet; 57 import java.util.HashSet;
58 import java.util.Iterator; 58 import java.util.Iterator;
59 import java.util.List; 59 import java.util.List;
60 import java.util.Set; 60 import java.util.Set;
61 import jdk.internal.org.objectweb.asm.ClassWriter; 61 import jdk.internal.org.objectweb.asm.ClassWriter;
62 import jdk.internal.org.objectweb.asm.Handle;
62 import jdk.internal.org.objectweb.asm.Label; 63 import jdk.internal.org.objectweb.asm.Label;
63 import jdk.internal.org.objectweb.asm.Opcodes; 64 import jdk.internal.org.objectweb.asm.Opcodes;
64 import jdk.internal.org.objectweb.asm.Type; 65 import jdk.internal.org.objectweb.asm.Type;
65 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter; 66 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
66 import jdk.nashorn.internal.runtime.Context; 67 import jdk.nashorn.internal.runtime.Context;
67 import jdk.nashorn.internal.runtime.ScriptFunction; 68 import jdk.nashorn.internal.runtime.ScriptFunction;
68 import jdk.nashorn.internal.runtime.ScriptObject; 69 import jdk.nashorn.internal.runtime.ScriptObject;
70 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
69 import sun.reflect.CallerSensitive; 71 import sun.reflect.CallerSensitive;
70 72
71 /** 73 /**
72 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}. 74 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}.
73 * </p><p> 75 * </p><p>
74 * For every protected or public constructor in the extended class, the adapter class will have between one to three 76 * For every protected or public constructor in the extended class, the adapter class will have either one or two
75 * public constructors (visibility of protected constructors in the extended class is promoted to public). 77 * public constructors (visibility of protected constructors in the extended class is promoted to public).
76 * <ul> 78 * <li>
77 * <li>In every case, a constructor taking a trailing ScriptObject argument preceded by original constructor arguments 79 * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded
78 * is always created on the adapter class. When such a constructor is invoked, the passed ScriptObject's member 80 * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the
79 * functions are used to implement and/or override methods on the original class, dispatched by name. A single 81 * passed ScriptObject's member functions are used to implement and/or override methods on the original class,
80 * JavaScript function will act as the implementation for all overloaded methods of the same name. When methods on an 82 * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the
81 * adapter instance are invoked, the functions are invoked having the ScriptObject passed in the instance constructor as 83 * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed
82 * their "this". Subsequent changes to the ScriptObject (reassignment or removal of its functions) are not reflected in 84 * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its
83 * the adapter instance; the method implementations are bound to functions at constructor invocation time. 85 * functions) are not reflected in the adapter instance; the method implementations are bound to functions at
86 * constructor invocation time.
84 * {@code java.lang.Object} methods {@code equals}, {@code hashCode}, and {@code toString} can also be overridden. The 87 * {@code java.lang.Object} methods {@code equals}, {@code hashCode}, and {@code toString} can also be overridden. The
85 * only restriction is that since every JavaScript object already has a {@code toString} function through the 88 * only restriction is that since every JavaScript object already has a {@code toString} function through the
86 * {@code Object.prototype}, the {@code toString} in the adapter is only overridden if the passed ScriptObject has a 89 * {@code Object.prototype}, the {@code toString} in the adapter is only overridden if the passed ScriptObject has a
87 * {@code toString} function as its own property, and not inherited from a prototype. All other adapter methods can be 90 * {@code toString} function as its own property, and not inherited from a prototype. All other adapter methods can be
88 * implemented or overridden through a prototype-inherited function of the ScriptObject passed to the constructor too. 91 * implemented or overridden through a prototype-inherited function of the ScriptObject passed to the constructor too.
89 * </li> 92 * </li>
90 * <li> 93 * <li>
91 * If the original types collectively have only one abstract method, or have several of them, but all share the 94 * If the original types collectively have only one abstract method, or have several of them, but all share the
92 * same name, an additional constructor is provided for every original constructor; this one takes a ScriptFunction as 95 * same name, an additional constructor for instance-level override adapter is provided for every original constructor;
93 * its last argument preceded by original constructor arguments. This constructor will use the passed function as the 96 * this one takes a ScriptFunction as its last argument preceded by original constructor arguments. This constructor
94 * implementation for all abstract methods. For consistency, any concrete methods sharing the single abstract method 97 * will use the passed function as the implementation for all abstract methods. For consistency, any concrete methods
95 * name will also be overridden by the function. When methods on the adapter instance are invoked, the ScriptFunction is 98 * sharing the single abstract method name will also be overridden by the function. When methods on the adapter instance
96 * invoked with global or UNDEFINED as its "this" depending whether the function is non-strict or not. 99 * are invoked, the ScriptFunction is invoked with UNDEFINED or Global as its "this" depending whether the function is
100 * strict or not.
97 * </li> 101 * </li>
98 * <li> 102 * <li>
99 * If the adapter being generated can have class-level overrides, constructors taking same arguments as the superclass 103 * If the adapter being generated can have class-level overrides, constructors taking same arguments as the superclass
100 * constructors are also created. These constructors simply delegate to the superclass constructor. They are used to 104 * constructors are created. These constructors simply delegate to the superclass constructor. They are simply used to
101 * create instances of the adapter class with no instance-level overrides. 105 * create instances of the adapter class, with no instance-level overrides, as they don't have them.
102 * </li> 106 * </li>
103 * </ul> 107 * </ul>
104 * </p><p> 108 * </p><p>
105 * For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect 109 * For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect
106 * to coerce the JavaScript function return value to the expected Java return type. 110 * to coerce the JavaScript function return value to the expected Java return type.
109 * declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The 113 * declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The
110 * reason we are passing the additional argument at the end of the argument list instead at the front is that the 114 * reason we are passing the additional argument at the end of the argument list instead at the front is that the
111 * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses 115 * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses
112 * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>. 116 * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>.
113 * </p><p> 117 * </p><p>
114 * It is possible to create two different classes: those that can have both class-level and instance-level overrides, 118 * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
115 * and those that can only have instance-level overrides. When 119 * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
116 * {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked with non-null {@code classOverrides} 120 * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
117 * parameter, an adapter class is created that can have class-level overrides, and the passed script object will be used 121 * the passed script object will be used as the implementations for its methods, just as in the above case of the
118 * as the implementations for its methods, just as in the above case of the constructor taking a script object. Note 122 * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
119 * that in the case of class-level overrides, a new adapter class is created on every invocation, and the implementation 123 * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
120 * object is bound to the class, not to any instance. All created instances will share these functions. Of course, when 124 * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the
121 * instances of such a class are being created, they can still take another object (or possibly a function) in their 125 * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to
122 * constructor's trailing position and thus provide further instance-specific overrides. The order of invocation is 126 * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to
123 * always instance-specified method, then a class-specified method, and finally the superclass method. 127 * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are
128 * defined with a protection domain of their creator code, and an adapter class that has both class and instance level
129 * overrides would need to have two potentially different protection domains: one for class-based behavior and one for
130 * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be
131 * implemented securely.
124 */ 132 */
125 final class JavaAdapterBytecodeGenerator { 133 final class JavaAdapterBytecodeGenerator {
126 static final Type CONTEXT_TYPE = Type.getType(Context.class); 134 static final Type CONTEXT_TYPE = Type.getType(Context.class);
127 static final Type OBJECT_TYPE = Type.getType(Object.class); 135 static final Type OBJECT_TYPE = Type.getType(Object.class);
128 static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class); 136 static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
169 private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter"; 177 private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter";
170 private static final String JAVA_PACKAGE_PREFIX = "java/"; 178 private static final String JAVA_PACKAGE_PREFIX = "java/";
171 private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255; 179 private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
172 180
173 private static final String CLASS_INIT = "<clinit>"; 181 private static final String CLASS_INIT = "<clinit>";
174 private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal";
175 182
176 // Method name prefix for invoking super-methods 183 // Method name prefix for invoking super-methods
177 static final String SUPER_PREFIX = "super$"; 184 static final String SUPER_PREFIX = "super$";
178 185
179 /** 186 /**
197 private final Set<String> abstractMethodNames = new HashSet<>(); 204 private final Set<String> abstractMethodNames = new HashSet<>();
198 private final String samName; 205 private final String samName;
199 private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED); 206 private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED);
200 private final Set<MethodInfo> methodInfos = new HashSet<>(); 207 private final Set<MethodInfo> methodInfos = new HashSet<>();
201 private boolean autoConvertibleFromFunction = false; 208 private boolean autoConvertibleFromFunction = false;
209 private boolean hasExplicitFinalizer = false;
202 210
203 private final ClassWriter cw; 211 private final ClassWriter cw;
204 212
205 /** 213 /**
206 * Creates a generator for the bytecode for the adapter for the specified superclass and interfaces. 214 * Creates a generator for the bytecode for the adapter for the specified superclass and interfaces.
207 * @param superClass the superclass the adapter will extend. 215 * @param superClass the superclass the adapter will extend.
208 * @param interfaces the interfaces the adapter will implement. 216 * @param interfaces the interfaces the adapter will implement.
209 * @param commonLoader the class loader that can see all of superClass, interfaces, and Nashorn classes. 217 * @param commonLoader the class loader that can see all of superClass, interfaces, and Nashorn classes.
210 * @param classOverride true to generate the bytecode for the adapter that has both class-level and instance-level 218 * @param classOverride true to generate the bytecode for the adapter that has class-level overrides, false to
211 * overrides, false to generate the bytecode for the adapter that only has instance-level overrides. 219 * generate the bytecode for the adapter that has instance-level overrides.
212 * @throws AdaptationException if the adapter can not be generated for some reason. 220 * @throws AdaptationException if the adapter can not be generated for some reason.
213 */ 221 */
214 JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces, 222 JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces,
215 final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException { 223 final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException {
216 assert superClass != null && !superClass.isInterface(); 224 assert superClass != null && !superClass.isInterface();
228 } 236 }
229 }; 237 };
230 superClassName = Type.getInternalName(superClass); 238 superClassName = Type.getInternalName(superClass);
231 generatedClassName = getGeneratedClassName(superClass, interfaces); 239 generatedClassName = getGeneratedClassName(superClass, interfaces);
232 240
233 cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, generatedClassName, null, superClassName, getInternalTypeNames(interfaces)); 241 cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER, generatedClassName, null, superClassName, getInternalTypeNames(interfaces));
234
235 generateGlobalFields(); 242 generateGlobalFields();
236 243
237 gatherMethods(superClass); 244 gatherMethods(superClass);
238 gatherMethods(interfaces); 245 gatherMethods(interfaces);
239 samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null; 246 samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
242 generateClassInit(); 249 generateClassInit();
243 } 250 }
244 generateConstructors(); 251 generateConstructors();
245 generateMethods(); 252 generateMethods();
246 generateSuperMethods(); 253 generateSuperMethods();
254 if (hasExplicitFinalizer) {
255 generateFinalizerMethods();
256 }
247 // } 257 // }
248 cw.visitEnd(); 258 cw.visitEnd();
249 } 259 }
250 260
251 private void generateGlobalFields() { 261 private void generateGlobalFields() {
252 cw.visitField(ACC_PRIVATE | ACC_FINAL, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd(); 262 cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
253 usedFieldNames.add(GLOBAL_FIELD_NAME); 263 usedFieldNames.add(GLOBAL_FIELD_NAME);
254 if(classOverride) {
255 cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
256 usedFieldNames.add(STATIC_GLOBAL_FIELD_NAME);
257 }
258 } 264 }
259 265
260 JavaAdapterClassLoader createAdapterClassLoader() { 266 JavaAdapterClassLoader createAdapterClassLoader() {
261 return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray()); 267 return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray());
262 } 268 }
303 } 309 }
304 return interfaceNames; 310 return interfaceNames;
305 } 311 }
306 312
307 private void generateHandleFields() { 313 private void generateHandleFields() {
314 final int flags = ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0);
308 for (final MethodInfo mi: methodInfos) { 315 for (final MethodInfo mi: methodInfos) {
309 cw.visitField(ACC_PRIVATE | ACC_FINAL, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd(); 316 cw.visitField(flags, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd();
310 if(classOverride) {
311 cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd();
312 }
313 } 317 }
314 } 318 }
315 319
316 private void generateClassInit() { 320 private void generateClassInit() {
317 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT, 321 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT,
335 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 339 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
336 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_FUNCTION_DESCRIPTOR); 340 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_FUNCTION_DESCRIPTOR);
337 } else { 341 } else {
338 mv.visitInsn(ACONST_NULL); 342 mv.visitInsn(ACONST_NULL);
339 } 343 }
340 mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 344 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
341 } 345 }
342 initGlobal = new Label(); 346 initGlobal = new Label();
343 mv.goTo(initGlobal); 347 mv.goTo(initGlobal);
344 mv.visitLabel(notAFunction); 348 mv.visitLabel(notAFunction);
345 } else { 349 } else {
349 for (final MethodInfo mi : methodInfos) { 353 for (final MethodInfo mi : methodInfos) {
350 mv.dup(); 354 mv.dup();
351 mv.aconst(mi.getName()); 355 mv.aconst(mi.getName());
352 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 356 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
353 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR); 357 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR);
354 mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 358 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
355 } 359 }
356 360
357 if(initGlobal != null) { 361 if(initGlobal != null) {
358 mv.visitLabel(initGlobal); 362 mv.visitLabel(initGlobal);
359 } 363 }
360 // Assign "staticGlobal = Context.getGlobal()" 364 // Assign "global = Context.getGlobal()"
361 invokeGetGlobalWithNullCheck(mv); 365 invokeGetGlobalWithNullCheck(mv);
362 mv.putstatic(generatedClassName, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); 366 mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
363 367
364 endInitMethod(mv); 368 endInitMethod(mv);
365 } 369 }
366 370
367 private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) { 371 private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) {
388 private void generateConstructors(final Constructor<?> ctor) { 392 private void generateConstructors(final Constructor<?> ctor) {
389 if(classOverride) { 393 if(classOverride) {
390 // Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want 394 // Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want
391 // to create instances without further per-instance overrides. 395 // to create instances without further per-instance overrides.
392 generateDelegatingConstructor(ctor); 396 generateDelegatingConstructor(ctor);
393 } 397 } else {
394 398 // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the
395 // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the 399 // beginning of its parameter list.
396 // beginning of its parameter list. 400 generateOverridingConstructor(ctor, false);
397 generateOverridingConstructor(ctor, false); 401
398 402 if (samName != null) {
399 if (samName != null) { 403 if (!autoConvertibleFromFunction && ctor.getParameterTypes().length == 0) {
400 if (!autoConvertibleFromFunction && ctor.getParameterTypes().length == 0) { 404 // If the original type only has a single abstract method name, as well as a default ctor, then it can
401 // If the original type only has a single abstract method name, as well as a default ctor, then it can 405 // be automatically converted from JS function.
402 // be automatically converted from JS function. 406 autoConvertibleFromFunction = true;
403 autoConvertibleFromFunction = true; 407 }
404 } 408 // If all our abstract methods have a single name, generate an additional constructor, one that takes a
405 // If all our abstract methods have a single name, generate an additional constructor, one that takes a 409 // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods.
406 // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods. 410 generateOverridingConstructor(ctor, true);
407 generateOverridingConstructor(ctor, true); 411 }
408 } 412 }
409 } 413 }
410 414
411 private void generateDelegatingConstructor(final Constructor<?> ctor) { 415 private void generateDelegatingConstructor(final Constructor<?> ctor) {
412 final Type originalCtorType = Type.getType(ctor); 416 final Type originalCtorType = Type.getType(ctor);
428 432
429 endInitMethod(mv); 433 endInitMethod(mv);
430 } 434 }
431 435
432 /** 436 /**
433 * Generates a constructor for the adapter class. This constructor will take the same arguments as the supertype 437 * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype
434 * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of 438 * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of
435 * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize 439 * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize
436 * all the method handle fields of the adapter instance with functions from the script object (or the script 440 * all the method handle fields of the adapter instance with functions from the script object (or the script
437 * function itself, if that's what's passed). There is one method handle field in the adapter class for every method 441 * function itself, if that's what's passed). There is one method handle field in the adapter class for every method
438 * that can be implemented or overridden; the name of every field is same as the name of the method, with a number 442 * that can be implemented or overridden; the name of every field is same as the name of the method, with a number
496 mv.aconst(mi.getName()); 500 mv.aconst(mi.getName());
497 } 501 }
498 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 502 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
499 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor); 503 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor);
500 } 504 }
501 mv.putfield(generatedClassName, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 505 mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
502 } 506 }
503 507
504 // Assign "this.global = Context.getGlobal()" 508 // Assign "this.global = Context.getGlobal()"
505 mv.visitVarInsn(ALOAD, 0); 509 mv.visitVarInsn(ALOAD, 0);
506 invokeGetGlobalWithNullCheck(mv); 510 invokeGetGlobalWithNullCheck(mv);
534 * 538 *
535 */ 539 */
536 private static class MethodInfo { 540 private static class MethodInfo {
537 private final Method method; 541 private final Method method;
538 private final MethodType type; 542 private final MethodType type;
539 private String methodHandleInstanceFieldName; 543 private String methodHandleFieldName;
540 private String methodHandleClassFieldName;
541 544
542 private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException { 545 private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException {
543 this(clazz.getDeclaredMethod(name, argTypes)); 546 this(clazz.getDeclaredMethod(name, argTypes));
544 } 547 }
545 548
565 @Override 568 @Override
566 public int hashCode() { 569 public int hashCode() {
567 return getName().hashCode() ^ type.hashCode(); 570 return getName().hashCode() ^ type.hashCode();
568 } 571 }
569 572
570 void setIsCanonical(final Set<String> usedFieldNames, boolean classOverride) { 573 void setIsCanonical(final JavaAdapterBytecodeGenerator self) {
571 methodHandleInstanceFieldName = nextName(usedFieldNames); 574 methodHandleFieldName = self.nextName(getName());
572 if(classOverride) { 575 }
573 methodHandleClassFieldName = nextName(usedFieldNames); 576 }
574 } 577
575 } 578 private String nextName(final String name) {
576 579 int i = 0;
577 String nextName(final Set<String> usedFieldNames) { 580 String nextName = name;
578 int i = 0; 581 while (!usedFieldNames.add(nextName)) {
579 final String name = getName(); 582 final String ordinal = String.valueOf(i++);
580 String nextName = name; 583 final int maxNameLen = 255 - ordinal.length();
581 while (!usedFieldNames.add(nextName)) { 584 nextName = (name.length() <= maxNameLen ? name : name.substring(0, maxNameLen)).concat(ordinal);
582 final String ordinal = String.valueOf(i++); 585 }
583 final int maxNameLen = 255 - ordinal.length(); 586 return nextName;
584 nextName = (name.length() <= maxNameLen ? name : name.substring(0, maxNameLen)).concat(ordinal);
585 }
586 return nextName;
587 }
588
589 } 587 }
590 588
591 private void generateMethods() { 589 private void generateMethods() {
592 for(final MethodInfo mi: methodInfos) { 590 for(final MethodInfo mi: methodInfos) {
593 generateMethod(mi); 591 generateMethod(mi);
622 620
623 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name, 621 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name,
624 methodDesc, null, exceptionNames)); 622 methodDesc, null, exceptionNames));
625 mv.visitCode(); 623 mv.visitCode();
626 624
627 final Label instanceHandleDefined = new Label(); 625 final Label handleDefined = new Label();
628 final Label classHandleDefined = new Label();
629 626
630 final Type asmReturnType = Type.getType(type.returnType()); 627 final Type asmReturnType = Type.getType(type.returnType());
631 628
632 // See if we have instance handle defined 629 // See if we have overriding method handle defined
633 mv.visitVarInsn(ALOAD, 0);
634 mv.getfield(generatedClassName, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
635 // stack: [instanceHandle]
636 jumpIfNonNullKeepOperand(mv, instanceHandleDefined);
637
638 if(classOverride) { 630 if(classOverride) {
639 // See if we have the static handle 631 mv.getstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
640 mv.getstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 632 } else {
641 // stack: [classHandle] 633 mv.visitVarInsn(ALOAD, 0);
642 jumpIfNonNullKeepOperand(mv, classHandleDefined); 634 mv.getfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
643 } 635 }
636 // stack: [handle]
637 jumpIfNonNullKeepOperand(mv, handleDefined);
644 638
645 // No handle is available, fall back to default behavior 639 // No handle is available, fall back to default behavior
646 if(Modifier.isAbstract(method.getModifiers())) { 640 if(Modifier.isAbstract(method.getModifiers())) {
647 // If the super method is abstract, throw an exception 641 // If the super method is abstract, throw an exception
648 mv.anew(UNSUPPORTED_OPERATION_TYPE); 642 mv.anew(UNSUPPORTED_OPERATION_TYPE);
652 } else { 646 } else {
653 // If the super method is not abstract, delegate to it. 647 // If the super method is not abstract, delegate to it.
654 emitSuperCall(mv, name, methodDesc); 648 emitSuperCall(mv, name, methodDesc);
655 } 649 }
656 650
651 mv.visitLabel(handleDefined);
652 // Load the creatingGlobal object
653 if(classOverride) {
654 // If class handle is defined, load the static defining global
655 mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
656 } else {
657 mv.visitVarInsn(ALOAD, 0);
658 mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
659 }
660 // stack: [creatingGlobal, handle]
657 final Label setupGlobal = new Label(); 661 final Label setupGlobal = new Label();
658
659 if(classOverride) {
660 mv.visitLabel(classHandleDefined);
661 // If class handle is defined, load the static defining global
662 mv.getstatic(generatedClassName, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
663 // stack: [creatingGlobal := classGlobal, classHandle]
664 mv.goTo(setupGlobal);
665 }
666
667 mv.visitLabel(instanceHandleDefined);
668 // If instance handle is defined, load the instance defining global
669 mv.visitVarInsn(ALOAD, 0);
670 mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
671 // stack: [creatingGlobal := instanceGlobal, instanceHandle]
672
673 // fallthrough to setupGlobal
674
675 // stack: [creatingGlobal, someHandle]
676 mv.visitLabel(setupGlobal); 662 mv.visitLabel(setupGlobal);
677 663
678 // Determine the first index for a local variable 664 // Determine the first index for a local variable
679 int nextLocalVar = 1; // "this" is at 0 665 int nextLocalVar = 1; // "this" is at 0
680 for(final Type t: asmArgTypes) { 666 for(final Type t: asmArgTypes) {
683 // Set our local variable indices 669 // Set our local variable indices
684 final int currentGlobalVar = nextLocalVar++; 670 final int currentGlobalVar = nextLocalVar++;
685 final int globalsDifferVar = nextLocalVar++; 671 final int globalsDifferVar = nextLocalVar++;
686 672
687 mv.dup(); 673 mv.dup();
688 // stack: [creatingGlobal, creatingGlobal, someHandle] 674 // stack: [creatingGlobal, creatingGlobal, handle]
689 675
690 // Emit code for switching to the creating global 676 // Emit code for switching to the creating global
691 // ScriptObject currentGlobal = Context.getGlobal(); 677 // ScriptObject currentGlobal = Context.getGlobal();
692 invokeGetGlobal(mv); 678 invokeGetGlobal(mv);
693 mv.dup(); 679 mv.dup();
680
694 mv.visitVarInsn(ASTORE, currentGlobalVar); 681 mv.visitVarInsn(ASTORE, currentGlobalVar);
695 // stack: [currentGlobal, creatingGlobal, creatingGlobal, someHandle] 682 // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
696 // if(definingGlobal == currentGlobal) { 683 // if(definingGlobal == currentGlobal) {
697 final Label globalsDiffer = new Label(); 684 final Label globalsDiffer = new Label();
698 mv.ifacmpne(globalsDiffer); 685 mv.ifacmpne(globalsDiffer);
699 // stack: [someGlobal, someHandle] 686 // stack: [creatingGlobal, handle]
700 // globalsDiffer = false 687 // globalsDiffer = false
701 mv.pop(); 688 mv.pop();
702 // stack: [someHandle] 689 // stack: [handle]
703 mv.iconst(0); // false 690 mv.iconst(0); // false
704 // stack: [false, someHandle] 691 // stack: [false, handle]
705 final Label invokeHandle = new Label(); 692 final Label invokeHandle = new Label();
706 mv.goTo(invokeHandle); 693 mv.goTo(invokeHandle);
707 mv.visitLabel(globalsDiffer); 694 mv.visitLabel(globalsDiffer);
708 // } else { 695 // } else {
709 // Context.setGlobal(definingGlobal); 696 // Context.setGlobal(definingGlobal);
710 // stack: [someGlobal, someHandle] 697 // stack: [creatingGlobal, handle]
711 invokeSetGlobal(mv); 698 invokeSetGlobal(mv);
712 // stack: [someHandle] 699 // stack: [handle]
713 // globalsDiffer = true 700 // globalsDiffer = true
714 mv.iconst(1); 701 mv.iconst(1);
715 // stack: [true, someHandle] 702 // stack: [true, handle]
716 703
717 mv.visitLabel(invokeHandle); 704 mv.visitLabel(invokeHandle);
718 mv.visitVarInsn(ISTORE, globalsDifferVar); 705 mv.visitVarInsn(ISTORE, globalsDifferVar);
719 // stack: [someHandle] 706 // stack: [handle]
720 707
721 // Load all parameters back on stack for dynamic invocation. 708 // Load all parameters back on stack for dynamic invocation.
722 int varOffset = 1; 709 int varOffset = 1;
723 for (final Type t : asmArgTypes) { 710 for (final Type t : asmArgTypes) {
724 mv.load(varOffset, t); 711 mv.load(varOffset, t);
845 } 832 }
846 mv.invokespecial(superClassName, name, methodDesc); 833 mv.invokespecial(superClassName, name, methodDesc);
847 mv.areturn(methodType.getReturnType()); 834 mv.areturn(methodType.getReturnType());
848 } 835 }
849 836
837 private void generateFinalizerMethods() {
838 final String finalizerDelegateName = nextName("access$");
839 generateFinalizerDelegate(finalizerDelegateName);
840 generateFinalizerOverride(finalizerDelegateName);
841 }
842
843 private void generateFinalizerDelegate(final String finalizerDelegateName) {
844 // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll
845 // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see
846 // generateFinalizerOverride()).
847 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC,
848 finalizerDelegateName, Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE), null, null));
849
850 // Simply invoke super.finalize()
851 mv.visitVarInsn(ALOAD, 0);
852 mv.checkcast(Type.getType(generatedClassName));
853 mv.invokespecial(superClassName, "finalize", Type.getMethodDescriptor(Type.VOID_TYPE), false);
854
855 mv.visitInsn(RETURN);
856 endMethod(mv);
857 }
858
859 private void generateFinalizerOverride(final String finalizerDelegateName) {
860 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, "finalize",
861 VOID_NOARG_METHOD_DESCRIPTOR, null, null));
862 // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ...
863 mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, finalizerDelegateName,
864 Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE)));
865 mv.visitVarInsn(ALOAD, 0);
866 // ...and invoke it through JavaAdapterServices.invokeNoPermissions
867 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "invokeNoPermissions",
868 Type.getMethodDescriptor(METHOD_HANDLE_TYPE, OBJECT_TYPE), false);
869 mv.visitInsn(RETURN);
870 endMethod(mv);
871 }
872
850 private static String[] getExceptionNames(final Class<?>[] exceptions) { 873 private static String[] getExceptionNames(final Class<?>[] exceptions) {
851 final String[] exceptionNames = new String[exceptions.length]; 874 final String[] exceptionNames = new String[exceptions.length];
852 for (int i = 0; i < exceptions.length; ++i) { 875 for (int i = 0; i < exceptions.length; ++i) {
853 exceptionNames[i] = Type.getInternalName(exceptions[i]); 876 exceptionNames[i] = Type.getInternalName(exceptions[i]);
854 } 877 }
865 * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its 888 * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its
866 * superclass and the interfaces it implements, and add further methods that were not directly declared on the 889 * superclass and the interfaces it implements, and add further methods that were not directly declared on the
867 * class. 890 * class.
868 * @param type the type defining the methods. 891 * @param type the type defining the methods.
869 */ 892 */
870 private void gatherMethods(final Class<?> type) { 893 private void gatherMethods(final Class<?> type) throws AdaptationException {
871 if (Modifier.isPublic(type.getModifiers())) { 894 if (Modifier.isPublic(type.getModifiers())) {
872 final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods(); 895 final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods();
873 896
874 for (final Method typeMethod: typeMethods) { 897 for (final Method typeMethod: typeMethods) {
898 final String name = typeMethod.getName();
899 if(name.startsWith(SUPER_PREFIX)) {
900 continue;
901 }
875 final int m = typeMethod.getModifiers(); 902 final int m = typeMethod.getModifiers();
876 if (Modifier.isStatic(m)) { 903 if (Modifier.isStatic(m)) {
877 continue; 904 continue;
878 } 905 }
879 if (Modifier.isPublic(m) || Modifier.isProtected(m)) { 906 if (Modifier.isPublic(m) || Modifier.isProtected(m)) {
907 // Is it a "finalize()"?
908 if(name.equals("finalize") && typeMethod.getParameterCount() == 0) {
909 if(type != Object.class) {
910 hasExplicitFinalizer = true;
911 if(Modifier.isFinal(m)) {
912 // Must be able to override an explicit finalizer
913 throw new AdaptationException(Outcome.ERROR_FINAL_FINALIZER, type.getCanonicalName());
914 }
915 }
916 continue;
917 }
918
880 final MethodInfo mi = new MethodInfo(typeMethod); 919 final MethodInfo mi = new MethodInfo(typeMethod);
881 if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) { 920 if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) {
882 finalMethods.add(mi); 921 finalMethods.add(mi);
883 } else if (!finalMethods.contains(mi) && methodInfos.add(mi)) { 922 } else if (!finalMethods.contains(mi) && methodInfos.add(mi)) {
884 if (Modifier.isAbstract(m)) { 923 if (Modifier.isAbstract(m)) {
885 abstractMethodNames.add(mi.getName()); 924 abstractMethodNames.add(mi.getName());
886 } 925 }
887 mi.setIsCanonical(usedFieldNames, classOverride); 926 mi.setIsCanonical(this);
888 } 927 }
889 } 928 }
890 } 929 }
891 } 930 }
892 // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done. 931 // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done.
903 gatherMethods(itf); 942 gatherMethods(itf);
904 } 943 }
905 } 944 }
906 } 945 }
907 946
908 private void gatherMethods(final List<Class<?>> classes) { 947 private void gatherMethods(final List<Class<?>> classes) throws AdaptationException {
909 for(final Class<?> c: classes) { 948 for(final Class<?> c: classes) {
910 gatherMethods(c); 949 gatherMethods(c);
911 } 950 }
912 } 951 }
913 952

mercurial