author | attila |
Mon, 02 Mar 2015 14:33:55 +0100 | |
changeset 29282 | a8523237b66c |
parent 25865 | d38d876f1654 |
child 33332 | f180be6368d8 |
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; |
|
31 |
import java.lang.invoke.MethodHandles; |
|
16234
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
32 |
import jdk.internal.dynalink.linker.ConversionComparator; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
33 |
import jdk.internal.dynalink.linker.GuardedInvocation; |
22669 | 34 |
import jdk.internal.dynalink.linker.GuardedTypeConversion; |
16234
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
35 |
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
36 |
import jdk.internal.dynalink.linker.LinkRequest; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
37 |
import jdk.internal.dynalink.linker.LinkerServices; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
38 |
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
39 |
import jdk.internal.dynalink.support.TypeUtilities; |
23375
a1110f2cbe75
8037400: Remove getInitialMap getters and GlobalObject interface
sundar
parents:
22669
diff
changeset
|
40 |
import jdk.nashorn.internal.objects.Global; |
16147 | 41 |
import jdk.nashorn.internal.runtime.ConsString; |
29282 | 42 |
import jdk.nashorn.internal.runtime.JSType; |
24751 | 43 |
import jdk.nashorn.internal.runtime.ScriptRuntime; |
16147 | 44 |
|
45 |
/** |
|
16184
bea4e75d192c
8006525: Give StaticClass objects their own linker
attila
parents:
16171
diff
changeset
|
46 |
* Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other |
bea4e75d192c
8006525: Give StaticClass objects their own linker
attila
parents:
16171
diff
changeset
|
47 |
* engines. It is used for treatment of strings, boolean, and numbers as JavaScript primitives. Also provides ECMAScript |
bea4e75d192c
8006525: Give StaticClass objects their own linker
attila
parents:
16171
diff
changeset
|
48 |
* primitive type conversions for these types when linking to Java methods. |
16147 | 49 |
*/ |
16277 | 50 |
final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator { |
24751 | 51 |
private static final GuardedTypeConversion VOID_TO_OBJECT = new GuardedTypeConversion( |
52 |
new GuardedInvocation(MethodHandles.constant(Object.class, ScriptRuntime.UNDEFINED)), true); |
|
53 |
||
16147 | 54 |
@Override |
55 |
public boolean canLinkType(final Class<?> type) { |
|
56 |
return canLinkTypeStatic(type); |
|
57 |
} |
|
58 |
||
59 |
private static boolean canLinkTypeStatic(final Class<?> type) { |
|
16184
bea4e75d192c
8006525: Give StaticClass objects their own linker
attila
parents:
16171
diff
changeset
|
60 |
return type == String.class || type == Boolean.class || type == ConsString.class || Number.class.isAssignableFrom(type); |
16147 | 61 |
} |
62 |
||
63 |
@Override |
|
64 |
public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices) |
|
65 |
throws Exception { |
|
66 |
final LinkRequest request = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context |
|
67 |
||
68 |
final Object self = request.getReceiver(); |
|
69 |
final NashornCallSiteDescriptor desc = (NashornCallSiteDescriptor) request.getCallSiteDescriptor(); |
|
70 |
||
24731
ab0c8fc915ae
8038406: Testability: as a first step of moving loggers away from the process global space, the Debug object now supports logging POJOs from log entries as an event queue, which can be introspected from test scripts. This is way better than screen scraping brittle and subject-to-change log output.
lagergren
parents:
24727
diff
changeset
|
71 |
return Bootstrap.asTypeSafeReturn(Global.primitiveLookup(request, self), linkerServices, desc); |
16147 | 72 |
} |
73 |
||
74 |
/** |
|
75 |
* This implementation of type converter factory will pretty much allow implicit conversions of anything to anything |
|
76 |
* else that's allowed among JavaScript primitive types (string to number, boolean to string, etc.) |
|
77 |
* @param sourceType the type to convert from |
|
78 |
* @param targetType the type to convert to |
|
79 |
* @return a conditional converter from source to target type |
|
80 |
*/ |
|
81 |
@Override |
|
22669 | 82 |
public GuardedTypeConversion convertToType(final Class<?> sourceType, final Class<?> targetType) { |
16147 | 83 |
final MethodHandle mh = JavaArgumentConverters.getConverter(targetType); |
84 |
if (mh == null) { |
|
24751 | 85 |
if(targetType == Object.class && sourceType == void.class) { |
86 |
return VOID_TO_OBJECT; |
|
87 |
} |
|
16147 | 88 |
return null; |
89 |
} |
|
90 |
||
22669 | 91 |
return new GuardedTypeConversion(new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : GUARD_PRIMITIVE).asType(mh.type().changeParameterType(0, sourceType)), true); |
16147 | 92 |
} |
93 |
||
94 |
/** |
|
95 |
* Implements the somewhat involved prioritization of JavaScript primitive types conversions. Instead of explaining |
|
96 |
* it here in prose, just follow the source code comments. |
|
97 |
* @param sourceType the source type to convert from |
|
98 |
* @param targetType1 one candidate target type |
|
99 |
* @param targetType2 another candidate target type |
|
16234
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16195
diff
changeset
|
100 |
* @return one of {@link jdk.internal.dynalink.linker.ConversionComparator.Comparison} values signifying which |
16184
bea4e75d192c
8006525: Give StaticClass objects their own linker
attila
parents:
16171
diff
changeset
|
101 |
* target type should be favored for conversion. |
16147 | 102 |
*/ |
103 |
@Override |
|
104 |
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) { |
|
105 |
final Class<?> wrapper1 = getWrapperTypeOrSelf(targetType1); |
|
106 |
if (sourceType == wrapper1) { |
|
107 |
// Source type exactly matches target 1 |
|
108 |
return Comparison.TYPE_1_BETTER; |
|
109 |
} |
|
110 |
final Class<?> wrapper2 = getWrapperTypeOrSelf(targetType2); |
|
111 |
if (sourceType == wrapper2) { |
|
112 |
// Source type exactly matches target 2 |
|
113 |
return Comparison.TYPE_2_BETTER; |
|
114 |
} |
|
115 |
||
116 |
if (Number.class.isAssignableFrom(sourceType)) { |
|
117 |
// If exactly one of the targets is a number, pick it. |
|
118 |
if (Number.class.isAssignableFrom(wrapper1)) { |
|
119 |
if (!Number.class.isAssignableFrom(wrapper2)) { |
|
120 |
return Comparison.TYPE_1_BETTER; |
|
121 |
} |
|
122 |
} else if (Number.class.isAssignableFrom(wrapper2)) { |
|
123 |
return Comparison.TYPE_2_BETTER; |
|
124 |
} |
|
125 |
||
126 |
// If exactly one of the targets is a character, pick it. Numbers can be reasonably converted to chars using |
|
127 |
// the UTF-16 values. |
|
128 |
if (Character.class == wrapper1) { |
|
129 |
return Comparison.TYPE_1_BETTER; |
|
130 |
} else if (Character.class == wrapper2) { |
|
131 |
return Comparison.TYPE_2_BETTER; |
|
132 |
} |
|
133 |
||
134 |
// For all other cases, we fall through to the next if statement - not that we repeat the condition in it |
|
135 |
// too so if we entered this branch, we'll enter the below if statement too. |
|
136 |
} |
|
137 |
||
138 |
if (sourceType == String.class || sourceType == Boolean.class || Number.class.isAssignableFrom(sourceType)) { |
|
139 |
// Treat wrappers as primitives. |
|
140 |
final Class<?> primitiveType1 = getPrimitiveTypeOrSelf(targetType1); |
|
141 |
final Class<?> primitiveType2 = getPrimitiveTypeOrSelf(targetType2); |
|
142 |
// Basically, choose the widest possible primitive type. (First "if" returning TYPE_2_BETTER is correct; |
|
143 |
// when faced with a choice between double and int, choose double). |
|
144 |
if (TypeUtilities.isMethodInvocationConvertible(primitiveType1, primitiveType2)) { |
|
145 |
return Comparison.TYPE_2_BETTER; |
|
146 |
} else if (TypeUtilities.isMethodInvocationConvertible(primitiveType2, primitiveType1)) { |
|
147 |
return Comparison.TYPE_1_BETTER; |
|
148 |
} |
|
149 |
// Ok, at this point we're out of possible number conversions, so try strings. A String can represent any |
|
150 |
// value without loss, so if one of the potential targets is string, go for it. |
|
151 |
if (targetType1 == String.class) { |
|
152 |
return Comparison.TYPE_1_BETTER; |
|
153 |
} |
|
154 |
if (targetType2 == String.class) { |
|
155 |
return Comparison.TYPE_2_BETTER; |
|
156 |
} |
|
157 |
} |
|
158 |
||
159 |
return Comparison.INDETERMINATE; |
|
160 |
} |
|
161 |
||
162 |
private static Class<?> getPrimitiveTypeOrSelf(final Class<?> type) { |
|
163 |
final Class<?> primitive = TypeUtilities.getPrimitiveType(type); |
|
164 |
return primitive == null ? type : primitive; |
|
165 |
} |
|
166 |
||
167 |
private static Class<?> getWrapperTypeOrSelf(final Class<?> type) { |
|
168 |
final Class<?> wrapper = TypeUtilities.getWrapperType(type); |
|
169 |
return wrapper == null ? type : wrapper; |
|
170 |
} |
|
171 |
||
172 |
@SuppressWarnings("unused") |
|
173 |
private static boolean isJavaScriptPrimitive(final Object o) { |
|
29282 | 174 |
return JSType.isString(o) || o instanceof Boolean || o instanceof Number || o == null; |
16147 | 175 |
} |
176 |
||
177 |
private static final MethodHandle GUARD_PRIMITIVE = findOwnMH("isJavaScriptPrimitive", boolean.class, Object.class); |
|
178 |
||
179 |
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { |
|
180 |
return MH.findStatic(MethodHandles.lookup(), NashornPrimitiveLinker.class, name, MH.type(rtype, types)); |
|
181 |
} |
|
182 |
} |