Backed out 4 changesets (bug 1098412) for failing browser_webconsole_bug_632347_iterators_generators.js

Backed out changeset f4da55f291cb (bug 1098412)
Backed out changeset e9a0298824d6 (bug 1098412)
Backed out changeset 8281805e7c3c (bug 1098412)
Backed out changeset 1643079d7661 (bug 1098412)

MozReview-Commit-ID: 5kuHtUjx1UM
This commit is contained in:
Phil Ringnalda 2017-08-28 21:28:26 -07:00
parent d8022d7f17
commit fd6ec799b2
60 changed files with 1362 additions and 27 deletions

View File

@ -47,6 +47,7 @@ var ecmaGlobals =
"Int8Array",
"InternalError",
"Intl",
"Iterator",
"JSON",
"Map",
"Math",

View File

@ -42,6 +42,7 @@ var ecmaGlobals =
"Int8Array",
"InternalError",
"Intl",
"Iterator",
"JSON",
"Map",
"Math",

View File

@ -42,6 +42,7 @@ var ecmaGlobals =
"Int8Array",
"InternalError",
"Intl",
"Iterator",
"JSON",
"Map",
"Math",

View File

@ -18,7 +18,6 @@
#include "jscntxt.h"
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsiter.h"
#include "jsobj.h"
#include "jsprf.h"
#include "jswrapper.h"
@ -4429,17 +4428,6 @@ IsConstructor(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
IsLegacyIterator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1)
args.rval().setBoolean(false);
else
args.rval().setBoolean(IsLegacyIterator(args[0]));
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'zone' [, 'shrinking'])",
@ -5031,10 +5019,6 @@ gc::ZealModeHelpText),
"isConstructor(value)",
" Returns whether the value is considered IsConstructor.\n"),
JS_FN_HELP("isLegacyIterator", IsLegacyIterator, 1, 0,
"isLegacyIterator(value)",
" Returns whether the value is considered is a legacy iterator.\n"),
JS_FS_HELP_END
};

View File

@ -0,0 +1,7 @@
// |jit-test| error:TypeError
var o = {
__iterator__: function() {
return {};
}
};
for (var j in o) {}

View File

@ -0,0 +1,8 @@
// Binary: cache/js-dbg-32-16baceea5fe2-linux
// Flags:
//
for (a in (function () {
return Iterator(function () {}).__proto__
})()) {
++b
}

View File

@ -0,0 +1,9 @@
// Binary: cache/js-dbg-32-fe937d72a9ce-linux
// Flags:
//
x = Iterator([])
for (z in x) {}
(function() {
for (l in function() {}) {}
} ())
for (z in x) {}

View File

@ -0,0 +1,6 @@
// |jit-test| error:SyntaxError
// Binary: cache/js-dbg-64-4c1fbfcf1d0d-linux
// Flags:
//
Iterator(evalcx('#2=*'))

View File

@ -0,0 +1,13 @@
// Binary: cache/js-dbg-64-d708c2fa7fea-linux
// Flags:
//
var o0 = Iterator.prototype;
function f0(o) {}
try {
for(var i=0; i<7; i++) {
try { o0.prototype(); } catch(e) {
if (o0.next() != 7)
throw "7 not yielded";
};
}
} catch(exc1) {}

View File

@ -0,0 +1,7 @@
// Binary: cache/js-dbg-64-90828ac18dcf-linux
// Flags:
//
x = Set;
eval("function y() { return Iterator; }", this);
x.__iterator__ = y;
new Iterator(x)

View File

@ -0,0 +1,13 @@
// |jit-test| --baseline-eager; error: TypeError
try {
this.__defineGetter__("x", Iterator)()
} catch (e) {}
f = function() {
return (function() {
this.x
})
}()
try {
f()
} catch (e) {}
f()

View File

@ -0,0 +1,27 @@
// This was the actual bug
assertRaises(StopIteration, function() {
Iterator.prototype.next();
Iterator.prototype.next();
});
// The error should have triggered here, but was masked by a latent bug
assertRaises(StopIteration, function() {
Iterator.prototype.next();
});
// Found by fuzzing
assertRaises(StopIteration, function() {
(new Iterator({})).__proto__.next();
});
function assertRaises(exc, callback) {
var caught = false;
try {
callback();
} catch (e) {
assertEq(e instanceof StopIteration, true);
caught = true;
}
assertEq(caught, true);
}

View File

@ -0,0 +1,6 @@
// |jit-test| error: InternalError
var op = Object.prototype;
op.b = op;
op.__iterator__ = Iterator;
for (var c in {}) {}

View File

