47 import java.lang.invoke.MethodType;
48 import java.lang.reflect.AccessibleObject;
49 import java.lang.reflect.Constructor;
50 import java.lang.reflect.Method;
51 import java.lang.reflect.Modifier;
52 import java.security.AccessControlContext;
53 import java.security.AccessController;
54 import java.security.PrivilegedAction;
55 import java.util.Arrays;
56 import java.util.Collection;
57 import java.util.HashSet;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Set;
61 import jdk.internal.org.objectweb.asm.ClassWriter;
62 import jdk.internal.org.objectweb.asm.Handle;
63 import jdk.internal.org.objectweb.asm.Label;
64 import jdk.internal.org.objectweb.asm.Opcodes;
65 import jdk.internal.org.objectweb.asm.Type;
66 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
67 import jdk.nashorn.internal.runtime.Context;
68 import jdk.nashorn.internal.runtime.ScriptFunction;
69 import jdk.nashorn.internal.runtime.ScriptObject;
70 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
71 import sun.reflect.CallerSensitive;
72
73 /**
74 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}.
75 * </p><p>
76 * For every protected or public constructor in the extended class, the adapter class will have either one or two
77 * public constructors (visibility of protected constructors in the extended class is promoted to public).
78 * <li>
79 * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded
80 * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the
81 * passed ScriptObject's member functions are used to implement and/or override methods on the original class,
82 * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the
83 * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed
84 * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its
85 * functions) are not reflected in the adapter instance; the method implementations are bound to functions at
86 * constructor invocation time.
117 * </p><p>
118 * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
119 * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
120 * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
121 * the passed script object will be used as the implementations for its methods, just as in the above case of the
122 * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
123 * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
124 * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the
125 * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to
126 * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to
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.
132 */
133 final class JavaAdapterBytecodeGenerator {
134 static final Type CONTEXT_TYPE = Type.getType(Context.class);
135 static final Type OBJECT_TYPE = Type.getType(Object.class);
136 static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
137
138 static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName();
139 static final String OBJECT_TYPE_NAME = OBJECT_TYPE.getInternalName();
140
141 static final String INIT = "<init>";
142
143 static final String GLOBAL_FIELD_NAME = "global";
144
145 static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();
146
147 static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, SCRIPT_OBJECT_TYPE);
148 static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
149
150 private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
151 private static final Type STRING_TYPE = Type.getType(String.class);
152 private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
153 private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class);
154 private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
155 OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE);
156 private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
157 SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE);
158 private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
159 private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class);
160 private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
161 private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class);
162
163 private static final String SERVICES_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterServices.class);
164 private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName();
165 private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class);
166 private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName();
167 private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName();
168
169 private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor();
170 private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
171 private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class));
172
173 // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because
174 // it's a java.* package.
175 private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/javaadapters/";
176 // Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package.
177 private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter";
178 private static final String JAVA_PACKAGE_PREFIX = "java/";
179 private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
180
181 private static final String CLASS_INIT = "<clinit>";
182
183 // Method name prefix for invoking super-methods
184 static final String SUPER_PREFIX = "super$";
185
186 /**
187 * Collection of methods we never override: Object.clone(), Object.finalize().
188 */
189 private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
190
242 generateGlobalFields();
243
244 gatherMethods(superClass);
245 gatherMethods(interfaces);
246 samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
247 generateHandleFields();
248 if(classOverride) {
249 generateClassInit();
250 }
251 generateConstructors();
252 generateMethods();
253 generateSuperMethods();
254 if (hasExplicitFinalizer) {
255 generateFinalizerMethods();
256 }
257 // }
258 cw.visitEnd();
259 }
260
261 private void generateGlobalFields() {
262 cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
263 usedFieldNames.add(GLOBAL_FIELD_NAME);
264 }
265
266 JavaAdapterClassLoader createAdapterClassLoader() {
267 return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray());
268 }
269
270 boolean isAutoConvertibleFromFunction() {
271 return autoConvertibleFromFunction;
272 }
273
274 private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
275 // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
276 // just implementing interfaces or extending Object), then the first implemented interface or Object.
277 final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
278 final Package pkg = namingType.getPackage();
279 final String namingTypeName = Type.getInternalName(namingType);
280 final StringBuilder buf = new StringBuilder();
281 if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) {
282 // Can't define new classes in java.* packages
346 initGlobal = new Label();
347 mv.goTo(initGlobal);
348 mv.visitLabel(notAFunction);
349 } else {
350 initGlobal = null;
351 }
352 // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
353 for (final MethodInfo mi : methodInfos) {
354 mv.dup();
355 mv.aconst(mi.getName());
356 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
357 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
358 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
359 }
360
361 if(initGlobal != null) {
362 mv.visitLabel(initGlobal);
363 }
364 // Assign "global = Context.getGlobal()"
365 invokeGetGlobalWithNullCheck(mv);
366 mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
367
368 endInitMethod(mv);
369 }
370
371 private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) {
372 invokeGetGlobal(mv);
373 mv.dup();
374 mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR, false); // check against null Context
375 mv.pop();
376 }
377
378 private void generateConstructors() throws AdaptationException {
379 boolean gotCtor = false;
380 for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
381 final int modifier = ctor.getModifiers();
382 if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) {
383 generateConstructors(ctor);
384 gotCtor = true;
385 }
386 }
491 mv.visitVarInsn(ALOAD, 0);
492 if (fromFunction && !mi.getName().equals(samName)) {
493 // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
494 // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This
495 // is a deliberate design choice. All other method handles are initialized to null.
496 mv.visitInsn(ACONST_NULL);
497 } else {
498 mv.visitVarInsn(ALOAD, offset);
499 if(!fromFunction) {
500 mv.aconst(mi.getName());
501 }
502 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
503 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor, false);
504 }
505 mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
506 }
507
508 // Assign "this.global = Context.getGlobal()"
509 mv.visitVarInsn(ALOAD, 0);
510 invokeGetGlobalWithNullCheck(mv);
511 mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
512
513 endInitMethod(mv);
514 }
515
516 private static void endInitMethod(final InstructionAdapter mv) {
517 mv.visitInsn(RETURN);
518 endMethod(mv);
519 }
520
521 private static void endMethod(final InstructionAdapter mv) {
522 mv.visitMaxs(0, 0);
523 mv.visitEnd();
524 }
525
526 private static void invokeGetGlobal(final InstructionAdapter mv) {
527 mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR, false);
528 }
529
530 private static void invokeSetGlobal(final InstructionAdapter mv) {
531 mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, false);
635 }
636 // stack: [handle]
637 jumpIfNonNullKeepOperand(mv, handleDefined);
638
639 // No handle is available, fall back to default behavior
640 if(Modifier.isAbstract(method.getModifiers())) {
641 // If the super method is abstract, throw an exception
642 mv.anew(UNSUPPORTED_OPERATION_TYPE);
643 mv.dup();
644 mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false);
645 mv.athrow();
646 } else {
647 // If the super method is not abstract, delegate to it.
648 emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
649 }
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]
661 final Label setupGlobal = new Label();
662 mv.visitLabel(setupGlobal);
663
664 // Determine the first index for a local variable
665 int nextLocalVar = 1; // "this" is at 0
666 for(final Type t: asmArgTypes) {
667 nextLocalVar += t.getSize();
668 }
669 // Set our local variable indices
670 final int currentGlobalVar = nextLocalVar++;
671 final int globalsDifferVar = nextLocalVar++;
672
673 mv.dup();
674 // stack: [creatingGlobal, creatingGlobal, handle]
675
676 // Emit code for switching to the creating global
677 // ScriptObject currentGlobal = Context.getGlobal();
678 invokeGetGlobal(mv);
679 mv.dup();
680
681 mv.visitVarInsn(ASTORE, currentGlobalVar);
682 // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
683 // if(definingGlobal == currentGlobal) {
684 final Label globalsDiffer = new Label();
685 mv.ifacmpne(globalsDiffer);
686 // stack: [creatingGlobal, handle]
687 // globalsDiffer = false
688 mv.pop();
689 // stack: [handle]
690 mv.iconst(0); // false
691 // stack: [false, handle]
692 final Label invokeHandle = new Label();
693 mv.goTo(invokeHandle);
694 mv.visitLabel(globalsDiffer);
695 // } else {
696 // Context.setGlobal(definingGlobal);
697 // stack: [creatingGlobal, handle]
727 if (!throwableDeclared) {
728 // Add "throw new RuntimeException(Throwable)" handler for Throwable
729 throwableHandler = new Label();
730 mv.visitLabel(throwableHandler);
731 mv.anew(RUNTIME_EXCEPTION_TYPE);
732 mv.dupX1();
733 mv.swap();
734 mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false);
735 // Fall through to rethrow handler
736 } else {
737 throwableHandler = null;
738 }
739 final Label rethrowHandler = new Label();
740 mv.visitLabel(rethrowHandler);
741 // Rethrow handler for RuntimeException, Error, and all declared exception types
742 emitFinally(mv, currentGlobalVar, globalsDifferVar);
743 mv.athrow();
744 final Label methodEnd = new Label();
745 mv.visitLabel(methodEnd);
746
747 mv.visitLocalVariable("currentGlobal", SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
748 mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar);
749
750 if(throwableDeclared) {
751 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
752 assert throwableHandler == null;
753 } else {
754 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
755 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
756 for(final String excName: exceptionNames) {
757 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
758 }
759 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
760 }
761 endMethod(mv);
762 }
763
764 /**
765 * Emits code for jumping to a label if the top stack operand is not null. The operand is kept on the stack if it
766 * is not null (so is available to code at the jump address) and is popped if it is null.
767 * @param mv the instruction adapter being used to emit code
|
47 import java.lang.invoke.MethodType;
48 import java.lang.reflect.AccessibleObject;
49 import java.lang.reflect.Constructor;
50 import java.lang.reflect.Method;
51 import java.lang.reflect.Modifier;
52 import java.security.AccessControlContext;
53 import java.security.AccessController;
54 import java.security.PrivilegedAction;
55 import java.util.Arrays;
56 import java.util.Collection;
57 import java.util.HashSet;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Set;
61 import jdk.internal.org.objectweb.asm.ClassWriter;
62 import jdk.internal.org.objectweb.asm.Handle;
63 import jdk.internal.org.objectweb.asm.Label;
64 import jdk.internal.org.objectweb.asm.Opcodes;
65 import jdk.internal.org.objectweb.asm.Type;
66 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
67 import jdk.nashorn.internal.objects.Global;
68 import jdk.nashorn.internal.runtime.Context;
69 import jdk.nashorn.internal.runtime.ScriptFunction;
70 import jdk.nashorn.internal.runtime.ScriptObject;
71 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
72 import sun.reflect.CallerSensitive;
73
74 /**
75 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}.
76 * </p><p>
77 * For every protected or public constructor in the extended class, the adapter class will have either one or two
78 * public constructors (visibility of protected constructors in the extended class is promoted to public).
79 * <li>
80 * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded
81 * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the
82 * passed ScriptObject's member functions are used to implement and/or override methods on the original class,
83 * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the
84 * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed
85 * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its
86 * functions) are not reflected in the adapter instance; the method implementations are bound to functions at
87 * constructor invocation time.
118 * </p><p>
119 * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
120 * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
121 * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
122 * the passed script object will be used as the implementations for its methods, just as in the above case of the
123 * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
124 * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
125 * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the
126 * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to
127 * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to
128 * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are
129 * defined with a protection domain of their creator code, and an adapter class that has both class and instance level
130 * overrides would need to have two potentially different protection domains: one for class-based behavior and one for
131 * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be
132 * implemented securely.
133 */
134 final class JavaAdapterBytecodeGenerator {
135 static final Type CONTEXT_TYPE = Type.getType(Context.class);
136 static final Type OBJECT_TYPE = Type.getType(Object.class);
137 static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
138 static final Type GLOBAL_TYPE = Type.getType(Global.class);
139
140 static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName();
141 static final String OBJECT_TYPE_NAME = OBJECT_TYPE.getInternalName();
142
143 static final String INIT = "<init>";
144
145 static final String GLOBAL_FIELD_NAME = "global";
146
147 static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();
148 static final String GLOBAL_TYPE_DESCRIPTOR = GLOBAL_TYPE.getDescriptor();
149
150
151 static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, GLOBAL_TYPE);
152 static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
153
154 private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
155 private static final Type STRING_TYPE = Type.getType(String.class);
156 private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
157 private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class);
158 private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
159 OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE);
160 private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
161 SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE);
162 private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
163 private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class);
164 private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
165 private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class);
166
167 private static final String SERVICES_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterServices.class);
168 private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName();
169 private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class);
170 private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName();
171 private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName();
172
173 private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor();
174 private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(GLOBAL_TYPE);
175 private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class));
176
177 // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because
178 // it's a java.* package.
179 private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/javaadapters/";
180 // Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package.
181 private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter";
182 private static final String JAVA_PACKAGE_PREFIX = "java/";
183 private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
184
185 private static final String CLASS_INIT = "<clinit>";
186
187 // Method name prefix for invoking super-methods
188 static final String SUPER_PREFIX = "super$";
189
190 /**
191 * Collection of methods we never override: Object.clone(), Object.finalize().
192 */
193 private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
194
246 generateGlobalFields();
247
248 gatherMethods(superClass);
249 gatherMethods(interfaces);
250 samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
251 generateHandleFields();
252 if(classOverride) {
253 generateClassInit();
254 }
255 generateConstructors();
256 generateMethods();
257 generateSuperMethods();
258 if (hasExplicitFinalizer) {
259 generateFinalizerMethods();
260 }
261 // }
262 cw.visitEnd();
263 }
264
265 private void generateGlobalFields() {
266 cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR, null, null).visitEnd();
267 usedFieldNames.add(GLOBAL_FIELD_NAME);
268 }
269
270 JavaAdapterClassLoader createAdapterClassLoader() {
271 return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray());
272 }
273
274 boolean isAutoConvertibleFromFunction() {
275 return autoConvertibleFromFunction;
276 }
277
278 private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
279 // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
280 // just implementing interfaces or extending Object), then the first implemented interface or Object.
281 final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
282 final Package pkg = namingType.getPackage();
283 final String namingTypeName = Type.getInternalName(namingType);
284 final StringBuilder buf = new StringBuilder();
285 if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) {
286 // Can't define new classes in java.* packages
350 initGlobal = new Label();
351 mv.goTo(initGlobal);
352 mv.visitLabel(notAFunction);
353 } else {
354 initGlobal = null;
355 }
356 // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
357 for (final MethodInfo mi : methodInfos) {
358 mv.dup();
359 mv.aconst(mi.getName());
360 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
361 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
362 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
363 }
364
365 if(initGlobal != null) {
366 mv.visitLabel(initGlobal);
367 }
368 // Assign "global = Context.getGlobal()"
369 invokeGetGlobalWithNullCheck(mv);
370 mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
371
372 endInitMethod(mv);
373 }
374
375 private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) {
376 invokeGetGlobal(mv);
377 mv.dup();
378 mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR, false); // check against null Context
379 mv.pop();
380 }
381
382 private void generateConstructors() throws AdaptationException {
383 boolean gotCtor = false;
384 for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
385 final int modifier = ctor.getModifiers();
386 if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) {
387 generateConstructors(ctor);
388 gotCtor = true;
389 }
390 }
495 mv.visitVarInsn(ALOAD, 0);
496 if (fromFunction && !mi.getName().equals(samName)) {
497 // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
498 // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This
499 // is a deliberate design choice. All other method handles are initialized to null.
500 mv.visitInsn(ACONST_NULL);
501 } else {
502 mv.visitVarInsn(ALOAD, offset);
503 if(!fromFunction) {
504 mv.aconst(mi.getName());
505 }
506 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
507 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor, false);
508 }
509 mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
510 }
511
512 // Assign "this.global = Context.getGlobal()"
513 mv.visitVarInsn(ALOAD, 0);
514 invokeGetGlobalWithNullCheck(mv);
515 mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
516
517 endInitMethod(mv);
518 }
519
520 private static void endInitMethod(final InstructionAdapter mv) {
521 mv.visitInsn(RETURN);
522 endMethod(mv);
523 }
524
525 private static void endMethod(final InstructionAdapter mv) {
526 mv.visitMaxs(0, 0);
527 mv.visitEnd();
528 }
529
530 private static void invokeGetGlobal(final InstructionAdapter mv) {
531 mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR, false);
532 }
533
534 private static void invokeSetGlobal(final InstructionAdapter mv) {
535 mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, false);
639 }
640 // stack: [handle]
641 jumpIfNonNullKeepOperand(mv, handleDefined);
642
643 // No handle is available, fall back to default behavior
644 if(Modifier.isAbstract(method.getModifiers())) {
645 // If the super method is abstract, throw an exception
646 mv.anew(UNSUPPORTED_OPERATION_TYPE);
647 mv.dup();
648 mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false);
649 mv.athrow();
650 } else {
651 // If the super method is not abstract, delegate to it.
652 emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
653 }
654
655 mv.visitLabel(handleDefined);
656 // Load the creatingGlobal object
657 if(classOverride) {
658 // If class handle is defined, load the static defining global
659 mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
660 } else {
661 mv.visitVarInsn(ALOAD, 0);
662 mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
663 }
664 // stack: [creatingGlobal, handle]
665 final Label setupGlobal = new Label();
666 mv.visitLabel(setupGlobal);
667
668 // Determine the first index for a local variable
669 int nextLocalVar = 1; // "this" is at 0
670 for(final Type t: asmArgTypes) {
671 nextLocalVar += t.getSize();
672 }
673 // Set our local variable indices
674 final int currentGlobalVar = nextLocalVar++;
675 final int globalsDifferVar = nextLocalVar++;
676
677 mv.dup();
678 // stack: [creatingGlobal, creatingGlobal, handle]
679
680 // Emit code for switching to the creating global
681 // Global currentGlobal = Context.getGlobal();
682 invokeGetGlobal(mv);
683 mv.dup();
684
685 mv.visitVarInsn(ASTORE, currentGlobalVar);
686 // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
687 // if(definingGlobal == currentGlobal) {
688 final Label globalsDiffer = new Label();
689 mv.ifacmpne(globalsDiffer);
690 // stack: [creatingGlobal, handle]
691 // globalsDiffer = false
692 mv.pop();
693 // stack: [handle]
694 mv.iconst(0); // false
695 // stack: [false, handle]
696 final Label invokeHandle = new Label();
697 mv.goTo(invokeHandle);
698 mv.visitLabel(globalsDiffer);
699 // } else {
700 // Context.setGlobal(definingGlobal);
701 // stack: [creatingGlobal, handle]
731 if (!throwableDeclared) {
732 // Add "throw new RuntimeException(Throwable)" handler for Throwable
733 throwableHandler = new Label();
734 mv.visitLabel(throwableHandler);
735 mv.anew(RUNTIME_EXCEPTION_TYPE);
736 mv.dupX1();
737 mv.swap();
738 mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false);
739 // Fall through to rethrow handler
740 } else {
741 throwableHandler = null;
742 }
743 final Label rethrowHandler = new Label();
744 mv.visitLabel(rethrowHandler);
745 // Rethrow handler for RuntimeException, Error, and all declared exception types
746 emitFinally(mv, currentGlobalVar, globalsDifferVar);
747 mv.athrow();
748 final Label methodEnd = new Label();
749 mv.visitLabel(methodEnd);
750
751 mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
752 mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar);
753
754 if(throwableDeclared) {
755 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
756 assert throwableHandler == null;
757 } else {
758 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
759 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
760 for(final String excName: exceptionNames) {
761 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
762 }
763 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
764 }
765 endMethod(mv);
766 }
767
768 /**
769 * Emits code for jumping to a label if the top stack operand is not null. The operand is kept on the stack if it
770 * is not null (so is available to code at the jump address) and is popped if it is null.
771 * @param mv the instruction adapter being used to emit code
|