Backout changeset 8e3bc766092d (bug 725909) because of merge conflicts with the rest of the backouts

This commit is contained in:
Ehsan Akhgari 2012-07-04 19:43:42 -04:00
parent a809593e1c
commit f051d81342
48 changed files with 12 additions and 932 deletions

View File

@ -18,7 +18,6 @@
#include "vm/Stack.h"
#include "jsobjinlines.h"
#include "vm/MethodGuard-inl.h"
using namespace js;
@ -704,126 +703,6 @@ HashableValue::mark(JSTracer *trc) const
return hv;
}
/*** MapIterator *********************************************************************************/
class js::MapIteratorObject : public JSObject {
public:
enum { TargetSlot, RangeSlot, SlotCount };
static JSFunctionSpec methods[];
static MapIteratorObject *create(JSContext *cx, HandleObject mapobj, ValueMap *data);
static void finalize(FreeOp *fop, JSObject *obj);
private:
inline ValueMap::Range *range();
static JSBool next(JSContext *cx, unsigned argc, Value *vp);
};
inline js::MapIteratorObject &
JSObject::asMapIterator()
{
JS_ASSERT(isMapIterator());
return *static_cast<js::MapIteratorObject *>(this);
}
Class js::MapIteratorClass = {
"Iterator",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
MapIteratorObject::finalize
};
JSFunctionSpec MapIteratorObject::methods[] = {
JS_FN("next", next, 0, 0),
JS_FS_END
};
inline ValueMap::Range *
MapIteratorObject::range()
{
return static_cast<ValueMap::Range *>(getSlot(RangeSlot).toPrivate());
}
bool
GlobalObject::initMapIteratorProto(JSContext *cx, Handle<GlobalObject *> global)
{
JSObject *base = global->getOrCreateIteratorPrototype(cx);
if (!base)
return false;
Rooted<JSObject*> proto(cx,
NewObjectWithGivenProto(cx, &MapIteratorClass, base, global));
if (!proto)
return false;
proto->setSlot(MapIteratorObject::RangeSlot, PrivateValue(NULL));
if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods))
return false;
global->setReservedSlot(MAP_ITERATOR_PROTO, ObjectValue(*proto));
return true;
}
MapIteratorObject *
MapIteratorObject::create(JSContext *cx, HandleObject mapobj, ValueMap *data)
{
Rooted<GlobalObject *> global(cx, &mapobj->global());
Rooted<JSObject*> proto(cx, global->getOrCreateMapIteratorPrototype(cx));
if (!proto)
return false;
ValueMap::Range *range = cx->new_<ValueMap::Range>(data->all());
if (!range)
return false;
JSObject *iterobj = NewObjectWithGivenProto(cx, &MapIteratorClass, proto, global);
if (!iterobj) {
cx->delete_(range);
return false;
}
iterobj->setSlot(TargetSlot, ObjectValue(*mapobj));
iterobj->setSlot(RangeSlot, PrivateValue(range));
return static_cast<MapIteratorObject *>(iterobj);
}
void
MapIteratorObject::finalize(FreeOp *fop, JSObject *obj)
{
fop->delete_(obj->asMapIterator().range());
}
JSBool
MapIteratorObject::next(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *thisobj;
if (!NonGenericMethodGuard(cx, args, next, &MapIteratorClass, &thisobj))
return false;
if (!thisobj)
return true;
ValueMap::Range *range = thisobj->asMapIterator().range();
if (!range)
return js_ThrowStopIteration(cx);
if (range->empty()) {
cx->delete_(range);
thisobj->setReservedSlot(RangeSlot, PrivateValue(NULL));
return js_ThrowStopIteration(cx);
}
Value pair[2] = { range->front().key.get(), range->front().value };
JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
if (!pairobj)
return false;
range->popFront();
args.rval().setObject(*pairobj);
return true;
}
/*** Map *****************************************************************************************/
@ -852,7 +731,6 @@ JSFunctionSpec MapObject::methods[] = {
JS_FN("has", has, 1, 0),
JS_FN("set", set, 2, 0),
JS_FN("delete", delete_, 1, 0),
JS_FN("iterator", iterator, 0, 0),
JS_FS_END
};
@ -934,7 +812,7 @@ MapObject::finalize(FreeOp *fop, JSObject *obj)
JSBool
MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
{
Rooted<JSObject*> obj(cx, NewBuiltinClassInstance(cx, &class_));
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
if (!obj)
return false;
@ -1061,138 +939,12 @@ MapObject::delete_(JSContext *cx, unsigned argc, Value *vp)
return true;
}
JSBool
MapObject::iterator(JSContext *cx, unsigned argc, Value *vp)
{
THIS_MAP(iterator, cx, argc, vp, args, map);
Rooted<JSObject*> mapobj(cx, &args.thisv().toObject());
Rooted<JSObject*> iterobj(cx, MapIteratorObject::create(cx, mapobj, &map));
if (!iterobj)
return false;
args.rval().setObject(*iterobj);
return true;
}
JSObject *
js_InitMapClass(JSContext *cx, JSObject *obj)
{
return MapObject::initClass(cx, obj);
}
/*** SetIterator *********************************************************************************/
class js::SetIteratorObject : public JSObject {
public:
enum { TargetSlot, RangeSlot, SlotCount };
static JSFunctionSpec methods[];
static SetIteratorObject *create(JSContext *cx, HandleObject setobj, ValueSet *data);
static void finalize(FreeOp *fop, JSObject *obj);
private:
inline ValueSet::Range *range();
static JSBool next(JSContext *cx, unsigned argc, Value *vp);
};
inline js::SetIteratorObject &
JSObject::asSetIterator()
{
JS_ASSERT(isSetIterator());
return *static_cast<js::SetIteratorObject *>(this);
}
Class js::SetIteratorClass = {
"Iterator",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount),
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
SetIteratorObject::finalize
};
JSFunctionSpec SetIteratorObject::methods[] = {
JS_FN("next", next, 0, 0),
JS_FS_END
};
inline ValueSet::Range *
SetIteratorObject::range()
{
return static_cast<ValueSet::Range *>(getSlot(RangeSlot).toPrivate());
}
bool
GlobalObject::initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global)
{
JSObject *base = global->getOrCreateIteratorPrototype(cx);
if (!base)
return false;
JSObject *proto = NewObjectWithGivenProto(cx, &SetIteratorClass, base, global);
if (!proto)
return false;
proto->setSlot(SetIteratorObject::RangeSlot, PrivateValue(NULL));
if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods))
return false;
global->setReservedSlot(SET_ITERATOR_PROTO, ObjectValue(*proto));
return true;
}
SetIteratorObject *
SetIteratorObject::create(JSContext *cx, HandleObject setobj, ValueSet *data)
{
Rooted<GlobalObject *> global(cx, &setobj->global());
Rooted<JSObject*> proto(cx, global->getOrCreateSetIteratorPrototype(cx));
if (!proto)
return false;
ValueSet::Range *range = cx->new_<ValueSet::Range>(data->all());
if (!range)
return false;
JSObject *iterobj = NewObjectWithGivenProto(cx, &SetIteratorClass, proto, global);
if (!iterobj) {
cx->delete_(range);
return false;
}
iterobj->setSlot(TargetSlot, ObjectValue(*setobj));
iterobj->setSlot(RangeSlot, PrivateValue(range));
return static_cast<SetIteratorObject *>(iterobj);
}
void
SetIteratorObject::finalize(FreeOp *fop, JSObject *obj)
{
fop->delete_(obj->asSetIterator().range());
}
JSBool
SetIteratorObject::next(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *thisobj;
if (!NonGenericMethodGuard(cx, args, next, &SetIteratorClass, &thisobj))
return false;
if (!thisobj)
return true;
ValueSet::Range *range = thisobj->asSetIterator().range();
if (!range || range->empty()) {
if (range) {
cx->delete_(range);
thisobj->setReservedSlot(RangeSlot, PrivateValue(NULL));
}
return js_ThrowStopIteration(cx);
}
args.rval() = range->front().get();
range->popFront();
return true;
}
/*** Set *****************************************************************************************/
@ -1220,7 +972,6 @@ JSFunctionSpec SetObject::methods[] = {
JS_FN("has", has, 1, 0),
JS_FN("add", add, 1, 0),
JS_FN("delete", delete_, 1, 0),
JS_FN("iterator", iterator, 0, 0),
JS_FS_END
};
@ -1252,7 +1003,7 @@ SetObject::finalize(FreeOp *fop, JSObject *obj)
JSBool
SetObject::construct(JSContext *cx, unsigned argc, Value *vp)
{
Rooted<JSObject*> obj(cx, NewBuiltinClassInstance(cx, &class_));
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
if (!obj)
return false;
@ -1331,18 +1082,6 @@ SetObject::delete_(JSContext *cx, unsigned argc, Value *vp)
return true;
}
JSBool
SetObject::iterator(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SET(iterator, cx, argc, vp, args, set);
Rooted<JSObject*> setobj(cx, &args.thisv().toObject());
Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, setobj, &set));
if (!iterobj)
return false;
args.rval().setObject(*iterobj);
return true;
}
JSObject *
js_InitSetClass(JSContext *cx, JSObject *obj)
{

View File

@ -95,7 +95,6 @@ class MapObject : public JSObject {
static JSBool has(JSContext *cx, unsigned argc, Value *vp);
static JSBool set(JSContext *cx, unsigned argc, Value *vp);
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
static JSBool iterator(JSContext *cx, unsigned argc, Value *vp);
};
class SetObject : public JSObject {
@ -113,7 +112,6 @@ class SetObject : public JSObject {
static JSBool has(JSContext *cx, unsigned argc, Value *vp);
static JSBool add(JSContext *cx, unsigned argc, Value *vp);
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
static JSBool iterator(JSContext *cx, unsigned argc, Value *vp);
};
} /* namespace js */

View File

@ -1,11 +0,0 @@
// for-of can be used to iterate over a Map twice.
var map = Map([['a', 0], ['b', 1], ['c', 2]]);
var log = '';
for (let i = 0; i < 2; i++) {
for (let [k, v] of map)
log += k + v;
log += ';'
}
assertEq(log, 'a0b1c2;a0b1c2;');

View File

@ -1,11 +0,0 @@
// Nested for-of loops can iterate over a Map.
var map = Map([['a', 0], ['b', 1]]);
var log = '';
for (let [k0, v0] of map) {
log += k0 + v0 + ':'
for (let [k1, v1] of map)
log += k1 + v1;
log += ';'
};
assertEq(log, 'a0:a0b1;b1:a0b1;');

View File

@ -1,15 +0,0 @@
// map.iterator() is live: entries added during iteration are visited.
var map = Map();
function force(k) {
if (!map.has(k) && k >= 0)
map.set(k, k - 1);
}
force(5);
var log = '';
for (let [k, v] of map) {
log += k + ';';
force(v);
}
assertEq(log, '5;4;3;2;1;0;');
assertEq(map.size(), 6);

View File

@ -1,11 +0,0 @@
// A Map iterator does not iterate over new entries added after it throws StopIteration.
load(libdir + "asserts.js");
load(libdir + "eqArrayHelper.js");
var map = Map();
var iter0 = map.iterator(), iter1 = map.iterator();
assertThrowsValue(function () { iter0.next(); }, StopIteration); // closes iter0
map.set(1, 2);
assertThrowsValue(function () { iter0.next(); }, StopIteration); // already closed
assertEqArray(iter1.next(), [1, 2]); // was not yet closed

View File

@ -1,14 +0,0 @@
// Removing and re-adding entries while an iterator is live causes the iterator to visit them again.
var map = Map([['a', 1]]);
var n = 5;
for (let [k, v] of map) {
assertEq(k, 'a');
assertEq(v, 1);
if (n === 0)
break;
map.delete('a');
map.set('a', 1);
n--;
}
assertEq(n, 0);

View File

@ -1,15 +0,0 @@
// Map iterators produces entries in the order they were inserted.
load(libdir + "eqArrayHelper.js");
var map = Map();
for (var i = 7; i !== 1; i = i * 7 % 1117)
map.set("" + i, i);
assertEq(map.size(), 557);
i = 7;
for (var pair of map) {
assertEqArray(pair, ["" + i, i]);
i = i * 7 % 1117;
}
assertEq(i, 1);

View File

@ -1,15 +0,0 @@
// mapiter.next() returns an actual array.
var key = {};
var map = Map([[key, 'value']]);
var entry = map.iterator().next();
assertEq(Array.isArray(entry), true);
assertEq(Object.getPrototypeOf(entry), Array.prototype);
assertEq(Object.isExtensible(entry), true);
assertEq(entry.length, 2);
var names = Object.getOwnPropertyNames(entry).sort();
assertEq(names.length, 3);
assertEq(names.join(","), "0,1,length");
assertEq(entry[0], key);
assertEq(entry[1], 'value');

View File

@ -1,10 +0,0 @@
// mapiter.next() returns a fresh array each time.
var map = Map([['a', 1], ['b', 2]]);
var iter = map.iterator();
var a = iter.next(), b = iter.next();
assertEq(a !== b, true);
assertEq(a[0], 'a');
assertEq(b[0], 'b');
var a1 = map.iterator().next();
assertEq(a !== a1, true);

View File

@ -1,12 +0,0 @@
// Modifying an array returned by mapiter.next() does not modify the Map.
var map = Map([['a', 1]]);
var pair = map.iterator().next();
assertEq(pair[0], 'a');
pair[0] = 'b';
pair[1] = 2;
assertEq(pair[0], 'b');
assertEq(pair[1], 2);
assertEq(map.get('a'), 1);
assertEq(map.has('b'), false);
assertEq(map.size(), 1);

View File

@ -1,8 +0,0 @@
// for-of works on a cross-compartment wrapper of a Map.
var g = newGlobal('new-compartment');
var mw = g.eval("Map([['a', 1], ['b', 2]])");
var log = '';
for (let [k, v] of mw)
log += k + v;
assertEq(log, "a1b2");

View File

@ -1,19 +0,0 @@
// map.iterator() and iter.next() are non-generic but work on cross-compartment wrappers.
load(libdir + "asserts.js");
load(libdir + "eqArrayHelper.js");
var g = newGlobal('new-compartment');
var iterator_fn = Map.prototype.iterator;
assertThrowsInstanceOf(function () { iterator_fn.call({}); }, TypeError);
assertThrowsInstanceOf(function () { iterator_fn.call(Set()); }, TypeError);
var mapw = g.eval("Map([['x', 1], ['y', 2]])");
assertEqArray(iterator_fn.call(mapw).next(), ["x", 1]);
var next_fn = Map().iterator().next;
assertThrowsInstanceOf(function () { next_fn.call({}); }, TypeError);
assertThrowsInstanceOf(function () { next_fn.call(Set().iterator()); }, TypeError);
var iterw = mapw.iterator();
assertEqArray(next_fn.call(iterw), ["x", 1]);
assertEqArray(next_fn.call(iterw), ["y", 2]);
assertThrowsValue(function () { next_fn.call(iterw); }, g.StopIteration);

View File

@ -1,40 +0,0 @@
// A map iterator can cope with removing the current entry.
function test(pairs) {
print(uneval(pairs));
var map = Map(pairs);
var all_keys = '';
var false_keys = '';
for (let [k, v] of map) {
all_keys += k;
if (!v)
false_keys += k;
}
var log = '';
for (let [k, remove] of map) {
log += k;
if (remove)
map.delete(k);
}
assertEq(log, all_keys);
var remaining_keys = [k for ([k] of map)].join('');
assertEq(remaining_keys, false_keys);
}
// removing the only entry
test([['a', true]]);
// removing the first entry
test([['a', true], ['b', false], ['c', false]]);
// removing a middle entry
test([['a', false], ['b', true], ['c', false]]);
// removing the last entry
test([['a', false], ['b', false], ['c', true]]);
// removing all entries
test([['a', true], ['b', true], ['c', true]]);

View File

@ -1,11 +0,0 @@
// A map iterator can cope with removing the next entry.
var map = Map([['a', 0], ['b', 1], ['c', 2], ['d', 3]]);
var iter = map.iterator();
var log = '';
for (let [k, v] of iter) {
log += k + v;
if (k === 'b')
map.delete('c');
}
assertEq(log, 'a0b1d3');

View File

@ -1,12 +0,0 @@
// A map iterator can cope with removing the next entry, then the current entry.
load(libdir + "asserts.js");
var map = Map([['a', 0], ['b', 1], ['c', 2], ['d', 3]]);
var iter = map.iterator();
assertEq(iter.next()[0], 'a');
assertEq(iter.next()[0], 'b');
map.delete('c');
map.delete('b');
assertEq(iter.next()[0], 'd');
assertThrowsValue(function () { iter.next(); }, StopIteration);

View File

@ -1,32 +0,0 @@
// Multiple live iterators on the same Map can cope with removing entries.
load(libdir + "eqArrayHelper.js");
load(libdir + "asserts.js");
// Make a map.
var map = Map();
var SIZE = 7;
for (var j = 0; j < SIZE; j++)
map.set(j, j);
// Make lots of iterators pointing to entry 2 of the map.
var NITERS = 5;
var iters = [];
for (var i = 0; i < NITERS; i++) {
var iter = map.iterator();
assertEqArray(iter.next(), [0, 0]);
assertEqArray(iter.next(), [1, 1]);
iters[i] = iter;
}
// Remove half of the map entries.
for (var j = 0; j < SIZE; j += 2)
map.delete(j);
// Make sure all the iterators still work.
for (var i = 0; i < NITERS; i++) {
var iter = iters[i];
for (var j = 3; j < SIZE; j += 2)
assertEqArray(iter.next(), [j, j]);
assertThrowsValue(function () { iter.next(); }, StopIteration);
}

View File

@ -1,22 +0,0 @@
// Removing a Map entry already visited by an iterator does not cause any
// entries to be skipped.
var map = Map();
for (var i = 0; i < 20; i++)
map.set(String.fromCharCode('A'.charCodeAt(0) + i), i);
var log = '';
for (var [k, v] of map) {
log += k;
if (v % 5 === 4) {
// Delete all entries preceding this one.
for (let [k1, v1] of map) {
if (k1 === k)
break;
map.delete(k1);
}
}
}
assertEq(log, 'ABCDEFGHIJKLMNOPQRST');
assertEq(map.size(), 1); // Only the last entry remains.
assertEq(map.get('T'), 19);

View File

@ -1,20 +0,0 @@
// Removing many Map entries does not cause a live iterator to skip any of the
// entries that were not removed. (Compacting a Map must not be observable to
// script.)
load(libdir + "asserts.js");
var map = Map();
for (var i = 0; i < 32; i++)
map.set(i, i);
var iter = map.iterator();
assertEq(iter.next()[0], 0);
for (var i = 0; i < 30; i++)
map.delete(i);
assertEq(map.size(), 2);
for (var i = 32; i < 100; i++)
map.set(i, i); // eventually triggers compaction
for (var i = 30; i < 100; i++)
assertEq(iter.next()[0], i);
assertThrowsValue(function () { iter.next(); }, StopIteration);

View File

@ -1,11 +0,0 @@
// for-of can be used to iterate over a Set twice.
var set = Set(['a', 'b', 'c']);
var log = '';
for (let i = 0; i < 2; i++) {
for (let x of set)
log += x;
log += ';'
}
assertEq(log, 'abc;abc;');

View File

@ -1,11 +0,0 @@
// Nested for-of loops can iterate over a Set.
var map = Set(['a', 'b']);
var log = '';
for (let x of map) {
log += x + ':'
for (let y of map)
log += y;
log += ';'
};
assertEq(log, 'a:ab;b:ab;');

View File

@ -1,11 +0,0 @@
// Iterating over a set of objects yields those exact objects.
var arr = [{}, {}, {}, [], /xyz/, new Date];
var set = Set(arr);
assertEq(set.size(), arr.length);
var i = 0;
for (var x of set)
assertEq(x, arr[i++]);
assertEq(i, arr.length);

View File

@ -1,11 +0,0 @@
// set.iterator() is live: entries added during iteration are visited.
var set = Set([5]);
var log = '';
for (let x of set) {
log += x + ';';
if (x > 0)
set.add(x - 1);
}
assertEq(log, '5;4;3;2;1;0;');
assertEq(set.size(), 6);

View File

@ -1,10 +0,0 @@
// A Set iterator does not iterate over new entries added after it throws StopIteration.
load(libdir + "asserts.js");
var set = Set();
var iter0 = set.iterator(), iter1 = set.iterator();
assertThrowsValue(function () { iter0.next(); }, StopIteration); // closes iter0
set.add("x");
assertThrowsValue(function () { iter0.next(); }, StopIteration); // already closed
assertEq(iter1.next(), "x"); // was not yet closed

View File

@ -1,13 +0,0 @@
// Removing and re-adding entries while an iterator is live causes the iterator to visit them again.
var set = Set(['a']);
var n = 5;
for (let v of set) {
assertEq(v, 'a');
if (n === 0)
break;
set.delete('a');
set.add('a');
n--;
}
assertEq(n, 0);

View File

@ -1,8 +0,0 @@
// A Set iterator keeps the data alive.
load(libdir + "referencesVia.js");
var key = {};
var set = Set([key]);
var iter = set.iterator();
referencesVia(iter, "**UNKNOWN SLOT 0**", set);
referencesVia(set, "key", key);

View File

@ -1,8 +0,0 @@
// GC-ing during a for-of loop doesn't crash.
var i = 0;
for (var x of Set(Object.getOwnPropertyNames(this))) {
gc();
if (++i >= 20)
break;
}

View File

@ -1,20 +0,0 @@
// GC in nested for-loops is safe.
var x;
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
for (x of Set([1]))
gc();

View File

@ -1,14 +0,0 @@
// Set iterators produces entries in the order they were inserted.
var set = Set();
var i;
for (i = 7; i !== 1; i = i * 7 % 1117)
set.add(i);
assertEq(set.size(), 557);
i = 7;
for (var v of set) {
assertEq(v, i);
i = i * 7 % 1117;
}
assertEq(i, 1);

View File

@ -1,8 +0,0 @@
// for-of works on a cross-compartment wrapper of a Set.
var g = newGlobal('new-compartment');
var mw = g.eval("Set(['a', 'b', 1, 2])");
var log = '';
for (let x of mw)
log += x;
assertEq(log, "ab12");

View File

@ -1,18 +0,0 @@
// map.iterator() and iter.next() are non-generic but work on cross-compartment wrappers.
load(libdir + "asserts.js");
var g = newGlobal('new-compartment');
var iterator_fn = Set.prototype.iterator;
assertThrowsInstanceOf(function () { iterator_fn.call({}); }, TypeError);
assertThrowsInstanceOf(function () { iterator_fn.call(Map()); }, TypeError);
var setw = g.eval("Set(['x', 'y'])");
assertEq(iterator_fn.call(setw).next(), "x");
var next_fn = Set().iterator().next;
assertThrowsInstanceOf(function () { next_fn.call({}); }, TypeError);
assertThrowsInstanceOf(function () { next_fn.call(Map().iterator()); }, TypeError);
var iterw = setw.iterator();
assertEq(next_fn.call(iterw), "x");
assertEq(next_fn.call(iterw), "y");
assertThrowsValue(function () { next_fn.call(iterw); }, g.StopIteration);

View File

@ -1,26 +0,0 @@
// A set iterator can cope with removing the current entry.
function test(letters, toRemove) {
var set = Set(letters);
toRemove = Set(toRemove);
var leftovers = [x for (x of set) if (!toRemove.has(x))].join("");
var log = "";
for (let x of set) {
log += x;
if (toRemove.has(x))
set.delete(x);
}
assertEq(log, letters);
var remaining = [x for (x of set)].join("");
assertEq(remaining, leftovers);
}
test('a', 'a'); // removing the only entry
test('abc', 'a'); // removing the first entry
test('abc', 'b'); // removing a middle entry
test('abc', 'c'); // removing the last entry
test('abc', 'abc') // removing all entries

View File

@ -1,11 +0,0 @@
// A map iterator can cope with removing the next entry.
var set = Set("abcd");
var iter = set.iterator();
var log = "";
for (let x of iter) {
log += x;
if (x === "b")
set.delete("c");
}
assertEq(log, "abd");

View File

@ -1,12 +0,0 @@
// A set iterator can cope with removing the next entry, then the current entry.
load(libdir + "asserts.js");
var set = Set("abcd");
var iter = set.iterator();
assertEq(iter.next(), "a");
assertEq(iter.next(), "b");
set.delete("c");
set.delete("b");
assertEq(iter.next(), "d");
assertThrowsValue(function () { iter.next(); }, StopIteration);

View File

@ -1,31 +0,0 @@
// Multiple live iterators on the same Set can cope with removing entries.
load(libdir + "asserts.js");
// Make a set.
var set = Set();
var SIZE = 7;
for (var j = 0; j < SIZE; j++)
set.add(j);
// Make lots of iterators pointing to entry 2 of the set.
var NITERS = 5;
var iters = [];
for (var i = 0; i < NITERS; i++) {
var iter = set.iterator();
assertEq(iter.next(), 0);
assertEq(iter.next(), 1);
iters[i] = iter;
}
// Remove half of the set entries.
for (var j = 0; j < SIZE; j += 2)
set.delete(j);
// Make sure all the iterators still work.
for (var i = 0; i < NITERS; i++) {
var iter = iters[i];
for (var j = 3; j < SIZE; j += 2)
assertEq(iter.next(), j);
assertThrowsValue(function () { iter.next(); }, StopIteration);
}

View File

@ -1,22 +0,0 @@
// Removing a Set entry already visited by an iterator does not cause any
// entries to be skipped.
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var set = Set(str);
var log = '';
var i = 0;
for (var x of set) {
log += x;
if (i++ % 5 === 0) {
// Delete all entries preceding this one.
for (let y of set) {
if (y === x)
break;
set.delete(y);
}
}
}
assertEq(log, str);
assertEq(set.size(), 1); // Elements 0 to 24 are removed, leaving only 25 (Z).
assertEq(set.has('Z'), true);

View File

@ -1,20 +0,0 @@
// Removing many Set entries does not cause a live iterator to skip any of the
// entries that were not removed. (Compacting a Set must not be observable to
// script.)
load(libdir + "asserts.js");
var set = Set();
for (var i = 0; i < 32; i++)
set.add(i);
var iter = set.iterator();
assertEq(iter.next(), 0);
for (var i = 0; i < 30; i++)
set.delete(i);
assertEq(set.size(), 2);
for (var i = 32; i < 100; i++)
set.add(i); // eventually triggers compaction
for (var i = 30; i < 100; i++)
assertEq(iter.next(), i);
assertThrowsValue(function () { iter.next(); }, StopIteration);

View File

@ -1,12 +0,0 @@
// collection.iterator() returns an Iterator object.
function test(obj) {
var iter = obj.iterator();
assertEq(typeof iter, "object");
assertEq(iter instanceof Iterator, true);
assertEq(iter.toString(), "[object Iterator]");
}
test([]);
test(new Map);
test(new Set);

View File

@ -1,12 +0,0 @@
// for-of on an empty collection does not execute the loop body or modify the loop variable.
function test(empty) {
var x = 'unchanged';
for (x of empty)
throw fit;
assertEq(x, 'unchanged');
}
test([]);
test(new Map);
test(new Set);

View File

@ -1,14 +0,0 @@
// An iterator keeps its data alive.
load(libdir + "referencesVia.js");
var key = {};
function test(obj, edgeName) {
var iter = obj.iterator();
referencesVia(iter, "**UNKNOWN SLOT 0**", obj);
referencesVia(obj, edgeName, key);
}
test([key], "element[0]");
test(Map([[key, 'value']]), "key");
test(Set([key]), "key");

View File

@ -1,13 +0,0 @@
// All iterators of the same collection type share their immediate prototype.
// Those prototype objects in turn inherit directly from Iterator.prototype.
function test(obj0, obj1) {
var iter0 = obj0.iterator(), iter1 = obj1.iterator();
var proto = Object.getPrototypeOf(iter0);
assertEq(Object.getPrototypeOf(iter1), proto);
assertEq(Object.getPrototypeOf(proto), Iterator.prototype);
}
test([], [1]);
test(Map(), Map([[1, 1]]));
test(Set(), Set([1]));

View File

@ -1,11 +0,0 @@
// Iterators of different collection types have different prototypes.
var aproto = Object.getPrototypeOf(Array().iterator());
var mproto = Object.getPrototypeOf(Map().iterator());
var sproto = Object.getPrototypeOf(Set().iterator());
assertEq(aproto !== mproto, true);
assertEq(aproto !== sproto, true);
assertEq(mproto !== sproto, true);
assertEq(aproto.next !== mproto.next, true);
assertEq(aproto.next !== sproto.next, true);
assertEq(mproto.next !== sproto.next, true);

View File

@ -1,22 +0,0 @@
// Iterator prototype surfaces.
load(libdir + "asserts.js");
function test(constructor) {
var proto = Object.getPrototypeOf(constructor().iterator());
var names = Object.getOwnPropertyNames(proto);
assertEq(names.length, 1);
assertEq(names[0], 'next');
var desc = Object.getOwnPropertyDescriptor(proto, 'next');
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertEq(desc.writable, true);
assertEq(proto.iterator(), proto);
assertThrowsValue(function () { proto.next(); }, StopIteration);
}
//test(Array);
test(Map);
test(Set);

View File

@ -3786,7 +3786,7 @@ struct JSClass {
* with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
* prevously allowed, but is now an ES5 violation and thus unsupported.
*/
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 11)
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 9)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