@ -0,0 +1,9 @@
gczeal(4,1);
var iterable = {persistedProp: 17};
iterable.__iterator__ = function() {
yield ["foo", 2];
yield ["bar", 3];
};
var it = Iterator(iterable);
assertEq(it.next().toString(), "foo,2");
assertEq(it.next().toString(), "bar,3");

View File

@ -65,6 +65,7 @@ test("new Number(1)", n => Number.prototype.valueOf.call(n));
test("new Number(1)", n => Number.prototype.toFixed.call(n));
test("new Number(1)", n => Number.prototype.toExponential.call(n));
test("new Number(1)", n => Number.prototype.toPrecision.call(n));
test("new Iterator({x:1})", i => Iterator.prototype.next.call(i).toString());
test("(function(){yield 1})()", i => (function(){yield})().next.call(i).toString());
test("new String('one')", s => String.prototype.toSource.call(s));
test("new String('one')", s => String.prototype.toString.call(s));

View File

@ -0,0 +1,26 @@
function my_iterator_next() {
if (this.i == 10) {
this.i = 0;
throw this.StopIteration;
}
return this.i++;
}
function testCustomIterator() {
var o = {
__iterator__: function () {
return {
i: 0,
next: my_iterator_next,
StopIteration: StopIteration
};
}
};
var a=[];
for (var k = 0; k < 100; k += 10) {
for(var j in o) {
a[k + (j >> 0)] = j*k;
}
}
return a.join();
}
assertEq(testCustomIterator(), "0,0,0,0,0,0,0,0,0,0,0,10,20,30,40,50,60,70,80,90,0,20,40,60,80,100,120,140,160,180,0,30,60,90,120,150,180,210,240,270,0,40,80,120,160,200,240,280,320,360,0,50,100,150,200,250,300,350,400,450,0,60,120,180,240,300,360,420,480,540,0,70,140,210,280,350,420,490,560,630,0,80,160,240,320,400,480,560,640,720,0,90,180,270,360,450,540,630,720,810");

View File

@ -5,6 +5,7 @@ load(libdir + "iteration.js");
function test(obj, name) {
var iter = obj[Symbol.iterator]();
assertEq(typeof iter, "object");
assertEq(iter instanceof Iterator, false); // Not a legacy Iterator.
assertEq(iter.toString(), "[object " + obj.constructor.name + " Iterator]");
}

View File

@ -48,6 +48,14 @@ check("x << 1");
check("x >> 1");
check("x >>> 1");
g.eval("function lastStep() { throw StopIteration; }");
g.eval("function emptyIterator() { debugger; log += 'x'; return { next: lastStep }; }");
g.eval("var customEmptyIterator = { __iterator__: emptyIterator };");
g.log = '';
g.eval("for (i in customEmptyIterator);\n" +
"log += 'y';\n");
assertEq(g.log, 'dxsy');
g.eval("var getter = { get x() { debugger; return log += 'x'; } }");
check("getter.x");

View File

@ -0,0 +1,5 @@
// Iterator.prototype.next throws if applied to a value that isn't an iterator.
load(libdir + "asserts.js");
for (var v of [null, undefined, false, 0, "ponies", {}, [], this])
assertThrowsInstanceOf(function () { Iterator.prototype.next.call(v); }, TypeError);

View File

@ -0,0 +1,8 @@
// Iterator.prototype.next throws if applied to a non-iterator that inherits from an iterator.
load(libdir + "asserts.js");
load(libdir + "iteration.js");
var it = [1, 2][Symbol.iterator]();
var v = Object.create(it);
assertThrowsInstanceOf(function () { Iterator.prototype.next.call(v); }, TypeError);

View File

@ -0,0 +1,7 @@
// Test superficial features of the Iterator.prototype.next builtin function.
assertEq(Iterator.prototype.next.length, 0);
var desc = Object.getOwnPropertyDescriptor(Iterator.prototype, "next");
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertEq(desc.writable, true);

View File

@ -0,0 +1,11 @@
o = {}
for (let i = 0; i < 70; i++) {
try {
p
} catch (e) {}
(function() {
for (x in Iterator.prototype) {}
})()
o.__proto__ = null
delete o.__proto__
}

View File

@ -0,0 +1,8 @@
// |jit-test| error: TypeError; need-for-each
(function() {
var a, b;
for each (a in [{}, {__iterator__: function(){}}])
for (b in a) { }
})();

View File

@ -0,0 +1,12 @@
function eval() {
return isPrototypeOf[Iterator.length];
}
function DoWhile_3() {
return eval();
}
DoWhile_3();
function f() {
return DoWhile_3(f - 0);
}
for (var i in f());

View File

@ -0,0 +1,7 @@
// |jit-test| error: TypeError
for (var a = 0; a < 7; ++a) {
if (a == 1) {
Iterator()
}
}

