--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java Wed Nov 11 16:28:17 2015 +0100
@@ -165,7 +165,7 @@
try {
final Object res = context.eval(global, source, global, "<shell>");
if (res != ScriptRuntime.UNDEFINED) {
- err.println(JSType.toString(res));
+ err.println(toString(res, global));
}
} catch (final Exception exp) {
// Is this a ECMAScript SyntaxError at last column (of the single line)?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/WeakValueCache.java Wed Nov 11 16:28:17 2015 +0100
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.function.Function;
+
+/**
+ * This class provides a map based cache with weakly referenced values. Cleared references are
+ * purged from the underlying map when values are retrieved or created.
+ * It uses a {@link java.util.HashMap} to store values and needs to be externally synchronized.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ */
+public final class WeakValueCache<K, V> {
+
+ private final HashMap<K, KeyValueReference<K, V>> map = new HashMap<>();
+ private final ReferenceQueue<V> refQueue = new ReferenceQueue<>();
+
+ /**
+ * Returns the value associated with {@code key}, or {@code null} if no such value exists.
+ *
+ * @param key the key
+ * @return the value or null if none exists
+ */
+ public V get(final K key) {
+ removeClearedEntries();
+ return findValue(key);
+ }
+
+ /**
+ * Returns the value associated with {@code key}, or creates and returns a new value if
+ * no value exists using the {@code creator} function.
+ *
+ * @param key the key
+ * @param creator function to create a new value
+ * @return the existing value, or a new one if none existed
+ */
+ public V getOrCreate(final K key, final Function<? super K, ? extends V> creator) {
+ removeClearedEntries();
+
+ V value = findValue(key);
+
+ if (value == null) {
+ // Define a new value if it does not exist
+ value = creator.apply(key);
+ map.put(key, new KeyValueReference<>(key, value));
+ }
+
+ return value;
+ }
+
+ private V findValue(final K key) {
+ final KeyValueReference<K, V> ref = map.get(key);
+ if (ref != null) {
+ return ref.get();
+ }
+ return null;
+ }
+
+ private void removeClearedEntries() {
+ // Remove cleared entries
+ for (;;) {
+ final KeyValueReference ref = (KeyValueReference) refQueue.poll();
+ if (ref == null) {
+ break;
+ }
+ map.remove(ref.key, ref);
+ }
+ }
+
+ private static class KeyValueReference<K, V> extends WeakReference<V> {
+ final K key;
+
+ KeyValueReference(final K key, final V value) {
+ super(value);
+ this.key = key;
+ }
+ }
+
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Nov 11 16:28:17 2015 +0100
@@ -738,7 +738,7 @@
* @param recovery start label for catch
*/
void _try(final Label entry, final Label exit, final Label recovery) {
- _try(entry, exit, recovery, (String)null, false);
+ _try(entry, exit, recovery, null, false);
}
void markLabelAsOptimisticCatchHandler(final Label label, final int liveLocalCount) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Wed Nov 11 16:28:17 2015 +0100
@@ -173,9 +173,10 @@
loadTuple(method, tuple);
method.dynamicSetIndex(callSiteFlags);
} else {
+ assert property.getKey() instanceof String; // symbol keys not yet supported in object literals
method.dup();
loadTuple(method, tuple);
- method.dynamicSet(property.getKey(), codegen.getCallSiteFlags(), false);
+ method.dynamicSet((String) property.getKey(), codegen.getCallSiteFlags(), false);
}
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Nov 11 16:28:17 2015 +0100
@@ -75,6 +75,7 @@
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.ScriptingFunctions;
import jdk.nashorn.internal.runtime.Specialization;
+import jdk.nashorn.internal.runtime.Symbol;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -221,6 +222,10 @@
@Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object number;
+ /** ECMA 2016 19.4.1 - Symbol constructor */
+ @Property(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
+ public volatile Object symbol;
+
/**
* Getter for ECMA 15.1.4.7 Date property
*
@@ -901,6 +906,7 @@
private ScriptFunction builtinUint32Array;
private ScriptFunction builtinFloat32Array;
private ScriptFunction builtinFloat64Array;
+ private ScriptFunction builtinSymbol;
/*
* ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
@@ -1106,6 +1112,8 @@
return new NativeArray(ArrayData.allocate((int[]) obj), this);
} else if (obj instanceof ArrayData) {
return new NativeArray((ArrayData) obj, this);
+ } else if (obj instanceof Symbol) {
+ return new NativeSymbol((Symbol) obj, this);
} else {
// FIXME: more special cases? Map? List?
return obj;
@@ -1586,7 +1594,7 @@
/**
* Get the builtin Object prototype.
- * @return the object prototype.
+ * @return the Object prototype.
*/
public ScriptObject getObjectPrototype() {
return ScriptFunction.getPrototype(builtinObject);
@@ -1594,13 +1602,17 @@
/**
* Get the builtin Function prototype.
- * @return the Function.prototype.
+ * @return the Function prototype.
*/
public ScriptObject getFunctionPrototype() {
return ScriptFunction.getPrototype(builtinFunction);
}
- ScriptObject getArrayPrototype() {
+ /**
+ * Get the builtin Array prototype.
+ * @return the Array prototype
+ */
+ public ScriptObject getArrayPrototype() {
return ScriptFunction.getPrototype(builtinArray);
}
@@ -1660,6 +1672,10 @@
return ScriptFunction.getPrototype(getBuiltinJSAdapter());
}
+ ScriptObject getSymbolPrototype() {
+ return ScriptFunction.getPrototype(builtinSymbol);
+ }
+
private synchronized ScriptFunction getBuiltinArrayBuffer() {
if (this.builtinArrayBuffer == null) {
this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
@@ -2127,11 +2143,11 @@
// ES6 15.1.8 steps 6. and 7.
final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey());
if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) {
- throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
+ throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString());
}
final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey());
if (lexicalProperty != null && !property.isConfigurable()) {
- throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
+ throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString());
}
}
}
@@ -2186,7 +2202,7 @@
}
@Override
- protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+ protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
if (lexicalScope != null && start != this && start.isScope()) {
final FindProperty find = lexicalScope.findProperty(key, false);
if (find != null) {
@@ -2306,6 +2322,14 @@
this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class);
this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class);
+ if (env._es6) {
+ this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class);
+ } else {
+ // We need to manually delete nasgen-generated properties we don't want
+ this.delete("Symbol", false);
+ this.builtinObject.delete("getOwnPropertySymbols", false);
+ }
+
// initialize String.prototype.length to 0
// add String.prototype.length
final ScriptObject stringPrototype = getStringPrototype();
@@ -2514,6 +2538,7 @@
this.string = this.builtinString;
this.syntaxError = this.builtinSyntaxError;
this.typeError = this.builtinTypeError;
+ this.symbol = this.builtinSymbol;
}
private void initDebug() {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArguments.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArguments.java Wed Nov 11 16:28:17 2015 +0100
@@ -151,7 +151,7 @@
* ECMA 10.6 for Arguments object.
*/
@Override
- public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
+ public boolean defineOwnProperty(final Object key, final Object propertyDesc, final boolean reject) {
final int index = ArrayIndex.getArrayIndex(key);
if (index >= 0) {
final boolean isMapped = isMapped(index);
@@ -159,7 +159,7 @@
if (!super.defineOwnProperty(key, propertyDesc, false)) {
if (reject) {
- throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+ throw typeError("cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Nov 11 16:28:17 2015 +0100
@@ -328,7 +328,7 @@
* ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw )
*/
@Override
- public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
+ public boolean defineOwnProperty(final Object key, final Object propertyDesc, final boolean reject) {
final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc);
// never be undefined as "length" is always defined and can't be deleted for arrays
@@ -369,7 +369,7 @@
// Step 4d
if (!succeeded) {
if (reject) {
- throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+ throw typeError("cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java Wed Nov 11 16:28:17 2015 +0100
@@ -135,8 +135,11 @@
}
@Override
- protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
- final Object retval = createProperty(name);
+ protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
+ if (!(key instanceof String)) {
+ return super.invokeNoSuchProperty(key, isScope, programPoint);
+ }
+ final Object retval = createProperty((String) key);
if (isValid(programPoint)) {
throw new UnwarrantedOptimismException(retval, programPoint);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Wed Nov 11 16:28:17 2015 +0100
@@ -252,6 +252,23 @@
}
/**
+ * ECMA 2 19.1.2.8 Object.getOwnPropertySymbols ( O )
+ *
+ * @param self self reference
+ * @param obj object to query for property names
+ * @return array of property names
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public static ScriptObject getOwnPropertySymbols(final Object self, final Object obj) {
+ if (obj instanceof ScriptObject) {
+ return new NativeArray(((ScriptObject)obj).getOwnSymbols(true));
+ } else {
+ // TODO: we don't support this on ScriptObjectMirror objects yet
+ throw notAnObject(obj);
+ }
+ }
+
+ /**
* ECMA 15.2.3.5 Object.create ( O [, Properties] )
*
* @param self self reference
@@ -288,7 +305,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
final ScriptObject sobj = Global.checkObject(obj);
- sobj.defineOwnProperty(JSType.toString(prop), attr, true);
+ sobj.defineOwnProperty(JSType.toPropertyKey(prop), attr, true);
return sobj;
}
@@ -465,6 +482,7 @@
case BOOLEAN:
case NUMBER:
case STRING:
+ case SYMBOL:
return Global.toObject(value);
case OBJECT:
return value;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Nov 11 16:28:17 2015 +0100
@@ -33,6 +33,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
@@ -106,20 +107,6 @@
return getStringValue();
}
- @Override
- public boolean equals(final Object other) {
- if (other instanceof NativeString) {
- return getStringValue().equals(((NativeString) other).getStringValue());
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return getStringValue().hashCode();
- }
-
private String getStringValue() {
return value instanceof String ? (String) value : value.toString();
}
@@ -382,7 +369,7 @@
}
@Override
- public Object getOwnPropertyDescriptor(final String key) {
+ public Object getOwnPropertyDescriptor(final Object key) {
final int index = ArrayIndex.getArrayIndex(key);
if (index >= 0 && index < value.length()) {
final Global global = Global.instance();
@@ -400,7 +387,12 @@
* @return Array of keys.
*/
@Override
- protected String[] getOwnKeys(final boolean all, final Set<String> nonEnumerable) {
+ @SuppressWarnings("unchecked")
+ protected <T> T[] getOwnKeys(final Class<T> type, final boolean all, final Set<T> nonEnumerable) {
+ if (type != String.class) {
+ return super.getOwnKeys(type, all, nonEnumerable);
+ }
+
final List<Object> keys = new ArrayList<>();
// add string index keys
@@ -409,8 +401,8 @@
}
// add super class properties
- keys.addAll(Arrays.asList(super.getOwnKeys(all, nonEnumerable)));
- return keys.toArray(new String[keys.size()]);
+ keys.addAll(Arrays.asList(super.getOwnKeys(type, all, nonEnumerable)));
+ return keys.toArray((T[]) Array.newInstance(type, keys.size()));
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java Wed Nov 11 16:28:17 2015 +0100
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.objects;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+import jdk.nashorn.internal.WeakValueCache;
+import jdk.nashorn.internal.objects.annotations.Attribute;
+import jdk.nashorn.internal.objects.annotations.Constructor;
+import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Symbol;
+import jdk.nashorn.internal.runtime.Undefined;
+
+/**
+ * ECMAScript 6 - 19.4 Symbol Objects
+ */
+@ScriptClass("Symbol")
+public final class NativeSymbol extends ScriptObject {
+
+ private final Symbol symbol;
+
+ // 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, final Global global) {
+ this(symbol, global.getSymbolPrototype(), $nasgenmap$);
+ }
+
+ private NativeSymbol(final Symbol symbol, final ScriptObject prototype, final PropertyMap map) {
+ super(prototype, map);
+ this.symbol = symbol;
+ }
+
+ private static Symbol getSymbolValue(final Object self) {
+ if (self instanceof Symbol) {
+ return (Symbol) self;
+ } else if (self instanceof NativeSymbol) {
+ return ((NativeSymbol) self).symbol;
+ } else {
+ throw typeError("not.a.symbol");
+ }
+ }
+
+ // ECMA 6 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
+ @Override
+ public Object getDefaultValue(final Class<?> typeHint) {
+ // Just return the symbol value.
+ return symbol;
+ }
+
+ /**
+ * ECMA 6 19.4.3.2 Symbol.prototype.toString ( )
+ *
+ * @param self self reference
+ * @return localized string for this Number
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static String toString(final Object self) {
+ return getSymbolValue(self).toString();
+ }
+
+
+ /**
+ * ECMA 6 19.4.3.3 Symbol.prototype.valueOf ( )
+ *
+ * @param self self reference
+ * @return number value for this Number
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object valueOf(final Object self) {
+ return getSymbolValue(self);
+ }
+
+ /**
+ * ECMA 6 19.4.1.1 Symbol ( [ description ] )
+ *
+ * @param newObj is this function invoked with the new operator
+ * @param self self reference
+ * @param args arguments
+ * @return new symbol value
+ */
+ @Constructor(arity = 1)
+ public static Object constructor(final boolean newObj, final Object self, final Object... args) {
+ if (newObj) {
+ throw typeError("symbol.as.constructor");
+ }
+ final String description = args.length > 0 && args[0] != Undefined.getUndefined() ?
+ JSType.toString(args[0]) : "";
+ return new Symbol(description);
+ }
+
+ /**
+ * ES6 19.4.2.1 Symbol.for ( key )
+ *
+ * @param self self reference
+ * @param arg the argument
+ * @return the symbol value
+ */
+ @Function(name = "for", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public synchronized static Object _for(final Object self, final Object arg) {
+ final String name = JSType.toString(arg);
+ return globalSymbolRegistry.getOrCreate(name, Symbol::new);
+ }
+
+ /**
+ * ES6 19.4.2.5 Symbol.keyFor ( sym )
+ *
+ * @param self self reference
+ * @param arg the argument
+ * @return the symbol name
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public synchronized static Object keyFor(final Object self, final Object arg) {
+ if (!(arg instanceof Symbol)) {
+ throw typeError("not.a.symbol", ScriptRuntime.safeToString(arg));
+ }
+ final String name = ((Symbol) arg).getName();
+ return globalSymbolRegistry.get(name) == arg ? name : Undefined.getUndefined();
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Nov 11 16:28:17 2015 +0100
@@ -180,7 +180,7 @@
* @param objectSetter object setter
*/
protected AccessorProperty(
- final String key,
+ final Object key,
final int flags,
final int slot,
final MethodHandle primitiveGetter,
@@ -209,7 +209,7 @@
* @param getter the property getter
* @param setter the property setter or null if non writable, non configurable
*/
- private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
+ private AccessorProperty(final Object key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
super(key, flags | IS_BUILTIN | DUAL_FIELDS | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
assert !isSpill();
@@ -249,7 +249,7 @@
* @param structure structure for objects associated with this property
* @param slot property field number or spill slot
*/
- public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot) {
+ public AccessorProperty(final Object key, final int flags, final Class<?> structure, final int slot) {
super(key, flags, slot);
initGetterSetter(structure);
@@ -292,7 +292,7 @@
* @param owner owner of property
* @param initialValue initial value to which the property can be set
*/
- protected AccessorProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
+ protected AccessorProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
this(key, flags, owner.getClass(), slot);
setInitialValue(owner, initialValue);
}
@@ -307,7 +307,7 @@
* @param slot field slot index
* @param initialType initial type of the property
*/
- public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) {
+ public AccessorProperty(final Object key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) {
this(key, flags, structure, slot);
setType(hasDualFields() ? initialType : Object.class);
}
@@ -603,7 +603,7 @@
private void checkUndeclared() {
if ((getFlags() & NEEDS_DECLARATION) != 0) {
// a lexically defined variable that hasn't seen its declaration - throw ReferenceError
- throw ECMAErrors.referenceError("not.defined", getKey());
+ throw ECMAErrors.referenceError("not.defined", getKey().toString());
}
}
@@ -659,7 +659,7 @@
}
if (isBuiltin()) {
- mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey()));
+ mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey().toString()));
}
assert mh.type().returnType() == void.class : mh.type();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Nov 11 16:28:17 2015 +0100
@@ -42,10 +42,8 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
-import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
@@ -80,6 +78,7 @@
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.WeakValueCache;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
@@ -303,47 +302,7 @@
}
}
- private final Map<CodeSource, HostClassReference> anonymousHostClasses = new HashMap<>();
- private final ReferenceQueue<Class<?>> anonymousHostClassesRefQueue = new ReferenceQueue<>();
-
- private static class HostClassReference extends WeakReference<Class<?>> {
- final CodeSource codeSource;
-
- HostClassReference(final CodeSource codeSource, final Class<?> clazz, final ReferenceQueue<Class<?>> refQueue) {
- super(clazz, refQueue);
- this.codeSource = codeSource;
- }
- }
-
- private synchronized Class<?> getAnonymousHostClass(final CodeSource codeSource) {
- // Remove cleared entries
- for(;;) {
- final HostClassReference clearedRef = (HostClassReference)anonymousHostClassesRefQueue.poll();
- if (clearedRef == null) {
- break;
- }
- anonymousHostClasses.remove(clearedRef.codeSource, clearedRef);
- }
-
- // Try to find an existing host class
- final Reference<Class<?>> ref = anonymousHostClasses.get(codeSource);
- if (ref != null) {
- final Class<?> existingHostClass = ref.get();
- if (existingHostClass != null) {
- return existingHostClass;
- }
- }
-
- // Define a new host class if existing is not found
- final Class<?> newHostClass = createNewLoader().installClass(
- // NOTE: we're defining these constants in AnonymousContextCodeInstaller so they are not
- // initialized if we don't use AnonymousContextCodeInstaller. As this method is only ever
- // invoked from AnonymousContextCodeInstaller, this is okay.
- AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_NAME,
- AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_BYTES, codeSource);
- anonymousHostClasses.put(codeSource, new HostClassReference(codeSource, newHostClass, anonymousHostClassesRefQueue));
- return newHostClass;
- }
+ private final WeakValueCache<CodeSource, Class<?>> anonymousHostClasses = new WeakValueCache<>();
private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller {
private static final Unsafe UNSAFE = getUnsafe();
@@ -1455,7 +1414,14 @@
final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
installer = new NamedContextCodeInstaller(this, cs, loader);
} else {
- installer = new AnonymousContextCodeInstaller(this, cs, getAnonymousHostClass(cs));
+ installer = new AnonymousContextCodeInstaller(this, cs,
+ anonymousHostClasses.getOrCreate(cs, (key) ->
+ createNewLoader().installClass(
+ // NOTE: we're defining these constants in AnonymousContextCodeInstaller so they are not
+ // initialized if we don't use AnonymousContextCodeInstaller. As this method is only ever
+ // invoked from AnonymousContextCodeInstaller, this is okay.
+ AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_NAME,
+ AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_BYTES, cs)));
}
if (storedScript == null) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java Wed Nov 11 16:28:17 2015 +0100
@@ -105,7 +105,7 @@
* Access map for this global - associates a symbol name with an Access object, with getter
* and invalidation information
*/
- private final Map<String, Access> map = new HashMap<>();
+ private final Map<Object, Access> map = new HashMap<>();
private final AtomicBoolean invalidatedForever = new AtomicBoolean(false);
@@ -301,7 +301,7 @@
* that might be linked as MethodHandle.constant and force relink
* @param name name of property
*/
- void delete(final String name) {
+ void delete(final Object name) {
if (!invalidatedForever.get()) {
synchronized (this) {
final Access acc = map.get(name);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Wed Nov 11 16:28:17 2015 +0100
@@ -40,6 +40,7 @@
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeSymbol;
import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
@@ -68,7 +69,10 @@
OBJECT("object"),
/** The function type */
- FUNCTION("function");
+ FUNCTION("function"),
+
+ /** The symbol type */
+ SYMBOL("symbol");
/** The type name as returned by ECMAScript "typeof" operator*/
private final String typeName;
@@ -312,6 +316,10 @@
return JSType.NUMBER;
}
+ if (obj instanceof Symbol) {
+ return JSType.SYMBOL;
+ }
+
if (obj == ScriptRuntime.UNDEFINED) {
return JSType.UNDEFINED;
}
@@ -354,6 +362,10 @@
return JSType.UNDEFINED;
}
+ if (obj instanceof Symbol) {
+ return JSType.SYMBOL;
+ }
+
return JSType.OBJECT;
}
@@ -470,9 +482,10 @@
public static boolean isPrimitive(final Object obj) {
return obj == null ||
obj == ScriptRuntime.UNDEFINED ||
- obj instanceof Boolean ||
+ isString(obj) ||
obj instanceof Number ||
- isString(obj);
+ obj instanceof Boolean ||
+ obj instanceof Symbol;
}
/**
@@ -614,6 +627,15 @@
}
/**
+ * See ES6 #7.1.14
+ * @param obj key object
+ * @return property key
+ */
+ public static Object toPropertyKey(final Object obj) {
+ return obj instanceof Symbol ? obj : toStringImpl(obj, false);
+ }
+
+ /**
* If obj is an instance of {@link ConsString} cast to CharSequence, else return
* result of {@link #toString(Object)}.
*
@@ -787,7 +809,9 @@
* @return a number
*/
public static double toNumberForEq(final Object obj) {
- return obj == null ? Double.NaN : toNumber(obj);
+ // we are not able to detect Symbol objects from codegen, so we need to
+ // handle them here to avoid throwing an error in toNumber conversion.
+ return obj == null || obj instanceof Symbol || obj instanceof NativeSymbol ? Double.NaN : toNumber(obj);
}
/**
@@ -1404,6 +1428,13 @@
return obj.toString();
}
+ if (obj instanceof Symbol) {
+ if (safe) {
+ return obj.toString();
+ }
+ throw typeError("symbol.to.string");
+ }
+
if (safe && obj instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject)obj;
final Global gobj = Context.getGlobal();
@@ -1916,6 +1947,10 @@
return Double.NaN;
}
+ if (obj instanceof Symbol) {
+ throw typeError("symbol.to.number");
+ }
+
return toNumber(toPrimitive(obj, Number.class));
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NativeJavaPackage.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NativeJavaPackage.java Wed Nov 11 16:28:17 2015 +0100
@@ -207,8 +207,11 @@
}
@Override
- protected Object invokeNoSuchProperty(final String key, final boolean isScope, final int programPoint) {
- final Object retval = createProperty(key);
+ protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
+ if (!(key instanceof String)) {
+ return super.invokeNoSuchProperty(key, isScope, programPoint);
+ }
+ final Object retval = createProperty((String) key);
if (isValid(programPoint)) {
throw new UnwarrantedOptimismException(retval, programPoint);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Nov 11 16:28:17 2015 +0100
@@ -100,7 +100,7 @@
public static final int DUAL_FIELDS = 1 << 11;
/** Property key. */
- private final String key;
+ private final Object key;
/** Property flags. */
private int flags;
@@ -127,7 +127,7 @@
* @param flags property flags
* @param slot property field number or spill slot
*/
- Property(final String key, final int flags, final int slot) {
+ Property(final Object key, final int flags, final int slot) {
assert key != null;
this.key = key;
this.flags = flags;
@@ -420,7 +420,7 @@
* Get the key for this property. This key is an ordinary string. The "name".
* @return key for property
*/
- public String getKey() {
+ public Object getKey() {
return key;
}
@@ -627,7 +627,7 @@
final StringBuilder sb = new StringBuilder();
final Class<?> t = getLocalType();
- sb.append(indent(getKey(), 20)).
+ sb.append(indent(getKey().toString(), 20)).
append(" id=").
append(Debug.id(this)).
append(" (0x").
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyHashMap.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyHashMap.java Wed Nov 11 16:28:17 2015 +0100
@@ -102,7 +102,7 @@
* immutable hash map, addition is constant time. For LinkedHashMap it's O(N+C)
* since we have to clone the older map.
*/
-public final class PropertyHashMap implements Map <String, Property> {
+public final class PropertyHashMap implements Map <Object, Property> {
/** Number of initial bins. Power of 2. */
private static final int INITIAL_BINS = 32;
@@ -243,7 +243,7 @@
*
* @return New {@link PropertyHashMap}.
*/
- public PropertyHashMap immutableRemove(final String key) {
+ public PropertyHashMap immutableRemove(final Object key) {
if (bins != null) {
final int binIndex = binIndex(bins, key);
final Element bin = bins[binIndex];
@@ -271,7 +271,7 @@
*
* @return {@link Property} matching key or {@code null} if not found.
*/
- public Property find(final String key) {
+ public Property find(final Object key) {
final Element element = findElement(key);
return element != null ? element.getProperty() : null;
}
@@ -301,7 +301,7 @@
*
* @return The bin index.
*/
- private static int binIndex(final Element[] bins, final String key) {
+ private static int binIndex(final Element[] bins, final Object key) {
return key.hashCode() & bins.length - 1;
}
@@ -340,7 +340,7 @@
final Element[] newBins = new Element[binSize];
for (Element element = list; element != null; element = element.getLink()) {
final Property property = element.getProperty();
- final String key = property.getKey();
+ final Object key = property.getKey();
final int binIndex = binIndex(newBins, key);
newBins[binIndex] = new Element(newBins[binIndex], property);
@@ -355,7 +355,7 @@
*
* @return {@link Element} matching key or {@code null} if not found.
*/
- private Element findElement(final String key) {
+ private Element findElement(final Object key) {
if (bins != null) {
final int binIndex = binIndex(bins, key);
return findElement(bins[binIndex], key);
@@ -370,7 +370,7 @@
* @param key {@link Element} key.
* @return {@link Element} matching key or {@code null} if not found.
*/
- private static Element findElement(final Element elementList, final String key) {
+ private static Element findElement(final Element elementList, final Object key) {
final int hashCode = key.hashCode();
for (Element element = elementList; element != null; element = element.getLink()) {
if (element.match(key, hashCode)) {
@@ -416,7 +416,7 @@
*/
private PropertyHashMap addNoClone(final Property property) {
int newSize = size;
- final String key = property.getKey();
+ final Object key = property.getKey();
Element newList = list;
if (bins != null) {
final int binIndex = binIndex(bins, key);
@@ -437,7 +437,7 @@
return new PropertyHashMap(newSize, bins, newList);
}
- private PropertyHashMap replaceNoClone(final String key, final Property property) {
+ private PropertyHashMap replaceNoClone(final Object key, final Property property) {
if (bins != null) {
final int binIndex = binIndex(bins, key);
Element bin = bins[binIndex];
@@ -457,7 +457,7 @@
*
* @return New list with {@link Element} removed.
*/
- private static Element removeFromList(final Element list, final String key) {
+ private static Element removeFromList(final Element list, final Object key) {
if (list == null) {
return null;
}
@@ -480,7 +480,7 @@
}
// for element x. if x get link matches,
- private static Element replaceInList(final Element list, final String key, final Property property) {
+ private static Element replaceInList(final Element list, final Object key, final Property property) {
assert list != null;
final int hashCode = key.hashCode();
@@ -519,21 +519,7 @@
@Override
public boolean containsKey(final Object key) {
- if (key instanceof String) {
- return findElement((String)key) != null;
- }
- assert key instanceof String;
- return false;
- }
-
- /**
- * Check if the map contains a key.
- *
- * @param key {@link Property} key.
- *
- * @return {@code true} of key is in {@link PropertyHashMap}.
- */
- public boolean containsKey(final String key) {
+ assert key instanceof String || key instanceof Symbol;
return findElement(key) != null;
}
@@ -549,29 +535,13 @@
@Override
public Property get(final Object key) {
- if (key instanceof String) {
- final Element element = findElement((String)key);
- return element != null ? element.getProperty() : null;
- }
- assert key instanceof String;
- return null;
- }
-
- /**
- * Get the {@link Property} given a key that is an explicit {@link String}.
- * See also {@link PropertyHashMap#get(Object)}
- *
- * @param key {@link Property} key.
- *
- * @return {@link Property}, or {@code null} if no property with that key was found.
- */
- public Property get(final String key) {
+ assert key instanceof String || key instanceof Symbol;
final Element element = findElement(key);
return element != null ? element.getProperty() : null;
}
@Override
- public Property put(final String key, final Property value) {
+ public Property put(final Object key, final Property value) {
throw new UnsupportedOperationException("Immutable map.");
}
@@ -581,7 +551,7 @@
}
@Override
- public void putAll(final Map<? extends String, ? extends Property> m) {
+ public void putAll(final Map<? extends Object, ? extends Property> m) {
throw new UnsupportedOperationException("Immutable map.");
}
@@ -591,8 +561,8 @@
}
@Override
- public Set<String> keySet() {
- final HashSet<String> set = new HashSet<>();
+ public Set<Object> keySet() {
+ final HashSet<Object> set = new HashSet<>();
for (Element element = list; element != null; element = element.getLink()) {
set.add(element.getKey());
}
@@ -605,8 +575,8 @@
}
@Override
- public Set<Entry<String, Property>> entrySet() {
- final HashSet<Entry<String, Property>> set = new HashSet<>();
+ public Set<Entry<Object, Property>> entrySet() {
+ final HashSet<Entry<Object, Property>> set = new HashSet<>();
for (Element element = list; element != null; element = element.getLink()) {
set.add(element);
}
@@ -616,7 +586,7 @@
/**
* List map element.
*/
- static final class Element implements Entry<String, Property> {
+ static final class Element implements Entry<Object, Property> {
/** Link for list construction. */
private Element link;
@@ -624,7 +594,7 @@
private final Property property;
/** Element key. Kept separate for performance.) */
- private final String key;
+ private final Object key;
/** Element key hash code. */
private final int hashCode;
@@ -640,7 +610,7 @@
this.hashCode = this.key.hashCode();
}
- boolean match(final String otherKey, final int otherHashCode) {
+ boolean match(final Object otherKey, final int otherHashCode) {
return this.hashCode == otherHashCode && this.key.equals(otherKey);
}
@@ -655,7 +625,7 @@
}
@Override
- public String getKey() {
+ public Object getKey() {
return key;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java Wed Nov 11 16:28:17 2015 +0100
@@ -35,7 +35,7 @@
*/
public class PropertyListeners {
- private Map<String, WeakPropertyMapSet> listeners;
+ private Map<Object, WeakPropertyMapSet> listeners;
// These counters are updated in debug mode
private static LongAdder listenersAdded;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Wed Nov 11 16:28:17 2015 +0100
@@ -96,7 +96,7 @@
private transient SharedPropertyMap sharedProtoMap;
/** {@link SwitchPoint}s for gets on inherited properties. */
- private transient HashMap<String, SwitchPoint> protoSwitches;
+ private transient HashMap<Object, SwitchPoint> protoSwitches;
/** History of maps, used to limit map duplication. */
private transient WeakHashMap<Property, Reference<PropertyMap>> history;
@@ -354,7 +354,7 @@
*
* @param key {@link Property} key to invalidate.
*/
- synchronized void invalidateProtoSwitchPoint(final String key) {
+ synchronized void invalidateProtoSwitchPoint(final Object key) {
if (protoSwitches != null) {
final SwitchPoint sp = protoSwitches.get(key);
if (sp != null) {
@@ -496,7 +496,7 @@
public final synchronized PropertyMap deleteProperty(final Property property) {
propertyDeleted(property, true);
PropertyMap newMap = checkHistory(property);
- final String key = property.getKey();
+ final Object key = property.getKey();
if (newMap == null && properties.containsKey(key)) {
final PropertyHashMap newProperties = properties.immutableRemove(key);
@@ -577,7 +577,7 @@
* @param propertyFlags attribute flags of the property
* @return the newly created UserAccessorProperty
*/
- public final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
+ public final UserAccessorProperty newUserAccessors(final Object key, final int propertyFlags) {
return new UserAccessorProperty(key, propertyFlags, getFreeSpillSlot());
}
@@ -588,7 +588,7 @@
*
* @return {@link Property} matching key.
*/
- public final Property findProperty(final String key) {
+ public final Property findProperty(final Object key) {
return properties.find(key);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Nov 11 16:28:17 2015 +0100
@@ -53,6 +53,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
+import java.lang.reflect.Array;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
@@ -310,11 +311,11 @@
*/
protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property, final boolean extensible) {
PropertyMap newMap = propMap;
- final String key = property.getKey();
+ final Object key = property.getKey();
final Property oldProp = newMap.findProperty(key);
if (oldProp == null) {
if (! extensible) {
- throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+ throw typeError("object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
}
if (property instanceof UserAccessorProperty) {
@@ -330,7 +331,7 @@
if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) {
if (oldProp instanceof UserAccessorProperty ||
!(oldProp.isWritable() && oldProp.isEnumerable())) {
- throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+ throw typeError("cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
}
}
@@ -348,11 +349,11 @@
final boolean extensible = newMap.isExtensible();
for (final AccessorProperty property : properties) {
- final String key = property.getKey();
+ final Object key = property.getKey();
if (newMap.findProperty(key) == null) {
if (! extensible) {
- throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+ throw typeError("object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
}
newMap = newMap.addPropertyBind(property, source);
}
@@ -456,7 +457,7 @@
* @return Returns the Property Descriptor of the named own property of this
* object, or undefined if absent.
*/
- public Object getOwnPropertyDescriptor(final String key) {
+ public Object getOwnPropertyDescriptor(final Object key) {
final Property property = getMap().findProperty(key);
final Global global = Context.getGlobal();
@@ -518,7 +519,7 @@
* Invalidate any existing global constant method handles that may exist for {@code key}.
* @param key the property name
*/
- protected void invalidateGlobalConstant(final String key) {
+ protected void invalidateGlobalConstant(final Object key) {
final GlobalConstants globalConstants = getGlobalConstants();
if (globalConstants != null) {
globalConstants.delete(key);
@@ -534,11 +535,10 @@
*
* @return true if property was successfully defined
*/
- public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
+ public boolean defineOwnProperty(final Object key, final Object propertyDesc, final boolean reject) {
final Global global = Context.getGlobal();
final PropertyDescriptor desc = toPropertyDescriptor(global, propertyDesc);
final Object current = getOwnPropertyDescriptor(key);
- final String name = JSType.toString(key);
invalidateGlobalConstant(key);
@@ -550,7 +550,7 @@
}
// new property added to non-extensible object
if (reject) {
- throw typeError(global, "object.non.extensible", name, ScriptRuntime.safeToString(this));
+ throw typeError(global, "object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -573,7 +573,7 @@
if (newDesc.has(CONFIGURABLE) && newDesc.isConfigurable()) {
// not configurable can not be made configurable
if (reject) {
- throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+ throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -582,7 +582,7 @@
currentDesc.isEnumerable() != newDesc.isEnumerable()) {
// cannot make non-enumerable as enumerable or vice-versa
if (reject) {
- throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+ throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -598,7 +598,7 @@
if (newDesc.has(WRITABLE) && newDesc.isWritable() ||
newDesc.has(VALUE) && !ScriptRuntime.sameValue(currentDesc.getValue(), newDesc.getValue())) {
if (reject) {
- throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+ throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -636,7 +636,7 @@
if (newDesc.has(PropertyDescriptor.GET) && !ScriptRuntime.sameValue(currentDesc.getGetter(), newDesc.getGetter()) ||
newDesc.has(PropertyDescriptor.SET) && !ScriptRuntime.sameValue(currentDesc.getSetter(), newDesc.getSetter())) {
if (reject) {
- throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+ throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -650,7 +650,7 @@
if (!currentDesc.isConfigurable()) {
// not configurable can not be made configurable
if (reject) {
- throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+ throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -716,7 +716,7 @@
setArray(getArray().set(index, value, false));
}
- private void checkIntegerKey(final String key) {
+ private void checkIntegerKey(final Object key) {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
@@ -734,7 +734,7 @@
* @param key property key
* @param propertyDesc property descriptor for property
*/
- public final void addOwnProperty(final String key, final PropertyDescriptor propertyDesc) {
+ public final void addOwnProperty(final Object key, final PropertyDescriptor propertyDesc) {
// Already checked that there is no own property with that key.
PropertyDescriptor pdesc = propertyDesc;
@@ -776,7 +776,7 @@
*
* @return FindPropertyData or null if not found.
*/
- public final FindProperty findProperty(final String key, final boolean deep) {
+ public final FindProperty findProperty(final Object key, final boolean deep) {
return findProperty(key, deep, this);
}
@@ -798,7 +798,7 @@
*
* @return FindPropertyData or null if not found.
*/
- protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+ protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
final PropertyMap selfMap = getMap();
final Property property = selfMap.findProperty(key);
@@ -820,13 +820,13 @@
}
/**
- * Low level property API. This is similar to {@link #findProperty(String, boolean)} but returns a
+ * Low level property API. This is similar to {@link #findProperty(Object, boolean)} but returns a
* {@code boolean} value instead of a {@link FindProperty} object.
* @param key Property key.
* @param deep Whether the search should look up proto chain.
* @return true if the property was found.
*/
- boolean hasProperty(final String key, final boolean deep) {
+ boolean hasProperty(final Object key, final boolean deep) {
if (getMap().findProperty(key) != null) {
return true;
}
@@ -841,7 +841,7 @@
return false;
}
- private SwitchPoint findBuiltinSwitchPoint(final String key) {
+ private SwitchPoint findBuiltinSwitchPoint(final Object key) {
for (ScriptObject myProto = getProto(); myProto != null; myProto = myProto.getProto()) {
final Property prop = myProto.getMap().findProperty(key);
if (prop != null) {
@@ -866,7 +866,7 @@
*
* @return New property.
*/
- public final Property addOwnProperty(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
+ public final Property addOwnProperty(final Object key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
return addOwnProperty(newUserAccessors(key, propertyFlags, getter, setter));
}
@@ -881,7 +881,7 @@
*
* @return New property.
*/
- public final Property addOwnProperty(final String key, final int propertyFlags, final Object value) {
+ public final Property addOwnProperty(final Object key, final int propertyFlags, final Object value) {
return addSpillProperty(key, propertyFlags, value, true);
}
@@ -1349,42 +1349,60 @@
final Set<String> keys = new HashSet<>();
final Set<String> nonEnumerable = new HashSet<>();
for (ScriptObject self = this; self != null; self = self.getProto()) {
- keys.addAll(Arrays.asList(self.getOwnKeys(true, nonEnumerable)));
+ keys.addAll(Arrays.asList(self.getOwnKeys(String.class, true, nonEnumerable)));
}
return keys.toArray(new String[keys.size()]);
}
/**
- * return an array of own property keys associated with the object.
+ * Return an array of own property keys associated with the object.
*
* @param all True if to include non-enumerable keys.
* @return Array of keys.
*/
public final String[] getOwnKeys(final boolean all) {
- return getOwnKeys(all, null);
+ return getOwnKeys(String.class, all, null);
+ }
+
+ /**
+ * Return an array of own property keys associated with the object.
+ *
+ * @param all True if to include non-enumerable keys.
+ * @return Array of keys.
+ */
+ public final Symbol[] getOwnSymbols(final boolean all) {
+ return getOwnKeys(Symbol.class, all, null);
}
/**
* return an array of own property keys associated with the object.
*
+ * @param <T> the type returned keys.
+ * @param type the type of keys to return, either {@code String.class} or {@code Symbol.class}.
* @param all True if to include non-enumerable keys.
- * @param nonEnumerable set of non-enumerable properties seen already.Used
- to filter out shadowed, but enumerable properties from proto children.
+ * @param nonEnumerable set of non-enumerable properties seen already. Used to
+ * filter out shadowed, but enumerable properties from proto children.
* @return Array of keys.
*/
- protected String[] getOwnKeys(final boolean all, final Set<String> nonEnumerable) {
+ @SuppressWarnings("unchecked")
+ protected <T> T[] getOwnKeys(final Class<T> type, final boolean all, final Set<T> nonEnumerable) {
final List<Object> keys = new ArrayList<>();
final PropertyMap selfMap = this.getMap();
final ArrayData array = getArray();
- for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
- keys.add(JSType.toString(iter.next().longValue()));
+ if (type == String.class) {
+ for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
+ keys.add(JSType.toString(iter.next().longValue()));
+ }
}
for (final Property property : selfMap.getProperties()) {
final boolean enumerable = property.isEnumerable();
- final String key = property.getKey();
+ final Object key = property.getKey();
+ if (!type.isInstance(key)) {
+ continue;
+ }
if (all) {
keys.add(key);
} else if (enumerable) {
@@ -1396,12 +1414,12 @@
} else {
// store this non-enumerable property for later proto walk
if (nonEnumerable != null) {
- nonEnumerable.add(key);
+ nonEnumerable.add((T) key);
}
}
}
- return keys.toArray(new String[keys.size()]);
+ return keys.toArray((T[]) Array.newInstance(type, keys.size()));
}
/**
@@ -2397,12 +2415,12 @@
/**
* Invoke fall back if a property is not found.
- * @param name Name of property.
+ * @param key Name of property.
* @param isScope is this a scope access?
* @param programPoint program point
* @return Result from call.
*/
- protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
+ protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
final Object func = (find != null)? find.getObjectValue() : null;
@@ -2410,9 +2428,9 @@
if (func instanceof ScriptFunction) {
final ScriptFunction sfunc = (ScriptFunction)func;
final Object self = isScope && sfunc.isStrict()? UNDEFINED : this;
- ret = ScriptRuntime.apply(sfunc, self, name);
+ ret = ScriptRuntime.apply(sfunc, self, key);
} else if (isScope) {
- throw referenceError("not.defined", name);
+ throw referenceError("not.defined", key.toString());
}
if (isValid(programPoint)) {
@@ -2502,7 +2520,7 @@
final Set<String> keys = new LinkedHashSet<>();
final Set<String> nonEnumerable = new HashSet<>();
for (ScriptObject self = object; self != null; self = self.getProto()) {
- keys.addAll(Arrays.asList(self.getOwnKeys(false, nonEnumerable)));
+ keys.addAll(Arrays.asList(self.getOwnKeys(String.class, false, nonEnumerable)));
}
this.values = keys.toArray(new String[keys.size()]);
}
@@ -2518,7 +2536,7 @@
final ArrayList<Object> valueList = new ArrayList<>();
final Set<String> nonEnumerable = new HashSet<>();
for (ScriptObject self = object; self != null; self = self.getProto()) {
- for (final String key : self.getOwnKeys(false, nonEnumerable)) {
+ for (final String key : self.getOwnKeys(String.class, false, nonEnumerable)) {
valueList.add(self.get(key));
}
}
@@ -2532,7 +2550,7 @@
* @param flags Property flags.
* @return Added property.
*/
- private Property addSpillProperty(final String key, final int flags, final Object value, final boolean hasInitialValue) {
+ private Property addSpillProperty(final Object key, final int flags, final Object value, final boolean hasInitialValue) {
final PropertyMap propertyMap = getMap();
final int fieldSlot = propertyMap.getFreeFieldSlot();
final int propertyFlags = flags | (useDualFields() ? Property.DUAL_FIELDS : 0);
@@ -2726,7 +2744,7 @@
}
}
- private int getInt(final int index, final String key, final int programPoint) {
+ private int getInt(final int index, final Object key, final int programPoint) {
if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
if (object.getMap().containsArrayKeys()) {
@@ -2770,7 +2788,7 @@
return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
}
- return getInt(index, JSType.toString(primitiveKey), programPoint);
+ return getInt(index, JSType.toPropertyKey(primitiveKey), programPoint);
}
@Override
@@ -2809,7 +2827,7 @@
return getInt(index, JSType.toString(key), programPoint);
}
- private long getLong(final int index, final String key, final int programPoint) {
+ private long getLong(final int index, final Object key, final int programPoint) {
if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
if (object.getMap().containsArrayKeys()) {
@@ -2852,7 +2870,7 @@
return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
}
- return getLong(index, JSType.toString(primitiveKey), programPoint);
+ return getLong(index, JSType.toPropertyKey(primitiveKey), programPoint);
}
@Override
@@ -2891,7 +2909,7 @@
return getLong(index, JSType.toString(key), programPoint);
}
- private double getDouble(final int index, final String key, final int programPoint) {
+ private double getDouble(final int index, final Object key, final int programPoint) {
if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
if (object.getMap().containsArrayKeys()) {
@@ -2934,7 +2952,7 @@
return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
}
- return getDouble(index, JSType.toString(primitiveKey), programPoint);
+ return getDouble(index, JSType.toPropertyKey(primitiveKey), programPoint);
}
@Override
@@ -2973,7 +2991,7 @@
return getDouble(index, JSType.toString(key), programPoint);
}
- private Object get(final int index, final String key) {
+ private Object get(final int index, final Object key) {
if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
if (object.getMap().containsArrayKeys()) {
@@ -3015,7 +3033,7 @@
return array.getObject(index);
}
- return get(index, JSType.toString(primitiveKey));
+ return get(index, JSType.toPropertyKey(primitiveKey));
}
@Override
@@ -3161,7 +3179,7 @@
* @param key property key
* @param value property value
*/
- public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) {
+ public final void setObject(final FindProperty find, final int callSiteFlags, final Object key, final Object value) {
FindProperty f = find;
invalidateGlobalConstant(key);
@@ -3189,10 +3207,10 @@
if (f != null) {
if (!f.getProperty().isWritable()) {
if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
- throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode.
+ throw typeError("assign.constant", key.toString()); // Overwriting ES6 const should throw also in non-strict mode.
}
if (isStrictFlag(callSiteFlags)) {
- throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
+ throw typeError("property.not.writable", key.toString(), ScriptRuntime.safeToString(this));
}
return;
}
@@ -3201,7 +3219,7 @@
} else if (!isExtensible()) {
if (isStrictFlag(callSiteFlags)) {
- throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+ throw typeError("object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
}
} else {
ScriptObject sobj = this;
@@ -3235,7 +3253,7 @@
return;
}
- final String propName = JSType.toString(primitiveKey);
+ final Object propName = JSType.toPropertyKey(primitiveKey);
setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
}
@@ -3255,7 +3273,7 @@
return;
}
- final String propName = JSType.toString(primitiveKey);
+ final Object propName = JSType.toPropertyKey(primitiveKey);
setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
}
@@ -3275,7 +3293,7 @@
return;
}
- final String propName = JSType.toString(primitiveKey);
+ final Object propName = JSType.toPropertyKey(primitiveKey);
setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
}
@@ -3295,7 +3313,7 @@
return;
}
- final String propName = JSType.toString(primitiveKey);
+ final Object propName = JSType.toPropertyKey(primitiveKey);
setObject(findProperty(propName, true), callSiteFlags, propName, value);
}
@@ -3529,7 +3547,7 @@
public boolean has(final Object key) {
final Object primitiveKey = JSType.toPrimitive(key);
final int index = getArrayIndex(primitiveKey);
- return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), true);
+ return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), true);
}
@Override
@@ -3567,7 +3585,7 @@
public boolean hasOwnProperty(final Object key) {
final Object primitiveKey = JSType.toPrimitive(key, String.class);
final int index = getArrayIndex(primitiveKey);
- return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), false);
+ return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), false);
}
@Override
@@ -3657,7 +3675,7 @@
}
private boolean deleteObject(final Object key, final boolean strict) {
- final String propName = JSType.toString(key);
+ final Object propName = JSType.toPropertyKey(key);
final FindProperty find = findProperty(propName, false);
if (find == null) {
@@ -3666,7 +3684,7 @@
if (!find.getProperty().isConfigurable()) {
if (strict) {
- throw typeError("cant.delete.property", propName, ScriptRuntime.safeToString(this));
+ throw typeError("cant.delete.property", propName.toString(), ScriptRuntime.safeToString(this));
}
return false;
}
@@ -3712,7 +3730,7 @@
* @param setter setter function for the property
* @return the newly created UserAccessorProperty
*/
- protected final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
+ protected final UserAccessorProperty newUserAccessors(final Object key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
final UserAccessorProperty uc = getMap().newUserAccessors(key, propertyFlags);
//property.getSetter(Object.class, getMap());
uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Nov 11 16:28:17 2015 +0100
@@ -836,11 +836,11 @@
} else if (yType == JSType.BOOLEAN) {
// Can reverse order as y is primitive
return equalBooleanToAny(y, x);
- } else if (isNumberOrStringAndObject(xType, yType)) {
- return equalNumberOrStringToObject(x, y);
- } else if (isNumberOrStringAndObject(yType, xType)) {
+ } else if (isWrappedPrimitiveAndObject(xType, yType)) {
+ return equalWrappedPrimitiveToObject(x, y);
+ } else if (isWrappedPrimitiveAndObject(yType, xType)) {
// Can reverse order as y is primitive
- return equalNumberOrStringToObject(y, x);
+ return equalWrappedPrimitiveToObject(y, x);
}
return false;
@@ -854,8 +854,8 @@
return xType == JSType.NUMBER && yType == JSType.STRING;
}
- private static boolean isNumberOrStringAndObject(final JSType xType, final JSType yType) {
- return (xType == JSType.NUMBER || xType == JSType.STRING) && yType == JSType.OBJECT;
+ private static boolean isWrappedPrimitiveAndObject(final JSType xType, final JSType yType) {
+ return (xType == JSType.NUMBER || xType == JSType.STRING || xType == JSType.SYMBOL) && yType == JSType.OBJECT;
}
private static boolean equalNumberToString(final Object num, final Object str) {
@@ -869,7 +869,7 @@
return equals(JSType.toNumber((Boolean)bool), any);
}
- private static boolean equalNumberOrStringToObject(final Object numOrStr, final Object any) {
+ private static boolean equalWrappedPrimitiveToObject(final Object numOrStr, final Object any) {
return equals(numOrStr, JSType.toPrimitive(any));
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SpillProperty.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SpillProperty.java Wed Nov 11 16:28:17 2015 +0100
@@ -158,7 +158,7 @@
* @param flags the property flags
* @param slot spill slot
*/
- public SpillProperty(final String key, final int flags, final int slot) {
+ public SpillProperty(final Object key, final int flags, final int slot) {
super(key, flags, slot, primitiveGetter(slot, flags), primitiveSetter(slot, flags), objectGetter(slot), objectSetter(slot));
}
@@ -174,7 +174,7 @@
setType(hasDualFields() ? initialType : Object.class);
}
- SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
+ SpillProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
this(key, flags, slot);
setInitialValue(owner, initialValue);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java Wed Nov 11 16:28:17 2015 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.io.Serializable;
+
+/**
+ * This class represents a unique, non-String Object property key as defined in ECMAScript 6.
+ */
+public final class Symbol implements Serializable {
+
+ private final String name;
+
+ private static final long serialVersionUID = -2988436597549486913L;
+
+ /**
+ * Symbol constructor
+ * @param name symbol name
+ */
+ public Symbol(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "Symbol(" + name + ")";
+ }
+
+ /**
+ * Return the symbol's name
+ * @return the name
+ */
+ public final String getName() {
+ return name;
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Nov 11 16:28:17 2015 +0100
@@ -120,7 +120,7 @@
* @param flags property flags
* @param slot spill slot
*/
- UserAccessorProperty(final String key, final int flags, final int slot) {
+ UserAccessorProperty(final Object key, final int flags, final int slot) {
super(key, flags, slot);
}
@@ -226,7 +226,7 @@
@Override
public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
try {
- invokeObjectSetter(getAccessors((owner != null) ? owner : self), getObjectSetterInvoker(), strict ? getKey() : null, self, value);
+ invokeObjectSetter(getAccessors((owner != null) ? owner : self), getObjectSetterInvoker(), strict ? getKey().toString() : null, self, value);
} catch (final Error | RuntimeException t) {
throw t;
} catch (final Throwable t) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Wed Nov 11 16:28:17 2015 +0100
@@ -198,7 +198,7 @@
* @return FindPropertyData or null if not found.
*/
@Override
- protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+ protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
// We call findProperty on 'expression' with 'expression' itself as start parameter.
// This way in ScriptObject.setObject we can tell the property is from a 'with' expression
// (as opposed from another non-scope object in the proto chain such as Object.prototype).
@@ -210,18 +210,18 @@
}
@Override
- protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
+ protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
final FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
if (find != null) {
final Object func = find.getObjectValue();
if (func instanceof ScriptFunction) {
final ScriptFunction sfunc = (ScriptFunction)func;
final Object self = isScope && sfunc.isStrict()? UNDEFINED : expression;
- return ScriptRuntime.apply(sfunc, self, name);
+ return ScriptRuntime.apply(sfunc, self, key);
}
}
- return getProto().invokeNoSuchProperty(name, isScope, programPoint);
+ return getProto().invokeNoSuchProperty(key, isScope, programPoint);
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Nov 11 16:28:17 2015 +0100
@@ -154,6 +154,11 @@
type.error.java.array.conversion.failed=Java.to conversion to array type {0} failed
type.error.constructor.requires.new=Constructor {0} requires "new".
type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}.
+type.error.invalid.weak.key=invalid value {0} used as weak key.
+type.error.symbol.to.string=Can not convert Symbol value to string.
+type.error.symbol.to.number=Can not convert Symbol value to number.
+type.error.not.a.symbol={0} is not a symbol.
+type.error.symbol.as.constructor=Symbol is not a constructor.
range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor
range.error.dataview.offset=Offset is outside the bounds of the DataView
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Wed Nov 11 16:28:17 2015 +0100
@@ -36,6 +36,7 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
@@ -47,6 +48,7 @@
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeSymbol;
import jdk.nashorn.internal.parser.Parser;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager;
@@ -54,7 +56,10 @@
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Symbol;
+import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.options.Options;
/**
@@ -474,7 +479,7 @@
try {
final Object res = context.eval(global, source, global, "<shell>");
if (res != ScriptRuntime.UNDEFINED) {
- err.println(JSType.toString(res));
+ err.println(toString(res, global));
}
} catch (final Exception e) {
err.println(e);
@@ -491,4 +496,56 @@
return SUCCESS;
}
+
+ /**
+ * Converts {@code result} to a printable string. The reason we don't use {@link JSType#toString(Object)}
+ * or {@link ScriptRuntime#safeToString(Object)} is that we want to be able to render Symbol values
+ * even if they occur within an Array, and therefore have to implement our own Array to String
+ * conversion.
+ *
+ * @param result the result
+ * @param global the global object
+ * @return the string representation
+ */
+ protected static String toString(final Object result, final Global global) {
+ if (result instanceof Symbol) {
+ // Normal implicit conversion of symbol to string would throw TypeError
+ return result.toString();
+ }
+
+ if (result instanceof NativeSymbol) {
+ return JSType.toPrimitive(result).toString();
+ }
+
+ if (isArrayWithDefaultToString(result, global)) {
+ // This should yield the same string as Array.prototype.toString but
+ // will not throw if the array contents include symbols.
+ final StringBuilder sb = new StringBuilder();
+ final Iterator<Object> iter = ArrayLikeIterator.arrayLikeIterator(result, true);
+
+ while (iter.hasNext()) {
+ final Object obj = iter.next();
+
+ if (obj != null && obj != ScriptRuntime.UNDEFINED) {
+ sb.append(toString(obj, global));
+ }
+
+ if (iter.hasNext()) {
+ sb.append(',');
+ }
+ }
+
+ return sb.toString();
+ }
+
+ return JSType.toString(result);
+ }
+
+ private static boolean isArrayWithDefaultToString(final Object result, final Global global) {
+ if (result instanceof ScriptObject) {
+ final ScriptObject sobj = (ScriptObject) result;
+ return sobj.isArray() && sobj.get("toString") == global.getArrayPrototype().get("toString");
+ }
+ return false;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6.js Wed Nov 11 16:28:17 2015 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Make sure ECMAScript 6 features are not available in ES5 mode.
+ *
+ * @test
+ * @run
+ */
+
+if (typeof Symbol !== 'undefined' || 'Symbol' in this) {
+ Assert.fail('Symbol is defined in global scope');
+}
+
+if (typeof Object.getOwnPropertySymbols !== 'undefined' || 'getOwnPropertySymbols' in Object) {
+ Assert.fail('getOwnPropertySymbols is defined in global Object');
+}
+
+function expectError(src, msg, error) {
+ try {
+ eval(src);
+ Assert.fail(msg);
+ } catch (e) {
+ if (e.name !== error) {
+ Assert.fail('Unexpected error: ' + e);
+ }
+ }
+}
+
+expectError('let i = 0', 'let', 'SyntaxError');
+expectError('const i = 0', 'const', 'SyntaxError');
+expectError('for (let i = 0; i < 10; i++) print(i)', 'for-let', 'SyntaxError');
+expectError('0b0', 'numeric literal', 'SyntaxError');
+expectError('0o0', 'numeric litera', 'SyntaxError');
+expectError('`text`', 'template literal', 'SyntaxError');
+expectError('`${ x }`', 'template literal', 'SyntaxError');
+expectError('`text ${ x } text`', 'template literal', 'SyntaxError');
+expectError('f`text`', 'template literal', 'SyntaxError');
--- a/nashorn/test/script/basic/es6/let.js Wed Nov 11 15:22:14 2015 +0100
+++ b/nashorn/test/script/basic/es6/let.js Wed Nov 11 16:28:17 2015 +0100
@@ -26,7 +26,8 @@
*
* @test
* @run
- * @option --language=es6 */
+ * @option --language=es6
+ */
"use strict";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/symbols.js Wed Nov 11 16:28:17 2015 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8141702: Add support for Symbol property keys
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+Assert.assertTrue(typeof Symbol === 'function');
+Assert.assertTrue(typeof Symbol() === 'symbol');
+
+Assert.assertTrue(Symbol().toString() === 'Symbol()');
+Assert.assertTrue(Symbol('foo').toString() === 'Symbol(foo)');
+Assert.assertTrue(Symbol(1).toString() === 'Symbol(1)');
+Assert.assertTrue(Symbol(true).toString() === 'Symbol(true)');
+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");
+Assert.assertFalse(s1 instanceof Symbol); // not an object
+
+var obj = {};
+obj['foo'] = 'foo';
+obj[s1] = s1;
+obj['bar'] = 'bar';
+obj[1] = 1;
+obj[s2] = s2;
+
+Assert.assertTrue(obj['foo'] === 'foo');
+Assert.assertTrue(obj[s1] === s1);
+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);
+Assert.assertTrue(expectedNames.length == actualNames.length);
+Assert.assertTrue(expectedSymbols.length == actualSymbols.length);
+
+for (var key in expectedNames) {
+ Assert.assertTrue(expectedNames[key] === actualNames[key]);
+}
+for (var key in expectedSymbols) {
+ Assert.assertTrue(expectedSymbols[key] === actualSymbols[key]);
+}
+
+// Delete
+Assert.assertTrue(delete obj[s1]);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj).length === 1);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj)[0] === s2);
+
+// Object.defineProperty
+Object.defineProperty(obj, s1, {value : 'hello'});
+Assert.assertTrue(obj[s1] === 'hello');
+actualSymbols = Object.getOwnPropertySymbols(obj);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj).length === 2);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj)[1] === s1);
+
+// Symbol called as constructor
+try {
+ new Symbol();
+ Assert.fail("Symbol invoked as constructor");
+} catch (e) {
+ if (e.name !== "TypeError" || e.message !== "Symbol is not a constructor.") {
+ Assert.fail("Unexpected error: " + e);
+ }
+}
+
+// Implicit conversion to string or number should throw
+try {
+ ' ' + s1;
+ Assert.fail("Symbol converted to string");
+} catch (e) {
+ if (e.name !== "TypeError" || e.message !== "Can not convert Symbol value to string.") {
+ Assert.fail("Unexpected error: " + e);
+ }
+}
+
+try {
+ 4 * s1;
+ Assert.fail("Symbol converted to number");
+} catch (e) {
+ if (e.name !== "TypeError" || e.message !== "Can not convert Symbol value to number.") {
+ Assert.fail("Unexpected error: " + e);
+ }
+}
+
+// Symbol.for and Symbol.keyFor
+
+var uncached = Symbol('foo');
+var cached = Symbol.for('foo');
+
+Assert.assertTrue(uncached !== cached);
+Assert.assertTrue(Symbol.keyFor(uncached) === undefined);
+Assert.assertTrue(Symbol.keyFor(cached) === 'foo');
+Assert.assertTrue(cached === Symbol.for('foo'));
+Assert.assertTrue(cached === Symbol.for('f' + 'oo'));
+
+// Object wrapper
+
+var o = Object(s1);
+obj = {};
+obj[s1] = "s1";
+Assert.assertTrue(o == s1);
+Assert.assertTrue(o !== s1);
+Assert.assertTrue(typeof o === 'object');
+Assert.assertTrue(o instanceof Symbol);
+Assert.assertTrue(obj[o] == 's1');
+Assert.assertTrue(o in obj);
+
+// various non-strict comparisons that should fail
+
+Assert.assertFalse(0 == Symbol());
+Assert.assertFalse(1 == Symbol(1));
+Assert.assertFalse(null == Symbol());
+Assert.assertFalse(undefined == Symbol);
+Assert.assertFalse('Symbol()' == Symbol());
+Assert.assertFalse('Symbol(foo)' == Symbol('foo'));
+