--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Mon Feb 15 17:02:32 2016 +0100
@@ -48,6 +48,7 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.LIST_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.NATIVESYMBOL_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME;
@@ -63,6 +64,8 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SYMBOL_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SYMBOL_PREFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
import java.io.BufferedInputStream;
@@ -277,7 +280,7 @@
static void newFunction(final MethodGenerator mi, final String objName, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) {
final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY);
- mi.loadLiteral(memInfo.getName());
+ loadFunctionName(mi, memInfo.getName());
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc()));
assert specs != null;
@@ -305,8 +308,8 @@
// dup of Collection instance
mi.dup();
- // property = AccessorProperty.create(key, flags, getter, setter);
- mi.loadLiteral(propertyName);
+ // Load property name, converting to Symbol if it begins with "@@"
+ loadPropertyKey(mi, propertyName);
// setup flags
mi.push(memInfo.getAttributes());
// setup getter method handle
@@ -319,6 +322,7 @@
javaName = SETTER_PREFIX + memInfo.getJavaName();
mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo)));
}
+ // property = AccessorProperty.create(key, flags, getter, setter);
mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC);
// boolean Collection.add(property)
mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC);
@@ -333,8 +337,8 @@
// dup of Collection instance
mi.dup();
- // property = AccessorProperty.create(key, flags, getter, setter);
- mi.loadLiteral(propertyName);
+ // Load property name, converting to Symbol if it begins with "@@"
+ loadPropertyKey(mi, propertyName);
// setup flags
mi.push(getter.getAttributes());
// setup getter method handle
@@ -347,6 +351,7 @@
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
setter.getJavaName(), setter.getJavaDesc()));
}
+ // property = AccessorProperty.create(key, flags, getter, setter);
mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC);
// boolean Collection.add(property)
mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC);
@@ -365,6 +370,22 @@
return getScriptClassInfo(new ClassReader(classBuf));
}
+ private static void loadFunctionName(final MethodGenerator mi, final String propertyName) {
+ if (propertyName.startsWith(SYMBOL_PREFIX)) {
+ mi.loadLiteral("Symbol[" + propertyName.substring(2) + "]");
+ } else {
+ mi.loadLiteral(propertyName);
+ }
+ }
+
+ private static void loadPropertyKey(final MethodGenerator mi, final String propertyName) {
+ if (propertyName.startsWith(SYMBOL_PREFIX)) {
+ mi.getStatic(NATIVESYMBOL_TYPE, propertyName.substring(2), SYMBOL_DESC);
+ } else {
+ mi.loadLiteral(propertyName);
+ }
+ }
+
private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) {
final ScriptClassInfoCollector scic = new ScriptClassInfoCollector();
reader.accept(scic, 0);
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Mon Feb 15 17:02:32 2016 +0100
@@ -28,6 +28,8 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SYMBOL;
+
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.Where;
@@ -466,11 +468,10 @@
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.INT:
- case Type.LONG:
case Type.DOUBLE:
return true;
default:
- return false;
+ return type != TYPE_SYMBOL;
}
}
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Mon Feb 15 17:02:32 2016 +0100
@@ -31,12 +31,14 @@
import java.util.Collections;
import java.util.List;
import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.objects.NativeSymbol;
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.PrototypeObject;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Specialization;
+import jdk.nashorn.internal.runtime.Symbol;
/**
* String constants used for code generation/instrumentation.
@@ -88,6 +90,8 @@
static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class);
static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class);
static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
+ static final Type TYPE_NATIVESYMBOL = Type.getType(NativeSymbol.class);
+ static final Type TYPE_SYMBOL = Type.getType(Symbol.class);
static final String PROTOTYPE_SUFFIX = "$Prototype";
static final String CONSTRUCTOR_SUFFIX = "$Constructor";
@@ -101,7 +105,7 @@
static final String ACCESSORPROPERTY_TYPE = TYPE_ACCESSORPROPERTY.getInternalName();
static final String ACCESSORPROPERTY_CREATE = "create";
static final String ACCESSORPROPERTY_CREATE_DESC =
- Type.getMethodDescriptor(TYPE_ACCESSORPROPERTY, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
+ Type.getMethodDescriptor(TYPE_ACCESSORPROPERTY, TYPE_OBJECT, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
// PropertyMap
static final String PROPERTYMAP_TYPE = TYPE_PROPERTYMAP.getInternalName();
@@ -143,4 +147,9 @@
// ScriptObject.getClassName() method.
static final String GET_CLASS_NAME = "getClassName";
static final String GET_CLASS_NAME_DESC = Type.getMethodDescriptor(TYPE_STRING);
+
+ // NativeSymbol
+ static final String NATIVESYMBOL_TYPE = TYPE_NATIVESYMBOL.getInternalName();
+ static final String SYMBOL_DESC = TYPE_SYMBOL.getDescriptor();
+ static final String SYMBOL_PREFIX = "@@";
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/AbstractIterator.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016, 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 java.lang.invoke.MethodHandle;
+import java.util.function.Consumer;
+import jdk.nashorn.internal.objects.annotations.Attribute;
+import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+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.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.linker.InvokeByName;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+/**
+ * ECMA6 25.1.2 The %IteratorPrototype% Object
+ */
+@ScriptClass("Iterator")
+public abstract class AbstractIterator extends ScriptObject {
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private final static Object ITERATOR_INVOKER_KEY = new Object();
+ private final static Object NEXT_INVOKER_KEY = new Object();
+ private final static Object DONE_INVOKER_KEY = new Object();
+ private final static Object VALUE_INVOKER_KEY = new Object();
+
+ /** ECMA6 iteration kinds */
+ enum IterationKind {
+ /** key iteration */
+ KEY,
+ /** value iteration */
+ VALUE,
+ /** key+value iteration */
+ KEY_VALUE
+ }
+
+ /**
+ * Create an abstract iterator object with the given prototype and property map.
+ *
+ * @param prototype the prototype
+ * @param map the property map
+ */
+ protected AbstractIterator(final ScriptObject prototype, final PropertyMap map) {
+ super(prototype, map);
+ }
+
+ /**
+ * 25.1.2.1 %IteratorPrototype% [ @@iterator ] ( )
+ *
+ * @param self the self object
+ * @return this iterator
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return self;
+ }
+
+ @Override
+ public String getClassName() {
+ return "Iterator";
+ }
+
+ /**
+ * ES6 25.1.1.2 The Iterator Interface
+ *
+ * @param arg argument
+ * @return next iterator result
+ */
+ protected abstract IteratorResult next(final Object arg);
+
+ /**
+ * ES6 25.1.1.3 The IteratorResult Interface
+ *
+ * @param value result value
+ * @param done result status
+ * @param global the global object
+ * @return result object
+ */
+ protected IteratorResult makeResult(final Object value, final Boolean done, final Global global) {
+ return new IteratorResult(value, done, global);
+ }
+
+ /**
+ * ES6 7.4.1 GetIterator abstract operation
+ *
+ * @param iterable an object
+ * @param global the global object
+ * @return the iterator
+ */
+ public static Object getIterator(final Object iterable, final Global global) {
+ final Object object = Global.toObject(iterable);
+
+ if (object instanceof ScriptObject) {
+ // TODO we need to implement fast property access for Symbol keys in order to use InvokeByName here.
+ final Object getter = ((ScriptObject) object).get(NativeSymbol.iterator);
+
+ if (Bootstrap.isCallable(getter)) {
+ try {
+ final MethodHandle invoker = global.getDynamicInvoker(ITERATOR_INVOKER_KEY,
+ () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class));
+
+ final Object value = invoker.invokeExact(getter, iterable);
+ if (JSType.isPrimitive(value)) {
+ throw typeError("not.an.object", ScriptRuntime.safeToString(value));
+ }
+ return value;
+
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ throw typeError("not.a.function", ScriptRuntime.safeToString(getter));
+ }
+
+ throw typeError("cannot.get.iterator", ScriptRuntime.safeToString(iterable));
+ }
+
+ /**
+ * Iterate over an iterable object, passing every value to {@code consumer}.
+ *
+ * @param iterable an iterable object
+ * @param global the current global
+ * @param consumer the value consumer
+ */
+ public static void iterate(final Object iterable, final Global global, final Consumer<Object> consumer) {
+
+ final Object iterator = AbstractIterator.getIterator(Global.toObject(iterable), global);
+
+ final InvokeByName nextInvoker = global.getInvokeByName(AbstractIterator.NEXT_INVOKER_KEY,
+ () -> new InvokeByName("next", Object.class, Object.class, Object.class));
+ final MethodHandle doneInvoker = global.getDynamicInvoker(AbstractIterator.DONE_INVOKER_KEY,
+ () -> Bootstrap.createDynamicInvoker("done", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class));
+ final MethodHandle valueInvoker = global.getDynamicInvoker(AbstractIterator.VALUE_INVOKER_KEY,
+ () -> Bootstrap.createDynamicInvoker("value", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class));
+
+ try {
+ do {
+ final Object next = nextInvoker.getGetter().invokeExact(iterator);
+ if (!Bootstrap.isCallable(next)) {
+ break;
+ }
+
+ final Object result = nextInvoker.getInvoker().invokeExact(next, iterator, (Object) null);
+ if (!(result instanceof ScriptObject)) {
+ break;
+ }
+
+ final Object done = doneInvoker.invokeExact(result);
+ if (JSType.toBoolean(done)) {
+ break;
+ }
+
+ consumer.accept(valueInvoker.invokeExact(result));
+
+ } while (true);
+
+ } catch (final RuntimeException r) {
+ throw r;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+
+ }
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, 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 jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+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.Undefined;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+@ScriptClass("ArrayIterator")
+public class ArrayIterator extends AbstractIterator {
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private ScriptObject iteratedObject;
+ private long nextIndex = 0L;
+ private final IterationKind iterationKind;
+ private final Global global;
+
+
+ ArrayIterator(final Object iteratedObject, final IterationKind iterationKind, final Global global) {
+ super(global.getArrayIteratorPrototype(), $nasgenmap$);
+ this.iteratedObject = iteratedObject instanceof ScriptObject ? (ScriptObject) iteratedObject : null;
+ this.iterationKind = iterationKind;
+ this.global = global;
+ }
+
+ /**
+ * 22.1.5.2.1 %ArrayIteratorPrototype%.next()
+ *
+ * @param self the self reference
+ * @param arg the argument
+ * @return the next result
+ */
+ @Function
+ public static Object next(final Object self, final Object arg) {
+ if (!(self instanceof ArrayIterator)) {
+ throw typeError("not.a.array.iterator", ScriptRuntime.safeToString(self));
+ }
+ return ((ArrayIterator)self).next(arg);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Array Iterator";
+ }
+
+ @Override
+ protected IteratorResult next(final Object arg) {
+ final long index = nextIndex;
+
+ if (iteratedObject == null || index >= JSType.toUint32(iteratedObject.getLength())) {
+ // ES6 22.1.5.2.1 step 10
+ iteratedObject = null;
+ return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
+ }
+
+ nextIndex++;
+
+ if (iterationKind == IterationKind.KEY_VALUE) {
+ final NativeArray value = new NativeArray(
+ new Object[] {JSType.toNarrowestNumber(index), iteratedObject.get((double) index)});
+ return makeResult(value, Boolean.FALSE, global);
+ }
+
+ final Object value = iterationKind == IterationKind.KEY ?
+ JSType.toNarrowestNumber(index) : iteratedObject.get((double) index);
+ return makeResult(value, Boolean.FALSE, global);
+ }
+
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Mon Feb 15 17:02:32 2016 +0100
@@ -95,6 +95,8 @@
// (__FILE__, __DIR__, __LINE__)
private static final Object LAZY_SENTINEL = new Object();
+ private static final String PACKAGE_PREFIX = "jdk.nashorn.internal.objects.";
+
private InvokeByName TO_STRING;
private InvokeByName VALUE_OF;
@@ -222,9 +224,6 @@
@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
@@ -748,6 +747,147 @@
private volatile Object float64Array;
+
+ /**
+ * Getter for the Symbol property.
+ *
+ * @param self self reference
+ * @return the value of the Symbol property
+ */
+ @Getter(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
+ public static Object getSymbol(final Object self) {
+ final Global global = Global.instanceFrom(self);
+ if (global.symbol == LAZY_SENTINEL) {
+ global.symbol = global.getBuiltinSymbol();
+ }
+ return global.symbol;
+ }
+
+ /**
+ * Setter for the Symbol property.
+ *
+ * @param self self reference
+ * @param value value of the Symbol property
+ */
+ @Setter(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
+ public static void setSymbol(final Object self, final Object value) {
+ Global.instanceFrom(self).symbol = value;
+ }
+
+ private volatile Object symbol;
+
+ /**
+ * Getter for the Map property.
+ *
+ * @param self self reference
+ * @return the value of the Map property
+ */
+ @Getter(name = "Map", attributes = Attribute.NOT_ENUMERABLE)
+ public static Object getMap(final Object self) {
+ final Global global = Global.instanceFrom(self);
+ if (global.map == LAZY_SENTINEL) {
+ global.map = global.getBuiltinMap();
+ }
+ return global.map;
+ }
+
+ /**
+ * Setter for the Map property.
+ *
+ * @param self self reference
+ * @param value value of the Map property
+ */
+ @Setter(name = "Map", attributes = Attribute.NOT_ENUMERABLE)
+ public static void setMap(final Object self, final Object value) {
+ Global.instanceFrom(self).map = value;
+ }
+
+ private volatile Object map;
+
+ /**
+ * Getter for the WeakMap property.
+ *
+ * @param self self reference
+ * @return the value of the WeakMap property
+ */
+ @Getter(name = "WeakMap", attributes = Attribute.NOT_ENUMERABLE)
+ public static Object getWeakMap(final Object self) {
+ final Global global = Global.instanceFrom(self);
+ if (global.weakMap == LAZY_SENTINEL) {
+ global.weakMap = global.getBuiltinWeakMap();
+ }
+ return global.weakMap;
+ }
+
+ /**
+ * Setter for the WeakMap property.
+ *
+ * @param self self reference
+ * @param value value of the WeakMap property
+ */
+ @Setter(name = "WeakMap", attributes = Attribute.NOT_ENUMERABLE)
+ public static void setWeakMap(final Object self, final Object value) {
+ Global.instanceFrom(self).weakMap = value;
+ }
+
+ private volatile Object weakMap;
+
+ /**
+ * Getter for the Set property.
+ *
+ * @param self self reference
+ * @return the value of the Set property
+ */
+ @Getter(name = "Set", attributes = Attribute.NOT_ENUMERABLE)
+ public static Object getSet(final Object self) {
+ final Global global = Global.instanceFrom(self);
+ if (global.set == LAZY_SENTINEL) {
+ global.set = global.getBuiltinSet();
+ }
+ return global.set;
+ }
+
+ /**
+ * Setter for the Set property.
+ *
+ * @param self self reference
+ * @param value value of the Set property
+ */
+ @Setter(name = "Set", attributes = Attribute.NOT_ENUMERABLE)
+ public static void setSet(final Object self, final Object value) {
+ Global.instanceFrom(self).set = value;
+ }
+
+ private volatile Object set;
+
+ /**
+ * Getter for the WeakSet property.
+ *
+ * @param self self reference
+ * @return the value of the WeakSet property
+ */
+ @Getter(name = "WeakSet", attributes = Attribute.NOT_ENUMERABLE)
+ public static Object getWeakSet(final Object self) {
+ final Global global = Global.instanceFrom(self);
+ if (global.weakSet == LAZY_SENTINEL) {
+ global.weakSet = global.getBuiltinWeakSet();
+ }
+ return global.weakSet;
+ }
+
+ /**
+ * Setter for the WeakSet property.
+ *
+ * @param self self reference
+ * @param value value of the WeakSet property
+ */
+ @Setter(name = "WeakSet", attributes = Attribute.NOT_ENUMERABLE)
+ public static void setWeakSet(final Object self, final Object value) {
+ Global.instanceFrom(self).weakSet = value;
+ }
+
+ private volatile Object weakSet;
+
/** Nashorn extension: Java access - global.Packages */
@Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object packages;
@@ -907,6 +1047,15 @@
private ScriptFunction builtinFloat32Array;
private ScriptFunction builtinFloat64Array;
private ScriptFunction builtinSymbol;
+ private ScriptFunction builtinMap;
+ private ScriptFunction builtinWeakMap;
+ private ScriptFunction builtinSet;
+ private ScriptFunction builtinWeakSet;
+ private ScriptObject builtinIteratorPrototype;
+ private ScriptObject builtinMapIteratorPrototype;
+ private ScriptObject builtinSetIteratorPrototype;
+ private ScriptObject builtinArrayIteratorPrototype;
+ private ScriptObject builtinStringIteratorPrototype;
/*
* ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
@@ -1673,7 +1822,58 @@
}
ScriptObject getSymbolPrototype() {
- return ScriptFunction.getPrototype(builtinSymbol);
+ return ScriptFunction.getPrototype(getBuiltinSymbol());
+ }
+
+ ScriptObject getMapPrototype() {
+ return ScriptFunction.getPrototype(getBuiltinMap());
+ }
+
+ ScriptObject getWeakMapPrototype() {
+ return ScriptFunction.getPrototype(getBuiltinWeakMap());
+ }
+
+ ScriptObject getSetPrototype() {
+ return ScriptFunction.getPrototype(getBuiltinSet());
+ }
+
+ ScriptObject getWeakSetPrototype() {
+ return ScriptFunction.getPrototype(getBuiltinWeakSet());
+ }
+
+ ScriptObject getIteratorPrototype() {
+ if (builtinIteratorPrototype == null) {
+ builtinIteratorPrototype = initPrototype("AbstractIterator", getObjectPrototype());
+ }
+ return builtinIteratorPrototype;
+ }
+
+ ScriptObject getMapIteratorPrototype() {
+ if (builtinMapIteratorPrototype == null) {
+ builtinMapIteratorPrototype = initPrototype("MapIterator", getIteratorPrototype());
+ }
+ return builtinMapIteratorPrototype;
+ }
+
+ ScriptObject getSetIteratorPrototype() {
+ if (builtinSetIteratorPrototype == null) {
+ builtinSetIteratorPrototype = initPrototype("SetIterator", getIteratorPrototype());
+ }
+ return builtinSetIteratorPrototype;
+ }
+
+ ScriptObject getArrayIteratorPrototype() {
+ if (builtinArrayIteratorPrototype == null) {
+ builtinArrayIteratorPrototype = initPrototype("ArrayIterator", getIteratorPrototype());
+ }
+ return builtinArrayIteratorPrototype;
+ }
+
+ ScriptObject getStringIteratorPrototype() {
+ if (builtinStringIteratorPrototype == null) {
+ builtinStringIteratorPrototype = initPrototype("StringIterator", getIteratorPrototype());
+ }
+ return builtinStringIteratorPrototype;
}
private synchronized ScriptFunction getBuiltinArrayBuffer() {
@@ -1916,6 +2116,41 @@
return this.builtinURIError;
}
+ private synchronized ScriptFunction getBuiltinSymbol() {
+ if (this.builtinSymbol == null) {
+ this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class);
+ }
+ return this.builtinSymbol;
+ }
+
+ private synchronized ScriptFunction getBuiltinMap() {
+ if (this.builtinMap == null) {
+ this.builtinMap = initConstructorAndSwitchPoint("Map", ScriptFunction.class);
+ }
+ return this.builtinMap;
+ }
+
+ private synchronized ScriptFunction getBuiltinWeakMap() {
+ if (this.builtinWeakMap == null) {
+ this.builtinWeakMap = initConstructorAndSwitchPoint("WeakMap", ScriptFunction.class);
+ }
+ return this.builtinWeakMap;
+ }
+
+ private synchronized ScriptFunction getBuiltinSet() {
+ if (this.builtinSet == null) {
+ this.builtinSet = initConstructorAndSwitchPoint("Set", ScriptFunction.class);
+ }
+ return this.builtinSet;
+ }
+
+ private synchronized ScriptFunction getBuiltinWeakSet() {
+ if (this.builtinWeakSet == null) {
+ this.builtinWeakSet = initConstructorAndSwitchPoint("WeakSet", ScriptFunction.class);
+ }
+ return this.builtinWeakSet;
+ }
+
@Override
public String getClassName() {
return "global";
@@ -2311,14 +2546,6 @@
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();
@@ -2328,6 +2555,25 @@
final ScriptObject arrayPrototype = getArrayPrototype();
arrayPrototype.setIsArray();
+ if (env._es6) {
+ this.symbol = LAZY_SENTINEL;
+ this.map = LAZY_SENTINEL;
+ this.weakMap = LAZY_SENTINEL;
+ this.set = LAZY_SENTINEL;
+ this.weakSet = LAZY_SENTINEL;
+ } else {
+ // We need to manually delete nasgen-generated properties we don't want
+ this.delete("Symbol", false);
+ this.delete("Map", false);
+ this.delete("WeakMap", false);
+ this.delete("Set", false);
+ this.delete("WeakSet", false);
+ builtinObject.delete("getOwnPropertySymbols", false);
+ arrayPrototype.delete("entries", false);
+ arrayPrototype.delete("keys", false);
+ arrayPrototype.delete("values", false);
+ }
+
// Error stuff
initErrorObjects();
@@ -2522,7 +2768,6 @@
this.string = this.builtinString;
this.syntaxError = this.builtinSyntaxError;
this.typeError = this.builtinTypeError;
- this.symbol = this.builtinSymbol;
}
private void initDebug() {
@@ -2558,7 +2803,7 @@
private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
try {
// Assuming class name pattern for built-in JS constructors.
- final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects.");
+ final StringBuilder sb = new StringBuilder(PACKAGE_PREFIX);
sb.append("Native");
sb.append(name);
@@ -2586,6 +2831,22 @@
}
}
+ private ScriptObject initPrototype(final String name, final ScriptObject prototype) {
+ try {
+ // Assuming class name pattern for JS prototypes
+ final String className = PACKAGE_PREFIX + name + "$Prototype";
+
+ final Class<?> funcClass = Class.forName(className);
+ final ScriptObject res = (ScriptObject) funcClass.newInstance();
+
+ res.setIsBuiltin();
+ res.setInitialProto(prototype);
+ return res;
+ } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/IteratorResult.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010, 2014, 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 jdk.nashorn.internal.objects.annotations.Property;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+
+@ScriptClass("IteratorResult")
+public class IteratorResult extends ScriptObject {
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ IteratorResult(final Object value, final Boolean done, final Global global) {
+ super(global.getObjectPrototype(), $nasgenmap$);
+ this.value = value;
+ this.done = done;
+ }
+
+ /**
+ * The result value property.
+ */
+ @Property
+ public Object value;
+
+ /**
+ * The result status property.
+ */
+ @Property
+ public Object done;
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/LinkedMap.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2016, 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 jdk.nashorn.internal.runtime.Undefined;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>A linked hash map used by the ES6 Map and Set objects. As required by the ECMA specification for these objects,
+ * this class allows arbitrary modifications to the base collection while being iterated over. However, note that
+ * such modifications are only safe from the same thread performing the iteration; the class is not thread-safe.</p>
+ *
+ * <p>Deletions and additions that occur during iteration are reflected in the elements visited by the iterator
+ * (except for deletion of elements that have already been visited). In non-concurrent Java collections such as
+ * {@code java.util.LinkedHashMap} this would result in a {@link java.util.ConcurrentModificationException}
+ * being thrown.</p>
+ *
+ * <p>This class is implemented using a {@link java.util.HashMap} as backing storage with doubly-linked
+ * list nodes as values.</p>
+ *
+ * @see <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-map.prototype.foreach">Map.prototype.forEach</a>
+ * @see <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-set.prototype.foreach">Set.prototype.forEach</a>
+ */
+public class LinkedMap {
+
+ // We use a plain hash map as our hash storage.
+ private final Map<Object, Node> data = new HashMap<>();
+
+ // The head and tail of our doubly-linked list. We use the same node to represent both the head and the
+ // tail of the list, so the list is circular. This node is never unlinked and thus always remain alive.
+ private final Node head = new Node();
+
+ /**
+ * A node of a linked list that is used as value in our map. The linked list uses insertion order
+ * and allows fast iteration over its element even while the map is modified.
+ */
+ static class Node {
+ private final Object key;
+ private final Object value;
+
+ private volatile boolean alive = true;
+ private volatile Node prev;
+ private volatile Node next;
+
+ /**
+ * Constructor for the list head. This creates an empty circular list.
+ */
+ private Node() {
+ this(null, null);
+ this.next = this;
+ this.prev = this;
+ }
+
+ /**
+ * Constructor for value nodes.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ private Node(final Object key, final Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Get the node's key.
+ * @return the hash key
+ */
+ public Object getKey() {
+ return key;
+ }
+
+ /**
+ * Get the node's value.
+ * @return the value
+ */
+ public Object getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * An iterator over the elements in the map.
+ */
+ class LinkedMapIterator {
+
+ private Node cursor;
+
+ private LinkedMapIterator() {
+ this.cursor = head;
+ }
+
+ /**
+ * Get the next node in this iteration. Changes in the underlying map are reflected in the iteration
+ * as required by the ES6 specification. Note that this method could return a deleted node if deletion
+ * occurred concurrently on another thread.
+ *
+ * @return the next node
+ */
+ public Node next() {
+
+ if (cursor != null) {
+ // If last node is not alive anymore (i.e. has been deleted) go back to the last live node
+ // and continue from there. This may be the list head, which always remains alive.
+ while (!cursor.alive) {
+ assert cursor != head;
+ cursor = cursor.prev;
+ }
+
+ cursor = cursor.next;
+
+ if (cursor == head) {
+ cursor = null; // We've come full circle to the end
+ }
+ }
+
+ return cursor;
+ }
+ }
+
+ /**
+ * Add a key-value pair to the map.
+ * @param key the key
+ * @param value the value
+ */
+ public void set(final Object key, final Object value) {
+ final Node newNode = new Node(key, value);
+ final Node oldNode = data.put(key, newNode);
+ if (oldNode != null) {
+ unlink(oldNode);
+ }
+ link(newNode);
+ }
+
+ /**
+ * Get the value associated with {@code key}.
+ * @param key the key
+ * @return the associated value, or {@code null} if {@code key} is not contained in the map
+ */
+ public Object get(final Object key) {
+ final Node node = data.get(key);
+ return node == null ? Undefined.getUndefined() : node.getValue();
+ }
+
+ /**
+ * Returns {@code true} if {@code key} is contained in the map.
+ * @param key the key
+ * @return {@code true} if {@code key} is contained
+ */
+ public boolean has(final Object key) {
+ return data.containsKey(key);
+ }
+
+ /**
+ * Delete the node associated with {@code key} from the map.
+ * @param key the key
+ * @return {@code true} if {@code key} was contained in the map
+ */
+ public boolean delete (final Object key) {
+ final Node node = data.remove(key);
+ if (node != null) {
+ unlink(node);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Remove all key-value pairs from the map.
+ */
+ public void clear() {
+ data.clear();
+ for (Node node = head.next; node != head; node = node.next) {
+ node.alive = false;
+ }
+ head.next = head;
+ head.prev = head;
+ }
+
+ /**
+ * Return the current number of key-value pairs in the map.
+ * @return the map size
+ */
+ public int size() {
+ return data.size();
+ }
+
+ /**
+ * Get an iterator over the key-value pairs in the map.
+ * @return an iterator
+ */
+ public LinkedMapIterator getIterator() {
+ return new LinkedMapIterator();
+ }
+
+ private void link(final Node newNode) {
+ // We always insert at the end (head == tail)
+ newNode.next = head;
+ newNode.prev = head.prev;
+ newNode.prev.next = newNode;
+ head.prev = newNode;
+ }
+
+ private void unlink(final Node oldNode) {
+ // Note that we unlink references to the node being deleted, but keep the references from the deleted node.
+ // This is necessary to allow iterators to go back to the last live node in case the current node has been
+ // deleted. Also, the forward link of a deleted node may still be followed by an iterator and must not be null.
+ oldNode.prev.next = oldNode.next;
+ oldNode.next.prev = oldNode.prev;
+ oldNode.alive = false;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/MapIterator.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, 2014, 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 jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Undefined;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+/**
+ * ECMA6 23.1.5 Map Iterator Objects
+ */
+@ScriptClass("MapIterator")
+public class MapIterator extends AbstractIterator {
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private LinkedMap.LinkedMapIterator iterator;
+
+ private final IterationKind iterationKind;
+
+ // Cached global needed for each iteration result
+ private final Global global;
+
+ /**
+ * Constructor for Map iterators.
+ * @param map the map to iterate over
+ * @param iterationKind the iteration kind
+ * @param global the current global object
+ */
+ MapIterator(final NativeMap map, final IterationKind iterationKind, final Global global) {
+ super(global.getMapIteratorPrototype(), $nasgenmap$);
+ this.iterator = map.getJavaMap().getIterator();
+ this.iterationKind = iterationKind;
+ this.global = global;
+ }
+
+ /**
+ * ES6 23.1.5.2.1 %MapIteratorPrototype%.next()
+ *
+ * @param self the self reference
+ * @param arg the argument
+ * @return the next result
+ */
+ @Function
+ public static Object next(final Object self, final Object arg) {
+ if (!(self instanceof MapIterator)) {
+ throw typeError("not.a.map.iterator", ScriptRuntime.safeToString(self));
+ }
+ return ((MapIterator)self).next(arg);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Map Iterator";
+ }
+
+ @Override
+ protected IteratorResult next(final Object arg) {
+ if (iterator == null) {
+ return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
+ }
+
+ final LinkedMap.Node node = iterator.next();
+
+ if (node == null) {
+ iterator = null;
+ return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
+ }
+
+ if (iterationKind == IterationKind.KEY_VALUE) {
+ final NativeArray array = new NativeArray(new Object[] {node.getKey(), node.getValue()});
+ return makeResult(array, Boolean.FALSE, global);
+ }
+
+ return makeResult(iterationKind == IterationKind.KEY ? node.getKey() : node.getValue(), Boolean.FALSE, global);
+ }
+
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Mon Feb 15 17:02:32 2016 +0100
@@ -1718,6 +1718,50 @@
}
/**
+ * ECMA6 22.1.3.4 Array.prototype.entries ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's entries
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object entries(final Object self) {
+ return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
+ }
+
+ /**
+ * ECMA6 22.1.3.13 Array.prototype.keys ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's keys
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object keys(final Object self) {
+ return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY, Global.instance());
+ }
+
+ /**
+ * ECMA6 22.1.3.29 Array.prototype.values ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object values(final Object self) {
+ return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ }
+
+ /**
+ * 22.1.3.30 Array.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ }
+
+ /**
* Determine if Java bulk array operations may be used on the underlying
* storage. This is possible only if the object's prototype chain is empty
* or each of the prototypes in the chain is empty.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeMap.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2016, 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 java.lang.invoke.MethodHandle;
+
+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.Getter;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.ConsString;
+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.Undefined;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+/**
+ * This implements the ECMA6 Map object.
+ */
+@ScriptClass("Map")
+public class NativeMap extends ScriptObject {
+
+ // our underlying map
+ private final LinkedMap map = new LinkedMap();
+
+ // key for the forEach invoker callback
+ private final static Object FOREACH_INVOKER_KEY = new Object();
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private NativeMap(final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
+ }
+
+ /**
+ * ECMA6 23.1.1 The Map Constructor
+ *
+ * @param isNew is this called with the new operator?
+ * @param self self reference
+ * @param arg optional iterable argument
+ * @return a new Map instance
+ */
+ @Constructor(arity = 0)
+ public static Object construct(final boolean isNew, final Object self, final Object arg) {
+ if (!isNew) {
+ throw typeError("constructor.requires.new", "Map");
+ }
+ final Global global = Global.instance();
+ final NativeMap map = new NativeMap(global.getMapPrototype(), $nasgenmap$);
+ populateMap(map.getJavaMap(), arg, global);
+ return map;
+ }
+
+ /**
+ * ECMA6 23.1.3.1 Map.prototype.clear ( )
+ *
+ * @param self the self reference
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static void clear(final Object self) {
+ getNativeMap(self).map.clear();
+ }
+
+ /**
+ * ECMA6 23.1.3.3 Map.prototype.delete ( key )
+ *
+ * @param self the self reference
+ * @param key the key to delete
+ * @return true if the key was deleted
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean delete(final Object self, final Object key) {
+ return getNativeMap(self).map.delete(convertKey(key));
+ }
+
+ /**
+ * ECMA6 23.1.3.7 Map.prototype.has ( key )
+ *
+ * @param self the self reference
+ * @param key the key
+ * @return true if key is contained
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean has(final Object self, final Object key) {
+ return getNativeMap(self).map.has(convertKey(key));
+ }
+
+ /**
+ * ECMA6 23.1.3.9 Map.prototype.set ( key , value )
+ *
+ * @param self the self reference
+ * @param key the key
+ * @param value the value
+ * @return this Map object
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object set(final Object self, final Object key, final Object value) {
+ getNativeMap(self).map.set(convertKey(key), value);
+ return self;
+ }
+
+ /**
+ * ECMA6 23.1.3.6 Map.prototype.get ( key )
+ *
+ * @param self the self reference
+ * @param key the key
+ * @return the associated value or undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object get(final Object self, final Object key) {
+ return getNativeMap(self).map.get(convertKey(key));
+ }
+
+ /**
+ * ECMA6 23.1.3.10 get Map.prototype.size
+ *
+ * @param self the self reference
+ * @return the size of the map
+ */
+ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.IS_ACCESSOR, where = Where.PROTOTYPE)
+ public static int size(final Object self) {
+ return getNativeMap(self).map.size();
+ }
+
+ /**
+ * ECMA6 23.1.3.4 Map.prototype.entries ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Map's entries
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object entries(final Object self) {
+ return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.1.3.8 Map.prototype.keys ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Map's keys
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object keys(final Object self) {
+ return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.KEY, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.1.3.11 Map.prototype.values ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Map's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object values(final Object self) {
+ return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.1.3.12 Map.prototype [ @@iterator ]( )
+ *
+ * @param self the self reference
+ * @return An iterator over the Map's entries
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
+ }
+
+ /**
+ *
+ * @param self the self reference
+ * @param callbackFn the callback function
+ * @param thisArg optional this-object
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static void forEach(final Object self, final Object callbackFn, final Object thisArg) {
+ final NativeMap map = getNativeMap(self);
+ if (!Bootstrap.isCallable(callbackFn)) {
+ throw typeError("not.a.function", ScriptRuntime.safeToString(callbackFn));
+ }
+ final MethodHandle invoker = Global.instance().getDynamicInvoker(FOREACH_INVOKER_KEY,
+ () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class));
+
+ final LinkedMap.LinkedMapIterator iterator = map.getJavaMap().getIterator();
+ for (;;) {
+ final LinkedMap.Node node = iterator.next();
+ if (node == null) {
+ break;
+ }
+
+ try {
+ final Object result = invoker.invokeExact(callbackFn, thisArg, node.getValue(), node.getKey(), self);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+ @Override
+ public String getClassName() {
+ return "Map";
+ }
+
+ static void populateMap(final LinkedMap map, final Object arg, final Global global) {
+ if (arg != null && arg != Undefined.getUndefined()) {
+ AbstractIterator.iterate(arg, global, value -> {
+ if (JSType.isPrimitive(value)) {
+ throw typeError(global, "not.an.object", ScriptRuntime.safeToString(value));
+ }
+ if (value instanceof ScriptObject) {
+ final ScriptObject sobj = (ScriptObject) value;
+ map.set(convertKey(sobj.get(0)), sobj.get(1));
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns a canonicalized key object by converting numbers to their narrowest representation and
+ * ConsStrings to strings. Conversion of Double to Integer also takes care of converting -0 to 0
+ * as required by step 6 of ECMA6 23.1.3.9.
+ *
+ * @param key a key
+ * @return the canonical key
+ */
+ static Object convertKey(final Object key) {
+ if (key instanceof ConsString) {
+ return key.toString();
+ }
+ if (key instanceof Double) {
+ final Double d = (Double) key;
+ if (JSType.isRepresentableAsInt(d.doubleValue())) {
+ return d.intValue();
+ }
+ }
+ return key;
+ }
+
+ /**
+ * Get the underlying Java map.
+ * @return the Java map
+ */
+ LinkedMap getJavaMap() {
+ return map;
+ }
+
+ private static NativeMap getNativeMap(final Object self) {
+ if (self instanceof NativeMap) {
+ return (NativeMap)self;
+ } else {
+ throw typeError("not.a.map", ScriptRuntime.safeToString(self));
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSet.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2016, 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 java.lang.invoke.MethodHandle;
+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.Getter;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Undefined;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+
+import static jdk.nashorn.internal.objects.NativeMap.convertKey;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+/**
+ * This implements the ECMA6 Set object.
+ */
+@ScriptClass("Set")
+public class NativeSet extends ScriptObject {
+
+ // our set/map implementation
+ private final LinkedMap map = new LinkedMap();
+
+ // Invoker for the forEach callback
+ private final static Object FOREACH_INVOKER_KEY = new Object();
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private NativeSet(final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
+ }
+
+ /**
+ * ECMA6 23.1 Set constructor
+ *
+ * @param isNew whether the new operator used
+ * @param self self reference
+ * @param arg optional iterable argument
+ * @return a new Set object
+ */
+ @Constructor(arity = 0)
+ public static Object construct(final boolean isNew, final Object self, final Object arg){
+ if (!isNew) {
+ throw typeError("constructor.requires.new", "Set");
+ }
+ final Global global = Global.instance();
+ final NativeSet set = new NativeSet(global.getSetPrototype(), $nasgenmap$);
+ populateSet(set.getJavaMap(), arg, global);
+ return set;
+ }
+
+ /**
+ * ECMA6 23.2.3.1 Set.prototype.add ( value )
+ *
+ * @param self the self reference
+ * @param value the value to add
+ * @return this Set object
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object add(final Object self, final Object value) {
+ getNativeSet(self).map.set(convertKey(value), null);
+ return self;
+ }
+
+ /**
+ * ECMA6 23.2.3.7 Set.prototype.has ( value )
+ *
+ * @param self the self reference
+ * @param value the value
+ * @return true if value is contained
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean has(final Object self, final Object value) {
+ return getNativeSet(self).map.has(convertKey(value));
+ }
+
+ /**
+ * ECMA6 23.2.3.2 Set.prototype.clear ( )
+ *
+ * @param self the self reference
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static void clear(final Object self) {
+ getNativeSet(self).map.clear();
+ }
+
+ /**
+ * ECMA6 23.2.3.4 Set.prototype.delete ( value )
+ *
+ * @param self the self reference
+ * @param value the value
+ * @return true if value was deleted
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean delete(final Object self, final Object value) {
+ return getNativeSet(self).map.delete(convertKey(value));
+ }
+
+ /**
+ * ECMA6 23.2.3.9 get Set.prototype.size
+ *
+ * @param self the self reference
+ * @return the number of contained values
+ */
+ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.IS_ACCESSOR, where = Where.PROTOTYPE)
+ public static int size(final Object self) {
+ return getNativeSet(self).map.size();
+ }
+
+ /**
+ * ECMA6 23.2.3.5 Set.prototype.entries ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Set object's entries
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object entries(final Object self) {
+ return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.2.3.8 Set.prototype.keys ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Set object's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object keys(final Object self) {
+ return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.KEY, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.2.3.10 Set.prototype.values ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Set object's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object values(final Object self) {
+ return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.2.3.11 Set.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the Set object's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ }
+
+ /**
+ * ECMA6 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] )
+ *
+ * @param self the self reference
+ * @param callbackFn the callback function
+ * @param thisArg optional this object
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static void forEach(final Object self, final Object callbackFn, final Object thisArg) {
+ final NativeSet set = getNativeSet(self);
+ if (!Bootstrap.isCallable(callbackFn)) {
+ throw typeError("not.a.function", ScriptRuntime.safeToString(callbackFn));
+ }
+ final MethodHandle invoker = Global.instance().getDynamicInvoker(FOREACH_INVOKER_KEY,
+ () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class));
+
+ final LinkedMap.LinkedMapIterator iterator = set.getJavaMap().getIterator();
+ for (;;) {
+ final LinkedMap.Node node = iterator.next();
+ if (node == null) {
+ break;
+ }
+
+ try {
+ final Object result = invoker.invokeExact(callbackFn, thisArg, node.getKey(), node.getKey(), self);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+ @Override
+ public String getClassName() {
+ return "Set";
+ }
+
+ static void populateSet(final LinkedMap map, final Object arg, final Global global) {
+ if (arg != null && arg != Undefined.getUndefined()) {
+ AbstractIterator.iterate(arg, global, value -> map.set(convertKey(value), null));
+ }
+ }
+
+ LinkedMap getJavaMap() {
+ return map;
+ }
+
+ private static NativeSet getNativeSet(final Object self) {
+ if (self instanceof NativeSet) {
+ return (NativeSet) self;
+ } else {
+ throw typeError("not.a.set", ScriptRuntime.safeToString(self));
+ }
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Mon Feb 15 17:02:32 2016 +0100
@@ -1228,6 +1228,17 @@
}
/**
+ * ECMA 6 21.1.3.27 String.prototype [ @@iterator ]( )
+ *
+ * @param self self reference
+ * @return a string iterator
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return new StringIterator(checkObjectToString(self), Global.instance());
+ }
+
+ /**
* Lookup the appropriate method for an invoke dynamic call.
*
* @param request the link request
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java Mon Feb 15 17:02:32 2016 +0100
@@ -37,6 +37,8 @@
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.Getter;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
@@ -66,6 +68,12 @@
/** See ES6 19.4.2.1 */
private static WeakValueCache<String, Symbol> globalSymbolRegistry = new WeakValueCache<>();
+ /**
+ * ECMA 6 19.4.2.4 Symbol.iterator
+ */
+ @Property(where = Where.CONSTRUCTOR, attributes = Attribute.NON_ENUMERABLE_CONSTANT, name = "iterator")
+ public static final Symbol iterator = new Symbol("Symbol.iterator");
+
NativeSymbol(final Symbol symbol) {
this(symbol, Global.instance());
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeWeakMap.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016, 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 java.util.Map;
+import java.util.WeakHashMap;
+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.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.Undefined;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.JSType.isPrimitive;
+
+/**
+ * This implements the ECMA6 WeakMap object.
+ */
+@ScriptClass("WeakMap")
+public class NativeWeakMap extends ScriptObject {
+
+ private final Map<Object, Object> jmap = new WeakHashMap<>();
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private NativeWeakMap(final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
+ }
+
+ /**
+ * ECMA6 23.3.1 The WeakMap Constructor
+ *
+ * @param isNew whether the new operator used
+ * @param self self reference
+ * @param arg optional iterable argument
+ * @return a new WeakMap object
+ */
+ @Constructor(arity = 0)
+ public static Object construct(final boolean isNew, final Object self, final Object arg) {
+ if (!isNew) {
+ throw typeError("constructor.requires.new", "WeakMap");
+ }
+ final Global global = Global.instance();
+ final NativeWeakMap weakMap = new NativeWeakMap(global.getWeakMapPrototype(), $nasgenmap$);
+ populateMap(weakMap.jmap, arg, global);
+ return weakMap;
+ }
+
+ /**
+ * ECMA6 23.3.3.5 WeakMap.prototype.set ( key , value )
+ *
+ * @param self the self reference
+ * @param key the key
+ * @param value the value
+ * @return this WeakMap object
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object set(final Object self, final Object key, final Object value) {
+ final NativeWeakMap map = getMap(self);
+ map.jmap.put(checkKey(key), value);
+ return self;
+ }
+
+ /**
+ * ECMA6 23.3.3.3 WeakMap.prototype.get ( key )
+ *
+ * @param self the self reference
+ * @param key the key
+ * @return the associated value or undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object get(final Object self, final Object key) {
+ final NativeWeakMap map = getMap(self);
+ if (isPrimitive(key)) {
+ return Undefined.getUndefined();
+ }
+ return map.jmap.get(key);
+ }
+
+ /**
+ * ECMA6 23.3.3.2 WeakMap.prototype.delete ( key )
+ *
+ * @param self the self reference
+ * @param key the key to delete
+ * @return true if the key was deleted
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean delete(final Object self, final Object key) {
+ final Map<Object, Object> map = getMap(self).jmap;
+ if (isPrimitive(key)) {
+ return false;
+ }
+ final boolean returnValue = map.containsKey(key);
+ map.remove(key);
+ return returnValue;
+ }
+
+ /**
+ * ECMA6 23.3.3.4 WeakMap.prototype.has ( key )
+ *
+ * @param self the self reference
+ * @param key the key
+ * @return true if key is contained
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean has(final Object self, final Object key) {
+ final NativeWeakMap map = getMap(self);
+ return !isPrimitive(key) && map.jmap.containsKey(key);
+ }
+
+ @Override
+ public String getClassName() {
+ return "WeakMap";
+ }
+
+ /**
+ * Make sure {@code key} is not a JavaScript primitive value.
+ *
+ * @param key a key object
+ * @return the valid key
+ */
+ static Object checkKey(final Object key) {
+ if (isPrimitive(key)) {
+ throw typeError("invalid.weak.key", ScriptRuntime.safeToString(key));
+ }
+ return key;
+ }
+
+ static void populateMap(final Map<Object, Object> map, final Object arg, final Global global) {
+ // This method is similar to NativeMap.populateMap, but it uses a different
+ // map implementation and the checking/conversion of keys differs as well.
+ if (arg != null && arg != Undefined.getUndefined()) {
+ AbstractIterator.iterate(arg, global, value -> {
+ if (isPrimitive(value)) {
+ throw typeError(global, "not.an.object", ScriptRuntime.safeToString(value));
+ }
+ if (value instanceof ScriptObject) {
+ final ScriptObject sobj = (ScriptObject) value;
+ map.put(checkKey(sobj.get(0)), sobj.get(1));
+ }
+ });
+ }
+ }
+
+ private static NativeWeakMap getMap(final Object self) {
+ if (self instanceof NativeWeakMap) {
+ return (NativeWeakMap)self;
+ } else {
+ throw typeError("not.a.weak.map", ScriptRuntime.safeToString(self));
+ }
+ }
+
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeWeakSet.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016, 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 java.util.Map;
+import java.util.WeakHashMap;
+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.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.Undefined;
+
+import static jdk.nashorn.internal.objects.NativeWeakMap.checkKey;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.JSType.isPrimitive;
+
+/**
+ * This implements the ECMA6 WeakSet object.
+ */
+@ScriptClass("WeakSet")
+public class NativeWeakSet extends ScriptObject {
+
+ private final Map<Object, Boolean> map = new WeakHashMap<>();
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private NativeWeakSet(final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
+ }
+
+ /**
+ * ECMA6 23.3.1 The WeakSet Constructor
+ *
+ * @param isNew whether the new operator used
+ * @param self self reference
+ * @param arg optional iterable argument
+ * @return a new WeakSet object
+ */
+ @Constructor(arity = 0)
+ public static Object construct(final boolean isNew, final Object self, final Object arg) {
+ if (!isNew) {
+ throw typeError("constructor.requires.new", "WeakSet");
+ }
+ final Global global = Global.instance();
+ final NativeWeakSet weakSet = new NativeWeakSet(global.getWeakSetPrototype(), $nasgenmap$);
+ populateWeakSet(weakSet.map, arg, global);
+ return weakSet;
+ }
+
+ /**
+ * ECMA6 23.4.3.1 WeakSet.prototype.add ( value )
+ *
+ * @param self the self reference
+ * @param value the value to add
+ * @return this Set object
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static Object add(final Object self, final Object value) {
+ final NativeWeakSet set = getSet(self);
+ set.map.put(checkKey(value), Boolean.TRUE);
+ return self;
+ }
+
+ /**
+ * ECMA6 23.4.3.4 WeakSet.prototype.has ( value )
+ *
+ * @param self the self reference
+ * @param value the value
+ * @return true if value is contained
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean has(final Object self, final Object value) {
+ final NativeWeakSet set = getSet(self);
+ return !isPrimitive(value) && set.map.containsKey(value);
+ }
+
+ /**
+ * ECMA6 23.4.3.3 WeakSet.prototype.delete ( value )
+ *
+ * @param self the self reference
+ * @param value the value
+ * @return true if value was deleted
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static boolean delete(final Object self, final Object value) {
+ final Map<Object, Boolean> map = getSet(self).map;
+ if (isPrimitive(value)) {
+ return false;
+ }
+ final boolean returnValue = map.containsKey(value);
+ map.remove(value);
+ return returnValue;
+ }
+
+ @Override
+ public String getClassName() {
+ return "WeakSet";
+ }
+
+ static void populateWeakSet(final Map<Object, Boolean> set, final Object arg, final Global global) {
+ if (arg != null && arg != Undefined.getUndefined()) {
+ AbstractIterator.iterate(arg, global, value -> {
+ set.put(checkKey(value), Boolean.TRUE);
+ });
+ }
+ }
+
+ private static NativeWeakSet getSet(final Object self) {
+ if (self instanceof NativeWeakSet) {
+ return (NativeWeakSet) self;
+ } else {
+ throw typeError("not.a.weak.set", ScriptRuntime.safeToString(self));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/SetIterator.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, 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 jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Undefined;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+/**
+ * ECMA6 23.2.5 Set Iterator Objects
+ */
+@ScriptClass("SetIterator")
+public class SetIterator extends AbstractIterator {
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private LinkedMap.LinkedMapIterator iterator;
+
+ private final IterationKind iterationKind;
+
+ // Cached global needed for every iteration result
+ private final Global global;
+
+ SetIterator(final NativeSet set, final IterationKind iterationKind, final Global global) {
+ super(global.getSetIteratorPrototype(), $nasgenmap$);
+ this.iterator = set.getJavaMap().getIterator();
+ this.iterationKind = iterationKind;
+ this.global = global;
+ }
+
+ /**
+ * ES6 23.2.5.2.1 %SetIteratorPrototype%.next()
+ *
+ * @param self the self reference
+ * @param arg the argument
+ * @return the next result
+ */
+ @Function
+ public static Object next(final Object self, final Object arg) {
+ if (!(self instanceof SetIterator)) {
+ throw typeError("not.a.set.iterator", ScriptRuntime.safeToString(self));
+ }
+ return ((SetIterator)self).next(arg);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Set Iterator";
+ }
+
+ @Override
+ protected IteratorResult next(final Object arg) {
+ if (iterator == null) {
+ return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
+ }
+
+ final LinkedMap.Node node = iterator.next();
+
+ if (node == null) {
+ iterator = null;
+ return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
+ }
+
+ if (iterationKind == IterationKind.KEY_VALUE) {
+ final NativeArray array = new NativeArray(new Object[] {node.getKey(), node.getKey()});
+ return makeResult(array, Boolean.FALSE, global);
+ }
+
+ return makeResult(node.getKey(), Boolean.FALSE, global);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/StringIterator.java Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016, 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 jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Undefined;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+/**
+ * ECMA6 21.1.5 String Iterator Objects
+ */
+@ScriptClass("StringIterator")
+public class StringIterator extends AbstractIterator {
+
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ private String iteratedString;
+ private int nextIndex = 0;
+ private final Global global;
+
+ StringIterator(final String iteratedString, final Global global) {
+ super(global.getStringIteratorPrototype(), $nasgenmap$);
+ this.iteratedString = iteratedString;
+ this.global = global;
+ }
+
+ /**
+ * ES6 21.1.5.2.1 %StringIteratorPrototype%.next()
+ *
+ * @param self the self reference
+ * @param arg the argument
+ * @return the next result
+ */
+ @Function
+ public static Object next(final Object self, final Object arg) {
+ if (!(self instanceof StringIterator)) {
+ throw typeError("not.a.string.iterator", ScriptRuntime.safeToString(self));
+ }
+ return ((StringIterator)self).next(arg);
+ }
+
+ @Override
+ public String getClassName() {
+ return "String Iterator";
+ }
+
+ @Override
+ protected IteratorResult next(final Object arg) {
+ final int index = nextIndex;
+ final String string = iteratedString;
+
+ if (string == null || index >= string.length()) {
+ // ES6 21.1.5.2.1 step 8
+ iteratedString = null;
+ return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
+ }
+
+ final char first = string.charAt(index);
+ if (first >= 0xd800 && first <= 0xdbff && index < string.length() - 1) {
+ final char second = string.charAt(index + 1);
+ if (second >= 0xdc00 && second <= 0xdfff) {
+ nextIndex += 2;
+ return makeResult(String.valueOf(new char[] {first, second}), Boolean.FALSE, global);
+ }
+ }
+
+ nextIndex++;
+ return makeResult(String.valueOf(first), Boolean.FALSE, global);
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Attribute.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Attribute.java Mon Feb 15 17:02:32 2016 +0100
@@ -31,21 +31,31 @@
*/
public interface Attribute {
- /** flag for non writable objects */
+ /** Flag for non-writable properties */
public static final int NOT_WRITABLE = jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
- /** flag for non enumerable objects */
+ /** Flag for non-enumerable properties */
public static final int NOT_ENUMERABLE = jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
- /** flag for non configurable objects */
+ /** Flag for non-configurable properties */
public static final int NOT_CONFIGURABLE = jdk.nashorn.internal.runtime.Property.NOT_CONFIGURABLE;
- /** read-only, non-configurable property */
+ /**
+ * Flag for accessor (getter/setter) properties as opposed to data properties.
+ *
+ * <p>This allows nasgen-created properties to behave like user-accessors. it should only be used for
+ * properties that are explicitly specified as accessor properties in the ECMAScript specification
+ * such as Map.prototype.size in ES6, not value properties that happen to be implemented by getter/setter
+ * such as the "length" properties of String or Array objects.</p>
+ */
+ public static final int IS_ACCESSOR = jdk.nashorn.internal.runtime.Property.IS_ACCESSOR_PROPERTY;
+
+ /** Read-only, non-configurable property */
public static final int CONSTANT = NOT_WRITABLE | NOT_CONFIGURABLE;
- /** non-enumerable, read-only, non-configurable property */
+ /** Non-enumerable, read-only, non-configurable property */
public static final int NON_ENUMERABLE_CONSTANT = NOT_ENUMERABLE | CONSTANT;
- /** by default properties are writable, enumerable and configurable */
+ /** By default properties are writable, enumerable and configurable */
public static final int DEFAULT_ATTRIBUTES = 0;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Mon Feb 15 17:02:32 2016 +0100
@@ -127,7 +127,7 @@
*
* @return New {@link AccessorProperty} created.
*/
- public static AccessorProperty create(final String key, final int propertyFlags, final MethodHandle getter, final MethodHandle setter) {
+ public static AccessorProperty create(final Object key, final int propertyFlags, final MethodHandle getter, final MethodHandle setter) {
return new AccessorProperty(key, propertyFlags, -1, getter, setter);
}
@@ -602,6 +602,11 @@
}
@Override
+ public boolean hasNativeSetter() {
+ return objectSetter != null;
+ }
+
+ @Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
checkUndeclared();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Mon Feb 15 17:02:32 2016 +0100
@@ -163,7 +163,7 @@
* @return appropriate receiver
*/
public ScriptObject getGetterReceiver() {
- return property != null && property instanceof UserAccessorProperty ? self : prototype;
+ return property != null && property.isAccessorProperty() ? self : prototype;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Mon Feb 15 17:02:32 2016 +0100
@@ -99,6 +99,9 @@
/** Does this property support dual field representation? */
public static final int DUAL_FIELDS = 1 << 11;
+ /** Is this an accessor property as as defined in ES5 8.6.1? */
+ public static final int IS_ACCESSOR_PROPERTY = 1 << 12;
+
/** Property key. */
private final Object key;
@@ -496,6 +499,16 @@
public abstract void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict);
/**
+ * Returns true if this property has a low-level setter handle. This can be used to determine whether a
+ * nasgen-generated accessor property should be treated as non-writable. For user-created accessor properties
+ * {@link #hasSetterFunction(ScriptObject)} should be used to find whether a setter function exists in
+ * a given object.
+ *
+ * @return true if a native setter handle exists
+ */
+ public abstract boolean hasNativeSetter();
+
+ /**
* Abstract method for retrieving the setter for the property. We do not know
* anything about the internal representation when we request the setter, we only
* know that the setter will take the property as a parameter of the given type.
@@ -693,4 +706,12 @@
public boolean hasDualFields() {
return (flags & DUAL_FIELDS) != 0;
}
+
+ /**
+ * Is this an accessor property as defined in ES5 8.6.1?
+ * @return true if this is an accessor property
+ */
+ public boolean isAccessorProperty() {
+ return (flags & IS_ACCESSOR_PROPERTY) != 0;
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Mon Feb 15 17:02:32 2016 +0100
@@ -702,10 +702,8 @@
private boolean allFrozen() {
for (final Property property : properties.getProperties()) {
// check if it is a data descriptor
- if (!(property instanceof UserAccessorProperty)) {
- if (property.isWritable()) {
- return false;
- }
+ if (!property.isAccessorProperty() && property.isWritable()) {
+ return false;
}
if (property.isConfigurable()) {
return false;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Mon Feb 15 17:02:32 2016 +0100
@@ -612,7 +612,7 @@
*
* @param newPrototype new prototype object
*/
- public synchronized final void setPrototype(final Object newPrototype) {
+ public final void setPrototype(final Object newPrototype) {
if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
// Unset allocator map to be replaced with one matching the new prototype.
allocatorMap = null;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Mon Feb 15 17:02:32 2016 +0100
@@ -468,7 +468,7 @@
final boolean enumerable = property.isEnumerable();
final boolean writable = property.isWritable();
- if (property instanceof UserAccessorProperty) {
+ if (property.isAccessorProperty()) {
return global.newAccessorDescriptor(
get != null ?
get :
@@ -910,10 +910,9 @@
}
private void erasePropertyValue(final Property property) {
- // Erase the property field value with undefined. If the property is defined
- // by user-defined accessors, we don't want to call the setter!!
- if (!(property instanceof UserAccessorProperty)) {
- assert property != null;
+ // Erase the property field value with undefined. If the property is an accessor property
+ // we don't want to call the setter!!
+ if (property != null && !property.isAccessorProperty()) {
property.setValue(this, this, UNDEFINED, false);
}
}
@@ -996,7 +995,7 @@
assert gs != null;
//reuse existing getter setter for speed
gs.set(getter, setter);
- if (uc.getFlags() == propertyFlags) {
+ if (uc.getFlags() == (propertyFlags | Property.IS_ACCESSOR_PROPERTY)) {
return oldProperty;
}
newProperty = new UserAccessorProperty(uc.getKey(), propertyFlags, slot);
@@ -2022,7 +2021,7 @@
} else if (!find.isSelf()) {
assert mh.type().returnType().equals(returnType) :
"return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
- if (!(property instanceof UserAccessorProperty)) {
+ if (!property.isAccessorProperty()) {
// Add a filter that replaces the self object with the prototype owning the property.
mh = addProtoFilter(mh, find.getProtoChainLength());
}
@@ -2185,7 +2184,7 @@
FindProperty find = findProperty(name, true, this);
// If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
- if (find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
+ if (find != null && find.isInherited() && !find.getProperty().isAccessorProperty()) {
// We should still check if inherited data property is not writable
if (isExtensible() && !find.getProperty().isWritable()) {
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
@@ -2201,9 +2200,13 @@
if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) {
throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode.
}
- // Existing, non-writable property
+ // Existing, non-writable data property
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
}
+ if (!find.getProperty().hasNativeSetter()) {
+ // Existing accessor property without setter
+ return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.has.no.setter", true);
+ }
} else {
if (!isExtensible()) {
return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
@@ -3040,7 +3043,7 @@
invalidateGlobalConstant(key);
- if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
+ if (f != null && f.isInherited() && !f.getProperty().isAccessorProperty()) {
final boolean isScope = isScopeFlag(callSiteFlags);
// If the start object of the find is not this object it means the property was found inside a
// 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
@@ -3061,12 +3064,14 @@
}
if (f != null) {
- if (!f.getProperty().isWritable()) {
+ if (!f.getProperty().isWritable() || !f.getProperty().hasNativeSetter()) {
if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
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.toString(), ScriptRuntime.safeToString(this));
+ throw typeError(
+ f.getProperty().isAccessorProperty() ? "property.has.no.setter" : "property.not.writable",
+ key.toString(), ScriptRuntime.safeToString(this));
}
return;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Mon Feb 15 17:02:32 2016 +0100
@@ -54,7 +54,7 @@
/**
* Creates a new property setter method creator.
* @param sobj the object for which we're creating the property setter
- * @param find a result of a {@link ScriptObject#findProperty(String, boolean)} on the object for the property we
+ * @param find a result of a {@link ScriptObject#findProperty(Object, boolean)} on the object for the property we
* want to create a setter for. Can be null if the property does not yet exist on the object.
* @param desc the descriptor of the call site that triggered the property setter lookup
* @param request the link request
@@ -66,7 +66,6 @@
this.desc = desc;
this.type = desc.getMethodType().parameterType(1);
this.request = request;
-
}
private String getName() {
@@ -172,7 +171,7 @@
assert property != null;
final MethodHandle boundHandle;
- if (!(property instanceof UserAccessorProperty) && find.isInherited()) {
+ if (!property.isAccessorProperty() && find.isInherited()) {
boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
} else {
boundHandle = methodHandle;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Mon Feb 15 17:02:32 2016 +0100
@@ -119,7 +119,8 @@
* @param slot spill slot
*/
UserAccessorProperty(final Object key, final int flags, final int slot) {
- super(key, flags, slot);
+ // Always set accessor property flag for this class
+ super(key, flags | IS_ACCESSOR_PROPERTY, slot);
}
private UserAccessorProperty(final UserAccessorProperty property) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Mon Feb 15 17:02:32 2016 +0100
@@ -42,7 +42,6 @@
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.UserAccessorProperty;
/**
* Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and
@@ -118,7 +117,7 @@
return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
}
- if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
+ if (find.isInherited() && !(find.getProperty().isAccessorProperty())) {
// If property is found in the prototype object bind the method handle directly to
// the proto filter instead of going through wrapper instantiation below.
final ScriptObject proto = wrappedReceiver.getProto();
@@ -180,9 +179,13 @@
// See ES5.1 8.7.2 PutValue (V, W)
final String name = JSType.toString(key);
final FindProperty find = wrappedSelf.findProperty(name, true);
- if (find == null || !(find.getProperty() instanceof UserAccessorProperty) || !find.getProperty().isWritable()) {
+ if (find == null || !find.getProperty().isAccessorProperty() || !find.getProperty().hasNativeSetter()) {
if (strict) {
- throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self));
+ if (find == null || !find.getProperty().isAccessorProperty()) {
+ throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self));
+ } else {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
}
return;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Mon Feb 15 17:02:32 2016 +0100
@@ -82,6 +82,14 @@
type.error.not.a.function={0} is not a function
type.error.not.a.function.value={0}, which has value {1}, is not a function
type.error.not.a.constructor={0} is not a constructor function
+type.error.not.a.map={0} is not a Map object
+type.error.not.a.set={0} is not a Set object
+type.error.not.a.weak.map={0} is not a WeakMap object
+type.error.not.a.weak.set={0} is not a WeakSet object
+type.error.not.a.map.iterator={0} is not a Map iterator
+type.error.not.a.set.iterator={0} is not a Set iterator
+type.error.not.a.array.iterator={0} is not an Array iterator
+type.error.not.a.string.iterator={0} is not a String iterator
type.error.not.a.file={0} is not a File
type.error.not.a.numeric.array={0} is not a numeric array
type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer
@@ -122,6 +130,7 @@
type.error.assign.constant=Assignment to constant "{0}"
type.error.cannot.get.default.string=Cannot get default string value
type.error.cannot.get.default.number=Cannot get default number value
+type.error.cannot.get.iterator=Cannot get iterator from {1}
type.error.cant.apply.with.to.null=Cannot apply "with" to null
type.error.cant.apply.with.to.undefined=Cannot apply "with" to undefined
type.error.cant.apply.with.to.non.scriptobject=Cannot apply "with" to non script object. Consider using "with(Object.bindProperties('{'}, nonScriptObject))".
@@ -154,7 +163,7 @@
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.invalid.weak.key=primitive 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.
--- a/nashorn/test/script/basic/es6.js Wed Jul 05 21:20:45 2017 +0200
+++ b/nashorn/test/script/basic/es6.js Mon Feb 15 17:02:32 2016 +0100
@@ -28,13 +28,21 @@
* @run
*/
-if (typeof Symbol !== 'undefined' || 'Symbol' in this) {
- Assert.fail('Symbol is defined in global scope');
+function checkUndefined(name, object) {
+ if (typeof object[name] !== 'undefined' || name in object) {
+ Assert.fail(name + ' is defined in ' + object);
+ }
}
-if (typeof Object.getOwnPropertySymbols !== 'undefined' || 'getOwnPropertySymbols' in Object) {
- Assert.fail('getOwnPropertySymbols is defined in global Object');
-}
+checkUndefined('Symbol', this);
+checkUndefined('Map', this);
+checkUndefined('Set', this);
+checkUndefined('WeakMap', this);
+checkUndefined('WeakSet', this);
+checkUndefined('getOwnPropertySymbols', Object);
+checkUndefined('entries', Array.prototype);
+checkUndefined('values', Array.prototype);
+checkUndefined('keys', Array.prototype);
function expectError(src, msg, error) {
try {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/iterator.js Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, 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-8147558: Add support for ES6 collections
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+
+function testIterator(iter, expectedValues) {
+ let next;
+
+ for (var i = 0; i < expectedValues.length; i++) {
+ next = iter.next();
+ Assert.assertTrue(next.done === false);
+
+ if (Array.isArray(expectedValues[i])) {
+ Assert.assertTrue(Array.isArray(next.value));
+ Assert.assertTrue(next.value.length === expectedValues[i].length);
+ Assert.assertTrue(next.value.every(function(v, j) {
+ return v === expectedValues[i][j];
+ }));
+
+ } else {
+ Assert.assertTrue(next.value === expectedValues[i]);
+ }
+ }
+
+ next = iter.next();
+ Assert.assertTrue(next.done === true);
+ Assert.assertTrue(next.value === undefined);
+}
+
+const str = "abcdefg";
+const array = ["a", "b", "c", "d", "e", "f", "g"];
+const arrayKeys = [0, 1, 2, 3, 4, 5, 6];
+const setEntries = [["a", "a"], ["b", "b"], ["c", "c"], ["d", "d"], ["e", "e"], ["f", "f"], ["g", "g"]];
+const mapEntries = [["a", "A"], ["b", "B"], ["c", "C"], ["d", "D"], ["e", "E"], ["f", "F"], ["g", "G"]];
+const mapValues = ["A", "B", "C", "D", "E", "F", "G"];
+const arrayEntries = [[0, "a"], [1, "b"], [2, "c"], [3, "d"], [4, "e"], [5, "f"], [6, "g"]];
+
+// Set iterator tests
+const set = new Set(str);
+testIterator(set[Symbol.iterator](), str);
+testIterator(set.values(), str);
+testIterator(set.keys(), str);
+testIterator(set.entries(), setEntries);
+
+// Map iterator tests
+const map = new Map(mapEntries);
+testIterator(map[Symbol.iterator](), mapEntries);
+testIterator(map.values(), mapValues);
+testIterator(map.keys(), array);
+testIterator(map.entries(), mapEntries);
+
+// String iterator tests
+testIterator(str[Symbol.iterator](), str);
+
+// Array iterator tests
+testIterator(array[Symbol.iterator](), array);
+testIterator(array.values(), array);
+testIterator(array.keys(), arrayKeys);
+testIterator(array.entries(), arrayEntries);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/map.js Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2016, 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-8147558: Add support for ES6 collections
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function assertThrows(src, error) {
+ try {
+ eval(src);
+ Assert.fail("No error, expected " + error);
+ } catch (e) {
+ if (!(e instanceof error)) {
+ Assert.fail("Wrong error, expected " + error + " but got " + e);
+ }
+ }
+}
+
+// Map constructor and prototype
+
+var desc = Object.getOwnPropertyDescriptor(this, "Map");
+Assert.assertEquals(desc.writable, true);
+Assert.assertEquals(desc.configurable, true);
+Assert.assertEquals(desc.enumerable, false);
+
+Assert.assertTrue(Object.getPrototypeOf(new Map()) === Map.prototype);
+Assert.assertTrue(Object.getPrototypeOf(Map.prototype) === Object.prototype);
+Assert.assertTrue(new Map().size === 0);
+Assert.assertTrue(Object.getPrototypeOf(new Map([["a", 1], ["b", 2]])) === Map.prototype);
+Assert.assertTrue(new Map([["a", 1], ["b", 2]]).size === 2);
+Assert.assertTrue(Object.getPrototypeOf(new Map("")) === Map.prototype);
+Assert.assertTrue(new Map("").size === 0);
+Assert.assertTrue(Object.getPrototypeOf(new Map([])) === Map.prototype);
+Assert.assertTrue(new Map([]).size === 0);
+
+assertThrows("Map()", TypeError);
+assertThrows("new Map(3)", TypeError);
+assertThrows("new Map('abc')", TypeError);
+assertThrows("new Map({})", TypeError);
+assertThrows("new Map([1, 2, 3])", TypeError);
+
+assertThrows("Map.prototype.set.apply({}, ['', ''])", TypeError);
+assertThrows("Map.prototype.get.apply([], [''])", TypeError);
+assertThrows("Map.prototype.has.apply(3, [''])", TypeError);
+assertThrows("Map.prototype.clear.apply('', [])", TypeError);
+
+// Map methods
+
+var m = new Map([["a", 1], ["b", 2]]);
+Assert.assertTrue(m.size, 2);
+Assert.assertTrue(m.get("a") === 1);
+Assert.assertTrue(m.get("b") === 2);
+Assert.assertTrue(m.get("c") === undefined);
+Assert.assertTrue(m.has("a") === true);
+Assert.assertTrue(m.has("b") === true);
+Assert.assertTrue(m.has("c") === false);
+
+m.clear();
+Assert.assertTrue(m.size === 0);
+Assert.assertTrue(m.get("a") === undefined);
+Assert.assertTrue(m.get("b") === undefined);
+Assert.assertTrue(m.get("c") === undefined);
+Assert.assertTrue(m.has("a") === false);
+Assert.assertTrue(m.has("b") === false);
+Assert.assertTrue(m.has("c") === false);
+
+var a = "a", x = "x"; // for ConsString keys
+Assert.assertTrue(m.set("ab", false) === m);
+Assert.assertTrue(m.set(x + "y", m) === m);
+Assert.assertTrue(m.get(a + "b") === false);
+Assert.assertTrue(m.get("xy") === m);
+Assert.assertTrue(m.has(a + "b") === true);
+Assert.assertTrue(m.has("xy") === true);
+
+// Special keys
+
+m = new Map();
+Assert.assertTrue(m.set(NaN, NaN) === m); // NaN should work as key
+Assert.assertTrue(m.size === 1);
+Assert.assertTrue(isNaN(m.get(NaN)));
+Assert.assertTrue(isNaN(m.keys().next().value));
+Assert.assertTrue(isNaN(m.values().next().value));
+Assert.assertTrue(m.has(NaN) === true);
+Assert.assertTrue(m.delete(NaN));
+Assert.assertTrue(m.size === 0);
+Assert.assertTrue(m.get(NaN) === undefined);
+Assert.assertTrue(m.keys().next().done);
+Assert.assertTrue(m.values().next().done);
+Assert.assertTrue(m.has(NaN) === false);
+
+m.clear();
+m.set(-0, -0); // -0 key should be converted to +0
+Assert.assertTrue(m.size === 1);
+Assert.assertTrue(m.get(-0) === 0);
+Assert.assertTrue(1 / m.keys().next().value === Infinity);
+Assert.assertTrue(1 / m.values().next().value === -Infinity);
+Assert.assertTrue(m.has(-0) === true);
+Assert.assertTrue(m.has(0) === true);
+Assert.assertTrue(m.delete(-0));
+Assert.assertTrue(m.size === 0);
+Assert.assertTrue(m.get(-0) === undefined);
+Assert.assertTrue(m.get(0) === undefined);
+Assert.assertTrue(m.has(-0) === false);
+Assert.assertTrue(m.has(0) === false);
+
+Assert.assertFalse(m.delete("foo"));
+Assert.assertFalse(m.delete(0));
+Assert.assertFalse(m.delete(NaN));
+
+// foreach
+
+m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
+m.forEach(function(value, key, map) {
+ Assert.assertTrue(this === m);
+ Assert.assertTrue(map === m);
+}, m);
+
+function assertEqualArrays(a, b) {
+ Assert.assertTrue(Array.isArray(a));
+ Assert.assertTrue(Array.isArray(b));
+ Assert.assertTrue(a.length === b.length);
+ Assert.assertTrue(a.every(function(v, j) {
+ return v === b[j];
+ }));
+}
+
+let array = [];
+m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
+m.forEach(function(value, key, map) {
+ array.push(value);
+});
+assertEqualArrays(array, ["one", "two", "three"]);
+
+array = [];
+m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
+m.forEach(function(value, key, map) {
+ array.push(value);
+ if (key == 3) {
+ map.clear();
+ map.set(4, "four");
+ }
+});
+assertEqualArrays(array, ["one", "two", "three", "four"]);
+
+array = [];
+m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
+m.forEach(function(value, key, map) {
+ array.push(value);
+ if (key == 1) {
+ map.delete(1);
+ }
+ if (key == 2) {
+ map.delete(3);
+ }
+});
+assertEqualArrays(array, ["one", "two"]);
+
+array = [];
+m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
+m.forEach(function(value, key, map) {
+ array.push(value);
+ if (array.length < 4) {
+ map.delete(key);
+ map.set(key, key + 3)
+ }
+});
+assertEqualArrays(array, ["one", "two", "three", 4, 5, 6]);
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/set.js Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2016, 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-8147558: Add support for ES6 collections
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function assertThrows(src, error) {
+ try {
+ eval(src);
+ Assert.fail("No error, expected " + error);
+ } catch (e) {
+ if (!(e instanceof error)) {
+ Assert.fail("Wrong error, expected " + error + " but got " + e);
+ }
+ }
+}
+
+// Set constructor and prototype
+
+var desc = Object.getOwnPropertyDescriptor(this, "Set");
+Assert.assertEquals(desc.writable, true);
+Assert.assertEquals(desc.configurable, true);
+Assert.assertEquals(desc.enumerable, false);
+
+Assert.assertTrue(Object.getPrototypeOf(new Set()) === Set.prototype);
+Assert.assertTrue(Object.getPrototypeOf(Set.prototype) === Object.prototype);
+Assert.assertTrue(new Set().size === 0);
+Assert.assertTrue(Object.getPrototypeOf(new Set(["a", 3, false])) === Set.prototype);
+Assert.assertTrue(new Set(["a", 3, false]).size === 3);
+Assert.assertTrue(new Set("abc").size === 3);
+Assert.assertTrue(new Set("").size === 0);
+Assert.assertTrue(new Set([]).size === 0);
+
+assertThrows("Set()", TypeError);
+assertThrows("new Set(3)", TypeError);
+assertThrows("new Set({})", TypeError);
+
+assertThrows("Set.prototype.add.apply({}, [''])", TypeError);
+assertThrows("Set.prototype.has.apply(3, [''])", TypeError);
+assertThrows("Set.prototype.delete.apply('', [3])", TypeError);
+
+// Set methods
+
+var s = new Set(["a", 3, false]);
+Assert.assertTrue(s.size, 2);
+Assert.assertTrue(s.has("a") === true);
+Assert.assertTrue(s.has(3) === true);
+Assert.assertTrue(s.has(false) === true);
+
+Assert.assertTrue(s.clear() === undefined);
+Assert.assertTrue(s.size === 0);
+Assert.assertTrue(s.has("a") === false);
+Assert.assertTrue(s.has(3) === false);
+Assert.assertTrue(s.has(false) === false);
+
+var a = "a", x = "x"; // for ConsString keys
+Assert.assertTrue(s.add("ab", false) === s);
+Assert.assertTrue(s.add(x + "y", s) === s);
+Assert.assertTrue(s.has(a + "b") === true);
+Assert.assertTrue(s.has("xy") === true);
+
+// Special keys
+
+s.clear()
+Assert.assertTrue(s.add(NaN) === s); // NaN should work as key
+Assert.assertTrue(s.size === 1);
+Assert.assertTrue(isNaN(s.keys().next().value));
+Assert.assertTrue(isNaN(s.values().next().value));
+Assert.assertTrue(s.has(NaN) === true);
+Assert.assertTrue(s.delete(NaN) === true);
+Assert.assertTrue(s.size === 0);
+Assert.assertTrue(s.keys().next().done);
+Assert.assertTrue(s.values().next().done);
+Assert.assertTrue(s.has(NaN) === false);
+
+s.clear()
+s.add(-0); // -0 key should be converted to +0
+Assert.assertTrue(s.size === 1);
+Assert.assertTrue(1 / s.keys().next().value === Infinity);
+Assert.assertTrue(1 / s.values().next().value === Infinity);
+Assert.assertTrue(s.has(-0) === true);
+Assert.assertTrue(s.has(0) === true);
+Assert.assertTrue(s.delete(-0) === true);
+Assert.assertTrue(s.size === 0);
+Assert.assertTrue(s.has(-0) === false);
+Assert.assertTrue(s.has(0) === false);
+
+// foreach
+
+s = new Set([1, 2, 3]);
+
+s.forEach(function(value, key, set) {
+ Assert.assertTrue(this === s);
+ Assert.assertTrue(set === s);
+}, s);
+
+function assertEqualArrays(a, b) {
+ Assert.assertTrue(Array.isArray(a));
+ Assert.assertTrue(Array.isArray(b));
+ Assert.assertTrue(a.length === b.length);
+ Assert.assertTrue(a.every(function(v, j) {
+ return v === b[j];
+ }));
+}
+
+let array = [];
+s = new Set([1, 2, 3]);
+s.forEach(function(value, key, set) {
+ array.push(value);
+});
+assertEqualArrays(array, [1, 2, 3]);
+
+array = [];
+s = new Set([1, 2, 3]);
+s.forEach(function(value, key, set) {
+ array.push(value);
+ if (key == 3) {
+ set.clear();
+ set.add("four");
+ }
+});
+assertEqualArrays(array, [1, 2, 3, "four"]);
+
+array = [];
+s = new Set([1, 2, 3]);
+s.forEach(function(value, key, set) {
+ array.push(value);
+ if (key == 1) {
+ set.delete(1);
+ }
+ if (key == 2) {
+ set.delete(3);
+ }
+});
+assertEqualArrays(array, [1, 2]);
+
+array = [];
+s = new Set([1, 2, 3]);
+s.forEach(function(value, key, set) {
+ array.push(value);
+ if (key < 4) {
+ set.delete(key);
+ set.add(key + 3)
+ }
+});
+assertEqualArrays(array, [1, 2, 3, 4, 5, 6]);
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/weakmap.js Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, 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-8147558: Add support for ES6 collections
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function assertThrows(src, error) {
+ try {
+ eval(src);
+ Assert.fail("No error, expected " + error);
+ } catch (e) {
+ if (!(e instanceof error)) {
+ Assert.fail("Wrong error, expected " + error + " but got " + e);
+ }
+ }
+}
+
+// WeakMap constructor and prototype
+
+var desc = Object.getOwnPropertyDescriptor(this, "WeakMap");
+Assert.assertEquals(desc.writable, true);
+Assert.assertEquals(desc.configurable, true);
+Assert.assertEquals(desc.enumerable, false);
+
+Assert.assertTrue(Object.getPrototypeOf(new WeakMap()) === WeakMap.prototype);
+Assert.assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype);
+Assert.assertTrue(Object.getPrototypeOf(new WeakMap("")) === WeakMap.prototype);
+Assert.assertTrue(Object.getPrototypeOf(new WeakMap([])) === WeakMap.prototype);
+
+assertThrows("WeakMap()", TypeError);
+assertThrows("new WeakMap(3)", TypeError);
+assertThrows("new WeakMap({})", TypeError);
+assertThrows("new WeakMap([['a', {}]])", TypeError);
+assertThrows("new WeakMap([[3, {}]])", TypeError);
+assertThrows("new WeakMap([[true, {}]])", TypeError);
+assertThrows("new WeakMap([[Symbol.iterator, {}]])", TypeError);
+
+assertThrows("WeakMap.prototype.set.apply({}, [{}, {}])", TypeError);
+assertThrows("WeakMap.prototype.has.apply(3, [{}])", TypeError);
+assertThrows("WeakMap.prototype.delete.apply('', [3])", TypeError);
+
+// WeakMap methods
+
+let values = [[{}, 1], [{}, 2], [{}, 3]];
+let m = new WeakMap(values);
+
+for (let i = 0; i < values.length; i++) {
+ Assert.assertTrue(m.has(values[i][0]) === true);
+ Assert.assertTrue(m.get(values[i][0]) === values[i][1]);
+ Assert.assertTrue(m.delete(values[i][0]) === true);
+ Assert.assertTrue(m.has(values[i][0]) === false);
+}
+
+values.forEach(function(v) {
+ Assert.assertTrue(m.set(v[0], v[1]) === m);
+});
+
+for (let i = 0; i < values.length; i++) {
+ Assert.assertTrue(m.has(values[i][0]) === true);
+ Assert.assertTrue(m.get(values[i][0]) === values[i][1]);
+ Assert.assertTrue(m.delete(values[i][0]) === true);
+ Assert.assertTrue(m.has(values[i][0]) === false);
+}
+
+// Primitive keys
+
+assertThrows("m.set('a', {})", TypeError);
+assertThrows("m.set(3, {})", TypeError);
+assertThrows("m.set(false, {})", TypeError);
+assertThrows("m.set(Symbol.iterator, {})", TypeError);
+
+Assert.assertTrue(m.has('a') === false);
+Assert.assertTrue(m.delete(3) === false);
+Assert.assertTrue(m.get(Symbol.iterator) === undefined);
+Assert.assertTrue(m.get(true) === undefined);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/weakset.js Mon Feb 15 17:02:32 2016 +0100
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, 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-8147558: Add support for ES6 collections
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function assertThrows(src, error) {
+ try {
+ eval(src);
+ Assert.fail("No error, expected " + error);
+ } catch (e) {
+ if (!(e instanceof error)) {
+ Assert.fail("Wrong error, expected " + error + " but got " + e);
+ }
+ }
+}
+
+// WeakSet constructor and prototype
+
+var desc = Object.getOwnPropertyDescriptor(this, "WeakSet");
+Assert.assertEquals(desc.writable, true);
+Assert.assertEquals(desc.configurable, true);
+Assert.assertEquals(desc.enumerable, false);
+
+Assert.assertTrue(Object.getPrototypeOf(new WeakSet()) === WeakSet.prototype);
+Assert.assertTrue(Object.getPrototypeOf(WeakSet.prototype) === Object.prototype);
+Assert.assertTrue(Object.getPrototypeOf(new WeakSet("")) === WeakSet.prototype);
+Assert.assertTrue(Object.getPrototypeOf(new WeakSet([])) === WeakSet.prototype);
+
+assertThrows("WeakSet()", TypeError);
+assertThrows("new WeakSet(3)", TypeError);
+assertThrows("new WeakSet({})", TypeError);
+assertThrows("new WeakSet(['a'])", TypeError);
+assertThrows("new WeakSet([3])", TypeError);
+assertThrows("new WeakSet([true])", TypeError);
+assertThrows("new WeakSet([Symbol.iterator])", TypeError);
+
+assertThrows("WeakSet.prototype.add.apply({}, [''])", TypeError);
+assertThrows("WeakSet.prototype.has.apply(3, [''])", TypeError);
+assertThrows("WeakSet.prototype.delete.apply('', [3])", TypeError);
+
+// WeakSet methods
+
+let values = [{}, {}, {}];
+let s = new WeakSet(values);
+
+for (let i = 0; i < values.length; i++) {
+ Assert.assertTrue(s.has(values[i]) === true);
+ Assert.assertTrue(s.delete(values[i]) === true);
+ Assert.assertTrue(s.has(values[i]) === false);
+}
+
+values.forEach(function(v) {
+ Assert.assertTrue(s.add(v) === s);
+});
+
+for (let i = 0; i < values.length; i++) {
+ Assert.assertTrue(s.has(values[i]) === true);
+ Assert.assertTrue(s.delete(values[i]) === true);
+ Assert.assertTrue(s.has(values[i]) === false);
+}
+
+// Primitive keys
+
+assertThrows("s.add('a')", TypeError);
+assertThrows("s.add(3)", TypeError);
+assertThrows("s.add(false)", TypeError);
+assertThrows("s.add(Symbol.iterator)", TypeError);
+
+Assert.assertTrue(s.has('a') === false);
+Assert.assertTrue(s.delete(3) === false);
+Assert.assertTrue(s.has(Symbol.iterator) === false);
+Assert.assertTrue(s.delete(true) === false);
+
+