View File

@ -0,0 +1,12 @@
gczeal(2);
o1 = Iterator;
var o2 = (function() { return arguments; })();
function f(o) {
for(var j=0; j<20; j++) {
Object.seal(o2);
(function() { return eval(o); })() == o1;
(function() { return {x: arguments}.x; })();
if (false) {};
}
}
f({});

View File

@ -341,9 +341,13 @@ CallJSNativeConstructor(JSContext* cx, Native native, const CallArgs& args)
* - CallOrConstructBoundFunction is an exception as well because we might
* have used bind on a proxy function.
*
* - new Iterator(x) is user-hookable; it returns x.__iterator__() which
* could be any object.
*
* - (new Object(Object)) returns the callee.
*/
MOZ_ASSERT_IF(native != js::proxy_Construct &&
native != js::IteratorConstructor &&
(!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
args.rval().isObject() && callee != &args.rval().toObject());

View File

@ -546,6 +546,15 @@ JS_SetProtoCalled(JSContext*)
return sSetProtoCalled;
}
// Defined in jsiter.cpp.
extern size_t sCustomIteratorCount;
JS_FRIEND_API(size_t)
JS_GetCustomIteratorCount(JSContext* cx)
{
return sCustomIteratorCount;
}
JS_FRIEND_API(unsigned)
JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp)
{

View File

@ -74,6 +74,9 @@ JS_ObjectCountDynamicSlots(JS::HandleObject obj);
extern JS_FRIEND_API(size_t)
JS_SetProtoCalled(JSContext* cx);
extern JS_FRIEND_API(size_t)
JS_GetCustomIteratorCount(JSContext* cx);
extern JS_FRIEND_API(bool)
JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);

View File

