mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-22 00:12:18 +00:00
8147008: Nashorn primitive linker should handle ES6 symbols
Reviewed-by: attila, sundar
This commit is contained in:
parent
dd9c62130f
commit
bfa98d042c
@ -1133,6 +1133,8 @@ public final class Global extends Scope {
|
||||
return NativeNumber.lookupPrimitive(request, self);
|
||||
} else if (self instanceof Boolean) {
|
||||
return NativeBoolean.lookupPrimitive(request, self);
|
||||
} else if (self instanceof Symbol) {
|
||||
return NativeSymbol.lookupPrimitive(request, self);
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported primitive: " + self);
|
||||
}
|
||||
|
||||
@ -168,9 +168,9 @@ public final class NativeBoolean extends ScriptObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a native string in a NativeString object.
|
||||
* Wrap a native boolean in a NativeBoolean object.
|
||||
*
|
||||
* @param receiver Native string.
|
||||
* @param receiver Native boolean.
|
||||
* @return Wrapped object.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@ -25,8 +25,14 @@
|
||||
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.nashorn.internal.WeakValueCache;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||
@ -39,6 +45,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Symbol;
|
||||
import jdk.nashorn.internal.runtime.Undefined;
|
||||
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
|
||||
|
||||
/**
|
||||
* ECMAScript 6 - 19.4 Symbol Objects
|
||||
@ -48,12 +55,21 @@ public final class NativeSymbol extends ScriptObject {
|
||||
|
||||
private final Symbol symbol;
|
||||
|
||||
/** Method handle to create an object wrapper for a primitive symbol. */
|
||||
static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeSymbol.class, Object.class));
|
||||
/** Method handle to retrieve the Symbol prototype object. */
|
||||
private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
|
||||
|
||||
// initialized by nasgen
|
||||
private static PropertyMap $nasgenmap$;
|
||||
|
||||
/** See ES6 19.4.2.1 */
|
||||
private static WeakValueCache<String, Symbol> globalSymbolRegistry = new WeakValueCache<>();
|
||||
|
||||
NativeSymbol(final Symbol symbol) {
|
||||
this(symbol, Global.instance());
|
||||
}
|
||||
|
||||
NativeSymbol(final Symbol symbol, final Global global) {
|
||||
this(symbol, global.getSymbolPrototype(), $nasgenmap$);
|
||||
}
|
||||
@ -73,6 +89,17 @@ public final class NativeSymbol extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the appropriate method for an invoke dynamic call.
|
||||
*
|
||||
* @param request The link request
|
||||
* @param receiver The receiver for the call
|
||||
* @return Link to be invoked at call site.
|
||||
*/
|
||||
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
|
||||
return PrimitiveLookup.lookupPrimitive(request, Symbol.class, new NativeSymbol((Symbol)receiver), WRAPFILTER, PROTOFILTER);
|
||||
}
|
||||
|
||||
// ECMA 6 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
|
||||
@Override
|
||||
public Object getDefaultValue(final Class<?> typeHint) {
|
||||
@ -149,4 +176,19 @@ public final class NativeSymbol extends ScriptObject {
|
||||
final String name = ((Symbol) arg).getName();
|
||||
return globalSymbolRegistry.get(name) == arg ? name : Undefined.getUndefined();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static NativeSymbol wrapFilter(final Object receiver) {
|
||||
return new NativeSymbol((Symbol)receiver);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object protoFilter(final Object object) {
|
||||
return Global.instance().getSymbolPrototype();
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final MethodType type) {
|
||||
return MH.findStatic(MethodHandles.lookup(), NativeSymbol.class, name, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.runtime.ConsString;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Symbol;
|
||||
|
||||
/**
|
||||
* Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other
|
||||
@ -58,7 +59,8 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu
|
||||
|
||||
private static boolean canLinkTypeStatic(final Class<?> type) {
|
||||
return type == String.class || type == Boolean.class || type == ConsString.class || type == Integer.class
|
||||
|| type == Double.class || type == Float.class || type == Short.class || type == Byte.class;
|
||||
|| type == Double.class || type == Float.class || type == Short.class || type == Byte.class
|
||||
|| type == Symbol.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,7 +170,7 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isJavaScriptPrimitive(final Object o) {
|
||||
return JSType.isString(o) || o instanceof Boolean || JSType.isNumber(o) || o == null;
|
||||
return JSType.isString(o) || o instanceof Boolean || JSType.isNumber(o) || o == null || o instanceof Symbol;
|
||||
}
|
||||
|
||||
private static final MethodHandle GUARD_PRIMITIVE = findOwnMH("isJavaScriptPrimitive", boolean.class, Object.class);
|
||||
|
||||
@ -40,11 +40,11 @@ Assert.assertTrue(Symbol([1, 2, 3]).toString() === 'Symbol(1,2,3)');
|
||||
Assert.assertTrue(Symbol(null).toString() === 'Symbol(null)');
|
||||
Assert.assertTrue(Symbol(undefined).toString() === 'Symbol()');
|
||||
|
||||
var s1 = Symbol();
|
||||
var s2 = Symbol("s2");
|
||||
const s1 = Symbol();
|
||||
const s2 = Symbol("s2");
|
||||
Assert.assertFalse(s1 instanceof Symbol); // not an object
|
||||
|
||||
var obj = {};
|
||||
let obj = {};
|
||||
obj['foo'] = 'foo';
|
||||
obj[s1] = s1;
|
||||
obj['bar'] = 'bar';
|
||||
@ -57,17 +57,17 @@ Assert.assertTrue(obj['bar'] === 'bar');
|
||||
Assert.assertTrue(obj[1] === 1);
|
||||
Assert.assertTrue(obj[s2] === s2);
|
||||
|
||||
var expectedNames = ['1', 'foo', 'bar'];
|
||||
var expectedSymbols = [s1, s2];
|
||||
var actualNames = Object.getOwnPropertyNames(obj);
|
||||
var actualSymbols = Object.getOwnPropertySymbols(obj);
|
||||
const expectedNames = ['1', 'foo', 'bar'];
|
||||
const expectedSymbols = [s1, s2];
|
||||
const actualNames = Object.getOwnPropertyNames(obj);
|
||||
let actualSymbols = Object.getOwnPropertySymbols(obj);
|
||||
Assert.assertTrue(expectedNames.length == actualNames.length);
|
||||
Assert.assertTrue(expectedSymbols.length == actualSymbols.length);
|
||||
|
||||
for (var key in expectedNames) {
|
||||
for (let key in expectedNames) {
|
||||
Assert.assertTrue(expectedNames[key] === actualNames[key]);
|
||||
}
|
||||
for (var key in expectedSymbols) {
|
||||
for (let key in expectedSymbols) {
|
||||
Assert.assertTrue(expectedSymbols[key] === actualSymbols[key]);
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ try {
|
||||
|
||||
// Symbol.for and Symbol.keyFor
|
||||
|
||||
var uncached = Symbol('foo');
|
||||
var cached = Symbol.for('foo');
|
||||
const uncached = Symbol('foo');
|
||||
const cached = Symbol.for('foo');
|
||||
|
||||
Assert.assertTrue(uncached !== cached);
|
||||
Assert.assertTrue(Symbol.keyFor(uncached) === undefined);
|
||||
@ -123,9 +123,15 @@ Assert.assertTrue(Symbol.keyFor(cached) === 'foo');
|
||||
Assert.assertTrue(cached === Symbol.for('foo'));
|
||||
Assert.assertTrue(cached === Symbol.for('f' + 'oo'));
|
||||
|
||||
// JDK-8147008: Make sure symbols are handled by primitive linker
|
||||
Symbol.prototype.foo = 123;
|
||||
Symbol.prototype[s2] = s2;
|
||||
Assert.assertEquals(s1.foo, 123);
|
||||
Assert.assertEquals(s2[s2], s2);
|
||||
|
||||
// Object wrapper
|
||||
|
||||
var o = Object(s1);
|
||||
const o = Object(s1);
|
||||
obj = {};
|
||||
obj[s1] = "s1";
|
||||
Assert.assertTrue(o == s1);
|
||||
@ -134,6 +140,8 @@ Assert.assertTrue(typeof o === 'object');
|
||||
Assert.assertTrue(o instanceof Symbol);
|
||||
Assert.assertTrue(obj[o] == 's1');
|
||||
Assert.assertTrue(o in obj);
|
||||
Assert.assertEquals(o.foo, 123);
|
||||
Assert.assertEquals(o[s2], s2);
|
||||
|
||||
// various non-strict comparisons that should fail
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user