Bug 918828, part 2 - Change iteration code to call iterable[Symbol.iterator]() rather than iterable["@@iterator"](). r=nbp.

--HG--
extra : rebase_source : 529d0cd48cd1993cd8cc648ac385ca12342ecfd1
This commit is contained in:
Jason Orendorff 2014-07-01 21:01:21 -05:00
parent 1629fa04d9
commit 68b38c7094
46 changed files with 146 additions and 130 deletions

View File

@ -7,20 +7,9 @@ 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

View File

@ -2662,7 +2662,7 @@ this.CustomizableUI = {
* for (let window of CustomizableUI.windows) { ... }
*/
windows: {
"@@iterator": function*() {
*[Symbol.iterator]() {
for (let [window,] of gBuildWindows)
yield window;
}

View File

@ -3261,9 +3261,9 @@ LineResults.prototype = {
/**
* 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;
};

View File

@ -475,14 +475,14 @@ DevTools.prototype = {
// 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;
}
};

View File

@ -3056,10 +3056,10 @@ Property.prototype = Heritage.extend(Variable.prototype, {
/**
* 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;
};

View File

@ -1729,7 +1729,7 @@ this.WidgetMethods = {
/**
* 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();
};

View File

@ -32,7 +32,7 @@ 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");
@ -41,8 +41,7 @@ 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");

View File

@ -28,7 +28,7 @@ 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")
@ -36,8 +36,7 @@ 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");

View File

@ -42,7 +42,7 @@ 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")
@ -54,7 +54,6 @@ 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>

View File

@ -38,7 +38,7 @@ 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")
@ -48,8 +48,7 @@ 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");

View File

@ -1942,7 +1942,7 @@ class PropertyDefiner:
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.
@ -1951,7 +1951,8 @@ class PropertyDefiner:
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)
@ -1962,7 +1963,7 @@ class PropertyDefiner:
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
@ -2005,7 +2006,7 @@ class PropertyDefiner:
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 }")
@ -2279,9 +2280,15 @@ class MethodDefiner(PropertyDefiner):
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)
@ -2384,7 +2391,7 @@ class AttrDefiner(PropertyDefiner):
return self.generatePrefableArray(
array, name,
' { "%s", %s, %s, %s}',
lambda fields: ' { "%s", %s, %s, %s}' % fields,
' JS_PS_END',
'JSPropertySpec',
PropertyDefiner.getControllingCondition, specData, doIdArrays)
@ -2412,7 +2419,7 @@ class ConstDefiner(PropertyDefiner):
return self.generatePrefableArray(
array, name,
' { "%s", %s }',
lambda fields: ' { "%s", %s }' % fields,
' { 0, JS::UndefinedValue() }',
'ConstantSpec',
PropertyDefiner.getControllingCondition, specData, doIdArrays)

View File

@ -678,7 +678,7 @@ function ArrayFrom(arrayLike, mapfn=undefined, thisArg=undefined) {
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() : [];

View File

@ -876,7 +876,7 @@ const Class MapIteratorObject::class_ = {
};
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
};
@ -1074,7 +1074,8 @@ MapObject::initClass(JSContext *cx, JSObject *obj)
// 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;
@ -1524,7 +1525,7 @@ const Class SetIteratorObject::class_ = {
};
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
};
@ -1697,7 +1698,8 @@ SetObject::initClass(JSContext *cx, JSObject *obj)
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;

View File

@ -83,7 +83,7 @@ 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];

View File

@ -4657,9 +4657,9 @@ 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
if (Emit2(cx, bce, JSOP_SYMBOL, jsbytecode(JS::SymbolCode::iterator)) < 0) // OBJ OBJ @@ITERATOR
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // @@ITERATOR OBJ
if (!EmitElemOpBase(cx, bce, JSOP_CALLELEM)) // FN OBJ
return false;
if (EmitCall(cx, bce, JSOP_CALL, 0) < 0) // ITER
return false;
@ -5478,9 +5478,9 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
// 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
if (Emit2(cx, bce, JSOP_SYMBOL, jsbytecode(JS::SymbolCode::iterator)) < 0) // ITERABLE ITERABLE @@ITERATOR
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // @@ITERATOR ITERABLE
if (!EmitElemOpBase(cx, bce, JSOP_CALLELEM)) // FN ITERABLE
return false;
if (EmitCall(cx, bce, JSOP_CALL, 0, iter) < 0) // ITER
return false;

View File

@ -5,8 +5,7 @@
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) {

View File

@ -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);

View File

@ -109,8 +109,8 @@ 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);

View File

@ -19,7 +19,7 @@ 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);

View File

@ -6,8 +6,8 @@ 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);

View File

@ -8,6 +8,6 @@ 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)

View File

@ -3,7 +3,8 @@
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';

View File

@ -57,7 +57,8 @@ var iterProto = Object.getPrototypeOf(iter);
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);

View File

@ -5618,7 +5618,7 @@ JS::GetSymbolCode(Handle<Symbol*> symbol)
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)

View File

@ -3020,7 +3020,7 @@ static const JSFunctionSpec array_methods[] = {
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

View File

@ -885,7 +885,7 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp)
}
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
};
@ -964,7 +964,7 @@ const Class ArrayIteratorObject::class_ = {
};
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
};
@ -1003,7 +1003,7 @@ const Class StringIteratorObject::class_ = {
};
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
};
@ -1405,7 +1405,8 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio
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.
@ -2014,14 +2015,14 @@ NativeMethod(JSContext *cx, unsigned argc, Value *vp)
#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),

View File

@ -4200,7 +4200,7 @@ static const JSFunctionSpec string_methods[] = {
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
};

View File

@ -25,7 +25,7 @@ function TestChangeArrayIteratorNext() {
return M2;
}
var iter = ([])['@@iterator']();
var iter = ([])[Symbol.iterator]();
var iterProto = Object.getPrototypeOf(iter);
var OldNext = iterProto.next;
var NewNext = function () {

View File

@ -27,7 +27,7 @@ function TestIncreaseArrayLength() {
return M2;
}
var iter = ([])['@@iterator']();
var iter = ([])[Symbol.iterator]();
var iterProto = Object.getPrototypeOf(iter);
var OldNext = iterProto.next;
var NewNext = function () {

View File

@ -26,7 +26,7 @@ function TestDecreaseArrayLength() {
return M2;
}
var iter = ([])['@@iterator']();
var iter = ([])[Symbol.iterator]();
var iterProto = Object.getPrototypeOf(iter);
var OldNext = iterProto.next;
var NewNext = function () {

View File

@ -132,12 +132,12 @@ 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);
}

View File

@ -8,7 +8,7 @@
// 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];
};

View File

@ -6,19 +6,19 @@ 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;
}
};
@ -30,23 +30,25 @@ function LoggingProxy(target) {
// 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);

View File

@ -11,11 +11,11 @@ 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']);

View File

@ -17,8 +17,6 @@ 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
@ -66,7 +64,7 @@ function TestGeneratorObjectPrototype() {
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);

View File

@ -67,9 +67,7 @@ if (typeof Symbol === "function") {
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);

View File

@ -26,7 +26,7 @@ function test()
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
{

View File

@ -44,7 +44,6 @@
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") \

View File

@ -1133,6 +1133,7 @@ HandleError(JSContext *cx, InterpreterRegs &regs)
#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)
@ -1611,7 +1612,6 @@ CASE(EnableInterruptsPseudoOpcode)
/* Various 1-byte no-ops. */
CASE(JSOP_NOP)
CASE(JSOP_UNUSED2)
CASE(JSOP_UNUSED45)
CASE(JSOP_UNUSED46)
CASE(JSOP_UNUSED47)
CASE(JSOP_UNUSED48)
@ -2755,6 +2755,10 @@ CASE(JSOP_TOSTRING)
}
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;

View File

@ -416,7 +416,15 @@
*/ \
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) \

View File

@ -44,8 +44,9 @@ js::ForOfPIC::Chain::initialize(JSContext *cx)
// 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;
@ -144,8 +145,8 @@ js::ForOfPIC::Chain::tryOptimizeArray(JSContext *cx, HandleObject array, bool *o
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.
@ -198,7 +199,7 @@ js::ForOfPIC::Chain::isArrayStateStillSane()
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;

View File

@ -130,7 +130,7 @@ struct ForOfPIC
/*
* 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
{
@ -164,8 +164,8 @@ struct ForOfPIC
* 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.
*
@ -182,7 +182,7 @@ struct ForOfPIC
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_;

View File

@ -1256,6 +1256,12 @@ CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp)
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.");
}

View File

@ -1590,7 +1590,7 @@ TypedArrayObject::setElement(TypedArrayObject &obj, uint32_t index, double d)
#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), \

View File

@ -174,14 +174,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
["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) {
@ -211,9 +211,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
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 ||

View File

@ -511,7 +511,7 @@ Promise.reject = function (aReason)
*/
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.");
}
@ -562,7 +562,7 @@ Promise.all = function (aValues)
*/
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.");
}