author | attila |
Fri, 25 Apr 2014 14:20:07 +0200 | |
changeset 24205 | 0a7fbab84fb0 |
parent 23375 | a1110f2cbe75 |
child 24769 | de4dcfa9380f |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
16151 | 2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
16147 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package jdk.nashorn.internal.runtime.linker; |
|
27 |
||
16277 | 28 |
import static jdk.nashorn.internal.lookup.Lookup.MH; |
16147 | 29 |
|
30 |
import java.lang.invoke.MethodHandle; |
|
18841
9bbc4b8832b2
8010946: AccessControl.doPrivileged is broken when called from js script
attila
parents:
17769
diff
changeset
|
31 |
import java.lang.invoke.MethodHandles; |
22669 | 32 |
import java.lang.invoke.MethodHandles.Lookup; |
16147 | 33 |
import java.lang.invoke.MethodType; |
34 |
import java.lang.reflect.Modifier; |
|
19459 | 35 |
import java.security.AccessControlContext; |
16147 | 36 |
import java.security.AccessController; |
22669 | 37 |
import java.security.CodeSigner; |
38 |
import java.security.CodeSource; |
|
39 |
import java.security.Permissions; |
|
16147 | 40 |
import java.security.PrivilegedAction; |
22669 | 41 |
import java.security.ProtectionDomain; |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
42 |
import java.util.ArrayList; |
16147 | 43 |
import java.util.Arrays; |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
44 |
import java.util.Collections; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
45 |
import java.util.HashMap; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
46 |
import java.util.List; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
47 |
import java.util.Map; |
22669 | 48 |
import java.util.concurrent.ConcurrentHashMap; |
16234
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16221
diff
changeset
|
49 |
import jdk.internal.dynalink.beans.StaticClass; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16221
diff
changeset
|
50 |
import jdk.internal.dynalink.support.LinkRequestImpl; |
18865
8844964e5fc5
8020325: static property does not work on accessible, public classes
sundar
parents:
18864
diff
changeset
|
51 |
import jdk.nashorn.internal.runtime.Context; |
16147 | 52 |
import jdk.nashorn.internal.runtime.ECMAException; |
53 |
import jdk.nashorn.internal.runtime.ScriptFunction; |
|
54 |
import jdk.nashorn.internal.runtime.ScriptObject; |
|
55 |
||
56 |
/** |
|
16272 | 57 |
* <p>A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
58 |
* extending of Java classes from JavaScript. For every combination of a superclass to extend and interfaces to |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
59 |
* implement (collectively: "original types"), exactly one adapter class is generated that extends the specified |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
60 |
* superclass and implements the specified interfaces. (But see the discussion of class-based overrides for exceptions.) |
16147 | 61 |
* </p><p> |
62 |
* The adapter class is generated in a new secure class loader that inherits Nashorn's protection domain, and has either |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
63 |
* one of the original types' class loader or the Nashorn's class loader as its parent - the parent class loader |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
64 |
* is chosen so that all the original types and the Nashorn core classes are visible from it (as the adapter will have |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
65 |
* constant pool references to ScriptObject and ScriptFunction classes). In case none of the candidate class loaders has |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
66 |
* visibility of all the required types, an error is thrown. The class uses {@link JavaAdapterBytecodeGenerator} to |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
67 |
* generate the adapter class itself; see its documentation for details about the generated class. |
16167
d99db3541813
8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents:
16151
diff
changeset
|
68 |
* </p><p> |
16147 | 69 |
* You normally don't use this class directly, but rather either create adapters from script using |
23375
a1110f2cbe75
8037400: Remove getInitialMap getters and GlobalObject interface
sundar
parents:
22669
diff
changeset
|
70 |
* {@link jdk.nashorn.internal.objects.NativeJava#extend(Object, Object...)}, using the {@code new} operator on abstract classes and interfaces (see |
a1110f2cbe75
8037400: Remove getInitialMap getters and GlobalObject interface
sundar
parents:
22669
diff
changeset
|
71 |
* {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)}), or implicitly when passing script functions to Java methods expecting SAM |
16147 | 72 |
* types. |
73 |
* </p> |
|
74 |
*/ |
|
75 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
16777
diff
changeset
|
76 |
@SuppressWarnings("javadoc") |
16185 | 77 |
public final class JavaAdapterFactory { |
22669 | 78 |
private static final ProtectionDomain MINIMAL_PERMISSION_DOMAIN = createMinimalPermissionDomain(); |
79 |
||
19459 | 80 |
// context with permissions needs for AdapterInfo creation |
81 |
private static final AccessControlContext CREATE_ADAPTER_INFO_ACC_CTXT = |
|
82 |
ClassAndLoader.createPermAccCtxt("createClassLoader", "getClassLoader", |
|
83 |
"accessDeclaredMembers", "accessClassInPackage.jdk.nashorn.internal.runtime"); |
|
84 |
||
16147 | 85 |
/** |
86 |
* A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents. |
|
87 |
*/ |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
88 |
private static final ClassValue<Map<List<Class<?>>, AdapterInfo>> ADAPTER_INFO_MAPS = new ClassValue<Map<List<Class<?>>, AdapterInfo>>() { |
16147 | 89 |
@Override |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
90 |
protected Map<List<Class<?>>, AdapterInfo> computeValue(final Class<?> type) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
91 |
return new HashMap<>(); |
16147 | 92 |
} |
93 |
}; |
|
94 |
||
95 |
/** |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
96 |
* Returns an adapter class for the specified original types. The adapter class extends/implements the original |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
97 |
* class/interfaces. |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
98 |
* @param types the original types. The caller must pass at least one Java type representing either a public |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
99 |
* interface or a non-final public class with at least one public or protected constructor. If more than one type is |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
100 |
* specified, at most one can be a class and the rest have to be interfaces. The class can be in any position in the |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
101 |
* array. Invoking the method twice with exactly the same types in the same order will return the same adapter |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
102 |
* class, any reordering of types or even addition or removal of redundant types (i.e. interfaces that other types |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
103 |
* in the list already implement/extend, or {@code java.lang.Object} in a list of types consisting purely of |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
104 |
* interfaces) will result in a different adapter class, even though those adapter classes are functionally |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
105 |
* identical; we deliberately don't want to incur the additional processing cost of canonicalizing type lists. |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
106 |
* @param classOverrides a JavaScript object with functions serving as the class-level overrides and |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
107 |
* implementations. These overrides are defined for all instances of the class, and can be further overridden on a |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
108 |
* per-instance basis by passing additional objects in the constructor. |
22669 | 109 |
* @param lookup the lookup object identifying the caller class. The generated adapter class will have the |
110 |
* protection domain of the caller class iff the lookup object is full-strength, otherwise it will be completely |
|
111 |
* unprivileged. |
|
16147 | 112 |
* @return an adapter class. See this class' documentation for details on the generated adapter class. |
113 |
* @throws ECMAException with a TypeError if the adapter class can not be generated because the original class is |
|
114 |
* final, non-public, or has no public or protected constructors. |
|
115 |
*/ |
|
22669 | 116 |
public static StaticClass getAdapterClassFor(final Class<?>[] types, ScriptObject classOverrides, final MethodHandles.Lookup lookup) { |
117 |
return getAdapterClassFor(types, classOverrides, getProtectionDomain(lookup)); |
|
118 |
} |
|
119 |
||
120 |
private static StaticClass getAdapterClassFor(final Class<?>[] types, ScriptObject classOverrides, final ProtectionDomain protectionDomain) { |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
121 |
assert types != null && types.length > 0; |
18864
c701b823ed9e
8020276: interface checks in Invocable.getInterface implementation
sundar
parents:
18841
diff
changeset
|
122 |
final SecurityManager sm = System.getSecurityManager(); |
c701b823ed9e
8020276: interface checks in Invocable.getInterface implementation
sundar
parents:
18841
diff
changeset
|
123 |
if (sm != null) { |
18865
8844964e5fc5
8020325: static property does not work on accessible, public classes
sundar
parents:
18864
diff
changeset
|
124 |
for (Class<?> type : types) { |
18864
c701b823ed9e
8020276: interface checks in Invocable.getInterface implementation
sundar
parents:
18841
diff
changeset
|
125 |
// check for restricted package access |
20567 | 126 |
Context.checkPackageAccess(type); |
22667 | 127 |
// check for classes, interfaces in reflection |
22668 | 128 |
ReflectionCheckLinker.checkReflectionAccess(type, true); |
18864
c701b823ed9e
8020276: interface checks in Invocable.getInterface implementation
sundar
parents:
18841
diff
changeset
|
129 |
} |
c701b823ed9e
8020276: interface checks in Invocable.getInterface implementation
sundar
parents:
18841
diff
changeset
|
130 |
} |
22669 | 131 |
return getAdapterInfo(types).getAdapterClass(classOverrides, protectionDomain); |
132 |
} |
|
133 |
||
134 |
private static ProtectionDomain getProtectionDomain(final MethodHandles.Lookup lookup) { |
|
135 |
if((lookup.lookupModes() & Lookup.PRIVATE) == 0) { |
|
136 |
return MINIMAL_PERMISSION_DOMAIN; |
|
137 |
} |
|
138 |
return getProtectionDomain(lookup.lookupClass()); |
|
139 |
} |
|
140 |
||
141 |
private static ProtectionDomain getProtectionDomain(final Class<?> clazz) { |
|
142 |
return AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() { |
|
143 |
@Override |
|
144 |
public ProtectionDomain run() { |
|
145 |
return clazz.getProtectionDomain(); |
|
146 |
} |
|
147 |
}); |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
148 |
} |
16147 | 149 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
150 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
151 |
* Returns a method handle representing a constructor that takes a single argument of the source type (which, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
152 |
* really, should be one of {@link ScriptObject}, {@link ScriptFunction}, or {@link Object}, and returns an instance |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
153 |
* of the adapter for the target type. Used to implement the function autoconverters as well as the Nashorn's |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
154 |
* JSR-223 script engine's {@code getInterface()} method. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
155 |
* @param sourceType the source type; should be either {@link ScriptObject}, {@link ScriptFunction}, or |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
156 |
* {@link Object}. In case of {@code Object}, it will return a method handle that dispatches to either the script |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
157 |
* object or function constructor at invocation based on the actual argument. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
158 |
* @param targetType the target type, for which adapter instances will be created |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
159 |
* @return the constructor method handle. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
160 |
* @throws Exception if anything goes wrong |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
161 |
*/ |
22669 | 162 |
public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType, final MethodHandles.Lookup lookup) throws Exception { |
163 |
final StaticClass adapterClass = getAdapterClassFor(new Class<?>[] { targetType }, null, lookup); |
|
19459 | 164 |
return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl( |
22669 | 165 |
NashornCallSiteDescriptor.get(lookup, "dyn:new", |
19459 | 166 |
MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, |
167 |
adapterClass, null)).getInvocation(), adapterClass); |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
168 |
} |
16147 | 169 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
170 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
171 |
* Returns whether an instance of the specified class/interface can be generated from a ScriptFunction. Returns true |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
172 |
* iff: the adapter for the class/interface can be created, it is abstract (this includes interfaces), it has at |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
173 |
* least one abstract method, all the abstract methods share the same name, and it has a public or protected default |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
174 |
* constructor. Note that invoking this class will most likely result in the adapter class being defined in the JVM |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
175 |
* if it hasn't been already. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
176 |
* @param clazz the inspected class |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
177 |
* @return true iff an instance of the specified class/interface can be generated from a ScriptFunction. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
178 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
179 |
static boolean isAutoConvertibleFromFunction(final Class<?> clazz) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
180 |
return getAdapterInfo(new Class<?>[] { clazz }).autoConvertibleFromFunction; |
16147 | 181 |
} |
182 |
||
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
183 |
private static AdapterInfo getAdapterInfo(final Class<?>[] types) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
184 |
final ClassAndLoader definingClassAndLoader = ClassAndLoader.getDefiningClassAndLoader(types); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
185 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
186 |
final Map<List<Class<?>>, AdapterInfo> adapterInfoMap = ADAPTER_INFO_MAPS.get(definingClassAndLoader.getRepresentativeClass()); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
187 |
final List<Class<?>> typeList = types.length == 1 ? getSingletonClassList(types[0]) : Arrays.asList(types.clone()); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
188 |
AdapterInfo adapterInfo; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
189 |
synchronized(adapterInfoMap) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
190 |
adapterInfo = adapterInfoMap.get(typeList); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
191 |
if(adapterInfo == null) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
192 |
adapterInfo = createAdapterInfo(types, definingClassAndLoader); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
193 |
adapterInfoMap.put(typeList, adapterInfo); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
194 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
195 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
196 |
return adapterInfo; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
197 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
198 |
|
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
199 |
@SuppressWarnings({ "unchecked", "rawtypes" }) |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
200 |
private static List<Class<?>> getSingletonClassList(final Class<?> clazz) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
201 |
return (List)Collections.singletonList(clazz); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
202 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
203 |
|
19459 | 204 |
/** |
16147 | 205 |
* For a given class, create its adapter class and associated info. |
206 |
* @param type the class for which the adapter is created |
|
207 |
* @return the adapter info for the class. |
|
208 |
*/ |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
209 |
private static AdapterInfo createAdapterInfo(final Class<?>[] types, final ClassAndLoader definingClassAndLoader) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
210 |
Class<?> superClass = null; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
211 |
final List<Class<?>> interfaces = new ArrayList<>(types.length); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
212 |
for(final Class<?> t: types) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
213 |
final int mod = t.getModifiers(); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
214 |
if(!t.isInterface()) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
215 |
if(superClass != null) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
216 |
return new AdapterInfo(AdaptationResult.Outcome.ERROR_MULTIPLE_SUPERCLASSES, t.getCanonicalName() + " and " + superClass.getCanonicalName()); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
217 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
218 |
if (Modifier.isFinal(mod)) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
219 |
return new AdapterInfo(AdaptationResult.Outcome.ERROR_FINAL_CLASS, t.getCanonicalName()); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
220 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
221 |
superClass = t; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
222 |
} else { |
19459 | 223 |
if (interfaces.size() > 65535) { |
224 |
throw new IllegalArgumentException("interface limit exceeded"); |
|
225 |
} |
|
226 |
||
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
227 |
interfaces.add(t); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
228 |
} |
19459 | 229 |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
230 |
if(!Modifier.isPublic(mod)) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
231 |
return new AdapterInfo(AdaptationResult.Outcome.ERROR_NON_PUBLIC_CLASS, t.getCanonicalName()); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
232 |
} |
16147 | 233 |
} |
19459 | 234 |
|
235 |
||
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
236 |
final Class<?> effectiveSuperClass = superClass == null ? Object.class : superClass; |
16147 | 237 |
return AccessController.doPrivileged(new PrivilegedAction<AdapterInfo>() { |
238 |
@Override |
|
239 |
public AdapterInfo run() { |
|
240 |
try { |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
241 |
return new AdapterInfo(effectiveSuperClass, interfaces, definingClassAndLoader); |
16147 | 242 |
} catch (final AdaptationException e) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
243 |
return new AdapterInfo(e.getAdaptationResult()); |
16147 | 244 |
} |
245 |
} |
|
19459 | 246 |
}, CREATE_ADAPTER_INFO_ACC_CTXT); |
16147 | 247 |
} |
248 |
||
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
249 |
private static class AdapterInfo { |
24205 | 250 |
private static final ClassAndLoader SCRIPT_OBJECT_LOADER = new ClassAndLoader(ScriptFunction.class, true); |
16147 | 251 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
252 |
private final ClassLoader commonLoader; |
22669 | 253 |
// TODO: soft reference the JavaAdapterClassLoader objects. They can be recreated when needed. |
254 |
private final JavaAdapterClassLoader classAdapterGenerator; |
|
255 |
private final JavaAdapterClassLoader instanceAdapterGenerator; |
|
256 |
private final Map<CodeSource, StaticClass> instanceAdapters = new ConcurrentHashMap<>(); |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
257 |
final boolean autoConvertibleFromFunction; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
258 |
final AdaptationResult adaptationResult; |
16147 | 259 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
260 |
AdapterInfo(Class<?> superClass, List<Class<?>> interfaces, ClassAndLoader definingLoader) throws AdaptationException { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
261 |
this.commonLoader = findCommonLoader(definingLoader); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
262 |
final JavaAdapterBytecodeGenerator gen = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, false); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
263 |
this.autoConvertibleFromFunction = gen.isAutoConvertibleFromFunction(); |
22669 | 264 |
instanceAdapterGenerator = gen.createAdapterClassLoader(); |
265 |
this.classAdapterGenerator = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, true).createAdapterClassLoader(); |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
266 |
this.adaptationResult = AdaptationResult.SUCCESSFUL_RESULT; |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
267 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
268 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
269 |
AdapterInfo(final AdaptationResult.Outcome outcome, final String classList) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
270 |
this(new AdaptationResult(outcome, classList)); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
271 |
} |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
272 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
273 |
AdapterInfo(final AdaptationResult adaptationResult) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
274 |
this.commonLoader = null; |
22669 | 275 |
this.classAdapterGenerator = null; |
276 |
this.instanceAdapterGenerator = null; |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
277 |
this.autoConvertibleFromFunction = false; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
278 |
this.adaptationResult = adaptationResult; |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
279 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
280 |
|
22669 | 281 |
StaticClass getAdapterClass(final ScriptObject classOverrides, final ProtectionDomain protectionDomain) { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
282 |
if(adaptationResult.getOutcome() != AdaptationResult.Outcome.SUCCESS) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
283 |
throw adaptationResult.typeError(); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
284 |
} |
22669 | 285 |
return classOverrides == null ? getInstanceAdapterClass(protectionDomain) : |
286 |
getClassAdapterClass(classOverrides, protectionDomain); |
|
287 |
} |
|
288 |
||
289 |
private StaticClass getInstanceAdapterClass(final ProtectionDomain protectionDomain) { |
|
290 |
CodeSource codeSource = protectionDomain.getCodeSource(); |
|
291 |
if(codeSource == null) { |
|
292 |
codeSource = MINIMAL_PERMISSION_DOMAIN.getCodeSource(); |
|
293 |
} |
|
294 |
StaticClass instanceAdapterClass = instanceAdapters.get(codeSource); |
|
295 |
if(instanceAdapterClass != null) { |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
296 |
return instanceAdapterClass; |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
297 |
} |
22669 | 298 |
// Any "unknown source" code source will default to no permission domain. |
299 |
final ProtectionDomain effectiveDomain = codeSource.equals(MINIMAL_PERMISSION_DOMAIN.getCodeSource()) ? |
|
300 |
MINIMAL_PERMISSION_DOMAIN : protectionDomain; |
|
301 |
||
302 |
instanceAdapterClass = instanceAdapterGenerator.generateClass(commonLoader, effectiveDomain); |
|
303 |
final StaticClass existing = instanceAdapters.putIfAbsent(codeSource, instanceAdapterClass); |
|
304 |
return existing == null ? instanceAdapterClass : existing; |
|
305 |
} |
|
306 |
||
307 |
private StaticClass getClassAdapterClass(final ScriptObject classOverrides, final ProtectionDomain protectionDomain) { |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
308 |
JavaAdapterServices.setClassOverrides(classOverrides); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
309 |
try { |
22669 | 310 |
return classAdapterGenerator.generateClass(commonLoader, protectionDomain); |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
311 |
} finally { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
312 |
JavaAdapterServices.setClassOverrides(null); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
313 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
314 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
315 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
316 |
/** |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
317 |
* Choose between the passed class loader and the class loader that defines the ScriptObject class, based on which |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
318 |
* of the two can see the classes in both. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
319 |
* @param classAndLoader the loader and a representative class from it that will be used to add the generated |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
320 |
* adapter to its ADAPTER_INFO_MAPS. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
321 |
* @return the class loader that sees both the specified class and Nashorn classes. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
322 |
* @throws IllegalStateException if no such class loader is found. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
323 |
*/ |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
324 |
private static ClassLoader findCommonLoader(final ClassAndLoader classAndLoader) throws AdaptationException { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
325 |
if(classAndLoader.canSee(SCRIPT_OBJECT_LOADER)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
326 |
return classAndLoader.getLoader(); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
327 |
} |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
328 |
if (SCRIPT_OBJECT_LOADER.canSee(classAndLoader)) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
329 |
return SCRIPT_OBJECT_LOADER.getLoader(); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
330 |
} |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
331 |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16525
diff
changeset
|
332 |
throw new AdaptationException(AdaptationResult.Outcome.ERROR_NO_COMMON_LOADER, classAndLoader.getRepresentativeClass().getCanonicalName()); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
333 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16167
diff
changeset
|
334 |
} |
22669 | 335 |
|
336 |
private static ProtectionDomain createMinimalPermissionDomain() { |
|
337 |
// Generated classes need to have at least the permission to access Nashorn runtime and runtime.linker packages. |
|
338 |
final Permissions permissions = new Permissions(); |
|
23375
a1110f2cbe75
8037400: Remove getInitialMap getters and GlobalObject interface
sundar
parents:
22669
diff
changeset
|
339 |
permissions.add(new RuntimePermission("accessClassInPackage.jdk.nashorn.internal.objects")); |
22669 | 340 |
permissions.add(new RuntimePermission("accessClassInPackage.jdk.nashorn.internal.runtime")); |
341 |
permissions.add(new RuntimePermission("accessClassInPackage.jdk.nashorn.internal.runtime.linker")); |
|
342 |
return new ProtectionDomain(new CodeSource(null, (CodeSigner[])null), permissions); |
|
343 |
} |
|
16147 | 344 |
} |