8147558: Add support for ES6 collections
authorhannesw
Mon, 15 Feb 2016 17:02:32 +0100
changeset 36023 528cc67f1289
parent 35814 6c644cca3f3f
child 36024 1a7614804158
8147558: Add support for ES6 collections Reviewed-by: attila, mhaupt
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/AbstractIterator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/IteratorResult.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/LinkedMap.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/MapIterator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeMap.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSet.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeWeakMap.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeWeakSet.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/SetIterator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/StringIterator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Attribute.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
nashorn/test/script/basic/es6.js
nashorn/test/script/basic/es6/iterator.js
nashorn/test/script/basic/es6/map.js
nashorn/test/script/basic/es6/set.js
nashorn/test/script/basic/es6/weakmap.js
nashorn/test/script/basic/es6/weakset.js
--- 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);
+
+