Tue, 14 Oct 2014 16:16:12 +0530
8050977: Java8 Javascript Nashorn exception: no current Global instance for nashorn
Reviewed-by: attila, lagergren, hannesw
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
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 */
26 package jdk.nashorn.internal.runtime.linker;
28 import java.lang.invoke.MethodHandle;
29 import java.lang.invoke.MethodHandles;
30 import java.lang.invoke.MethodType;
31 import jdk.internal.dynalink.beans.BeansLinker;
32 import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
33 import jdk.internal.dynalink.linker.GuardedInvocation;
34 import jdk.internal.dynalink.linker.GuardingDynamicLinker;
35 import jdk.internal.dynalink.linker.LinkRequest;
36 import jdk.internal.dynalink.linker.LinkerServices;
37 import jdk.internal.dynalink.support.Lookup;
38 import jdk.nashorn.api.scripting.ScriptUtils;
39 import jdk.nashorn.internal.objects.NativeArray;
40 import jdk.nashorn.internal.runtime.ConsString;
41 import jdk.nashorn.internal.runtime.ScriptObject;
42 import jdk.nashorn.internal.runtime.options.Options;
44 /**
45 * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
46 * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
47 * observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
48 * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
49 * the target method handle parameter signature is {@code Object}.
50 */
51 public class NashornBeansLinker implements GuardingDynamicLinker {
52 // System property to control whether to wrap ScriptObject->ScriptObjectMirror for
53 // Object type arguments of Java method calls, field set and array set.
54 private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
56 private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
57 private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
58 private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
59 private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class);
61 private final BeansLinker beansLinker = new BeansLinker();
63 @Override
64 public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
65 return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
66 }
68 /**
69 * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special
70 * conversions that this class does.
71 * @param delegateLinker the linker to which the actual work is delegated to.
72 * @param linkRequest the delegated link request
73 * @param linkerServices the original link services that will be augmented with special conversions
74 * @return the guarded invocation from the delegate, possibly augmented with special conversions
75 * @throws Exception if the delegate throws an exception
76 */
77 public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
78 return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
79 }
81 @SuppressWarnings("unused")
82 private static Object exportArgument(final Object arg) {
83 return exportArgument(arg, MIRROR_ALWAYS);
84 }
86 @SuppressWarnings("unused")
87 private static Object exportNativeArray(final NativeArray arg) {
88 return exportArgument(arg, MIRROR_ALWAYS);
89 }
91 @SuppressWarnings("unused")
92 private static Object exportScriptObject(final ScriptObject arg) {
93 return exportArgument(arg, MIRROR_ALWAYS);
94 }
96 @SuppressWarnings("unused")
97 private static Object exportScriptArray(final NativeArray arg) {
98 return exportArgument(arg, MIRROR_ALWAYS);
99 }
101 static Object exportArgument(final Object arg, final boolean mirrorAlways) {
102 if (arg instanceof ConsString) {
103 return arg.toString();
104 } else if (mirrorAlways && arg instanceof ScriptObject) {
105 return ScriptUtils.wrap((ScriptObject)arg);
106 } else {
107 return arg;
108 }
109 }
111 @SuppressWarnings("unused")
112 private static Object importResult(final Object arg) {
113 return ScriptUtils.unwrap(arg);
114 }
116 private static class NashornBeansLinkerServices implements LinkerServices {
117 private final LinkerServices linkerServices;
119 NashornBeansLinkerServices(final LinkerServices linkerServices) {
120 this.linkerServices = linkerServices;
121 }
123 @Override
124 public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
125 final MethodType handleType = handle.type();
126 final int paramCount = handleType.parameterCount();
127 assert fromType.parameterCount() == handleType.parameterCount();
129 MethodType newFromType = fromType;
130 MethodHandle[] filters = null;
131 for(int i = 0; i < paramCount; ++i) {
132 final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
133 if (filter != null) {
134 if (filters == null) {
135 filters = new MethodHandle[paramCount];
136 }
137 // "erase" specific type with Object type or else we'll get filter mismatch
138 newFromType = newFromType.changeParameterType(i, Object.class);
139 filters[i] = filter;
140 }
141 }
143 final MethodHandle typed = linkerServices.asType(handle, newFromType);
144 MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
145 // Filter Object typed return value for possible ScriptObjectMirror. We convert
146 // ScriptObjectMirror as ScriptObject (if it is mirror from current global).
147 if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
148 result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
149 }
151 return result;
152 }
154 private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
155 if (handleType == Object.class) {
156 if (fromType == Object.class) {
157 return EXPORT_ARGUMENT;
158 } else if (fromType == NativeArray.class) {
159 return EXPORT_NATIVE_ARRAY;
160 } else if (fromType == ScriptObject.class) {
161 return EXPORT_SCRIPT_OBJECT;
162 }
163 }
164 return null;
165 }
167 private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
168 return handleType == Object.class && fromType == Object.class;
169 }
171 @Override
172 public MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) {
173 return Implementation.asTypeLosslessReturn(this, handle, fromType);
174 }
176 @Override
177 public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
178 return linkerServices.getTypeConverter(sourceType, targetType);
179 }
181 @Override
182 public boolean canConvert(final Class<?> from, final Class<?> to) {
183 return linkerServices.canConvert(from, to);
184 }
186 @Override
187 public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
188 return linkerServices.getGuardedInvocation(linkRequest);
189 }
191 @Override
192 public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
193 if (sourceType == ConsString.class) {
194 if (String.class == targetType1 || CharSequence.class == targetType1) {
195 return Comparison.TYPE_1_BETTER;
196 }
198 if (String.class == targetType2 || CharSequence.class == targetType2) {
199 return Comparison.TYPE_2_BETTER;
200 }
201 }
202 return linkerServices.compareConversion(sourceType, targetType1, targetType2);
203 }
204 }
205 }