Bug 918828, part 2 - Change iteration code to call iterable[Symbol.iterator]() rather than iterable["@@iterator"](). r=nbp.
☠☠ backed out by bb579e3de64b ☠ ☠
authorJason Orendorff <jorendorff@mozilla.com>
Tue, 01 Jul 2014 21:01:21 -0500
changeset 205654 621224c58e71fec5fad0ff270fe348be1b1bd560
parent 205653 4faff84eb1bac1fadf215cb05e161f6ae868ebb7
child 205655 b87ca498ea9a1641fa48868a7f7b02ae24618cd9
push id27498
push userkwierso@gmail.com
push dateWed, 17 Sep 2014 00:06:56 +0000
treeherdermozilla-central@8252eae8278c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs918828
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 918828, part 2 - Change iteration code to call iterable[Symbol.iterator]() rather than iterable["@@iterator"](). r=nbp.
addon-sdk/source/lib/sdk/util/iteration.js
browser/components/customizableui/CustomizableUI.jsm
browser/devtools/debugger/debugger-panes.js
browser/devtools/framework/gDevTools.jsm
browser/devtools/shared/widgets/VariablesView.jsm
browser/devtools/shared/widgets/ViewHelpers.jsm
content/html/content/test/test_formelements.html
content/html/content/test/test_htmlcollection.html
content/html/content/test/test_named_options.html
content/html/content/test/test_rowscollection.html
dom/bindings/Codegen.py
js/src/builtin/Array.js
js/src/builtin/MapObject.cpp
js/src/builtin/Utilities.js
js/src/frontend/BytecodeEmitter.cpp
js/src/jit-test/lib/iteration.js
js/src/jit-test/tests/arguments/destructuring-exprbody.js
js/src/jit-test/tests/basic/expression-autopsy.js
js/src/jit-test/tests/collections/WeakSet-error.js
js/src/jit-test/tests/collections/iterator-proto-surfaces.js
js/src/jit-test/tests/for-of/next-3.js
js/src/jit-test/tests/for-of/semantics-08.js
js/src/jit-test/tests/for-of/string-iterator-surfaces.js
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsiter.cpp
js/src/jsstr.cpp
js/src/tests/ecma_6/Array/for_of_2.js
js/src/tests/ecma_6/Array/for_of_3.js
js/src/tests/ecma_6/Array/for_of_4.js
js/src/tests/ecma_6/Array/from_errors.js
js/src/tests/ecma_6/Array/from_iterable.js
js/src/tests/ecma_6/Array/from_proxy.js
js/src/tests/ecma_6/Array/from_string.js
js/src/tests/ecma_6/Generators/runtime.js
js/src/tests/ecma_6/Symbol/property-reflection.js
js/src/tests/js1_8/regress/regress-469625-03.js
js/src/vm/CommonPropertyNames.h
js/src/vm/Interpreter.cpp
js/src/vm/Opcodes.h
js/src/vm/PIC.cpp
js/src/vm/PIC.h
js/src/vm/SelfHosting.cpp
js/src/vm/TypedArrayObject.cpp
js/xpconnect/tests/chrome/test_xrayToJS.xul
toolkit/modules/Promise-backend.js
--- a/addon-sdk/source/lib/sdk/util/iteration.js
+++ b/addon-sdk/source/lib/sdk/util/iteration.js
@@ -2,30 +2,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "experimental"
 };
 
-// This is known as @@iterator in the ES6 spec.  Until it is bound to
-// some well-known name, find the @@iterator object by expecting it as
-// the first property accessed on a for-of iterable.
-const iteratorSymbol = (function() {
-  try {
-    for (var _ of Proxy.create({get: function(_, name) { throw name; } }))
-      break;
-  } catch (name) {
-    return name;
-  }
-  throw new TypeError;
-})();
-
-exports.iteratorSymbol = iteratorSymbol;
+// Legacy binding for Symbol.iterator. (This export existed before Symbols were
+// implemented in the JS engine.)
+exports.iteratorSymbol = Symbol.iterator;
 
 // An adaptor that, given an object that is iterable with for-of, is
 // suitable for being bound to __iterator__ in order to make the object
 // iterable in the same way via for-in.
 function forInIterator() {
     for (let item of this)
         yield item;
 }
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -2657,17 +2657,17 @@ this.CustomizableUI = {
 
 
   /**
    * An iteratable property of windows managed by CustomizableUI.
    * Note that this can *only* be used as an iterator. ie:
    *     for (let window of CustomizableUI.windows) { ... }
    */
   windows: {
-    "@@iterator": function*() {
+    *[Symbol.iterator]() {
       for (let [window,] of gBuildWindows)
         yield window;
     }
   },
 
   /**
    * Add a listener object that will get fired for various events regarding
    * customization.
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -3256,19 +3256,19 @@ LineResults.prototype = {
   _sourceResults: null,
   _store: null,
   _target: null
 };
 
 /**
  * A generator-iterator over the global, source or line results.
  */
-GlobalResults.prototype["@@iterator"] =
-SourceResults.prototype["@@iterator"] =
-LineResults.prototype["@@iterator"] = function*() {
+GlobalResults.prototype[Symbol.iterator] =
+SourceResults.prototype[Symbol.iterator] =
+LineResults.prototype[Symbol.iterator] = function*() {
   yield* this._store;
 };
 
 /**
  * Gets the item associated with the specified element.
  *
  * @param nsIDOMNode aElement
  *        The element used to identify the item.
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -470,24 +470,24 @@ DevTools.prototype = {
     for (let [key, tool] of this.getToolDefinitionMap()) {
       this.unregisterTool(key, true);
     }
 
     // Cleaning down the toolboxes: i.e.
     //   for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
     // Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
   },
+};
 
-  /**
-   * Iterator that yields each of the toolboxes.
-   */
-  '@@iterator': function*() {
-    for (let toolbox of this._toolboxes) {
-      yield toolbox;
-    }
+/**
+ * Iterator that yields each of the toolboxes.
+ */
+Devtools.prototype[Symbol.iterator] = function*() {
+  for (let toolbox of this._toolboxes) {
+    yield toolbox;
   }
 };
 
 /**
  * gDevTools is a singleton that controls the Firefox Developer Tools.
  *
  * It is an instance of a DevTools class that holds a set of tools. It has the
  * same lifetime as the browser.
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -3051,20 +3051,20 @@ Property.prototype = Heritage.extend(Var
     this._absoluteName = this.ownerView.absoluteName + "[\"" + this._nameString + "\"]";
     return this._absoluteName;
   }
 });
 
 /**
  * A generator-iterator over the VariablesView, Scopes, Variables and Properties.
  */
-VariablesView.prototype["@@iterator"] =
-Scope.prototype["@@iterator"] =
-Variable.prototype["@@iterator"] =
-Property.prototype["@@iterator"] = function*() {
+VariablesView.prototype[Symbol.iterator] =
+Scope.prototype[Symbol.iterator] =
+Variable.prototype[Symbol.iterator] =
+Property.prototype[Symbol.iterator] = function*() {
   yield* this._store;
 };
 
 /**
  * Forget everything recorded about added scopes, variables or properties.
  * @see VariablesView.commitHierarchy
  */
 VariablesView.prototype.clearHierarchy = function() {
--- a/browser/devtools/shared/widgets/ViewHelpers.jsm
+++ b/browser/devtools/shared/widgets/ViewHelpers.jsm
@@ -1724,12 +1724,12 @@ this.WidgetMethods = {
   _headerText: "",
   _preferredValue: "",
   _cachedCommandDispatcher: null
 };
 
 /**
  * A generator-iterator over all the items in this container.
  */
-Item.prototype["@@iterator"] =
-WidgetMethods["@@iterator"] = function*() {
+Item.prototype[Symbol.iterator] =
+WidgetMethods[Symbol.iterator] = function*() {
   yield* this._itemsByElement.values();
 };
--- a/content/html/content/test/test_formelements.html
+++ b/content/html/content/test/test_formelements.html
@@ -27,27 +27,26 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 772869 **/
 var x = $("f").elements;
 x.something = "another";
 names = [];
 for (var name in x) {
   names.push(name);
 }
-is(names.length, 10, "Should have 10 enumerated names");
+is(names.length, 9, "Should have 9 enumerated names");
 is(names[0], "0", "Enum entry 1");
 is(names[1], "1", "Enum entry 2");
 is(names[2], "2", "Enum entry 3");
 is(names[3], "3", "Enum entry 4");
 is(names[4], "4", "Enum entry 5");
 is(names[5], "something", "Enum entry 6");
 is(names[6], "namedItem", "Enum entry 7");
 is(names[7], "item", "Enum entry 8");
-is(names[8], "@@iterator", "Enum entry 9");
-is(names[9], "length", "Enum entry 10");
+is(names[8], "length", "Enum entry 9");
 
 names = Object.getOwnPropertyNames(x);
 is(names.length, 10, "Should have 10 items");
 // Now sort entries 5 through 8, for comparison purposes.  We don't sort the
 // whole array, because we want to make sure the ordering between the parts
 // is correct
 temp = names.slice(5, 9);
 temp.sort();
--- a/content/html/content/test/test_htmlcollection.html
+++ b/content/html/content/test/test_htmlcollection.html
@@ -23,26 +23,25 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 772869 **/
 var x = document.getElementsByClassName("foo");
 x.something = "another";
 var names = [];
 for (var name in x) {
   names.push(name);
 }
-is(names.length, 9, "Should have 9 enumerated names");
+is(names.length, 8, "Should have 8 enumerated names");
 is(names[0], "0", "Enum entry 1")
 is(names[1], "1", "Enum entry 2")
 is(names[2], "2", "Enum entry 3")
 is(names[3], "3", "Enum entry 4")
 is(names[4], "something", "Enum entry 5")
 is(names[5], "item", "Enum entry 6")
 is(names[6], "namedItem", "Enum entry 7")
-is(names[7], "@@iterator", "Enum entry 8")
-is(names[8], "length", "Enum entry 9")
+is(names[7], "length", "Enum entry 8")
 
 names = Object.getOwnPropertyNames(x);
 is(names.length, 9, "Should have 9 items");
 is(names[0], "0", "Entry 1")
 is(names[1], "1", "Entry 2")
 is(names[2], "2", "Entry 3")
 is(names[3], "3", "Entry 4")
 is(names[4], "x", "Entry 5")
--- a/content/html/content/test/test_named_options.html
+++ b/content/html/content/test/test_named_options.html
@@ -37,26 +37,25 @@ is(names[5], "y", "Entry 6")
 is(names[6], "z", "Entry 7")
 is(names[7], "w", "Entry 8")
 is(names[8], "loopy", "Entry 9")
 
 var names2 = [];
 for (var name in opt) {
   names2.push(name);
 }
-is(names2.length, 12, "Should have twelve enumerated names");
+is(names2.length, 11, "Should have eleven enumerated names");
 is(names2[0], "0", "Enum entry 1")
 is(names2[1], "1", "Enum entry 2")
 is(names2[2], "2", "Enum entry 3")
 is(names2[3], "3", "Enum entry 4")
 is(names2[4], "loopy", "Enum entry 5")
 is(names2[5], "add", "Enum entrry 6")
 is(names2[6], "remove", "Enum entry 7")
 is(names2[7], "length", "Enum entry 8")
 is(names2[8], "selectedIndex", "Enum entry 9")
 is(names2[9], "item", "Enum entry 10")
 is(names2[10], "namedItem", "Enum entry 11")
-is(names2[11], "@@iterator", "Enum entry 12")
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_rowscollection.html
+++ b/content/html/content/test/test_rowscollection.html
@@ -33,28 +33,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 772869 **/
 var x = $("f").rows;
 x.something = "another";
 var names = [];
 for (var name in x) {
   names.push(name);
 }
-is(names.length, 11, "Should have 11 enumerated names");
+is(names.length, 10, "Should have 10 enumerated names");
 is(names[0], "0", "Enum entry 1")
 is(names[1], "1", "Enum entry 2")
 is(names[2], "2", "Enum entry 3")
 is(names[3], "3", "Enum entry 4")
 is(names[4], "4", "Enum entry 5")
 is(names[5], "5", "Enum entry 6")
 is(names[6], "something", "Enum entry 7")
 is(names[7], "item", "Enum entry 8")
 is(names[8], "namedItem", "Enum entry 9")
-is(names[9], "@@iterator", "Enum entry 10")
-is(names[10], "length", "Enum entry 11")
+is(names[9], "length", "Enum entry 10")
 
 names = Object.getOwnPropertyNames(x);
 is(names.length, 11, "Should have 11 items");
 is(names[0], "0", "Entry 1")
 is(names[1], "1", "Entry 2")
 is(names[2], "2", "Entry 3")
 is(names[3], "3", "Entry 4")
 is(names[4], "4", "Entry 5")
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1937,37 +1937,38 @@ class PropertyDefiner:
     def getControllingCondition(interfaceMember, descriptor):
         return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember,
                                                              "Pref"),
                                PropertyDefiner.getStringAttr(interfaceMember,
                                                              "Func"),
                                getAvailableInTestFunc(interfaceMember),
                                descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
 
-    def generatePrefableArray(self, array, name, specTemplate, specTerminator,
+    def generatePrefableArray(self, array, name, specFormatter, specTerminator,
                               specType, getCondition, getDataTuple, doIdArrays):
         """
         This method generates our various arrays.
 
         array is an array of interface members as passed to generateArray
 
         name is the name as passed to generateArray
 
-        specTemplate is a template for each entry of the spec array
+        specFormatter is a function that takes a single argument, a tuple,
+          and returns a string, a spec array entry
 
         specTerminator is a terminator for the spec array (inserted every time
           our controlling pref changes and at the end of the array)
 
         specType is the actual typename of our spec
 
         getCondition is a callback function that takes an array entry and
           returns the corresponding MemberCondition.
 
         getDataTuple is a callback function that takes an array entry and
-          returns a tuple suitable for substitution into specTemplate.
+          returns a tuple suitable to be passed to specFormatter.
         """
 
         # We want to generate a single list of specs, but with specTerminator
         # inserted at every point where the pref name controlling the member
         # changes.  That will make sure the order of the properties as exposed
         # on the interface and interface prototype objects does not change when
         # pref control is added to members while still allowing us to define all
         # the members in the smallest number of JSAPI calls.
@@ -2000,17 +2001,17 @@ class PropertyDefiner:
             curCondition = getCondition(member, self.descriptor)
             if lastCondition != curCondition:
                 # Terminate previous list
                 specs.append(specTerminator)
                 # And switch to our new pref
                 switchToCondition(self, curCondition)
                 lastCondition = curCondition
             # And the actual spec
-            specs.append(specTemplate % getDataTuple(member))
+            specs.append(specFormatter(getDataTuple(member)))
         specs.append(specTerminator)
         prefableSpecs.append("  { false, nullptr }")
 
         specType = "const " + specType
         arrays = fill(
             """
             static ${specType} ${name}_specs[] = {
             ${specs}
@@ -2274,19 +2275,25 @@ class MethodDefiner(PropertyDefiner):
                     if m.get("returnsPromise", False):
                         jitinfo = "&%s_methodinfo" % accessor
                         accessor = "StaticMethodPromiseWrapper"
                     else:
                         jitinfo = "nullptr"
 
             return (m["name"], accessor, jitinfo, m["length"], flags(m), selfHostedName)
 
+        def formatSpec(fields):
+            if fields[0].startswith("@@"):
+                fields = (fields[0][2:],) + fields[1:]
+                return '  JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
+            return '  JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
+
         return self.generatePrefableArray(
             array, name,
-            '  JS_FNSPEC("%s", %s, %s, %s, %s, %s)',
+            formatSpec,
             '  JS_FS_END',
             'JSFunctionSpec',
             condition, specData, doIdArrays)
 
 
 def IsCrossOriginWritable(attr, descriptor):
     """
     Return whether the IDLAttribute in question is cross-origin writable on the
@@ -2379,17 +2386,17 @@ class AttrDefiner(PropertyDefiner):
                    (accessor, jitinfo)
 
         def specData(attr):
             return (attr.identifier.name, flags(attr), getter(attr),
                     setter(attr))
 
         return self.generatePrefableArray(
             array, name,
-            '  { "%s", %s, %s, %s}',
+            lambda fields: '  { "%s", %s, %s, %s}' % fields,
             '  JS_PS_END',
             'JSPropertySpec',
             PropertyDefiner.getControllingCondition, specData, doIdArrays)
 
 
 class ConstDefiner(PropertyDefiner):
     """
     A class for definining constants on the interface object
@@ -2407,17 +2414,17 @@ class ConstDefiner(PropertyDefiner):
             return ""
 
         def specData(const):
             return (const.identifier.name,
                     convertConstIDLValueToJSVal(const.value))
 
         return self.generatePrefableArray(
             array, name,
-            '  { "%s", %s }',
+            lambda fields: '  { "%s", %s }' % fields,
             '  { 0, JS::UndefinedValue() }',
             'ConstantSpec',
             PropertyDefiner.getControllingCondition, specData, doIdArrays)
 
 
 class PropertyArrays():
     def __init__(self, descriptor):
         self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -673,17 +673,17 @@ function ArrayFrom(arrayLike, mapfn=unde
     var mapping = (mapfn !== undefined);
     if (mapping && !IsCallable(mapfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
 
     // All elements defined by this algorithm have the same attrs:
     var attrs = ATTR_CONFIGURABLE | ATTR_ENUMERABLE | ATTR_WRITABLE;
 
     // Steps 6-8.
-    var usingIterator = items["@@iterator"];
+    var usingIterator = items[std_iterator];
     if (usingIterator !== undefined) {
         // Steps 8.a-c.
         var A = IsConstructor(C) ? new C() : [];
 
         // Steps 8.d-e.
         var iterator = callFunction(usingIterator, items);
 
         // Step 8.f.
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -871,17 +871,17 @@ const Class MapIteratorObject::class_ = 
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     MapIteratorObject::finalize
 };
 
 const JSFunctionSpec MapIteratorObject::methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
 
 inline ValueMap::Range *
 MapIteratorObject::range()
 {
     return static_cast<ValueMap::Range *>(getSlot(RangeSlot).toPrivate());
@@ -1069,17 +1069,18 @@ MapObject::initClass(JSContext *cx, JSOb
     if (proto) {
         // Define the "entries" method.
         JSFunction *fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
         if (!fun)
             return nullptr;
 
         // Define its alias.
         RootedValue funval(cx, ObjectValue(*fun));
-        if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
+        RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+        if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
             return nullptr;
     }
     return proto;
 }
 
 template <class Range>
 static void
 MarkKey(Range &r, const HashableValue &key, JSTracer *trc)
@@ -1519,17 +1520,17 @@ const Class SetIteratorObject::class_ = 
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     SetIteratorObject::finalize
 };
 
 const JSFunctionSpec SetIteratorObject::methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
 
 inline ValueSet::Range *
 SetIteratorObject::range()
 {
     return static_cast<ValueSet::Range *>(getSlot(RangeSlot).toPrivate());
@@ -1692,17 +1693,18 @@ SetObject::initClass(JSContext *cx, JSOb
         JSFunction *fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
         if (!fun)
             return nullptr;
 
         // Define its aliases.
         RootedValue funval(cx, ObjectValue(*fun));
         if (!JS_DefineProperty(cx, proto, "keys", funval, 0))
             return nullptr;
-        if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
+        RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+        if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
             return nullptr;
     }
     return proto;
 }
 
 
 bool
 SetObject::keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys)
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -78,17 +78,17 @@ var std_String_toUpperCase = String.prot
 var std_WeakMap = WeakMap;
 var std_WeakMap_get = WeakMap.prototype.get;
 var std_WeakMap_has = WeakMap.prototype.has;
 var std_WeakMap_set = WeakMap.prototype.set;
 var std_WeakMap_clear = WeakMap.prototype.clear;
 var std_WeakMap_delete = WeakMap.prototype.delete;
 var std_Map_has = Map.prototype.has;
 var std_Set_has = Set.prototype.has;
-var std_iterator = '@@iterator'; // FIXME: Change to be a symbol.
+var std_iterator = Symbol.iterator;
 var std_StopIteration = StopIteration;
 var std_Map_iterator = Map.prototype[std_iterator];
 var std_Set_iterator = Set.prototype[std_iterator];
 var std_Map_iterator_next = Object.getPrototypeOf(Map()[std_iterator]()).next;
 var std_Set_iterator_next = Object.getPrototypeOf(Set()[std_iterator]()).next;
 
 
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4652,19 +4652,19 @@ EmitWith(ExclusiveContext *cx, BytecodeE
  * It will replace that stack value with the corresponding iterator
  */
 static bool
 EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
 {
     // Convert iterable to iterator.
     if (Emit1(cx, bce, JSOP_DUP) < 0)                          // OBJ OBJ
         return false;
-    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ @@ITERATOR
-        return false;
-    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
+    if (Emit2(cx, bce, JSOP_SYMBOL, jsbytecode(JS::SymbolCode::iterator)) < 0) // OBJ OBJ @@ITERATOR
+        return false;
+    if (!EmitElemOpBase(cx, bce, JSOP_CALLELEM))               // FN OBJ
         return false;
     if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
     return true;
 }
 
 static bool
@@ -5473,19 +5473,19 @@ EmitYieldStar(ExclusiveContext *cx, Byte
     JS_ASSERT(bce->sc->asFunctionBox()->isStarGenerator());
 
     if (!EmitTree(cx, bce, iter))                                // ITERABLE
         return false;
 
     // Convert iterable to iterator.
     if (Emit1(cx, bce, JSOP_DUP) < 0)                            // ITERABLE ITERABLE
         return false;
-    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // ITERABLE @@ITERATOR
-        return false;
-    if (Emit1(cx, bce, JSOP_SWAP) < 0)                           // @@ITERATOR ITERABLE
+    if (Emit2(cx, bce, JSOP_SYMBOL, jsbytecode(JS::SymbolCode::iterator)) < 0) // ITERABLE ITERABLE @@ITERATOR
+        return false;
+    if (!EmitElemOpBase(cx, bce, JSOP_CALLELEM))                 // FN ITERABLE
         return false;
     if (EmitCall(cx, bce, JSOP_CALL, 0, iter) < 0)               // ITER
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
 
     int depth = bce->stackDepth;
     JS_ASSERT(depth >= 1);
 
--- a/js/src/jit-test/lib/iteration.js
+++ b/js/src/jit-test/lib/iteration.js
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 load(libdir + "asserts.js");
 
-// FIXME: Import from std::iteration.
-const std_iterator = '@@iterator';
+const std_iterator = Symbol.iterator;
 
 if (typeof assertIteratorResult === 'undefined') {
     var assertIteratorResult = function assertIteratorResult(result, value, done) {
         assertEq(typeof result, "object");
         var expectedProps = ['done', 'value'];
         var actualProps = Object.getOwnPropertyNames(result);
         actualProps.sort(), expectedProps.sort();
         assertDeepEq(actualProps, expectedProps);
--- a/js/src/jit-test/tests/arguments/destructuring-exprbody.js
+++ b/js/src/jit-test/tests/arguments/destructuring-exprbody.js
@@ -1,7 +1,7 @@
 // See bug 763313
 function f([a]) a
 var i = 0;
-var o = {'@@iterator': function () { i++; return {
+var o = {[Symbol.iterator]: function () { i++; return {
   next: function () { i++; return {value: 42, done: false}; }}}};
 assertEq(f(o), 42);
 assertEq(i, 2);
--- a/js/src/jit-test/tests/basic/expression-autopsy.js
+++ b/js/src/jit-test/tests/basic/expression-autopsy.js
@@ -104,13 +104,13 @@ for (let tok of ["|", "^", "&", "==", "!
 check("o[!(o)]");
 check("o[~(o)]");
 check("o[+ (o)]");
 check("o[- (o)]");
 
 // A few one off tests
 check_one("6", (function () { 6() }), " is not a function");
 check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
-check_one("(intermediate value)['@@iterator'](...).next(...).value", function () { var [{ x }] = [null, {}]; }, " is null");
-check_one("(intermediate value)['@@iterator'](...).next(...).value", function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
+check_one("(intermediate value)[(intermediate value)](...).next(...).value", function () { var [{ x }] = [null, {}]; }, " is null");
+check_one("(intermediate value)[(intermediate value)](...).next(...).value", function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
 
 // Check fallback behavior
 assertThrowsInstanceOf(function () { for (let x of undefined) {} }, TypeError);
--- a/js/src/jit-test/tests/collections/WeakSet-error.js
+++ b/js/src/jit-test/tests/collections/WeakSet-error.js
@@ -14,12 +14,12 @@ function testMethod(name, hasArg = true)
     }
 }
 
 testMethod("has");
 testMethod("add");
 testMethod("delete");
 testMethod("clear", false);
 
-assertThrowsInstanceOf(function() { new WeakSet({"@@iterator": 2}) }, TypeError);
-assertEq(typeof []["@@iterator"], "function"); // Make sure we fail when @@iterator is removed
+assertThrowsInstanceOf(function() { new WeakSet({[Symbol.iterator]: 2}) }, TypeError);
+assertEq(typeof [][Symbol.iterator], "function");
 
 assertThrowsInstanceOf(function() { WeakSet(); }, TypeError);
--- a/js/src/jit-test/tests/collections/iterator-proto-surfaces.js
+++ b/js/src/jit-test/tests/collections/iterator-proto-surfaces.js
@@ -1,18 +1,18 @@
 // Iterator prototype surfaces.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 function test(constructor) {
     var proto = Object.getPrototypeOf(constructor()[std_iterator]());
     var names = Object.getOwnPropertyNames(proto);
-    names.sort();
-    assertDeepEq(names, [std_iterator, 'next']);
+    assertDeepEq(names, ['next']);
+    assertEq(proto.hasOwnProperty(std_iterator), true);
 
     var desc = Object.getOwnPropertyDescriptor(proto, 'next');
     assertEq(desc.configurable, true);
     assertEq(desc.enumerable, false);
     assertEq(desc.writable, true);
 
     assertEq(proto[std_iterator](), proto);
     assertIteratorDone(proto, undefined);
--- a/js/src/jit-test/tests/for-of/next-3.js
+++ b/js/src/jit-test/tests/for-of/next-3.js
@@ -3,11 +3,11 @@
 // compartment's .next method.
 
 // FIXME: 'next' should work cross-realm.  Bug 924059.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 var g = newGlobal();
-g.eval("var it = [1, 2]['" + std_iterator + "']();");
+g.eval("var it = [1, 2][Symbol.iterator]();");
 assertIteratorNext(g.it, 1);
 assertThrowsInstanceOf([][std_iterator]().next.bind(g.it), TypeError)
--- a/js/src/jit-test/tests/for-of/semantics-08.js
+++ b/js/src/jit-test/tests/for-of/semantics-08.js
@@ -1,9 +1,10 @@
 // Results from another compartment are correctly interpreted by for-of.
 
 load(libdir + "iteration.js");
 
 var g = newGlobal();
-var it = g.eval("({ '" + std_iterator + "': function () { return this; }, " +
-                "next: function () { return { done: true } } });");
-for (x of it)
+g.eval("var obj = {};\n" +
+       "obj[Symbol.iterator] = function () { return this; };\n" +
+       "obj.next = function () { return { done: true }; };\n");
+for (x of g.obj)
     throw 'FAIL';
--- a/js/src/jit-test/tests/for-of/string-iterator-surfaces.js
+++ b/js/src/jit-test/tests/for-of/string-iterator-surfaces.js
@@ -52,17 +52,18 @@ assertBuiltinFunction(String.prototype, 
 // Test StringIterator.prototype surface
 var iter = ""[std_iterator]();
 var iterProto = Object.getPrototypeOf(iter);
 
 // StringIterator.prototype inherits from Object.prototype
 assertEq(Object.getPrototypeOf(iterProto), Object.prototype);
 
 // Own properties for StringIterator.prototype: "next" and @@iterator
-arraysEqual(Object.getOwnPropertyNames(iterProto).sort(), ["next", std_iterator].sort());
+arraysEqual(Object.getOwnPropertyNames(iterProto), ["next"]);
+assertEq(iterProto.hasOwnProperty(std_iterator), true);
 
 // StringIterator.prototype[@@iterator] is a built-in function
 assertBuiltinFunction(iterProto, std_iterator, 0);
 
 // StringIterator.prototype.next is a built-in function
 assertBuiltinFunction(iterProto, "next", 0);
 
 // StringIterator.prototype[@@iterator] is generic and returns |this|
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5613,17 +5613,17 @@ JS_PUBLIC_API(JS::SymbolCode)
 JS::GetSymbolCode(Handle<Symbol*> symbol)
 {
     return symbol->code();
 }
 
 JS_PUBLIC_API(JS::Symbol *)
 JS::GetWellKnownSymbol(JSContext *cx, JS::SymbolCode which)
 {
-    return cx->runtime()->wellKnownSymbols->get(uint32_t(which));
+    return cx->wellKnownSymbols().get(uint32_t(which));
 }
 
 JS_PUBLIC_API(bool)
 JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
              HandleValue space, JSONWriteCallback callback, void *data)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3015,17 +3015,17 @@ static const JSFunctionSpec array_method
 
     /* ES6 additions */
     JS_SELF_HOSTED_FN("find",        "ArrayFind",        1,0),
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
     JS_SELF_HOSTED_FN("copyWithin",  "ArrayCopyWithin",  3,0),
 
     JS_SELF_HOSTED_FN("fill",        "ArrayFill",        3,0),
 
-    JS_SELF_HOSTED_FN("@@iterator",  "ArrayValues",      0,0),
+    JS_SELF_HOSTED_SYM_FN(iterator,  "ArrayValues",      0,0),
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -880,17 +880,17 @@ iterator_next_impl(JSContext *cx, CallAr
 static bool
 iterator_next(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsIterator, iterator_next_impl>(cx, args);
 }
 
 static const JSFunctionSpec iterator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "LegacyIteratorShim", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "LegacyIteratorShim", 0, 0),
     JS_FN("next",      iterator_next,       0, 0),
     JS_FS_END
 };
 
 static JSObject *
 iterator_iteratorObject(JSContext *cx, HandleObject obj, bool keysonly)
 {
     return obj;
@@ -959,17 +959,17 @@ const Class ArrayIteratorObject::class_ 
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr                  /* finalize    */
 };
 
 static const JSFunctionSpec array_iterator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "ArrayIteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "ArrayIteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "ArrayIteratorNext", 0, 0),
     JS_FS_END
 };
 
 static const Class StringIteratorPrototypeClass = {
     "String Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub,         /* addProperty */
@@ -998,17 +998,17 @@ const Class StringIteratorObject::class_
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr                  /* finalize    */
 };
 
 static const JSFunctionSpec string_iterator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "StringIteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "StringIteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "StringIteratorNext", 0, 0),
     JS_FS_END
 };
 
 static bool
 CloseLegacyGenerator(JSContext *cx, HandleObject genobj);
 
 bool
@@ -1400,17 +1400,18 @@ ForOfIterator::init(HandleValue iterable
 
     // The iterator is the result of calling obj[@@iterator]().
     InvokeArgs args(cx);
     if (!args.init(0))
         return false;
     args.setThis(ObjectValue(*iterableObj));
 
     RootedValue callee(cx);
-    if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
+    RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+    if (!JSObject::getGeneric(cx, iterableObj, iterableObj, iteratorId, &callee))
         return false;
 
     // Throw if obj[@@iterator] isn't callable if we were asked to do so.
     // js::Invoke is about to check for this kind of error anyway, but it would
     // throw an inscrutable error message about |method| rather than this nice
     // one about |obj|.
     if (!callee.isObject() || !callee.toObject().isCallable()) {
         if (nonIterableBehavior == AllowNonIterable)
@@ -2009,24 +2010,24 @@ NativeMethod(JSContext *cx, unsigned arg
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsObjectOfType<T>, Impl>(cx, args);
 }
 
 #define JSPROP_ROPERM   (JSPROP_READONLY | JSPROP_PERMANENT)
 #define JS_METHOD(name, T, impl, len, attrs) JS_FN(name, (NativeMethod<T,impl>), len, attrs)
 
 static const JSFunctionSpec star_generator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_METHOD("next", StarGeneratorObject, star_generator_next, 1, 0),
     JS_METHOD("throw", StarGeneratorObject, star_generator_throw, 1, 0),
     JS_FS_END
 };
 
 static const JSFunctionSpec legacy_generator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "LegacyGeneratorIteratorShim", 0, 0),
     // "send" is an alias for "next".
     JS_METHOD("next", LegacyGeneratorObject, legacy_generator_next, 1, JSPROP_ROPERM),
     JS_METHOD("send", LegacyGeneratorObject, legacy_generator_next, 1, JSPROP_ROPERM),
     JS_METHOD("throw", LegacyGeneratorObject, legacy_generator_throw, 1, JSPROP_ROPERM),
     JS_METHOD("close", LegacyGeneratorObject, legacy_generator_close, 0, JSPROP_ROPERM),
     JS_FS_END
 };
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4195,17 +4195,17 @@ static const JSFunctionSpec string_metho
     JS_SELF_HOSTED_FN("blink",    "String_blink",      0,0),
     JS_SELF_HOSTED_FN("sup",      "String_sup",        0,0),
     JS_SELF_HOSTED_FN("sub",      "String_sub",        0,0),
     JS_SELF_HOSTED_FN("anchor",   "String_anchor",     1,0),
     JS_SELF_HOSTED_FN("link",     "String_link",       1,0),
     JS_SELF_HOSTED_FN("fontcolor","String_fontcolor",  1,0),
     JS_SELF_HOSTED_FN("fontsize", "String_fontsize",   1,0),
 
-    JS_SELF_HOSTED_FN("@@iterator", "String_iterator", 0,0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "String_iterator", 0,0),
     JS_FS_END
 };
 
 // ES6 rev 27 (2014 Aug 24) 21.1.1
 bool
 js_String(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/tests/ecma_6/Array/for_of_2.js
+++ b/js/src/tests/ecma_6/Array/for_of_2.js
@@ -20,17 +20,17 @@ function TestChangeArrayIteratorNext() {
     var GET_COUNT = 0;
     function getter() {
         GET_COUNT++;
         if (GET_COUNT == MID)
             iterProto.next = NewNext;
         return M2;
     }
 
-    var iter = ([])['@@iterator']();
+    var iter = ([])[Symbol.iterator]();
     var iterProto = Object.getPrototypeOf(iter);
     var OldNext = iterProto.next;
     var NewNext = function () {
         return OldNext.apply(this, arguments);
     };
 
     var TRUE_SUM = 0;
     var N = 100;
--- a/js/src/tests/ecma_6/Array/for_of_3.js
+++ b/js/src/tests/ecma_6/Array/for_of_3.js
@@ -22,17 +22,17 @@ function TestIncreaseArrayLength() {
         GET_COUNT++;
         if (GET_COUNT == MID) {
             ARR_SUM += arr.length;
             arr.push(arr.length);
         }
         return M2;
     }
 
-    var iter = ([])['@@iterator']();
+    var iter = ([])[Symbol.iterator]();
     var iterProto = Object.getPrototypeOf(iter);
     var OldNext = iterProto.next;
     var NewNext = function () {
         return OldNext.apply(this, arguments);
     };
 
     var TRUE_SUM = 0;
     var N = 100;
--- a/js/src/tests/ecma_6/Array/for_of_4.js
+++ b/js/src/tests/ecma_6/Array/for_of_4.js
@@ -21,17 +21,17 @@ function TestDecreaseArrayLength() {
     function getter() {
         GET_COUNT++;
         if (GET_COUNT == MID) {
             arr.length = 0;
         }
         return M2;
     }
 
-    var iter = ([])['@@iterator']();
+    var iter = ([])[Symbol.iterator]();
     var iterProto = Object.getPrototypeOf(iter);
     var OldNext = iterProto.next;
     var NewNext = function () {
         return OldNext.apply(this, arguments);
     };
 
     var TRUE_SUM = 0;
     var N = 100;
--- a/js/src/tests/ecma_6/Array/from_errors.js
+++ b/js/src/tests/ecma_6/Array/from_errors.js
@@ -127,19 +127,19 @@ var arrayish = {
 log = "";
 var exc = {surprise: "ponies"};
 assertThrowsValue(() => Array.from.call(C, arrayish, () => { throw exc; }), exc);
 assertEq(log, "lC0");
 assertEq(obj instanceof C, true);
 
 // It's a TypeError if the iterator's .next() method returns a primitive.
 for (var primitive of [undefined, null, 17]) {
+    var iterable = {};
+    iterable[Symbol.iterator] = () => {
+        next: () => primitive
+    };
     assertThrowsInstanceOf(
-        () => Array.from({
-            "@@iterator": () => {
-                next: () => primitive
-            }
-        }),
+        () => Array.from(iterable),
         TypeError);
 }
 
 if (typeof reportCompare === 'function')
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Array/from_iterable.js
+++ b/js/src/tests/ecma_6/Array/from_iterable.js
@@ -3,17 +3,17 @@
 
 // Array.from works on arguments objects.
 (function () {
     assertDeepEq(Array.from(arguments), ["arg0", "arg1", undefined]);
 })("arg0", "arg1", undefined);
 
 // If an object has both .length and [@@iterator] properties, [@@iterator] is used.
 var a = ['a', 'e', 'i', 'o', 'u'];
-a["@@iterator"] = function* () {
+a[Symbol.iterator] = function* () {
     for (var i = 5; i--; )
         yield this[i];
 };
 
 var log = '';
 function f(x) {
     log += x;
     return x + x;
--- a/js/src/tests/ecma_6/Array/from_proxy.js
+++ b/js/src/tests/ecma_6/Array/from_proxy.js
@@ -1,52 +1,54 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/licenses/publicdomain/ */
 
 // Two tests involving Array.from and a Proxy.
 var log = [];
 function LoggingProxy(target) {
     var h = {
         defineProperty: function (t, id) {
-            log.push("define " + id);
+            log.push("define", id);
             return undefined;
         },
         has: function (t, id) {
-            log.push("has " + id);
+            log.push("has", id);
             return id in t;
         },
         get: function (t, id) {
-            log.push("get " + id);
+            log.push("get", id);
             return t[id];
         },
         set: function (t, id, v) {
-            log.push("set " + id);
+            log.push("set", id);
             t[id] = v;
         }
     };
     return new Proxy(target || [], h);
 }
 
 // When the new object created by Array.from is a Proxy,
 // Array.from calls handler.defineProperty to create new elements
 // but handler.set to set the length.
 LoggingProxy.from = Array.from;
 LoggingProxy.from([3, 4, 5]);
-assertDeepEq(log, ["define 0", "define 1", "define 2", "set length"]);
+assertDeepEq(log, ["define", "0", "define", "1", "define", "2", "set", "length"]);
 
 // When the argument passed to Array.from is a Proxy, Array.from
 // calls handler.get on it.
 log = [];
 assertDeepEq(Array.from(new LoggingProxy([3, 4, 5])), [3, 4, 5]);
-assertDeepEq(log, ["get @@iterator",
-                   "get length", "get 0", "get length", "get 1", "get length", "get 2",
-                   "get length"]);
+assertDeepEq(log, ["get", Symbol.iterator,
+                   "get", "length", "get", "0",
+                   "get", "length", "get", "1",
+                   "get", "length", "get", "2",
+                   "get", "length"]);
 
 // Array-like iteration only gets the length once.
 log = [];
 var arr = [5, 6, 7];
-arr["@@iterator"] = undefined;
+arr[Symbol.iterator] = undefined;
 assertDeepEq(Array.from(new LoggingProxy(arr)), [5, 6, 7]);
-assertDeepEq(log, ["get @@iterator",
-                   "get length", "get 0", "get 1", "get 2"]);
+assertDeepEq(log, ["get", Symbol.iterator,
+                   "get", "length", "get", "0", "get", "1", "get", "2"]);
 
 if (typeof reportCompare === 'function')
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Array/from_string.js
+++ b/js/src/tests/ecma_6/Array/from_string.js
@@ -6,18 +6,18 @@ assertDeepEq(Array.from("test string"),
              ['t', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g']);
 
 // Array.from on a string handles surrogate pairs correctly.
 var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF
 assertDeepEq(Array.from(gclef), [gclef]);
 assertDeepEq(Array.from(gclef + " G"), [gclef, " ", "G"]);
 
 // Array.from on a string calls the @@iterator method.
-String.prototype["@@iterator"] = function* () { yield 1; yield 2; };
+String.prototype[Symbol.iterator] = function* () { yield 1; yield 2; };
 assertDeepEq(Array.from("anything"), [1, 2]);
 
 // If the iterator method is deleted, Strings are still arraylike.
-delete String.prototype["@@iterator"];
+delete String.prototype[Symbol.iterator];
 assertDeepEq(Array.from("works"), ['w', 'o', 'r', 'k', 's']);
 assertDeepEq(Array.from(gclef), ['\uD834', '\uDD1E']);
 
 if (typeof reportCompare === 'function')
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Generators/runtime.js
+++ b/js/src/tests/ecma_6/Generators/runtime.js
@@ -12,18 +12,16 @@ function assertSyntaxError(str) {
 }
 
 
 function f() { }
 function* g() { yield 1; }
 var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
 var GeneratorFunction = GeneratorFunctionPrototype.constructor;
 var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
-// FIXME: This should be a symbol.
-var std_iterator = "@@iterator";
 
 
 // A generator function should have the same set of properties as any
 // other function.
 function TestGeneratorFunctionInstance() {
     var f_own_property_names = Object.getOwnPropertyNames(f);
     var g_own_property_names = Object.getOwnPropertyNames(g);
 
@@ -61,17 +59,17 @@ TestGeneratorFunctionPrototype();
 // Functions that we associate with generator objects are actually defined by
 // a common prototype.
 function TestGeneratorObjectPrototype() {
     assertEq(Object.getPrototypeOf(GeneratorObjectPrototype),
                Object.prototype);
     assertEq(Object.getPrototypeOf((function*(){yield 1}).prototype),
                GeneratorObjectPrototype);
 
-    var expected_property_names = ["next", "throw", "constructor", std_iterator];
+    var expected_property_names = ["next", "throw", "constructor"];
     var found_property_names =
         Object.getOwnPropertyNames(GeneratorObjectPrototype);
 
     expected_property_names.sort();
     found_property_names.sort();
 
     assertDeepEq(found_property_names, expected_property_names);
 }
--- a/js/src/tests/ecma_6/Symbol/property-reflection.js
+++ b/js/src/tests/ecma_6/Symbol/property-reflection.js
@@ -62,19 +62,17 @@ if (typeof Symbol === "function") {
     assertDeepEq(desc, descs[s2]);
     assertEq(desc.value, descs[s2].value);
 
     // Object.prototype.hasOwnProperty
     assertEq(descs.hasOwnProperty(s1), true);
     assertEq(descs.hasOwnProperty(s2), true);
     assertEq(descs.hasOwnProperty(s3), false);
     assertEq([].hasOwnProperty(Symbol.iterator), false);
-    if (!("@@iterator" in []))
-        throw new Error("Congratulations on implementing Symbol.iterator! Please update this test.");
-    assertEq(Array.prototype.hasOwnProperty(Symbol.iterator), false);  // should be true
+    assertEq(Array.prototype.hasOwnProperty(Symbol.iterator), true);
 
     // Object.prototype.propertyIsEnumerable
     assertEq(n.propertyIsEnumerable(s1), true);
     assertEq(n.propertyIsEnumerable(s2), false);
     assertEq(n.propertyIsEnumerable(s3), false);  // no such property
     assertEq(D.prototype.propertyIsEnumerable(s3), true);
     assertEq(descs.propertyIsEnumerable(s3), false); // inherited properties are not considered
 
--- a/js/src/tests/js1_8/regress/regress-469625-03.js
+++ b/js/src/tests/js1_8/regress/regress-469625-03.js
@@ -21,17 +21,17 @@ function test()
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
   function f(x) {
     var [a, b, [c0, c1]] = [x, x, x];
   }
 
-  expect = 'TypeError: (intermediate value)[\'@@iterator\'](...).next(...).value is null';
+  expect = 'TypeError: (intermediate value)[(intermediate value)](...).next(...).value is null';
   actual = 'No Error';
   try
   {
     f(null);
   }
   catch(ex)
   {
     actual = ex + '';
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -39,17 +39,16 @@
     macro(compare, compare, "compare") \
     macro(configurable, configurable, "configurable") \
     macro(construct, construct, "construct") \
     macro(constructor, constructor, "constructor") \
     macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \
     macro(count, count, "count") \
     macro(currency, currency, "currency") \
     macro(currencyDisplay, currencyDisplay, "currencyDisplay") \
-    macro(std_iterator, std_iterator, "@@iterator") \
     macro(DateTimeFormat, DateTimeFormat, "DateTimeFormat") \
     macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \
     macro(decodeURI, decodeURI, "decodeURI") \
     macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
     macro(default_, default_, "default") \
     macro(defineProperty, defineProperty, "defineProperty") \
     macro(defineGetter, defineGetter, "__defineGetter__") \
     macro(defineSetter, defineSetter, "__defineSetter__") \
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1128,16 +1128,17 @@ HandleError(JSContext *cx, InterpreterRe
 #define REGS                     (activation.regs())
 #define PUSH_COPY(v)             do { *REGS.sp++ = (v); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_COPY_SKIP_CHECK(v)  *REGS.sp++ = (v)
 #define PUSH_NULL()              REGS.sp++->setNull()
 #define PUSH_UNDEFINED()         REGS.sp++->setUndefined()
 #define PUSH_BOOLEAN(b)          REGS.sp++->setBoolean(b)
 #define PUSH_DOUBLE(d)           REGS.sp++->setDouble(d)
 #define PUSH_INT32(i)            REGS.sp++->setInt32(i)
+#define PUSH_SYMBOL(s)           REGS.sp++->setSymbol(s)
 #define PUSH_STRING(s)           do { REGS.sp++->setString(s); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_OBJECT(obj)         do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_HOLE()              REGS.sp++->setMagic(JS_ELEMENTS_HOLE)
 #define PUSH_UNINITIALIZED()     REGS.sp++->setMagic(JS_UNINITIALIZED_LEXICAL)
 #define POP_COPY_TO(v)           (v) = *--REGS.sp
 #define POP_RETURN_VALUE()       REGS.fp()->setReturnValue(*--REGS.sp)
 
@@ -1606,17 +1607,16 @@ CASE(EnableInterruptsPseudoOpcode)
     /* Commence executing the actual opcode. */
     SANITY_CHECKS();
     DISPATCH_TO(op);
 }
 
 /* Various 1-byte no-ops. */
 CASE(JSOP_NOP)
 CASE(JSOP_UNUSED2)
-CASE(JSOP_UNUSED45)
 CASE(JSOP_UNUSED46)
 CASE(JSOP_UNUSED47)
 CASE(JSOP_UNUSED48)
 CASE(JSOP_UNUSED49)
 CASE(JSOP_UNUSED50)
 CASE(JSOP_UNUSED51)
 CASE(JSOP_UNUSED52)
 CASE(JSOP_UNUSED57)
@@ -2750,16 +2750,20 @@ CASE(JSOP_TOSTRING)
         JSString *operString = ToString<CanGC>(cx, oper);
         if (!operString)
             goto error;
         oper.setString(operString);
     }
 }
 END_CASE(JSOP_TOSTRING)
 
+CASE(JSOP_SYMBOL)
+    PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
+END_CASE(JSOP_SYMBOL)
+
 CASE(JSOP_OBJECT)
 {
     RootedObject &ref = rootObject0;
     ref = script->getObject(REGS.pc);
     if (JS::CompartmentOptionsRef(cx).cloneSingletons()) {
         JSObject *obj = js::DeepCloneObjectLiteral(cx, ref, js::MaybeSingletonObject);
         if (!obj)
             goto error;
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -411,17 +411,25 @@ 1234567890123456789012345678901234567890
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands: uint24_t n
      *   Stack: v[n], v[n-1], ..., v[1], v[0] =>
      *          v[n], v[n-1], ..., v[1], v[0], v[n]
      */ \
     macro(JSOP_DUPAT,     44, "dupat",      NULL,         4,  0,  1,  JOF_UINT24) \
     \
-    macro(JSOP_UNUSED45,  45, "unused45",   NULL,         1,  0,  0,  JOF_BYTE) \
+    /*
+     * Push a well-known symbol onto the operand stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: uint8_t n, the JS::SymbolCode of the symbol to use
+     *   Stack: => symbol
+     */ \
+    macro(JSOP_SYMBOL,    45, "symbol",     NULL,         2,  0,  1,  JOF_UINT8) \
+    \
     macro(JSOP_UNUSED46,  46, "unused46",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED47,  47, "unused47",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED48,  48, "unused48",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED49,  49, "unused49",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED50,  50, "unused50",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED51,  51, "unused51",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED52,  52, "unused52",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
--- a/js/src/vm/PIC.cpp
+++ b/js/src/vm/PIC.cpp
@@ -39,18 +39,19 @@ js::ForOfPIC::Chain::initialize(JSContex
     initialized_ = true;
     arrayProto_ = arrayProto;
     arrayIteratorProto_ = arrayIteratorProto;
 
     // Shortcut returns below means Array for-of will never be optimizable,
     // do set disabled_ now, and clear it later when we succeed.
     disabled_ = true;
 
-    // Look up '@@iterator' on Array.prototype, ensure it's a slotful shape.
-    Shape *iterShape = arrayProto->nativeLookup(cx, cx->names().std_iterator);
+    // Look up Array.prototype[@@iterator], ensure it's a slotful shape.
+    Shape *iterShape =
+        arrayProto->nativeLookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
     if (!iterShape || !iterShape->hasSlot() || !iterShape->hasDefaultGetter())
         return true;
 
     // Get the referred value, and ensure it holds the canonical ArrayValues function.
     Value iterator = arrayProto->getSlot(iterShape->slot());
     JSFunction *iterFun;
     if (!IsFunctionObject(iterator, &iterFun))
         return true;
@@ -139,18 +140,18 @@ js::ForOfPIC::Chain::tryOptimizeArray(JS
     // churn on these.
     if (numStubs() >= MAX_STUBS)
         eraseChain();
 
     // Ensure array's prototype is the actual Array.prototype
     if (!isOptimizableArray(array))
         return true;
 
-    // Ensure array doesn't define '@@iterator' directly.
-    if (array->nativeLookup(cx, cx->names().std_iterator))
+    // Ensure array doesn't define @@iterator directly.
+    if (array->nativeLookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)))
         return true;
 
     // Good to optimize now, create stub to add.
     RootedShape shape(cx, array->lastProperty());
     stub = cx->new_<Stub>(shape);
     if (!stub)
         return false;
 
@@ -193,17 +194,17 @@ js::ForOfPIC::Chain::isOptimizableArray(
 
 bool
 js::ForOfPIC::Chain::isArrayStateStillSane()
 {
     // Ensure that canonical Array.prototype has matching shape.
     if (arrayProto_->lastProperty() != arrayProtoShape_)
         return false;
 
-    // Ensure that Array.prototype['@@iterator'] contains the
+    // Ensure that Array.prototype[@@iterator] contains the
     // canonical iterator function.
     if (arrayProto_->getSlot(arrayProtoIteratorSlot_) != canonicalIteratorFunc_)
         return false;
 
     // Chain to isArrayNextStillSane.
     return isArrayNextStillSane();
 }
 
--- a/js/src/vm/PIC.h
+++ b/js/src/vm/PIC.h
@@ -125,17 +125,17 @@ struct ForOfPIC
     ForOfPIC() MOZ_DELETE;
     ForOfPIC(const ForOfPIC &other) MOZ_DELETE;
 
     typedef PICStub<ForOfPIC> BaseStub;
     typedef PICChain<ForOfPIC> BaseChain;
 
     /*
      * A ForOfPIC has only one kind of stub for now: one that holds the shape
-     * of an array object that does not override its '@@iterator' property.
+     * of an array object that does not override its @@iterator property.
      */
     class Stub : public BaseStub
     {
       private:
         // Shape of matching array object.
         Shape *shape_;
 
       public:
@@ -159,35 +159,35 @@ struct ForOfPIC
      *
      *  Array.prototype's shape (arrayProtoShape_)
      *      To ensure that Array.prototype has not been modified.
      *
      *  ArrayIterator.prototype (arrayIteratorProto_)
      *  ArrayIterator.prototype's shape (arrayIteratorProtoShape_)
      *      To ensure that an ArrayIterator.prototype has not been modified.
      *
-     *  Array.prototype's slot number for '@@iterator' (arrayProtoIteratorSlot_)
-     *  Array.prototype's canonical value for '@@iterator' (canonicalIteratorFunc_)
+     *  Array.prototype's slot number for @@iterator (arrayProtoIteratorSlot_)
+     *  Array.prototype's canonical value for @@iterator (canonicalIteratorFunc_)
      *      To quickly retreive and ensure that the iterator constructor
      *      stored in the slot has not changed.
      *
      *  ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_)
      *  ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_)
      *      To quickly retreive and ensure that the 'next' method for ArrayIterator
      *      objects has not changed.
      */
     class Chain : public BaseChain
     {
       private:
         // Pointer to canonical Array.prototype and ArrayIterator.prototype
         HeapPtrObject arrayProto_;
         HeapPtrObject arrayIteratorProto_;
 
         // Shape of matching Array.prototype object, and slot containing
-        // the '@@iterator' for it, and the canonical value.
+        // the @@iterator for it, and the canonical value.
         HeapPtrShape arrayProtoShape_;
         uint32_t arrayProtoIteratorSlot_;
         HeapValue canonicalIteratorFunc_;
 
         // Shape of matching ArrayIteratorProto, and slot containing
         // the 'next' property, and the canonical value.
         HeapPtrShape arrayIteratorProtoShape_;
         uint32_t arrayIteratorProtoNextSlot_;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1251,16 +1251,22 @@ CloneValue(JSContext *cx, HandleValue se
     } else if (selfHostedValue.isString()) {
         if (!selfHostedValue.toString()->isFlat())
             MOZ_CRASH();
         JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
         JSString *clone = CloneString(cx, selfHostedString);
         if (!clone)
             return false;
         vp.setString(clone);
+    } else if (selfHostedValue.isSymbol()) {
+        // Well-known symbols are shared.
+        JS::Symbol *sym = selfHostedValue.toSymbol();
+        MOZ_ASSERT(sym->isWellKnownSymbol());
+        MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
+        vp.set(selfHostedValue);
     } else {
         MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
     }
     return true;
 }
 
 bool
 JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, HandlePropertyName name,
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1585,17 +1585,17 @@ TypedArrayObject::setElement(TypedArrayO
  ***/
 
 /*
  * TypedArrayObject boilerplate
  */
 
 #define IMPL_TYPED_ARRAY_STATICS(_typedArray)                                      \
 const JSFunctionSpec _typedArray##Object::jsfuncs[] = {                            \
-    JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0, 0),                          \
+    JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0),                          \
     JS_FN("subarray", _typedArray##Object::fun_subarray, 2, JSFUN_GENERIC_NATIVE), \
     JS_FN("set", _typedArray##Object::fun_set, 2, JSFUN_GENERIC_NATIVE),           \
     JS_FN("copyWithin", _typedArray##Object::fun_copyWithin, 2, JSFUN_GENERIC_NATIVE), \
     JS_FS_END                                                                      \
 };                                                                                 \
 /* These next 3 functions are brought to you by the buggy GCC we use to build      \
    B2G ICS. Older GCC versions have a bug in which they fail to compile            \
    reinterpret_casts of templated functions with the message: "insufficient        \
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -169,24 +169,24 @@ https://bugzilla.mozilla.org/show_bug.cg
                                       the JS engine filters it out of getOwnPropertyNames */
     ["constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch",
      "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
      "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__"];
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
-      "findIndex", "copyWithin", "fill", "@@iterator", "entries", "keys", "constructor"];
+      "findIndex", "copyWithin", "fill", Symbol.iterator, "entries", "keys", "constructor"];
   if (isNightlyBuild) {
     let pjsMethods = ['mapPar', 'reducePar', 'scanPar', 'scatterPar', 'filterPar'];
     gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
   }
   for (var c of typedArrayClasses) {
     gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT", "length", "buffer",
-                               "byteLength", "byteOffset", "@@iterator", "subarray", "set",
+                               "byteLength", "byteOffset", "Symbol.iterator", "subarray", "set",
                                "copyWithin"];
   }
   for (var c of errorObjectClasses) {
       gPrototypeProperties[c] = ["constructor", "name",
                                  // We don't actually resolve these empty data properties
                                  // onto the Xray prototypes, but we list them here to make
                                  // the test happy.
                                  "lineNumber", "columnNumber", "fileName", "message", "stack"];
@@ -206,19 +206,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     return array.filter(p => props.indexOf(p) == -1);
   }
 
   function testXray(classname, xray, xray2, propsToSkip) {
     propsToSkip = propsToSkip || [];
     let xrayProto = Object.getPrototypeOf(xray);
     let localProto = window[classname].prototype;
     is(Object.getOwnPropertyNames(localProto).sort().toSource(),
-       gPrototypeProperties[classname].sort().toSource(),
+       gPrototypeProperties[classname].filter(id => typeof id === "string").sort().toSource(),
        "A property on the " + classname +
-       " prototype has changed! You need a security audit from an XPConnect peer");
+       " prototype has been changed! You need a security audit from an XPConnect peer");
+    is(Object.getOwnPropertySymbols(localProto).map(uneval).sort().toSource(),
+       gPrototypeProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(),
+       "A symbol-keyed property on the " + classname +
+       " prototype has been changed! You need a security audit from an XPConnect peer");
 
     let protoProps = filterOut(Object.getOwnPropertyNames(localProto), propsToSkip).sort();
     let protoCallables = protoProps.filter(name => Object.getOwnPropertyDescriptor(localProto, name).get ||
                                                    typeof localProto[name] == 'function' &&
                                                    name != 'constructor');
     let protoGetters = protoProps.filter(name => Object.getOwnPropertyDescriptor(localProto, name).get);
     ok(protoCallables.length > 0, "Need something to test");
     is(xrayProto, iwin[classname].prototype, "Xray proto is correct");
--- a/toolkit/modules/Promise-backend.js
+++ b/toolkit/modules/Promise-backend.js
@@ -506,17 +506,17 @@ Promise.reject = function (aReason)
  *         that is rejected when any of the values are rejected. Its
  *         resolution value will be an array of all resolved values in the
  *         given order, or undefined if aValues is an empty array. The reject
  *         reason will be forwarded from the first promise in the list of
  *         given promises to be rejected.
  */
 Promise.all = function (aValues)
 {
-  if (aValues == null || typeof(aValues["@@iterator"]) != "function") {
+  if (aValues == null || typeof(aValues[Symbol.iterator]) != "function") {
     throw new Error("Promise.all() expects an iterable.");
   }
 
   return new Promise((resolve, reject) => {
     let values = Array.isArray(aValues) ? aValues : [...aValues];
     let countdown = values.length;
     let resolutionValues = new Array(countdown);
 
@@ -557,17 +557,17 @@ Promise.all = function (aValues)
  *        be resolved or rejected as to the given value or reason.
  *
  * @return A new promise that is fulfilled when any values are resolved or
  *         rejected. Its resolution value will be forwarded from the resolution
  *         value or rejection reason.
  */
 Promise.race = function (aValues)
 {
-  if (aValues == null || typeof(aValues["@@iterator"]) != "function") {
+  if (aValues == null || typeof(aValues[Symbol.iterator]) != "function") {
     throw new Error("Promise.race() expects an iterable.");
   }
 
   return new Promise((resolve, reject) => {
     for (let value of aValues) {
       Promise.resolve(value).then(resolve, reject);
     }
   });