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); |
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(); |
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 } |
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); |
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. |