blob: 3c8566d80a79c200ad8a021d4f251cf17def44cf [file] [log] [blame]
function assert(b) {
if (!b)
throw new Error("Bad assertion");
}
function test(f) { f(); }
function shallowEq(a, b) {
if (a.length !== b.length)
return false;
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i])
return false;
}
return true;
}
function makeArrayIterator(arr, f) {
let i = 0;
return {
next() {
f();
if (i >= arr.length)
return {done: true};
return {value: arr[i++], done: false};
}
};
}
test(function() {
let arr = [10, 20];
arr.__proto__ = {[Symbol.iterator]: Array.prototype[Symbol.iterator]};
function bar(a) {
a.x;
return [...a];
}
noInline(bar);
for (let i = 0; i < 10000; i++) {
assert(shallowEq(bar(arr), arr));
}
});
test(function() {
let arr = [10, 20];
let count = 0;
function callback() {
count++;
}
arr.__proto__ = {
[Symbol.iterator]: function() {
return makeArrayIterator(this, callback);
}
};
function bar(a) {
a.x;
return [...a];
}
noInline(bar);
for (let i = 0; i < 10000; i++) {
let t = bar(arr);
assert(count === 3);
count = 0;
assert(shallowEq(t, arr));
}
});
test(function() {
let arr = [10, 20];
let count = 0;
function callback() {
count++;
}
arr[Symbol.iterator] = function() {
return makeArrayIterator(this, callback);
};
function bar(a) {
a.x;
return [...a];
}
noInline(bar);
for (let i = 0; i < 10000; i++) {
let t = bar(arr);
assert(count === 3);
count = 0;
assert(shallowEq(t, arr));
}
});
test(function() {
let arr = [10, 20];
arr[Symbol.iterator] = Array.prototype[Symbol.iterator];
function bar(a) {
a.x;
return [...a];
}
noInline(bar);
for (let i = 0; i < 10000; i++) {
assert(shallowEq(bar(arr), arr));
}
});
test(function() {
let arr = [, 20];
let callCount = 0;
Object.defineProperty(arr, 0, {get() { ++callCount; return 10; }});
function bar(a) {
a.x;
return [...a];
}
noInline(bar);
for (let i = 0; i < 10000; i++) {
let t = bar(arr);
assert(callCount === 1);
assert(shallowEq(t, arr));
assert(callCount === 2);
callCount = 0;
}
});
// We run this test last since it fires watchpoints for the protocol.
test(function() {
let iter = [][Symbol.iterator]();
let iterProto = Object.getPrototypeOf(iter);
let oldNext = iterProto.next;
function hackedNext() {
let val = oldNext.call(this);
if ("value" in val) {
val.value++;
}
return val;
}
function test(a) {
a.x;
return [...a];
}
for (let i = 0; i < 10000; ++i) {
let arr = [1,,3];
let callCount = 0;
Object.defineProperty(arr, 1, { get: function() { ++callCount; iterProto.next = hackedNext; return 2; } });
let t = test(arr);
assert(callCount === 1);
assert(t.length === 3);
assert(t[0] === 1);
assert(t[1] === 2);
assert(t[2] === 3);
iterProto.next = oldNext;
}
});