View File

@ -210,7 +210,6 @@ extern Class ErrorClass;
extern Class ElementIteratorClass;
extern Class GeneratorClass;
extern Class JSONClass;
extern Class MapIteratorClass;
extern Class MathClass;
extern Class NumberClass;
extern Class NormalArgumentsObjectClass;
@ -218,7 +217,6 @@ extern Class ObjectClass;
extern Class ProxyClass;
extern Class RegExpClass;
extern Class RegExpStaticsClass;
extern Class SetIteratorClass;
extern Class SlowArrayClass;
extern Class StopIterationClass;
extern Class StringClass;
@ -237,14 +235,12 @@ class DebugScopeObject;
class DeclEnvObject;
class ElementIteratorObject;
class GlobalObject;
class MapIteratorObject;
class NestedScopeObject;
class NewObjectCache;
class NormalArgumentsObject;
class NumberObject;
class PropertyIteratorObject;
class ScopeObject;
class SetIteratorObject;
class StaticBlockObject;
class StrictArgumentsObject;
class StringObject;
@ -553,6 +549,7 @@ struct JSObject : public js::ObjectImpl
bool growElements(JSContext *cx, unsigned cap);
void shrinkElements(JSContext *cx, unsigned cap);
inline js::ElementIteratorObject *asElementIterator();
/*
* Array-specific getters and setters (for both dense and slow arrays).
@ -901,7 +898,6 @@ struct JSObject : public js::ObjectImpl
inline bool isFunction() const;
inline bool isGenerator() const;
inline bool isGlobal() const;
inline bool isMapIterator() const;
inline bool isObject() const;
inline bool isPrimitive() const;
inline bool isPropertyIterator() const;
@ -910,7 +906,6 @@ struct JSObject : public js::ObjectImpl
inline bool isRegExpStatics() const;
inline bool isScope() const;
inline bool isScript() const;
inline bool isSetIterator() const;
inline bool isStopIteration() const;
inline bool isTypedArray() const;
inline bool isWeakMap() const;
@ -956,14 +951,12 @@ struct JSObject : public js::ObjectImpl
inline js::DeclEnvObject &asDeclEnv();
inline js::DebugScopeObject &asDebugScope();
inline js::GlobalObject &asGlobal();
inline js::MapIteratorObject &asMapIterator();
inline js::NestedScopeObject &asNestedScope();
inline js::NormalArgumentsObject &asNormalArguments();
inline js::NumberObject &asNumber();
inline js::PropertyIteratorObject &asPropertyIterator();
inline js::RegExpObject &asRegExp();
inline js::ScopeObject &asScope();
inline js::SetIteratorObject &asSetIterator();
inline js::StrictArgumentsObject &asStrictArguments();
inline js::StaticBlockObject &asStaticBlock();
inline js::StringObject &asString();

View File

@ -28,7 +28,6 @@
#include "jsxml.h"
#include "jswrapper.h"
#include "builtin/MapObject.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "gc/Root.h"
@ -788,7 +787,6 @@ inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); }
inline bool JSObject::isFunction() const { return hasClass(&js::FunctionClass); }
inline bool JSObject::isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
inline bool JSObject::isGenerator() const { return hasClass(&js::GeneratorClass); }
inline bool JSObject::isMapIterator() const { return hasClass(&js::MapIteratorClass); }
inline bool JSObject::isNestedScope() const { return isBlock() || isWith(); }
inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); }
@ -797,7 +795,6 @@ inline bool JSObject::isPrimitive() const { return isNumber() || isString() || i
inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); }
inline bool JSObject::isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); }
inline bool JSObject::isScope() const { return isCall() || isDeclEnv() || isNestedScope(); }
inline bool JSObject::isSetIterator() const { return hasClass(&js::SetIteratorClass); }
inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); }
inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }

View File

@ -293,14 +293,14 @@ GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
#if JS_HAS_XML_SUPPORT
(!VersionHasAllowXML(cx->findVersion()) || js_InitXMLClasses(cx, global)) &&
#endif
#if JS_HAS_GENERATORS
js_InitIteratorClasses(cx, global) &&
#endif
js_InitDateClass(cx, global) &&
js_InitWeakMapClass(cx, global) &&
js_InitProxyClass(cx, global) &&
js_InitMapClass(cx, global) &&
GlobalObject::initMapIteratorProto(cx, global) &&
js_InitSetClass(cx, global) &&
GlobalObject::initSetIteratorProto(cx, global);
js_InitSetClass(cx, global);
}
void

View File

@ -73,9 +73,7 @@ class GlobalObject : public JSObject
static const unsigned THROWTYPEERROR = STANDARD_CLASS_SLOTS;
static const unsigned ELEMENT_ITERATOR_PROTO = THROWTYPEERROR + 1;
static const unsigned GENERATOR_PROTO = ELEMENT_ITERATOR_PROTO + 1;
static const unsigned MAP_ITERATOR_PROTO = GENERATOR_PROTO + 1;
static const unsigned SET_ITERATOR_PROTO = MAP_ITERATOR_PROTO + 1;
static const unsigned REGEXP_STATICS = SET_ITERATOR_PROTO + 1;
static const unsigned REGEXP_STATICS = GENERATOR_PROTO + 1;
static const unsigned FUNCTION_NS = REGEXP_STATICS + 1;
static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
static const unsigned EVAL = RUNTIME_CODEGEN_ENABLED + 1;
@ -275,37 +273,23 @@ class GlobalObject : public JSObject
}
private:
typedef bool (*ObjectInitOp)(JSContext *cx, Handle<GlobalObject*> global);
JSObject *getOrCreateObject(JSContext *cx, unsigned slot, ObjectInitOp init) {
JSObject *getOrCreateIteratorSubclassPrototype(JSContext *cx, unsigned slot) {
Value v = getSlotRef(slot);
if (v.isObject())
return &v.toObject();
Rooted<GlobalObject*> self(cx, this);
if (!init(cx, self))
if (!initIteratorClasses(cx, self))
return NULL;
return &self->getSlot(slot).toObject();
}
public:
JSObject *getOrCreateIteratorPrototype(JSContext *cx) {
return getOrCreateObject(cx, JSProto_LIMIT + JSProto_Iterator, initIteratorClasses);
}
JSObject *getOrCreateElementIteratorPrototype(JSContext *cx) {
return getOrCreateObject(cx, ELEMENT_ITERATOR_PROTO, initIteratorClasses);
return getOrCreateIteratorSubclassPrototype(cx, ELEMENT_ITERATOR_PROTO);
}
JSObject *getOrCreateGeneratorPrototype(JSContext *cx) {
return getOrCreateObject(cx, GENERATOR_PROTO, initIteratorClasses);
}
JSObject *getOrCreateMapIteratorPrototype(JSContext *cx) {
return getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto);
}
JSObject *getOrCreateSetIteratorPrototype(JSContext *cx) {
return getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto);
return getOrCreateIteratorSubclassPrototype(cx, GENERATOR_PROTO);
}
inline RegExpStatics *getRegExpStatics() const;
@ -333,10 +317,6 @@ class GlobalObject : public JSObject
// Implemented in jsiter.cpp.
static bool initIteratorClasses(JSContext *cx, Handle<GlobalObject*> global);
// Implemented in builtin/MapObject.cpp.
static bool initMapIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
static bool initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
static bool initStandardClasses(JSContext *cx, Handle<GlobalObject*> global);
typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector;