author | Jason Orendorff <jorendorff@mozilla.com> |
Tue, 01 Jul 2014 21:01:21 -0500 | |
changeset 213223 | 51a1fa4c521fef7fe83a15aeca12cd0dca356aea |
parent 213222 | da167ffa2060350f4271a272a696d6e94698ef67 |
child 213224 | 606dc149145e4d36f96103e1a029fa615537efe1 |
push id | 27745 |
push user | cbook@mozilla.com |
push date | Fri, 31 Oct 2014 13:09:12 +0000 |
treeherder | mozilla-central@6bd2071b373f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Waldo |
bugs | 918828 |
milestone | 36.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
|
--- a/addon-sdk/source/lib/sdk/util/iteration.js +++ b/addon-sdk/source/lib/sdk/util/iteration.js @@ -2,30 +2,21 @@ * 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; +// This is known as @@iterator in the ES6 spec. In builds that have ES6 +// Symbols, use Symbol.iterator; otherwise use the legacy method name, +// "@@iterator". +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +exports.iteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@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 @@ -46,16 +46,23 @@ const kPrefWebIDEInNavbar = " * of providing onViewShowing and onViewHiding event handlers. */ const kSubviewEvents = [ "ViewShowing", "ViewHiding" ]; /** + * The method name to use for ES6 iteration. If Symbols are enabled in + * this build, use Symbol.iterator; otherwise "@@iterator". + */ +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +const kIteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; + +/** * The current version. We can use this to auto-add new default widgets as necessary. * (would be const but isn't because of testing purposes) */ let kVersion = 1; /** * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed * on their IDs. @@ -2674,17 +2681,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*() { + *[kIteratorSymbol]() { 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 @@ -3255,20 +3255,25 @@ LineResults.prototype = { line: 0, _sourceResults: null, _store: null, _target: null }; /** * A generator-iterator over the global, source or line results. + * + * The method name depends on whether symbols are enabled in + * this build. If so, use Symbol.iterator; otherwise "@@iterator". */ -GlobalResults.prototype["@@iterator"] = -SourceResults.prototype["@@iterator"] = -LineResults.prototype["@@iterator"] = function*() { +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; +GlobalResults.prototype[ITERATOR_SYMBOL] = +SourceResults.prototype[ITERATOR_SYMBOL] = +LineResults.prototype[ITERATOR_SYMBOL] = 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 @@ -21,16 +21,23 @@ XPCOMUtils.defineLazyModuleGetter(this, XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); const EventEmitter = devtools.require("devtools/toolkit/event-emitter"); const FORBIDDEN_IDS = new Set(["toolbox", ""]); const MAX_ORDINAL = 99; /** + * The method name to use for ES6 iteration. If symbols are enabled in this + * build, use Symbol.iterator; otherwise "@@iterator". + */ +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; + +/** * DevTools is a class that represents a set of developer tools, it holds a * set of tools and keeps track of open toolboxes in the browser. */ this.DevTools = function DevTools() { this._tools = new Map(); // Map<toolId, tool> this._themes = new Map(); // Map<themeId, theme> this._toolboxes = new Map(); // Map<target, toolbox> @@ -481,17 +488,17 @@ DevTools.prototype = { // 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*() { + *[ITERATOR_SYMBOL]() { for (let toolbox of this._toolboxes) { yield toolbox; } } }; /** * gDevTools is a singleton that controls the Firefox Developer Tools.
--- a/browser/devtools/shared/widgets/VariablesView.jsm +++ b/browser/devtools/shared/widgets/VariablesView.jsm @@ -13,16 +13,23 @@ const LAZY_EMPTY_DELAY = 150; // ms const LAZY_EXPAND_DELAY = 50; // ms const SCROLL_PAGE_SIZE_DEFAULT = 0; const APPEND_PAGE_SIZE_DEFAULT = 500; const PAGE_SIZE_SCROLL_HEIGHT_RATIO = 100; const PAGE_SIZE_MAX_JUMPS = 30; const SEARCH_ACTION_MAX_DELAY = 300; // ms const ITEM_FLASH_DURATION = 300 // ms +/** + * The method name to use for ES6 iteration. If symbols are enabled in + * this build, use Symbol.iterator; otherwise "@@iterator". + */ +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; + Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); Cu.import("resource://gre/modules/devtools/event-emitter.js"); Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm"); Cu.import("resource://gre/modules/Task.jsm"); let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); @@ -3051,20 +3058,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[ITERATOR_SYMBOL] = +Scope.prototype[ITERATOR_SYMBOL] = +Variable.prototype[ITERATOR_SYMBOL] = +Property.prototype[ITERATOR_SYMBOL] = 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 @@ -8,16 +8,23 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const PANE_APPEARANCE_DELAY = 50; const PAGE_SIZE_ITEM_COUNT_RATIO = 5; const WIDGET_FOCUSABLE_NODES = new Set(["vbox", "hbox"]); +/** + * The method name to use for ES6 iteration. If symbols are enabled in + * this build, use Symbol.iterator; otherwise "@@iterator". + */ +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; + Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Timer.jsm"); Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm"); this.EXPORTED_SYMBOLS = [ "Heritage", "ViewHelpers", "WidgetMethods", "setNamedTimeout", "clearNamedTimeout", @@ -1724,12 +1731,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[ITERATOR_SYMBOL] = +WidgetMethods[ITERATOR_SYMBOL] = function*() { yield* this._itemsByElement.values(); };
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2009,37 +2009,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. @@ -2072,17 +2073,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} @@ -2349,19 +2350,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 @@ -2455,17 +2462,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 @@ -2483,17 +2490,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/dom/bindings/test/test_sequence_detection.html +++ b/dom/bindings/test/test_sequence_detection.html @@ -11,28 +11,19 @@ https://bugzilla.mozilla.org/show_bug.cg <script type="application/javascript"> /** Test for Bug 1066432 **/ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() { var testInterfaceJS = new TestInterfaceJS(); ok(testInterfaceJS, "got a TestInterfaceJS object"); - var nonIterableObject = { "@@iterator": 5 }; - if (typeof Symbol === "function") { - // Make this test fail if Symbol.iterator is correctly implemented. - // This is here to make sure this test is updated when bug 918828 lands, - // at which point the correct code will be: - // var JS_HAS_SYMBOLS = typeof Symbol === "function"; - // var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; - // var nonIterableObject = { [std_iterator]: 5}; - // Otherwise, fixing bug 918828 would cause this test to silently stop - // testing what it's supposed to be testing. - nonIterableObject[Symbol.iterator] = Array.prototype[Symbol.iterator]; - } + var JS_HAS_SYMBOLS = typeof Symbol === "function"; + var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; + var nonIterableObject = {[std_iterator]: 5}; try { testInterfaceJS.testSequenceOverload(nonIterableObject); ok(false, "Should have thrown in the overload case"); // see long comment above! } catch (e) { ise(e.name, "TypeError", "Should get a TypeError for the overload case"); ok(e.message.contains("not iterable"), "Should have a message about being non-iterable in the overload case");
--- a/dom/html/test/test_formelements.html +++ b/dom/html/test/test_formelements.html @@ -27,27 +27,33 @@ 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"); +var JS_HAS_SYMBOLS = typeof Symbol === "function"; +is(names.length, JS_HAS_SYMBOLS ? 9 : 10, + "Should have 9 enumerated names (or 10 with '@@iterator')"); 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"); +if (JS_HAS_SYMBOLS) { + is(names[8], "length", "Enum entry 9"); +} else { + is(names[8], "@@iterator", "Enum entry 9"); + is(names[9], "length", "Enum entry 10"); +} 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/dom/html/test/test_htmlcollection.html +++ b/dom/html/test/test_htmlcollection.html @@ -23,26 +23,32 @@ 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"); +var JS_HAS_SYMBOLS = typeof Symbol === "function"; +is(names.length, JS_HAS_SYMBOLS ? 8 : 9, + "Should have 8 enumerated names (or 9 with '@@iterator')"); 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") +if (JS_HAS_SYMBOLS) { + is(names[7], "length", "Enum entry 8"); +} else { + is(names[7], "@@iterator", "Enum entry 8"); + is(names[8], "length", "Enum entry 9"); +} 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/dom/html/test/test_named_options.html +++ b/dom/html/test/test_named_options.html @@ -37,26 +37,30 @@ 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"); +var JS_HAS_SYMBOLS = typeof Symbol === "function"; +is(names2.length, JS_HAS_SYMBOLS ? 11 : 12, + "Should have eleven enumerated names (or twelve with '@@iterator')"); 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") +if (!JS_HAS_SYMBOLS) { + is(names2[11], "@@iterator", "Enum entry 12"); +} </script> </pre> </body> </html>
--- a/dom/html/test/test_rowscollection.html +++ b/dom/html/test/test_rowscollection.html @@ -33,28 +33,34 @@ 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"); +var JS_HAS_SYMBOLS = typeof Symbol === "function"; +is(names.length, JS_HAS_SYMBOLS ? 10 : 11, + "Should have 10 enumerated names (or 11 with '@@iterator')"); 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") +if (JS_HAS_SYMBOLS) { + is(names[9], "length", "Enum entry 10"); +} else { + is(names[9], "@@iterator", "Enum entry 10"); + is(names[10], "length", "Enum entry 11"); +} 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/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 @@ -873,17 +873,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()); @@ -1071,18 +1071,24 @@ 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_HAS_SYMBOLS + RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)); + if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0)) + return nullptr; +#else if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0)) return nullptr; +#endif } return proto; } template <class Range> static void MarkKey(Range &r, const HashableValue &key, JSTracer *trc) { @@ -1523,17 +1529,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()); @@ -1697,18 +1703,25 @@ 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_HAS_SYMBOLS + RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)); + if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0)) + return nullptr; +#else if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0)) return nullptr; +#endif } return proto; } bool SetObject::keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys) {
--- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -26,17 +26,16 @@ #include "SelfHostingDefines.h" // All C++-implemented standard builtins library functions used in self-hosted // code are installed via the std_functions JSFunctionSpec[] in // SelfHosting.cpp. // // The few items below here are either self-hosted or installing them under a // std_Foo name would require ugly contortions, so they just get aliased here. -var std_iterator = '@@iterator'; // FIXME: Change to be a symbol. var std_Array_indexOf = ArrayIndexOf; // WeakMap is a bare constructor without properties or methods. var std_WeakMap = WeakMap; // StopIteration is a bare constructor without properties or methods. var std_StopIteration = StopIteration; /********** List specification type **********/
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4725,20 +4725,27 @@ 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; +#ifdef JS_HAS_SYMBOLS + 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; +#else if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ @@ITERATOR return false; if (Emit1(cx, bce, JSOP_SWAP) < 0) // @@ITERATOR OBJ return false; +#endif if (EmitCall(cx, bce, JSOP_CALL, 0) < 0) // ITER return false; CheckTypeSet(cx, bce, JSOP_CALL); return true; } static bool EmitForInOrOfVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool *letDecl) @@ -5593,27 +5600,18 @@ EmitYield(ExclusiveContext *cx, Bytecode static bool EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, ParseNode *gen) { MOZ_ASSERT(bce->sc->isFunctionBox()); MOZ_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 - return false; - if (EmitCall(cx, bce, JSOP_CALL, 0, iter) < 0) // ITER - return false; - CheckTypeSet(cx, bce, JSOP_CALL); + if (!EmitIterator(cx, bce)) // ITER + return false; // Initial send value is undefined. if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RECEIVED return false; int depth = bce->stackDepth; MOZ_ASSERT(depth >= 2);
--- a/js/src/jit-test/lib/iteration.js +++ b/js/src/jit-test/lib/iteration.js @@ -1,17 +1,17 @@ /* 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 JS_HAS_SYMBOLS = typeof Symbol === "function"; +const std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : '@@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,8 @@ // See bug 763313 +load(libdir + "iteration.js"); function f([a]) a var i = 0; -var o = {'@@iterator': function () { i++; return { +var o = {[std_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 @@ -1,9 +1,10 @@ load(libdir + "asserts.js"); +load(libdir + "iteration.js"); function check_one(expected, f, err) { var failed = true; try { f(); failed = false; } catch (ex) { var s = ex.toString(); @@ -104,13 +105,16 @@ 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"); +var ITERATOR = JS_HAS_SYMBOLS ? "(intermediate value)" : "'@@iterator'"; +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 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 @@ -1,21 +1,22 @@ load(libdir + "asserts.js"); +load(libdir + "iteration.js"); function testMethod(name) { var method = WeakSet.prototype[name]; assertThrowsInstanceOf(function() { method.call(1); }, TypeError); assertThrowsInstanceOf(function() { method.call({}); }, TypeError); assertThrowsInstanceOf(function() { method.call(new WeakMap); }, TypeError); assertThrowsInstanceOf(function() { method.call(WeakSet.prototype); }, TypeError); } testMethod("has"); testMethod("add"); testMethod("delete"); testMethod("clear"); assertThrowsInstanceOf(function() { var ws = new WeakSet(); ws.add(1); }, TypeError); -assertThrowsInstanceOf(function() { new WeakSet({"@@iterator": 2}) }, TypeError); -assertEq(typeof []["@@iterator"], "function"); // Make sure we fail when @@iterator is removed +assertThrowsInstanceOf(function() { new WeakSet({[std_iterator]: 2}) }, TypeError); +assertEq(typeof [][std_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 @@ -2,17 +2,18 @@ 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, JS_HAS_SYMBOLS ? ['next'] : ['@@iterator', '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][${uneval(std_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,12 @@ // 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 = {}; + obj[${uneval(std_iterator)}] = function () { return this; }; + obj.next = function () { return { done: true }; }; +`); +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,19 @@ 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).sort(), + JS_HAS_SYMBOLS ? ["next"] : ["@@iterator", "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-tests/testForOfIterator.cpp +++ b/js/src/jsapi-tests/testForOfIterator.cpp @@ -3,46 +3,42 @@ */ /* 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/. */ #include "jsapi-tests/tests.h" #ifdef JS_HAS_SYMBOLS -#define IF_JS_HAS_SYMBOLS(x) x +#define STD_ITERATOR "Symbol.iterator" #else -#define IF_JS_HAS_SYMBOLS(x) +#define STD_ITERATOR "'@@iterator'" #endif BEGIN_TEST(testForOfIterator_basicNonIterable) { JS::RootedValue v(cx); // Hack to make it simple to produce an object that has a property // named Symbol.iterator. - EVAL("var obj = {'@@iterator': 5" - IF_JS_HAS_SYMBOLS(", [Symbol.iterator]: Array.prototype[Symbol.iterator]") - "}; obj;", &v); + EVAL("({[" STD_ITERATOR "]: 5})", &v); JS::ForOfIterator iter(cx); bool ok = iter.init(v); CHECK(!ok); JS_ClearPendingException(cx); return true; } END_TEST(testForOfIterator_basicNonIterable) BEGIN_TEST(testForOfIterator_bug515273_part1) { JS::RootedValue v(cx); // Hack to make it simple to produce an object that has a property // named Symbol.iterator. - EVAL("var obj = {'@@iterator': 5" - IF_JS_HAS_SYMBOLS(", [Symbol.iterator]: Array.prototype[Symbol.iterator]") - "}; obj;", &v); + EVAL("({[" STD_ITERATOR "]: 5})", &v); JS::ForOfIterator iter(cx); bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable); CHECK(!ok); JS_ClearPendingException(cx); return true; } END_TEST(testForOfIterator_bug515273_part1)
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5587,17 +5587,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)); } static bool PropertySpecNameIsDigits(const char *s) { if (JS::PropertySpecNameIsSymbol(s)) return false; if (!*s) return false;
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2556,34 +2556,42 @@ struct JSFunctionSpec { * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays * homage to the old JSNative/JSFastNative split) simply adds the flag * JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of * JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. Finally * JS_FNSPEC has slots for all the fields. * * The _SYM variants allow defining a function with a symbol key rather than a * string key. For example, use JS_SYM_FN(iterator, ...) to define an - * @@iterator method. + * @@iterator method. (In builds without ES6 symbols, it defines a method with + * the string id "@@iterator".) */ #define JS_FS(name,call,nargs,flags) \ JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) #define JS_FN(name,call,nargs,flags) \ JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) #define JS_SYM_FN(name,call,nargs,flags) \ JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) #define JS_FNINFO(name,call,info,nargs,flags) \ JS_FNSPEC(name, call, info, nargs, flags, nullptr) #define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \ JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) #define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \ JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName) + +#ifdef JS_HAS_SYMBOLS #define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ JS_FNSPEC(reinterpret_cast<const char *>( \ uint32_t(::JS::SymbolCode::symbol) + 1), \ call, info, nargs, flags, selfHostedName) +#else +#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ + JS_FNSPEC("@@" #symbol, call, info, nargs, flags, selfHostedName) +#endif + #define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \ {name, {call, info}, nargs, flags, selfHostedName} extern JS_PUBLIC_API(JSObject *) JS_InitClass(JSContext *cx, JS::HandleObject obj, JS::HandleObject parent_proto, const JSClass *clasp, JSNative constructor, unsigned nargs, const JSPropertySpec *ps, const JSFunctionSpec *fs, const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs);
--- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3169,17 +3169,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 @@ -881,17 +881,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; @@ -960,17 +960,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 */ @@ -999,17 +999,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 }; bool js::ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp) { /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ @@ -1364,18 +1364,24 @@ 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); +#ifdef JS_HAS_SYMBOLS + RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)); + if (!JSObject::getGeneric(cx, iterableObj, iterableObj, iteratorId, &callee)) + return false; +#else if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee)) return false; +#endif // If obj[@@iterator] is undefined and we were asked to allow non-iterables, // bail out now without setting iterator. This will make valueIsIterable(), // which our caller should check, return false. if (nonIterableBehavior == AllowNonIterable && callee.isUndefined()) return true; // Throw if obj[@@iterator] isn't callable.
--- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4199,17 +4199,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 = ([])[std_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 = ([])[std_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 = ([])[std_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 @@ -129,17 +129,17 @@ 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]) { assertThrowsInstanceOf( () => Array.from({ - "@@iterator": () => { - next: () => primitive + [std_iterator]() { + return {next() { return primitive; }}; } }), 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[std_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", std_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[std_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", std_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[std_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[std_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,19 @@ 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"]; + if (!JS_HAS_SYMBOLS) + expected_property_names.push(std_iterator); 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 @@ -61,20 +61,18 @@ if (typeof Symbol === "function") { desc = Object.getOwnPropertyDescriptor(n, s2); 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([].hasOwnProperty(std_iterator), false); + assertEq(Array.prototype.hasOwnProperty(std_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,18 @@ 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'; + var ITERATOR = JS_HAS_SYMBOLS ? "(intermediate value)" : "'@@iterator'"; + expect = `TypeError: (intermediate value)[${ITERATOR}](...).next(...).value is null`; actual = 'No Error'; try { f(null); } catch(ex) { actual = ex + '';
--- a/js/src/tests/shell.js +++ b/js/src/tests/shell.js @@ -871,8 +871,11 @@ function GetContext() { return Packages.com.netscape.javascript.Context.getCurrentContext(); } function OptLevel( i ) { i = Number(i); var cx = GetContext(); cx.setOptimizationLevel(i); } /* end of Rhino functions */ + +var JS_HAS_SYMBOLS = typeof Symbol === "function"; +var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
--- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -242,26 +242,26 @@ const Class StarGeneratorObject::class_ nullptr, /* finalize */ nullptr, /* call */ nullptr, /* hasInstance */ nullptr, /* construct */ nullptr, /* trace */ }; static const JSFunctionSpec star_generator_methods[] = { - JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0), + JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0), JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0), JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0), JS_FS_END }; #define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) 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_SELF_HOSTED_FN("next", "LegacyGeneratorNext", 1, JSPROP_ROPERM), JS_SELF_HOSTED_FN("send", "LegacyGeneratorNext", 1, JSPROP_ROPERM), JS_SELF_HOSTED_FN("throw", "LegacyGeneratorThrow", 1, JSPROP_ROPERM), JS_SELF_HOSTED_FN("close", "LegacyGeneratorClose", 0, JSPROP_ROPERM), JS_FS_END };
--- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -319,24 +319,38 @@ InitBareBuiltinCtor(JSContext *cx, Handl * The self-hosting global only gets a small subset of all standard classes. * Even those are only created as bare constructors without any properties * or functions. */ /* static */ bool GlobalObject::initSelfHostingBuiltins(JSContext *cx, Handle<GlobalObject*> global, const JSFunctionSpec *builtins) { - /* Define a top-level property 'undefined' with the undefined value. */ + // Define a top-level property 'undefined' with the undefined value. if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return false; } + // Define a top-level property 'std_iterator' with the name of the method + // used by for-of loops to create an iterator. + RootedValue std_iterator(cx); +#ifdef JS_HAS_SYMBOLS + std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator)); +#else + std_iterator.setString(cx->names().std_iterator); +#endif + if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator, + JSPROP_PERMANENT | JSPROP_READONLY)) + { + return false; + } + return InitBareBuiltinCtor(cx, global, JSProto_Array) && InitBareBuiltinCtor(cx, global, JSProto_TypedArray) && InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) && InitBareBuiltinCtor(cx, global, JSProto_Uint32Array) && InitBareWeakMapCtor(cx, global) && initStopIterationClass(cx, global) && InitSelfHostingCollectionIteratorFunctions(cx, global) && JS_DefineFunctions(cx, global, builtins);
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1119,16 +1119,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) @@ -1596,17 +1597,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) @@ -2701,16 +2701,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) { RootedNativeObject &ref = rootNativeObject0; 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 @@ -13,16 +13,22 @@ #include "vm/SelfHosting.h" #include "jsobjinlines.h" #include "vm/NativeObject-inl.h" using namespace js; using namespace js::gc; +#ifdef JS_HAS_SYMBOLS +#define STD_ITERATOR_ID SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator) +#else +#define STD_ITERATOR_ID ::js::NameToId(cx->names().std_iterator) +#endif + bool js::ForOfPIC::Chain::initialize(JSContext *cx) { MOZ_ASSERT(!initialized_); // Get the canonical Array.prototype RootedNativeObject arrayProto(cx, GlobalObject::getOrCreateArrayPrototype(cx, cx->global())); if (!arrayProto) @@ -39,18 +45,18 @@ 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->lookup(cx, cx->names().std_iterator); + // Look up Array.prototype[@@iterator], ensure it's a slotful shape. + Shape *iterShape = arrayProto->lookup(cx, STD_ITERATOR_ID); 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; @@ -138,18 +144,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->lookup(cx, cx->names().std_iterator)) + // Ensure array doesn't define @@iterator directly. + if (array->lookup(cx, STD_ITERATOR_ID)) return true; // Good to optimize now, create stub to add. RootedShape shape(cx, array->lastProperty()); stub = cx->new_<Stub>(shape); if (!stub) return false; @@ -192,17 +198,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 HeapPtrNativeObject arrayProto_; HeapPtrNativeObject 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 @@ -1496,16 +1496,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 @@ -755,17 +755,17 @@ TypedArrayObject::subarray(JSContext *cx { CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod<TypedArrayObject::is, TypedArrayMethods<TypedArrayObject>::subarray>(cx, args); } /* static */ const JSFunctionSpec TypedArrayObject::protoFunctions[] = { - JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0, 0), + JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0), \ JS_FN("subarray", TypedArrayObject::subarray, 2, 0), JS_FN("set", TypedArrayObject::set, 2, 0), JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0), JS_FS_END }; /* static */ const JSFunctionSpec TypedArrayObject::staticFunctions[] = {
--- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -22,18 +22,31 @@ namespace js { * deserialization if there is a mismatch between the current and saved * versions. If deserialization fails, the data should be invalidated if * possible. * * When you change this, run make_opcode_doc.py and copy the new output into * this wiki page: * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode + * + * === GREETINGS, FELLOW SUBTRAHEND INCREMENTER! === + * For the time being, please increment the subtrahend by 2 each time it + * changes, because we have two flavors of bytecode: with JSOP_SYMBOL (in + * Nightly) and without (all others). FIXME: Bug 1066322 - Enable ES6 symbols + * in all builds. */ -static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 188); +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 190; +static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above"); +static const uint32_t XDR_BYTECODE_VERSION = + uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND +#ifdef JS_HAS_SYMBOLS + + 1 +#endif + )); class XDRBuffer { public: explicit XDRBuffer(JSContext *cx) : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { } JSContext *cx() const { return context;
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -141,16 +141,17 @@ https://bugzilla.mozilla.org/show_bug.cg // prototype, so that we make sure to audit any new ones to make sure they're // Xray-safe. // // DO NOT CHANGE WTIHOUT REVIEW FROM AN XPCONNECT PEER. var version = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).version; var isNightlyBuild = version.endsWith("a1"); var isReleaseBuild = !version.contains("a"); const jsHasSymbols = typeof Symbol === "function"; + const kIteratorSymbol = jsHasSymbols ? Symbol.iterator : "@@iterator"; var gPrototypeProperties = {}; gPrototypeProperties['Date'] = ["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", "setTime", "setYear", "setFullYear", "setUTCFullYear", "setMonth", "setUTCMonth", "setDate", "setUTCDate", "setHours", "setUTCHours", "setMinutes", @@ -163,26 +164,26 @@ 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", kIteratorSymbol, "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"]; } gPrototypeProperties['TypedArray'] = - ["length", "buffer", "byteLength", "byteOffset", "@@iterator", "subarray", + ["length", "buffer", "byteLength", "byteOffset", kIteratorSymbol, "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"]; @@ -495,20 +496,16 @@ https://bugzilla.mozilla.org/show_bug.cg function testTypedArrays() { // We don't invoke testXray with %TypedArray%, because that function isn't // set up to deal with "anonymous" dependent classes (that is, classes not // visible as a global property, which %TypedArray% is not), and fixing it // up is more trouble than it's worth. var typedArrayProto = Object.getPrototypeOf(Int8Array.prototype); - gPrototypeProperties['TypedArray'] = - ["length", "buffer", "byteLength", "byteOffset", "@@iterator", "subarray", - "set", "copyWithin"]; - var desiredInheritedProps = Object.getOwnPropertyNames(typedArrayProto).sort(); var inheritedProps = filterOut(desiredInheritedProps, ["BYTES_PER_ELEMENT", "constructor"]); var inheritedCallables = inheritedProps.filter(name => (propertyIsGetter(typedArrayProto, name) || typeof typedArrayProto[name] === "function") && name !== "constructor");
--- a/toolkit/modules/Promise-backend.js +++ b/toolkit/modules/Promise-backend.js @@ -32,16 +32,19 @@ const STATUS_REJECTED = 2; // This N_INTERNALS name allow internal properties of the Promise to be // accessed only by this module, while still being visible on the object // manually when using a debugger. This doesn't strictly guarantee that the // properties are inaccessible by other code, but provide enough protection to // avoid using them by mistake. const salt = Math.floor(Math.random() * 100); const N_INTERNALS = "{private:internals:" + salt + "}"; +const JS_HAS_SYMBOLS = typeof Symbol === "function"; +const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator"; + /////// Warn-upon-finalization mechanism // // One of the difficult problems with promises is locating uncaught // rejections. We adopt the following strategy: if a promise is rejected // at the time of its garbage-collection *and* if the promise is at the // end of a promise chain (i.e. |thatPromise.then| has never been // called), then we print a warning. // @@ -506,17 +509,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[ITERATOR_SYMBOL]) != "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 +560,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[ITERATOR_SYMBOL]) != "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); } });