author | attila |
Wed, 21 Aug 2013 13:39:09 +0200 | |
changeset 19617 | 310246d552b7 |
parent 19459 | 79e75274df99 |
child 19627 | 90d910ec15a3 |
permissions | -rw-r--r-- |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
1 |
/* |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
4 |
* |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
5 |
* This code is free software; you can redistribute it and/or modify it |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
7 |
* published by the Free Software Foundation. Oracle designates this |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
8 |
* particular file as subject to the "Classpath" exception as provided |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
10 |
* |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
15 |
* accompanied this code). |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
16 |
* |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
17 |
* You should have received a copy of the GNU General Public License version |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
20 |
* |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
22 |
* or visit www.oracle.com if you need additional information or have any |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
23 |
* questions. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
24 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
25 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
26 |
package jdk.nashorn.internal.runtime.linker; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
27 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
28 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
29 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
30 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
31 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
32 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
33 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
34 |
import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
35 |
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
36 |
import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
37 |
import static jdk.internal.org.objectweb.asm.Opcodes.DUP; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
38 |
import static jdk.internal.org.objectweb.asm.Opcodes.IFNONNULL; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
39 |
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
40 |
import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
41 |
import static jdk.internal.org.objectweb.asm.Opcodes.POP; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
42 |
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
43 |
import static jdk.nashorn.internal.lookup.Lookup.MH; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
44 |
import static jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome.ERROR_NO_ACCESSIBLE_CONSTRUCTOR; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
45 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
46 |
import java.lang.invoke.MethodHandle; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
47 |
import java.lang.invoke.MethodType; |
19086
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
48 |
import java.lang.reflect.AccessibleObject; |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
49 |
import java.lang.reflect.Constructor; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
50 |
import java.lang.reflect.Method; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
51 |
import java.lang.reflect.Modifier; |
19459 | 52 |
import java.security.AccessControlContext; |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
53 |
import java.security.AccessController; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
54 |
import java.security.PrivilegedAction; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
55 |
import java.util.Arrays; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
56 |
import java.util.Collection; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
57 |
import java.util.HashSet; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
58 |
import java.util.Iterator; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
59 |
import java.util.List; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
60 |
import java.util.Set; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
61 |
import jdk.internal.org.objectweb.asm.ClassWriter; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
62 |
import jdk.internal.org.objectweb.asm.Label; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
63 |
import jdk.internal.org.objectweb.asm.Opcodes; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
64 |
import jdk.internal.org.objectweb.asm.Type; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
65 |
import jdk.internal.org.objectweb.asm.commons.InstructionAdapter; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
66 |
import jdk.nashorn.internal.runtime.Context; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
67 |
import jdk.nashorn.internal.runtime.ScriptFunction; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
68 |
import jdk.nashorn.internal.runtime.ScriptObject; |
19086
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
69 |
import sun.reflect.CallerSensitive; |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
70 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
71 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
72 |
* Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
73 |
* </p><p> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
74 |
* For every protected or public constructor in the extended class, the adapter class will have between one to three |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
75 |
* public constructors (visibility of protected constructors in the extended class is promoted to public). |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
76 |
* <ul> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
77 |
* <li>In every case, a constructor taking a trailing ScriptObject argument preceded by original constructor arguments |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
78 |
* is always created on the adapter class. When such a constructor is invoked, the passed ScriptObject's member |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
79 |
* functions are used to implement and/or override methods on the original class, dispatched by name. A single |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
80 |
* JavaScript function will act as the implementation for all overloaded methods of the same name. When methods on an |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
81 |
* adapter instance are invoked, the functions are invoked having the ScriptObject passed in the instance constructor as |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
82 |
* their "this". Subsequent changes to the ScriptObject (reassignment or removal of its functions) are not reflected in |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
83 |
* the adapter instance; the method implementations are bound to functions at constructor invocation time. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
84 |
* {@code java.lang.Object} methods {@code equals}, {@code hashCode}, and {@code toString} can also be overridden. The |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
85 |
* only restriction is that since every JavaScript object already has a {@code toString} function through the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
86 |
* {@code Object.prototype}, the {@code toString} in the adapter is only overridden if the passed ScriptObject has a |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
87 |
* {@code toString} function as its own property, and not inherited from a prototype. All other adapter methods can be |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
88 |
* implemented or overridden through a prototype-inherited function of the ScriptObject passed to the constructor too. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
89 |
* </li> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
90 |
* <li> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
91 |
* If the original types collectively have only one abstract method, or have several of them, but all share the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
92 |
* same name, an additional constructor is provided for every original constructor; this one takes a ScriptFunction as |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
93 |
* its last argument preceded by original constructor arguments. This constructor will use the passed function as the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
94 |
* implementation for all abstract methods. For consistency, any concrete methods sharing the single abstract method |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
95 |
* name will also be overridden by the function. When methods on the adapter instance are invoked, the ScriptFunction is |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
96 |
* invoked with {@code null} as its "this". |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
97 |
* </li> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
98 |
* <li> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
99 |
* If the adapter being generated can have class-level overrides, constructors taking same arguments as the superclass |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
100 |
* constructors are also created. These constructors simply delegate to the superclass constructor. They are used to |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
101 |
* create instances of the adapter class with no instance-level overrides. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
102 |
* </li> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
103 |
* </ul> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
104 |
* </p><p> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
105 |
* For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
106 |
* to coerce the JavaScript function return value to the expected Java return type. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
107 |
* </p><p> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
108 |
* Since we are adding a trailing argument to the generated constructors in the adapter class, they will never be |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
109 |
* declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
110 |
* reason we are passing the additional argument at the end of the argument list instead at the front is that the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
111 |
* source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
112 |
* to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
113 |
* </p><p> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
114 |
* It is possible to create two different classes: those that can have both class-level and instance-level overrides, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
115 |
* and those that can only have instance-level overrides. When |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
116 |
* {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked with non-null {@code classOverrides} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
117 |
* parameter, an adapter class is created that can have class-level overrides, and the passed script object will be used |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
118 |
* as the implementations for its methods, just as in the above case of the constructor taking a script object. Note |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
119 |
* that in the case of class-level overrides, a new adapter class is created on every invocation, and the implementation |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
120 |
* object is bound to the class, not to any instance. All created instances will share these functions. Of course, when |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
121 |
* instances of such a class are being created, they can still take another object (or possibly a function) in their |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
122 |
* constructor's trailing position and thus provide further instance-specific overrides. The order of invocation is |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
123 |
* always instance-specified method, then a class-specified method, and finally the superclass method. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
124 |
*/ |
19085
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
125 |
final class JavaAdapterBytecodeGenerator { |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
126 |
static final Type CONTEXT_TYPE = Type.getType(Context.class); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
127 |
static final Type OBJECT_TYPE = Type.getType(Object.class); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
128 |
static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
129 |
|
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
130 |
static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName(); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
131 |
static final String OBJECT_TYPE_NAME = OBJECT_TYPE.getInternalName(); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
132 |
|
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
133 |
static final String INIT = "<init>"; |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
134 |
|
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
135 |
static final String GLOBAL_FIELD_NAME = "global"; |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
136 |
|
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
137 |
static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor(); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
138 |
|
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
139 |
static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, SCRIPT_OBJECT_TYPE); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
140 |
static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE); |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
141 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
142 |
private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
143 |
private static final Type STRING_TYPE = Type.getType(String.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
144 |
private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
145 |
private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
146 |
private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE, |
17239
6dd68632cdcd
8011065: Problems when script implements an interface with variadic methods
attila
parents:
16777
diff
changeset
|
147 |
OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
148 |
private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE, |
17239
6dd68632cdcd
8011065: Problems when script implements an interface with variadic methods
attila
parents:
16777
diff
changeset
|
149 |
SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
150 |
private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
151 |
private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
152 |
private static final Type THROWABLE_TYPE = Type.getType(Throwable.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
153 |
private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
154 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
155 |
private static final String SERVICES_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterServices.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
156 |
private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
157 |
private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
158 |
private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
159 |
private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
160 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
161 |
private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
162 |
private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
163 |
private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
164 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
165 |
// Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
166 |
// it's a java.* package. |
19094 | 167 |
private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/javaadapters/"; |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
168 |
// Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
169 |
private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter"; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
170 |
private static final String JAVA_PACKAGE_PREFIX = "java/"; |
19085
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
171 |
private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255; |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
172 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
173 |
private static final String CLASS_INIT = "<clinit>"; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
174 |
private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal"; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
175 |
|
19617 | 176 |
// Method name prefix for invoking super-methods |
177 |
private static final String SUPER_PREFIX = "super$"; |
|
178 |
||
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
179 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
180 |
* Collection of methods we never override: Object.clone(), Object.finalize(). |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
181 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
182 |
private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
183 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
184 |
// This is the superclass for our generated adapter. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
185 |
private final Class<?> superClass; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
186 |
// Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
187 |
// loader that has the visibility of all original types (class to extend and interfaces to implement) and of the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
188 |
// Nashorn classes. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
189 |
private final ClassLoader commonLoader; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
190 |
// Is this a generator for the version of the class that can have overrides on the class level? |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
191 |
private final boolean classOverride; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
192 |
// Binary name of the superClass |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
193 |
private final String superClassName; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
194 |
// Binary name of the generated class. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
195 |
private final String generatedClassName; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
196 |
private final Set<String> usedFieldNames = new HashSet<>(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
197 |
private final Set<String> abstractMethodNames = new HashSet<>(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
198 |
private final String samName; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
199 |
private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
200 |
private final Set<MethodInfo> methodInfos = new HashSet<>(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
201 |
private boolean autoConvertibleFromFunction = false; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
202 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
203 |
private final ClassWriter cw; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
204 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
205 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
206 |
* Creates a generator for the bytecode for the adapter for the specified superclass and interfaces. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
207 |
* @param superClass the superclass the adapter will extend. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
208 |
* @param interfaces the interfaces the adapter will implement. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
209 |
* @param commonLoader the class loader that can see all of superClass, interfaces, and Nashorn classes. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
210 |
* @param classOverride true to generate the bytecode for the adapter that has both class-level and instance-level |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
211 |
* overrides, false to generate the bytecode for the adapter that only has instance-level overrides. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
212 |
* @throws AdaptationException if the adapter can not be generated for some reason. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
213 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
214 |
JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
215 |
final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
216 |
assert superClass != null && !superClass.isInterface(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
217 |
assert interfaces != null; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
218 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
219 |
this.superClass = superClass; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
220 |
this.classOverride = classOverride; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
221 |
this.commonLoader = commonLoader; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
222 |
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
223 |
@Override |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
224 |
protected String getCommonSuperClass(final String type1, final String type2) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
225 |
// We need to override ClassWriter.getCommonSuperClass to use this factory's commonLoader as a class |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
226 |
// loader to find the common superclass of two types when needed. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
227 |
return JavaAdapterBytecodeGenerator.this.getCommonSuperClass(type1, type2); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
228 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
229 |
}; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
230 |
superClassName = Type.getInternalName(superClass); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
231 |
generatedClassName = getGeneratedClassName(superClass, interfaces); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
232 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
233 |
cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, generatedClassName, null, superClassName, getInternalTypeNames(interfaces)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
234 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
235 |
generateGlobalFields(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
236 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
237 |
gatherMethods(superClass); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
238 |
gatherMethods(interfaces); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
239 |
samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
240 |
generateHandleFields(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
241 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
242 |
generateClassInit(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
243 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
244 |
generateConstructors(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
245 |
generateMethods(); |
19617 | 246 |
generateSuperMethods(); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
247 |
// } |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
248 |
cw.visitEnd(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
249 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
250 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
251 |
private void generateGlobalFields() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
252 |
cw.visitField(ACC_PRIVATE | ACC_FINAL, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
253 |
usedFieldNames.add(GLOBAL_FIELD_NAME); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
254 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
255 |
cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
256 |
usedFieldNames.add(STATIC_GLOBAL_FIELD_NAME); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
257 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
258 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
259 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
260 |
JavaAdapterClassLoader createAdapterClassLoader() { |
19085
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
261 |
return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray()); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
262 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
263 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
264 |
boolean isAutoConvertibleFromFunction() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
265 |
return autoConvertibleFromFunction; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
266 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
267 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
268 |
private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
269 |
// The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
270 |
// just implementing interfaces or extending Object), then the first implemented interface or Object. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
271 |
final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
272 |
final Package pkg = namingType.getPackage(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
273 |
final String namingTypeName = Type.getInternalName(namingType); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
274 |
final StringBuilder buf = new StringBuilder(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
275 |
if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
276 |
// Can't define new classes in java.* packages |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
277 |
buf.append(ADAPTER_PACKAGE_PREFIX).append(namingTypeName); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
278 |
} else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
279 |
buf.append(namingTypeName).append(ADAPTER_CLASS_NAME_SUFFIX); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
280 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
281 |
final Iterator<Class<?>> it = interfaces.iterator(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
282 |
if(superType == Object.class && it.hasNext()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
283 |
it.next(); // Skip first interface, it was used to primarily name the adapter |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
284 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
285 |
// Append interface names to the adapter name |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
286 |
while(it.hasNext()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
287 |
buf.append("$$").append(it.next().getSimpleName()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
288 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
289 |
return buf.toString().substring(0, Math.min(MAX_GENERATED_TYPE_NAME_LENGTH, buf.length())); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
290 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
291 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
292 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
293 |
* Given a list of class objects, return an array with their binary names. Used to generate the array of interface |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
294 |
* names to implement. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
295 |
* @param classes the classes |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
296 |
* @return an array of names |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
297 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
298 |
private static String[] getInternalTypeNames(final List<Class<?>> classes) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
299 |
final int interfaceCount = classes.size(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
300 |
final String[] interfaceNames = new String[interfaceCount]; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
301 |
for(int i = 0; i < interfaceCount; ++i) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
302 |
interfaceNames[i] = Type.getInternalName(classes.get(i)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
303 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
304 |
return interfaceNames; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
305 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
306 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
307 |
private void generateHandleFields() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
308 |
for (final MethodInfo mi: methodInfos) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
309 |
cw.visitField(ACC_PRIVATE | ACC_FINAL, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
310 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
311 |
cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
312 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
313 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
314 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
315 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
316 |
private void generateClassInit() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
317 |
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
318 |
Type.getMethodDescriptor(Type.VOID_TYPE), null, null)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
319 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
320 |
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getClassOverrides", GET_CLASS_INITIALIZER_DESCRIPTOR); |
17750
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
321 |
final Label initGlobal; |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
322 |
if(samName != null) { |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
323 |
// If the class is a SAM, allow having a ScriptFunction passed as class overrides |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
324 |
final Label notAFunction = new Label(); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
325 |
mv.dup(); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
326 |
mv.instanceOf(SCRIPT_FUNCTION_TYPE); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
327 |
mv.ifeq(notAFunction); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
328 |
mv.checkcast(SCRIPT_FUNCTION_TYPE); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
329 |
|
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
330 |
// Assign MethodHandle fields through invoking getHandle() for a ScriptFunction, only assigning the SAM |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
331 |
// method(s). |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
332 |
for (final MethodInfo mi : methodInfos) { |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
333 |
if(mi.getName().equals(samName)) { |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
334 |
mv.dup(); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
335 |
mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
336 |
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_FUNCTION_DESCRIPTOR); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
337 |
} else { |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
338 |
mv.visitInsn(ACONST_NULL); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
339 |
} |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
340 |
mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
341 |
} |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
342 |
initGlobal = new Label(); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
343 |
mv.goTo(initGlobal); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
344 |
mv.visitLabel(notAFunction); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
345 |
} else { |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
346 |
initGlobal = null; |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
347 |
} |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
348 |
// Assign MethodHandle fields through invoking getHandle() for a ScriptObject |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
349 |
for (final MethodInfo mi : methodInfos) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
350 |
mv.dup(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
351 |
mv.aconst(mi.getName()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
352 |
mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
353 |
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
354 |
mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
355 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
356 |
|
17750
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
357 |
if(initGlobal != null) { |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
358 |
mv.visitLabel(initGlobal); |
eeab213edaa6
8014647: Allow class-based overrides to be initialized with a ScriptFunction
attila
parents:
17239
diff
changeset
|
359 |
} |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
360 |
// Assign "staticGlobal = Context.getGlobal()" |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
361 |
invokeGetGlobalWithNullCheck(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
362 |
mv.putstatic(generatedClassName, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
363 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
364 |
endInitMethod(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
365 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
366 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
367 |
private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
368 |
invokeGetGlobal(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
369 |
mv.dup(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
370 |
mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR); // check against null Context |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
371 |
mv.pop(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
372 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
373 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
374 |
private void generateConstructors() throws AdaptationException { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
375 |
boolean gotCtor = false; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
376 |
for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
377 |
final int modifier = ctor.getModifiers(); |
19086
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
378 |
if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
379 |
generateConstructors(ctor); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
380 |
gotCtor = true; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
381 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
382 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
383 |
if(!gotCtor) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
384 |
throw new AdaptationException(ERROR_NO_ACCESSIBLE_CONSTRUCTOR, superClass.getCanonicalName()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
385 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
386 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
387 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
388 |
private void generateConstructors(final Constructor<?> ctor) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
389 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
390 |
// Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
391 |
// to create instances without further per-instance overrides. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
392 |
generateDelegatingConstructor(ctor); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
393 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
394 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
395 |
// Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
396 |
// beginning of its parameter list. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
397 |
generateOverridingConstructor(ctor, false); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
398 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
399 |
if (samName != null) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
400 |
if (!autoConvertibleFromFunction && ctor.getParameterTypes().length == 0) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
401 |
// If the original type only has a single abstract method name, as well as a default ctor, then it can |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
402 |
// be automatically converted from JS function. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
403 |
autoConvertibleFromFunction = true; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
404 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
405 |
// If all our abstract methods have a single name, generate an additional constructor, one that takes a |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
406 |
// ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
407 |
generateOverridingConstructor(ctor, true); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
408 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
409 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
410 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
411 |
private void generateDelegatingConstructor(final Constructor<?> ctor) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
412 |
final Type originalCtorType = Type.getType(ctor); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
413 |
final Type[] argTypes = originalCtorType.getArgumentTypes(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
414 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
415 |
// All constructors must be public, even if in the superclass they were protected. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
416 |
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
417 |
Type.getMethodDescriptor(originalCtorType.getReturnType(), argTypes), null, null)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
418 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
419 |
mv.visitCode(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
420 |
// Invoke super constructor with the same arguments. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
421 |
mv.visitVarInsn(ALOAD, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
422 |
int offset = 1; // First arg is at position 1, after this. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
423 |
for (Type argType: argTypes) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
424 |
mv.load(offset, argType); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
425 |
offset += argType.getSize(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
426 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
427 |
mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
428 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
429 |
endInitMethod(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
430 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
431 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
432 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
433 |
* Generates a constructor for the adapter class. This constructor will take the same arguments as the supertype |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
434 |
* constructor passed as the argument here, and delegate to it. However, it will take an additional argument of |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
435 |
* either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
436 |
* all the method handle fields of the adapter instance with functions from the script object (or the script |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
437 |
* function itself, if that's what's passed). There is one method handle field in the adapter class for every method |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
438 |
* that can be implemented or overridden; the name of every field is same as the name of the method, with a number |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
439 |
* suffix that makes it unique in case of overloaded methods. The generated constructor will invoke |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
440 |
* {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
441 |
* boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
442 |
* adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
443 |
* The constructor that takes a script function will only initialize the methods with the same name as the single |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
444 |
* abstract method. The constructor will also store the Nashorn global that was current at the constructor |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
445 |
* invocation time in a field named "global". The generated constructor will be public, regardless of whether the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
446 |
* supertype constructor was public or protected. The generated constructor will not be variable arity, even if the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
447 |
* supertype constructor was. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
448 |
* @param ctor the supertype constructor that is serving as the base for the generated constructor. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
449 |
* @param fromFunction true if we're generating a constructor that initializes SAM types from a single |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
450 |
* ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
451 |
* ScriptObject passed to it. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
452 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
453 |
private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
454 |
final Type originalCtorType = Type.getType(ctor); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
455 |
final Type[] originalArgTypes = originalCtorType.getArgumentTypes(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
456 |
final int argLen = originalArgTypes.length; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
457 |
final Type[] newArgTypes = new Type[argLen + 1]; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
458 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
459 |
// Insert ScriptFunction|Object as the last argument to the constructor |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
460 |
final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
461 |
newArgTypes[argLen] = extraArgumentType; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
462 |
System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
463 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
464 |
// All constructors must be public, even if in the superclass they were protected. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
465 |
// Existing super constructor <init>(this, args...) triggers generating <init>(this, scriptObj, args...). |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
466 |
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
467 |
Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
468 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
469 |
mv.visitCode(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
470 |
// First, invoke super constructor with original arguments. If the form of the constructor we're generating is |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
471 |
// <init>(this, args..., scriptFn), then we're invoking super.<init>(this, args...). |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
472 |
mv.visitVarInsn(ALOAD, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
473 |
final Class<?>[] argTypes = ctor.getParameterTypes(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
474 |
int offset = 1; // First arg is at position 1, after this. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
475 |
for (int i = 0; i < argLen; ++i) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
476 |
final Type argType = Type.getType(argTypes[i]); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
477 |
mv.load(offset, argType); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
478 |
offset += argType.getSize(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
479 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
480 |
mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
481 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
482 |
// Get a descriptor to the appropriate "JavaAdapterFactory.getHandle" method. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
483 |
final String getHandleDescriptor = fromFunction ? GET_HANDLE_FUNCTION_DESCRIPTOR : GET_HANDLE_OBJECT_DESCRIPTOR; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
484 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
485 |
// Assign MethodHandle fields through invoking getHandle() |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
486 |
for (final MethodInfo mi : methodInfos) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
487 |
mv.visitVarInsn(ALOAD, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
488 |
if (fromFunction && !mi.getName().equals(samName)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
489 |
// Constructors initializing from a ScriptFunction only initialize methods with the SAM name. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
490 |
// NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
491 |
// is a deliberate design choice. All other method handles are initialized to null. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
492 |
mv.visitInsn(ACONST_NULL); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
493 |
} else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
494 |
mv.visitVarInsn(ALOAD, offset); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
495 |
if(!fromFunction) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
496 |
mv.aconst(mi.getName()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
497 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
498 |
mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
499 |
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
500 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
501 |
mv.putfield(generatedClassName, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
502 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
503 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
504 |
// Assign "this.global = Context.getGlobal()" |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
505 |
mv.visitVarInsn(ALOAD, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
506 |
invokeGetGlobalWithNullCheck(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
507 |
mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
508 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
509 |
endInitMethod(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
510 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
511 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
512 |
private static void endInitMethod(final InstructionAdapter mv) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
513 |
mv.visitInsn(RETURN); |
19617 | 514 |
endMethod(mv); |
515 |
} |
|
516 |
||
517 |
private static void endMethod(final InstructionAdapter mv) { |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
518 |
mv.visitMaxs(0, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
519 |
mv.visitEnd(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
520 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
521 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
522 |
private static void invokeGetGlobal(final InstructionAdapter mv) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
523 |
mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
524 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
525 |
|
19085
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
526 |
private static void invokeSetGlobal(final InstructionAdapter mv) { |
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
527 |
mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
528 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
529 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
530 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
531 |
* Encapsulation of the information used to generate methods in the adapter classes. Basically, a wrapper around the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
532 |
* reflective Method object, a cached MethodType, and the name of the field in the adapter class that will hold the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
533 |
* method handle serving as the implementation of this method in adapter instances. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
534 |
* |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
535 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
536 |
private static class MethodInfo { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
537 |
private final Method method; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
538 |
private final MethodType type; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
539 |
private String methodHandleInstanceFieldName; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
540 |
private String methodHandleClassFieldName; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
541 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
542 |
private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
543 |
this(clazz.getDeclaredMethod(name, argTypes)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
544 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
545 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
546 |
private MethodInfo(final Method method) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
547 |
this.method = method; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
548 |
this.type = MH.type(method.getReturnType(), method.getParameterTypes()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
549 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
550 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
551 |
@Override |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
552 |
public boolean equals(final Object obj) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
553 |
return obj instanceof MethodInfo && equals((MethodInfo)obj); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
554 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
555 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
556 |
private boolean equals(final MethodInfo other) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
557 |
// Only method name and type are used for comparison; method handle field name is not. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
558 |
return getName().equals(other.getName()) && type.equals(other.type); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
559 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
560 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
561 |
String getName() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
562 |
return method.getName(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
563 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
564 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
565 |
@Override |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
566 |
public int hashCode() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
567 |
return getName().hashCode() ^ type.hashCode(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
568 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
569 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
570 |
void setIsCanonical(final Set<String> usedFieldNames, boolean classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
571 |
methodHandleInstanceFieldName = nextName(usedFieldNames); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
572 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
573 |
methodHandleClassFieldName = nextName(usedFieldNames); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
574 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
575 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
576 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
577 |
String nextName(final Set<String> usedFieldNames) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
578 |
int i = 0; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
579 |
final String name = getName(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
580 |
String nextName = name; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
581 |
while (!usedFieldNames.add(nextName)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
582 |
final String ordinal = String.valueOf(i++); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
583 |
final int maxNameLen = 255 - ordinal.length(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
584 |
nextName = (name.length() <= maxNameLen ? name : name.substring(0, maxNameLen)).concat(ordinal); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
585 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
586 |
return nextName; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
587 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
588 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
589 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
590 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
591 |
private void generateMethods() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
592 |
for(final MethodInfo mi: methodInfos) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
593 |
generateMethod(mi); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
594 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
595 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
596 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
597 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
598 |
* Generates a method in the adapter class that adapts a method from the original class. The generated methods will |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
599 |
* inspect the method handle field assigned to them. If it is null (the JS object doesn't provide an implementation |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
600 |
* for the method) then it will either invoke its version in the supertype, or if it is abstract, throw an |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
601 |
* {@link UnsupportedOperationException}. Otherwise, if the method handle field's value is not null, the handle is |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
602 |
* invoked using invokeExact (signature polymorphic invocation as per JLS 15.12.3). Before the invocation, the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
603 |
* current Nashorn {@link Context} is checked, and if it is different than the global used to create the adapter |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
604 |
* instance, the creating global is set to be the current global. In this case, the previously current global is |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
605 |
* restored after the invocation. If invokeExact results in a Throwable that is not one of the method's declared |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
606 |
* exceptions, and is not an unchecked throwable, then it is wrapped into a {@link RuntimeException} and the runtime |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
607 |
* exception is thrown. The method handle retrieved from the field is guaranteed to exactly match the signature of |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
608 |
* the method; this is guaranteed by the way constructors of the adapter class obtain them using |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
609 |
* {@link #getHandle(Object, String, MethodType, boolean)}. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
610 |
* @param mi the method info describing the method to be generated. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
611 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
612 |
private void generateMethod(final MethodInfo mi) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
613 |
final Method method = mi.method; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
614 |
final Class<?>[] exceptions = method.getExceptionTypes(); |
19617 | 615 |
final String[] exceptionNames = getExceptionNames(exceptions); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
616 |
final MethodType type = mi.type; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
617 |
final String methodDesc = type.toMethodDescriptorString(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
618 |
final String name = mi.getName(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
619 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
620 |
final Type asmType = Type.getMethodType(methodDesc); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
621 |
final Type[] asmArgTypes = asmType.getArgumentTypes(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
622 |
|
19617 | 623 |
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name, |
624 |
methodDesc, null, exceptionNames)); |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
625 |
mv.visitCode(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
626 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
627 |
final Label instanceHandleDefined = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
628 |
final Label classHandleDefined = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
629 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
630 |
final Type asmReturnType = Type.getType(type.returnType()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
631 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
632 |
// See if we have instance handle defined |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
633 |
mv.visitVarInsn(ALOAD, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
634 |
mv.getfield(generatedClassName, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
635 |
// stack: [instanceHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
636 |
jumpIfNonNullKeepOperand(mv, instanceHandleDefined); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
637 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
638 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
639 |
// See if we have the static handle |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
640 |
mv.getstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
641 |
// stack: [classHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
642 |
jumpIfNonNullKeepOperand(mv, classHandleDefined); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
643 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
644 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
645 |
// No handle is available, fall back to default behavior |
19617 | 646 |
if(Modifier.isAbstract(method.getModifiers())) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
647 |
// If the super method is abstract, throw an exception |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
648 |
mv.anew(UNSUPPORTED_OPERATION_TYPE); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
649 |
mv.dup(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
650 |
mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
651 |
mv.athrow(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
652 |
} else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
653 |
// If the super method is not abstract, delegate to it. |
19617 | 654 |
emitSuperCall(mv, name, methodDesc); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
655 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
656 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
657 |
final Label setupGlobal = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
658 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
659 |
if(classOverride) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
660 |
mv.visitLabel(classHandleDefined); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
661 |
// If class handle is defined, load the static defining global |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
662 |
mv.getstatic(generatedClassName, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
663 |
// stack: [creatingGlobal := classGlobal, classHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
664 |
mv.goTo(setupGlobal); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
665 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
666 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
667 |
mv.visitLabel(instanceHandleDefined); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
668 |
// If instance handle is defined, load the instance defining global |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
669 |
mv.visitVarInsn(ALOAD, 0); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
670 |
mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
671 |
// stack: [creatingGlobal := instanceGlobal, instanceHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
672 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
673 |
// fallthrough to setupGlobal |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
674 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
675 |
// stack: [creatingGlobal, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
676 |
mv.visitLabel(setupGlobal); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
677 |
|
19617 | 678 |
// Determine the first index for a local variable |
679 |
int nextLocalVar = 1; // "this" is at 0 |
|
680 |
for(final Type t: asmArgTypes) { |
|
681 |
nextLocalVar += t.getSize(); |
|
682 |
} |
|
683 |
// Set our local variable indices |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
684 |
final int currentGlobalVar = nextLocalVar++; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
685 |
final int globalsDifferVar = nextLocalVar++; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
686 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
687 |
mv.dup(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
688 |
// stack: [creatingGlobal, creatingGlobal, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
689 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
690 |
// Emit code for switching to the creating global |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
691 |
// ScriptObject currentGlobal = Context.getGlobal(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
692 |
invokeGetGlobal(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
693 |
mv.dup(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
694 |
mv.visitVarInsn(ASTORE, currentGlobalVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
695 |
// stack: [currentGlobal, creatingGlobal, creatingGlobal, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
696 |
// if(definingGlobal == currentGlobal) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
697 |
final Label globalsDiffer = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
698 |
mv.ifacmpne(globalsDiffer); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
699 |
// stack: [someGlobal, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
700 |
// globalsDiffer = false |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
701 |
mv.pop(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
702 |
// stack: [someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
703 |
mv.iconst(0); // false |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
704 |
// stack: [false, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
705 |
final Label invokeHandle = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
706 |
mv.goTo(invokeHandle); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
707 |
mv.visitLabel(globalsDiffer); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
708 |
// } else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
709 |
// Context.setGlobal(definingGlobal); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
710 |
// stack: [someGlobal, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
711 |
invokeSetGlobal(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
712 |
// stack: [someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
713 |
// globalsDiffer = true |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
714 |
mv.iconst(1); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
715 |
// stack: [true, someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
716 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
717 |
mv.visitLabel(invokeHandle); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
718 |
mv.visitVarInsn(ISTORE, globalsDifferVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
719 |
// stack: [someHandle] |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
720 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
721 |
// Load all parameters back on stack for dynamic invocation. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
722 |
int varOffset = 1; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
723 |
for (final Type t : asmArgTypes) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
724 |
mv.load(varOffset, t); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
725 |
varOffset += t.getSize(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
726 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
727 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
728 |
// Invoke the target method handle |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
729 |
final Label tryBlockStart = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
730 |
mv.visitLabel(tryBlockStart); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
731 |
mv.invokevirtual(METHOD_HANDLE_TYPE.getInternalName(), "invokeExact", type.toMethodDescriptorString()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
732 |
final Label tryBlockEnd = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
733 |
mv.visitLabel(tryBlockEnd); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
734 |
emitFinally(mv, currentGlobalVar, globalsDifferVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
735 |
mv.areturn(asmReturnType); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
736 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
737 |
// If Throwable is not declared, we need an adapter from Throwable to RuntimeException |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
738 |
final boolean throwableDeclared = isThrowableDeclared(exceptions); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
739 |
final Label throwableHandler; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
740 |
if (!throwableDeclared) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
741 |
// Add "throw new RuntimeException(Throwable)" handler for Throwable |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
742 |
throwableHandler = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
743 |
mv.visitLabel(throwableHandler); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
744 |
mv.anew(RUNTIME_EXCEPTION_TYPE); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
745 |
mv.dupX1(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
746 |
mv.swap(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
747 |
mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
748 |
// Fall through to rethrow handler |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
749 |
} else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
750 |
throwableHandler = null; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
751 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
752 |
final Label rethrowHandler = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
753 |
mv.visitLabel(rethrowHandler); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
754 |
// Rethrow handler for RuntimeException, Error, and all declared exception types |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
755 |
emitFinally(mv, currentGlobalVar, globalsDifferVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
756 |
mv.athrow(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
757 |
final Label methodEnd = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
758 |
mv.visitLabel(methodEnd); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
759 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
760 |
mv.visitLocalVariable("currentGlobal", SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
761 |
mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
762 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
763 |
if(throwableDeclared) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
764 |
mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
765 |
assert throwableHandler == null; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
766 |
} else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
767 |
mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
768 |
mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
769 |
for(final String excName: exceptionNames) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
770 |
mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
771 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
772 |
mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
773 |
} |
19617 | 774 |
endMethod(mv); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
775 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
776 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
777 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
778 |
* Emits code for jumping to a label if the top stack operand is not null. The operand is kept on the stack if it |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
779 |
* is not null (so is available to code at the jump address) and is popped if it is null. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
780 |
* @param mv the instruction adapter being used to emit code |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
781 |
* @param label the label to jump to |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
782 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
783 |
private static void jumpIfNonNullKeepOperand(final InstructionAdapter mv, final Label label) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
784 |
mv.visitInsn(DUP); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
785 |
mv.visitJumpInsn(IFNONNULL, label); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
786 |
mv.visitInsn(POP); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
787 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
788 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
789 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
790 |
* Emit code to restore the previous Nashorn Context when needed. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
791 |
* @param mv the instruction adapter |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
792 |
* @param currentGlobalVar index of the local variable holding the reference to the current global at method |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
793 |
* entry. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
794 |
* @param globalsDifferVar index of the boolean local variable that is true if the global needs to be restored. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
795 |
*/ |
19085
066c9e5afd79
8020731: Revisit checkPermission calls in Context class
sundar
parents:
17750
diff
changeset
|
796 |
private static void emitFinally(final InstructionAdapter mv, final int currentGlobalVar, final int globalsDifferVar) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
797 |
// Emit code to restore the previous Nashorn global if needed |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
798 |
mv.visitVarInsn(ILOAD, globalsDifferVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
799 |
final Label skip = new Label(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
800 |
mv.ifeq(skip); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
801 |
mv.visitVarInsn(ALOAD, currentGlobalVar); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
802 |
invokeSetGlobal(mv); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
803 |
mv.visitLabel(skip); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
804 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
805 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
806 |
private static boolean isThrowableDeclared(final Class<?>[] exceptions) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
807 |
for (final Class<?> exception : exceptions) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
808 |
if (exception == Throwable.class) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
809 |
return true; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
810 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
811 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
812 |
return false; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
813 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
814 |
|
19617 | 815 |
private void generateSuperMethods() { |
816 |
for(final MethodInfo mi: methodInfos) { |
|
817 |
if(!Modifier.isAbstract(mi.method.getModifiers())) { |
|
818 |
generateSuperMethod(mi); |
|
819 |
} |
|
820 |
} |
|
821 |
} |
|
822 |
||
823 |
private void generateSuperMethod(MethodInfo mi) { |
|
824 |
final Method method = mi.method; |
|
825 |
||
826 |
final String methodDesc = mi.type.toMethodDescriptorString(); |
|
827 |
final String name = mi.getName(); |
|
828 |
||
829 |
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), |
|
830 |
SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); |
|
831 |
mv.visitCode(); |
|
832 |
||
833 |
emitSuperCall(mv, name, methodDesc); |
|
834 |
||
835 |
endMethod(mv); |
|
836 |
} |
|
837 |
||
838 |
private void emitSuperCall(final InstructionAdapter mv, final String name, final String methodDesc) { |
|
839 |
mv.visitVarInsn(ALOAD, 0); |
|
840 |
int nextParam = 1; |
|
841 |
final Type methodType = Type.getMethodType(methodDesc); |
|
842 |
for(final Type t: methodType.getArgumentTypes()) { |
|
843 |
mv.load(nextParam, t); |
|
844 |
nextParam += t.getSize(); |
|
845 |
} |
|
846 |
mv.invokespecial(superClassName, name, methodDesc); |
|
847 |
mv.areturn(methodType.getReturnType()); |
|
848 |
} |
|
849 |
||
850 |
private static String[] getExceptionNames(final Class<?>[] exceptions) { |
|
851 |
final String[] exceptionNames = new String[exceptions.length]; |
|
852 |
for (int i = 0; i < exceptions.length; ++i) { |
|
853 |
exceptionNames[i] = Type.getInternalName(exceptions[i]); |
|
854 |
} |
|
855 |
return exceptionNames; |
|
856 |
} |
|
857 |
||
858 |
private static int getAccessModifiers(final Method method) { |
|
859 |
return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0); |
|
860 |
} |
|
861 |
||
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
862 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
863 |
* Gathers methods that can be implemented or overridden from the specified type into this factory's |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
864 |
* {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
865 |
* the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
866 |
* superclass and the interfaces it implements, and add further methods that were not directly declared on the |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
867 |
* class. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
868 |
* @param type the type defining the methods. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
869 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
870 |
private void gatherMethods(final Class<?> type) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
871 |
if (Modifier.isPublic(type.getModifiers())) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
872 |
final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
873 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
874 |
for (final Method typeMethod: typeMethods) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
875 |
final int m = typeMethod.getModifiers(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
876 |
if (Modifier.isStatic(m)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
877 |
continue; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
878 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
879 |
if (Modifier.isPublic(m) || Modifier.isProtected(m)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
880 |
final MethodInfo mi = new MethodInfo(typeMethod); |
19086
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
881 |
if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
882 |
finalMethods.add(mi); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
883 |
} else if (!finalMethods.contains(mi) && methodInfos.add(mi)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
884 |
if (Modifier.isAbstract(m)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
885 |
abstractMethodNames.add(mi.getName()); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
886 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
887 |
mi.setIsCanonical(usedFieldNames, classOverride); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
888 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
889 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
890 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
891 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
892 |
// If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
893 |
// Needing to invoke the method recursively for a non-interface Class object is the consequence of needing to |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
894 |
// see all declared protected methods, and Class.getDeclaredMethods() doesn't provide those declared in a |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
895 |
// superclass. For interfaces, we used Class.getMethods(), as we're only interested in public ones there, and |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
896 |
// getMethods() does provide those declared in a superinterface. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
897 |
if (!type.isInterface()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
898 |
final Class<?> superType = type.getSuperclass(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
899 |
if (superType != null) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
900 |
gatherMethods(superType); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
901 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
902 |
for (final Class<?> itf: type.getInterfaces()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
903 |
gatherMethods(itf); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
904 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
905 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
906 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
907 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
908 |
private void gatherMethods(final List<Class<?>> classes) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
909 |
for(final Class<?> c: classes) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
910 |
gatherMethods(c); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
911 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
912 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
913 |
|
19459 | 914 |
private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers"); |
915 |
||
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
916 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
917 |
* Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
918 |
* as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
919 |
* {@code Object.clone()}. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
920 |
* @return a collection of method infos representing those methods that we never override in adapter classes. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
921 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
922 |
private static Collection<MethodInfo> getExcludedMethods() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
923 |
return AccessController.doPrivileged(new PrivilegedAction<Collection<MethodInfo>>() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
924 |
@Override |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
925 |
public Collection<MethodInfo> run() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
926 |
try { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
927 |
return Arrays.asList( |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
928 |
new MethodInfo(Object.class, "finalize"), |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
929 |
new MethodInfo(Object.class, "clone")); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
930 |
} catch (final NoSuchMethodException e) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
931 |
throw new AssertionError(e); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
932 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
933 |
} |
19459 | 934 |
}, GET_DECLARED_MEMBERS_ACC_CTXT); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
935 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
936 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
937 |
private String getCommonSuperClass(final String type1, final String type2) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
938 |
try { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
939 |
final Class<?> c1 = Class.forName(type1.replace('/', '.'), false, commonLoader); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
940 |
final Class<?> c2 = Class.forName(type2.replace('/', '.'), false, commonLoader); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
941 |
if (c1.isAssignableFrom(c2)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
942 |
return type1; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
943 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
944 |
if (c2.isAssignableFrom(c1)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
945 |
return type2; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
946 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
947 |
if (c1.isInterface() || c2.isInterface()) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
948 |
return OBJECT_TYPE_NAME; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
949 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
950 |
return assignableSuperClass(c1, c2).getName().replace('.', '/'); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
951 |
} catch(final ClassNotFoundException e) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
952 |
throw new RuntimeException(e); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
953 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
954 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
955 |
|
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
956 |
private static Class<?> assignableSuperClass(final Class<?> c1, final Class<?> c2) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
957 |
final Class<?> superClass = c1.getSuperclass(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
958 |
return superClass.isAssignableFrom(c2) ? superClass : assignableSuperClass(superClass, c2); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
959 |
} |
19086
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
960 |
|
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
961 |
private static boolean isCallerSensitive(final AccessibleObject e) { |
19088
153f268bfa72
8021122: Not all callables are handled for toString and other function valued properties
sundar
parents:
19086
diff
changeset
|
962 |
return e.isAnnotationPresent(CallerSensitive.class); |
19086
18dcb7a4906f
8020809: Java adapter should not allow overriding of caller sensitive methods
attila
parents:
19085
diff
changeset
|
963 |
} |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
diff
changeset
|
964 |
} |