@ -542,6 +542,55 @@ js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
props);
}
size_t sCustomIteratorCount = 0;
static inline bool
GetCustomIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp)
{
if (MOZ_UNLIKELY(!CheckRecursionLimit(cx)))
return false;
RootedValue rval(cx);
/* Check whether we have a valid __iterator__ method. */
HandlePropertyName name = cx->names().iteratorIntrinsic;
if (!GetProperty(cx, obj, obj, name, &rval))
return false;
/* If there is no custom __iterator__ method, we are done here. */
if (MOZ_LIKELY(!rval.isObject())) {
objp.set(nullptr);
return true;
}
if (!cx->runningWithTrustedPrincipals())
++sCustomIteratorCount;
/* Otherwise call it and return that object. */
{
FixedInvokeArgs<1> args(cx);
args[0].setBoolean((flags & JSITER_FOREACH) == 0);
RootedValue thisv(cx, ObjectValue(*obj));
if (!js::Call(cx, rval, thisv, args, &rval))
return false;
}
if (rval.isPrimitive()) {
// Ignore the stack when throwing. We can't tell whether we were
// supposed to skip over a new.target or not.
JSAutoByteString bytes;
if (!AtomToPrintableString(cx, name, &bytes))
return false;
RootedValue val(cx, ObjectValue(*obj));
ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
JSDVG_IGNORE_STACK, val, nullptr, bytes.ptr());
return false;
}
objp.set(&rval.toObject());
return true;
}
static bool legacy_iterator_next(JSContext* cx, unsigned argc, Value* vp);
static inline PropertyIteratorObject*
@ -877,6 +926,9 @@ CanStoreInIteratorCache(JSContext* cx, JSObject* obj)
return false;
if (MOZ_UNLIKELY(clasp->getNewEnumerate() || clasp->getEnumerate()))
return false;
if (MOZ_UNLIKELY(obj->as<NativeObject>().containsPure(cx->names().iteratorIntrinsic)))
return false;
} else {
MOZ_ASSERT(obj->is<UnboxedPlainObject>());
}
@ -945,12 +997,18 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags)
return Proxy::enumerate(cx, obj);
}
RootedObject res(cx);
if (!GetCustomIterator(cx, obj, flags, &res))
return nullptr;
if (res) {
assertSameCompartment(cx, res);
return res;
}
AutoIdVector keys(cx);
if (!Snapshot(cx, obj, flags, &keys))
return nullptr;
JSObject* res;
if (flags & JSITER_FOREACH) {
MOZ_ASSERT(numGuards == 0);
res = VectorToValueIterator(cx, obj, flags, keys);
@ -1022,6 +1080,27 @@ js::ThrowStopIteration(JSContext* cx)
/*** Iterator objects ****************************************************************************/
bool
js::IteratorConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() == 0) {
ReportMissingArg(cx, args.calleev(), 0);
return false;
}
bool keyonly = false;
if (args.length() >= 2)
keyonly = ToBoolean(args[1]);
unsigned flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE));
RootedObject iterobj(cx, ValueToIterator(cx, flags, args[0]));
if (!iterobj)
return false;
args.rval().setObject(*iterobj);
return true;
}
MOZ_ALWAYS_INLINE bool
NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval, bool* done)
{
@ -1054,8 +1133,8 @@ NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval, b
return true;
}
bool
js::IsLegacyIterator(HandleValue v)
MOZ_ALWAYS_INLINE bool
IsIterator(HandleValue v)
{
return v.isObject() && v.toObject().hasClass(&PropertyIteratorObject::class_);
}
@ -1063,7 +1142,7 @@ js::IsLegacyIterator(HandleValue v)
MOZ_ALWAYS_INLINE bool
legacy_iterator_next_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsLegacyIterator(args.thisv()));
MOZ_ASSERT(IsIterator(args.thisv()));
RootedObject thisObj(cx, &args.thisv().toObject());
@ -1087,9 +1166,15 @@ static bool
legacy_iterator_next(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsLegacyIterator, legacy_iterator_next_impl>(cx, args);
return CallNonGenericMethod<IsIterator, legacy_iterator_next_impl>(cx, args);
}
static const JSFunctionSpec legacy_iterator_methods[] = {
JS_SELF_HOSTED_SYM_FN(iterator, "LegacyIteratorShim", 0, 0),
JS_FN("next", legacy_iterator_next, 0, 0),
JS_FS_END
};
size_t
PropertyIteratorObject::sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const
{
@ -1126,6 +1211,7 @@ const ClassOps PropertyIteratorObject::classOps_ = {
const Class PropertyIteratorObject::class_ = {
"Iterator",
JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
JSCLASS_HAS_PRIVATE |
JSCLASS_BACKGROUND_FINALIZE,
&PropertyIteratorObject::classOps_
@ -1605,6 +1691,44 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> globa
return true;
}
JSObject*
js::InitLegacyIteratorClass(JSContext* cx, HandleObject obj)
{
Handle<GlobalObject*> global = obj.as<GlobalObject>();
if (global->getPrototype(JSProto_Iterator).isObject())
return &global->getPrototype(JSProto_Iterator).toObject();
RootedObject iteratorProto(cx);
iteratorProto = GlobalObject::createBlankPrototype(cx, global,
&PropertyIteratorObject::class_);
if (!iteratorProto)
return nullptr;
NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, 0);
if (!ni)
return nullptr;
iteratorProto->as<PropertyIteratorObject>().setNativeIterator(ni);
ni->init(nullptr, nullptr, 0 /* flags */, 0, 0);
Rooted<JSFunction*> ctor(cx);
ctor = GlobalObject::createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2);
if (!ctor)
return nullptr;
if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto))
return nullptr;
if (!DefinePropertiesAndFunctions(cx, iteratorProto, nullptr, legacy_iterator_methods))
return nullptr;
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Iterator,
ctor, iteratorProto))
{
return nullptr;
}
return &global->getPrototype(JSProto_Iterator).toObject();
}
JSObject*
js::InitStopIterationClass(JSContext* cx, HandleObject obj)
{

View File

@ -194,6 +194,9 @@ IteratorCloseForException(JSContext* cx, HandleObject obj);
void
UnwindIteratorForUncatchableException(JSContext* cx, JSObject* obj);
bool
IteratorConstructor(JSContext* cx, unsigned argc, Value* vp);
extern bool
SuppressDeletedProperty(JSContext* cx, HandleObject obj, jsid id);
@ -217,8 +220,8 @@ ThrowStopIteration(JSContext* cx);
extern JSObject*
CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
bool
IsLegacyIterator(HandleValue v);
extern JSObject*
InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
extern JSObject*
InitStopIterationClass(JSContext* cx, HandleObject obj);

View File

@ -84,7 +84,7 @@
real(CompileError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
real(LinkError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMLINKERROR)) \
real(RuntimeError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
imaginary(Iterator, dummy, dummy) \
real(Iterator, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \
real(StopIteration, InitStopIterationClass, OCLASP(StopIteration)) \
real(ArrayBuffer, InitViaClassSpec, OCLASP(ArrayBuffer)) \
real(Int8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \

View File

@ -0,0 +1,30 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 407957;
var summary = 'Iterator is mutable.';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
var obj = {};
var saveIterator = Iterator;
Iterator = obj;
reportCompare(obj, Iterator, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,60 @@
// |reftest| skip-if(Android)
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 381374;
var summary = 'js_AddScopeProperty - overwrite property with watchpoint';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
function huh()
{
var f;
Iterator; // ???
if (0 && 0) {
eval(""); // ???
}
f = new Function("x = 1");
try {
f();
} catch(e) {}
}
this.watch('x', function(){});
this.__defineGetter__('x', new Function());
huh();
if (typeof gczeal == 'function')
{
gczeal(2);
}
for (y in [0,1]) { this.__defineSetter__('x', function(){}); }
if (typeof gczeal == 'function')
{
gczeal(0);
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,165 @@
/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = "(none)";
var summary = "Basic support for accessing iterable objects using Iterator";
var actual, expect;
printBugNumber(BUGNUMBER);
printStatus(summary);
/**************
* BEGIN TEST *
**************/
var failed = false;
function Array_equals(a, b)
{
if (!(a instanceof Array) || !(b instanceof Array))
throw new Error("Arguments not both of type Array");
if (a.length != b.length)
return false;
for (var i = 0, sz = a.length; i < sz; i++)
if (a[i] !== b[i])
return false;
return true;
}
var iterable = { persistedProp: 17 };
try
{
// nothing unusual so far -- verify basic properties
for (var i in iterable)
{
if (i != "persistedProp")
throw "no persistedProp!";
if (iterable[i] != 17)
throw "iterable[\"persistedProp\"] == 17";
}
var keys = ["foo", "bar", "baz"];
var vals = [6, 5, 14];
iterable.__iterator__ =
function(keysOnly)
{
var gen =
function()
{
for (var i = 0; i < keys.length; i++)
{
if (keysOnly)
yield keys[i];
else
yield [keys[i], vals[i]];
}
};
return gen();
};
/* Test [key, value] Iterator */
var index = 0;
var lastSeen = "INITIALVALUE";
var it = Iterator(iterable);
try
{
while (true)
{
var nextVal = it.next();
if (!Array_equals(nextVal, [keys[index], vals[index]]))
throw "Iterator(iterable): wrong next result\n" +
" expected: " + [keys[index], vals[index]] + "\n" +
" actual: " + nextVal;
lastSeen = keys[index];
index++;
}
}
catch (e)
{
if (lastSeen !== keys[keys.length - 1])
throw "Iterator(iterable): not everything was iterated!\n" +
" last iterated was: " + lastSeen + "\n" +
" error: " + e;
if (e !== StopIteration)
throw "Iterator(iterable): missing or invalid StopIteration";
}
if (iterable.persistedProp != 17)
throw "iterable.persistedProp not persisted!";
/* Test [key, value] Iterator, called with an explicit |false| parameter */
var index = 0;
lastSeen = "INITIALVALUE";
it = Iterator(iterable, false);
try
{
while (true)
{
var nextVal = it.next();
if (!Array_equals(nextVal, [keys[index], vals[index]]))
throw "Iterator(iterable, false): wrong next result\n" +
" expected: " + [keys[index], vals[index]] + "\n" +
" actual: " + nextVal;
lastSeen = keys[index];
index++;
}
}
catch (e)
{
if (lastSeen !== keys[keys.length - 1])
throw "Iterator(iterable, false): not everything was iterated!\n" +
" last iterated was: " + lastSeen + "\n" +
" error: " + e;
if (e !== StopIteration)
throw "Iterator(iterable, false): missing or invalid StopIteration";
}
if (iterable.persistedProp != 17)
throw "iterable.persistedProp not persisted!";
/* Test key-only Iterator */
index = 0;
lastSeen = undefined;
it = Iterator(iterable, true);
try
{
while (true)
{
var nextVal = it.next();
if (nextVal !== keys[index])
throw "Iterator(iterable, true): wrong next result\n" +
" expected: " + keys[index] + "\n" +
" actual: " + nextVal;
lastSeen = keys[index];
index++;
}
}
catch (e)
{
if (lastSeen !== keys[keys.length - 1])
throw "Iterator(iterable, true): not everything was iterated!\n" +
" last iterated was: " + lastSeen + "\n" +
" error: " + e;
if (e !== StopIteration)
throw "Iterator(iterable, true): missing or invalid StopIteration";
}
if (iterable.persistedProp != 17)
throw "iterable.persistedProp not persisted!";
}
catch (e)
{
failed = e;
}
expect = false;
actual = failed;
reportCompare(expect, actual, summary);

View File

@ -42,6 +42,38 @@ try
throw "iterable[\"persistedProp\"] == 17";
}
var keys = ["foo", "bar", "baz"];
var vals = [6, 5, 14];
iterable.__iterator__ =
function(keysOnly)
{
var gen =
function()
{
for (var i = 0; i < keys.length; i++)
{
if (keysOnly)
yield keys[i];
else
yield [keys[i], vals[i]];
}
};
return gen();
};
// for each sets keysOnly==false
var index = 0;
for each (var v in iterable)
{
if (!Array_equals(v, [keys[index], vals[index]]))
throw "for-each iteration failed on index=" + index + "!";
index++;
}
if (index != keys.length)
throw "not everything iterated! index=" + index +
", keys.length=" + keys.length;
if (iterable.persistedProp != 17)
throw "iterable.persistedProp not persisted!";
}

View File

@ -30,6 +30,38 @@ try
throw "iterable[\"persistedProp\"] == 17";
}
var keys = ["foo", "bar", "baz"];
var vals = [6, 5, 14];
iterable.__iterator__ =
function(keysOnly)
{
var gen =
function()
{
for (var i = 0; i < keys.length; i++)
{
if (keysOnly)
yield keys[i];
else
yield [keys[i], vals[i]];
}
};
return gen();
};
// for in sets keysOnly==true
var index = 0;
for (var k in iterable)
{
if (k != keys[index])
throw "for-in iteration failed on keys[\"" + index + "\"]";
index++;
}
if (index != keys.length)
throw "not everything iterated! index=" + index +
", keys.length=" + keys.length;
if (iterable.persistedProp != 17)
throw "iterable.persistedProp not persisted!";
}

View File

@ -0,0 +1,102 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
// See http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Iterators_and_Generators
//-----------------------------------------------------------------------------
var BUGNUMBER = "410725";
var summary = "Test of the global Iterator constructor";
var actual, expect;
printBugNumber(BUGNUMBER);
printStatus(summary);
/**************
* BEGIN TEST *
**************/
function iteratorToArray(iterator) {
var result = [];
for (var i in iterator) {
result[result.length] = i;
}
return result.sort();
}
var obj = {a:1, b:2};
reportCompare('["a", "b"]',
uneval(iteratorToArray(obj)),
'uneval(iteratorToArray(obj))');
reportCompare('[["a", 1], ["b", 2]]',
uneval(iteratorToArray(Iterator(obj))),
'uneval(iteratorToArray(Iterator(obj)))');
reportCompare('[["a", 1], ["b", 2]]',
uneval(iteratorToArray(new Iterator(obj))),
'uneval(iteratorToArray(new Iterator(obj)))');
reportCompare('[["a", 1], ["b", 2]]',
uneval(iteratorToArray(Iterator(obj,false))),
'uneval(iteratorToArray(Iterator(obj,false)))');
reportCompare('[["a", 1], ["b", 2]]',
uneval(iteratorToArray(new Iterator(obj,false))),
'uneval(iteratorToArray(new Iterator(obj,false)))');
reportCompare('["a", "b"]',
uneval(iteratorToArray(Iterator(obj,true))),
'uneval(iteratorToArray(Iterator(obj,true)))');
reportCompare('["a", "b"]',
uneval(iteratorToArray(new Iterator(obj,true))),
'uneval(iteratorToArray(new Iterator(obj,true)))');
var flag;
var obji = {a:1, b:2};
obji.__iterator__ = function (b) { flag = b; yield -1; yield -2; }
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(obji)),
'uneval(iteratorToArray(obji))');
reportCompare(true, flag, 'uneval(iteratorToArray(obji)) flag');
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(Iterator(obji))),
'uneval(iteratorToArray(Iterator(obji)))');
reportCompare(false, flag, 'uneval(iteratorToArray(Iterator(obji))) flag');
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(new Iterator(obji))),
'uneval(iteratorToArray(new Iterator(obji)))');
reportCompare(false, flag, 'uneval(iteratorToArray(new Iterator(obji))) flag');
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(Iterator(obji,false))),
'uneval(iteratorToArray(Iterator(obji,false)))');
reportCompare(false, flag, 'uneval(iteratorToArray(Iterator(obji,false))) flag');
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(new Iterator(obji,false))),
'uneval(iteratorToArray(new Iterator(obji,false)))');
reportCompare(false, flag, 'uneval(iteratorToArray(new Iterator(obji,false))) flag');
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(Iterator(obji,true))),
'uneval(iteratorToArray(Iterator(obji,true)))');
reportCompare(true, flag, 'uneval(iteratorToArray(Iterator(obji,true))) flag');
flag = -1;
reportCompare('[-1, -2]',
uneval(iteratorToArray(new Iterator(obji,true))),
'uneval(iteratorToArray(new Iterator(obji,true)))');
reportCompare(true, flag, 'uneval(iteratorToArray(new Iterator(obji,true))) flag');

View File

@ -0,0 +1,45 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 346021;
var summary = 'Implementing __iterator__ as generator';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
var o = { __iterator__: function () { print(12); yield 42; } };
expect = 42;
actual = 0;
for (let i in Iterator(o))
{
actual = i;
}
reportCompare(expect, actual, summary);
actual = 0;
for (let i in o)
{
actual = i; // this doesn't iterate 42
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,46 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 354499;
var summary = 'Iterating over Array elements';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = actual = 'No Crash';
var obj = {get a(){ return new Object(); }};
function setter(v)
{
// Push out obj.a from all temp roots
var tmp = { get toString() { return new Object(); }};
try { String(tmp); } catch (e) { }
gc();
}
Array.prototype.__defineGetter__(0, function() { });
Array.prototype.__defineSetter__(0, setter);
for (var i in Iterator(obj))
print(uneval(i));
delete Array.prototype[0];
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,49 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 354499;
var summary = 'Iterating over Array elements';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = actual = 'No Crash';
function get_value()
{
// Unroot the first element
this[0] = 0;
// Call gc to collect atom corresponding to Math.sqrt(2)
gc();
}
var counter = 2;
Iterator.prototype.next = function()
{
if (counter-- <= 0) throw StopIteration;
var a = [Math.sqrt(2), 1];
a.__defineGetter__(1, get_value);
return a;
};
for (i in [1])
;
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,34 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 354945;
var summary = 'Do not crash with new Iterator';
var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value';
var actual;
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
try {
var obj = {};
obj.__iterator__ = function(){ };
for(t in (new Iterator(obj))) { }
} catch (ex) {
actual = ex.toString();
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,38 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 354945;
var summary = 'Do not crash with new Iterator';
var actual = 'No Crash';
var expect = 'No Crash';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value';
var obj = {};
obj.__iterator__ = function(){ };
try
{
for(t in (obj)) { }
}
catch(ex)
{
actual = ex + '';
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,6 @@
f = eval("(function(){return x=Iterator(/x/)})")
for (a in f()) {}
for (d in x) {}
reportCompare(0, 0, "");

View File

@ -0,0 +1,23 @@
var actual = '';
var expected = 'A0B1B2C0C1C2';
var x = Iterator([1,2,3], true);
for (var a in x) {
actual += 'A' + a;
for (var b in x) {
actual += 'B' + b;
}
}
var y = Iterator([1,2,3], true);
for (var c in y) {
actual += 'C' + c;
}
for (var d in y) {
actual += 'D' + d;
}
reportCompare(expected, actual, "Handle nested Iterator iteration right");

View File

@ -0,0 +1,89 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = "(none)";
var summary = "Iterator() test";
var actual, expect;
printBugNumber(BUGNUMBER);
printStatus(summary);
/**************
* BEGIN TEST *
**************/
var failed = false;
function Array_equals(a, b)
{
if (!(a instanceof Array) || !(b instanceof Array))
throw new Error("Arguments not both of type Array");
if (a.length != b.length)
return false;
for (var i = 0, sz = a.length; i < sz; i++)
if (a[i] !== b[i])
return false;
return true;
}
var meow = "meow", oink = "oink", baa = "baa";
var it = Iterator([meow, oink, baa]);
var it2 = Iterator([meow, oink, baa], true);
try
{
if (!Array_equals(it.next(), [0, meow]))
throw [0, meow];
if (!Array_equals(it.next(), [1, oink]))
throw [1, oink];
if (!Array_equals(it.next(), [2, baa]))
throw [2, baa];
var stopPassed = false;
try
{
it.next();
}
catch (e)
{
if (e === StopIteration)
stopPassed = true;
}
if (!stopPassed)
throw "it: missing or incorrect StopIteration";
if (it2.next() != 0)
throw "wanted key=0";
if (it2.next() != 1)
throw "wanted key=1";
if (it2.next() != 2)
throw "wanted key=2";
var stopPassed = false;
try
{
it2.next();
}
catch (e)
{
if (e === StopIteration)
stopPassed = true;
}
if (!stopPassed)
throw "it2: missing or incorrect StopIteration";
}
catch (e)
{
failed = e;
}
expect = false;
actual = failed;
reportCompare(expect, actual, summary);

View File

@ -0,0 +1,19 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 341496;
var summary = 'Iterators: check that adding properties does not crash';
var actual = 'No Crash';
var expect = 'No Crash';
printBugNumber(BUGNUMBER);
printStatus (summary);
var iter = Iterator({});
for (var i = 0; i != 10*1000; ++i)
iter[i] = i;
reportCompare(expect, actual, summary);

View File

@ -0,0 +1,42 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 354750;
var summary = 'Changing Iterator.prototype.next should not affect default iterator';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
Iterator.prototype.next = function() {
throw "This should not be thrown";
}
expect = 'No exception';
actual = 'No exception';
try
{
for (var i in [])
{
}
}
catch(ex)
{
actual = ex;
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,28 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 355025;
var summary = 'Test regression from bug 354750 - Iterable()';
var actual = 'No Error';
var expect = 'No Error';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
Iterator([]);
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,37 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 355090;
var summary = 'Iterator(8) is a function';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = 'No Error';
actual = 'No Error';
try
{
Iterator(8);
}
catch(ex)
{
actual = ex + '';
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,24 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var BUGNUMBER = 568056;
var summary = "Iterator(obj) must not go up obj's prototype chain";
var foo = {
z: 9,
};
var bar = {
__proto__: foo,
a: 1,
b: 2,
};
var results = [];
for each (let [key, value] in Iterator(bar))
results.push(key + ":" + value);
var actual = results.join(';')
var expect = "a:1;b:2";
reportCompare(expect, actual, summary);

View File

@ -0,0 +1,44 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 385393;
var summary = 'Regression test for bug 385393';
var actual = 'No Crash';
var expect = 'No Crash';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
function c(gen)
{
Iterator;
"" + gen;
for (var i in gen())
;
}
function gen()
{
({}).hasOwnProperty();
yield;
}
c(gen);
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -0,0 +1,30 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 407957;
var summary = 'Iterator is mutable.';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
var obj = {};
var saveIterator = Iterator;
Iterator = obj;
reportCompare(obj, Iterator, summary);
exitFunc ('test');
}

View File

@ -206,6 +206,7 @@
macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
macro(IterableToList, IterableToList, "IterableToList") \
macro(iterate, iterate, "iterate") \
macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \
macro(join, join, "join") \
macro(js, js, "js") \
macro(keys, keys, "keys") \

View File

@ -439,6 +439,10 @@ class GlobalObject : public NativeObject
TypedObjectModuleObject& getTypedObjectModule() const;
JSObject* getLegacyIteratorPrototype() {
return &getPrototype(JSProto_Iterator).toObject();
}
static JSObject*
getOrCreateCollatorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return getOrCreateObject(cx, global, COLLATOR_PROTO, initIntlObject);

View File

@ -687,6 +687,9 @@ EnsureParserCreatedClasses(JSContext* cx, ParseTaskKind kind)
if (!EnsureConstructor(cx, global, JSProto_RegExp))
return false; // needed by regular expression literals
if (!EnsureConstructor(cx, global, JSProto_Iterator))
return false; // needed by ???
if (!GlobalObject::initStarGenerators(cx, global))
return false; // needed by function*() {} and generator comprehensions
@ -1794,7 +1797,8 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSContext* cx, ParseTask* par
JSProtoKey key = JS::IdentifyStandardPrototype(protoObj);
if (key != JSProto_Null) {
MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array ||
key == JSProto_Function || key == JSProto_RegExp);
key == JSProto_Function || key == JSProto_RegExp ||
key == JSProto_Iterator);
newProto = GetBuiltinPrototypePure(global, key);
} else if (protoObj == parseTaskStarGenFunctionProto) {
newProto = global->getStarGeneratorFunctionPrototype();

View File

@ -2235,6 +2235,10 @@ GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
if (script->selfHosted())
return true;
// We may just be checking if that object has an iterator.
if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
return true;
// Do not warn about tests like (obj[prop] == undefined).
pc += CodeSpec[*pc].length;
if (Detecting(cx, script, pc))

View File

@ -3236,6 +3236,11 @@ nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext* cx, MutableHandleVal
if (!JS_DefineProperty(cx, obj, "setProto", v, attrs))
return NS_ERROR_OUT_OF_MEMORY;
i = JS_GetCustomIteratorCount(cx);
v.setDouble(i);
if (!JS_DefineProperty(cx, obj, "customIter", v, attrs))
return NS_ERROR_OUT_OF_MEMORY;
rval.setObject(*obj);
return NS_OK;
}

View File

@ -24,10 +24,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=500931
var ifr = document.getElementById('ifr');
var docnodes = ifr.contentDocument.body.childNodes;
var index, value;
for (let i of Object.entries(docnodes)) {
for (let i in Iterator(docnodes)) {
index = i[0], value = i[1];
}
is(index, "0", "enumerated the 0th element");
is(index, 0, "enumerated the 0th element");
ok(value instanceof Text, "the 0th element was a text node");
SimpleTest.finish();
}

View File

@ -189,6 +189,7 @@ Structure:
"js" : {
"setProto": <unsigned integer>, // Number of times __proto__ is set
"customIter": <unsigned integer> // Number of times __iterator__ is used (i.e., is found for a for-in loop)
}
maximalNumberOfConcurrentThreads