163b5d705e
This reverts commit bf4cc9ee15
.
Reason for revert: Breaks windows with msvc and linux with gcc
https://build.chromium.org/p/client.v8/builders/V8%20Win64%20-%20msvc/builds/841
https://build.chromium.org/p/client.v8/builders/V8%20Linux%20gcc%204.8/builds/17265
Original change's description:
> [esnext] load `iterator.next` only once at beginning of iteration
>
> https://github.com/tc39/ecma262/pull/988 gained concensus during the
> september 2017 TC39 meetings. This moves the load of the "next" method
> to the very beginning of the iteration protocol, rather than during
> each iteration step.
>
> This impacts:
>
> - yield*
> - for-of loops
> - spread arguments
> - array spreads
>
> In the v8 implementation, this also affects async iteration versions of
> these things (the sole exception being the Async-From-Sync iterator,
> which requires a few more changes to work with this, likely done in a
> followup patch).
>
> This change introduces a new AST node, ResolvedProperty, which can be used
> as a callee by Call nodes to produce the same bytecode as Property calls,
> without observably re-loading the property. This is used in several
> AST-desugarings involving the iteration protocol.
>
> BUG=v8:6861, v8:5699
> R=rmcilroy@chromium.org, neis@chromium.org, adamk@chromium.org
>
> Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
> Change-Id: Ib81106a0182687fc5efea0bc32302ad06376773b
> Reviewed-on: https://chromium-review.googlesource.com/687997
> Commit-Queue: Caitlin Potter <caitp@igalia.com>
> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> Reviewed-by: Adam Klein <adamk@chromium.org>
> Reviewed-by: Georg Neis <neis@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#50452}
TBR=rmcilroy@chromium.org,adamk@chromium.org,neis@chromium.org,caitp@igalia.com,caitp@chromium.org
Change-Id: I1797c0d596dfd6850d6f0f505f591a7a990dd1f1
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6861, v8:5699
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/857616
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50454}
502 lines
14 KiB
JavaScript
502 lines
14 KiB
JavaScript
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Flags: --allow-natives-syntax
|
|
|
|
function testSpreadCallsStrict() {
|
|
"use strict"
|
|
function countArgs() { return arguments.length; }
|
|
|
|
// Test this argument
|
|
function returnThis() { return this; }
|
|
assertEquals(void 0, returnThis(..."test"));
|
|
|
|
// Test argument counting with different iterables
|
|
assertEquals(0, countArgs(...""));
|
|
assertEquals(4, countArgs(..."test"));
|
|
assertEquals(4, countArgs(..."tes", ..."t"));
|
|
assertEquals(4, countArgs("t", ..."es", "t"));
|
|
assertEquals(4, countArgs("tes", ..."t!!"));
|
|
|
|
assertEquals(1, countArgs(...[1]));
|
|
assertEquals(2, countArgs(...[1, 2]));
|
|
assertEquals(3, countArgs(...[1, 2, 3]));
|
|
assertEquals(4, countArgs(...[1, 2, 3, 4]));
|
|
assertEquals(5, countArgs(...[1, 2, 3, 4, 5]));
|
|
assertEquals(6, countArgs(...[1, 2, 3, 4, 5, 6]));
|
|
|
|
assertEquals(1, countArgs(...[1.1]));
|
|
assertEquals(2, countArgs(...[1.1, 2.2]));
|
|
assertEquals(3, countArgs(...[1.1, 2.2, 3.3]));
|
|
assertEquals(4, countArgs(...[1.1, 2.2, 3.3, 4.4]));
|
|
assertEquals(5, countArgs(...[1.1, 2.2, 3.3, 4.4, 5.5]));
|
|
assertEquals(6, countArgs(...[1.1, 2.2, 3.3, 4.4, 5.5, 6.6]));
|
|
|
|
assertEquals(1, countArgs(...new Set([1])));
|
|
assertEquals(2, countArgs(...new Set([1, 2])));
|
|
assertEquals(3, countArgs(...new Set([1, 2, 3])));
|
|
assertEquals(4, countArgs(...new Set([1, 2, 3, 4])));
|
|
assertEquals(5, countArgs(...new Set([1, 2, 3, 4, 5])));
|
|
assertEquals(6, countArgs(...new Set([1, 2, 3, 4, 5, 6])));
|
|
|
|
assertEquals(3, countArgs(...(function*(){ yield 1; yield 2; yield 3; })()));
|
|
|
|
// Test values
|
|
function sum() {
|
|
var sum = arguments[0];
|
|
for (var i = 1; i < arguments.length; ++i) {
|
|
sum += arguments[i];
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
assertThrows(function() {
|
|
sum(...0);
|
|
}, TypeError);
|
|
assertEquals(void 0, sum(...""));
|
|
assertEquals(void 0, sum(...[]));
|
|
assertEquals(void 0, sum(...new Set));
|
|
assertEquals(void 0, sum(...(function*() { })()));
|
|
|
|
assertEquals("test", sum(..."test"));
|
|
assertEquals(10, sum(...[1, 2, 3, 4]));
|
|
assertEquals(10, sum(...[1, 2, 3], 4));
|
|
assertEquals(10, sum(1, ...[2, 3], 4));
|
|
assertEquals(10, sum(1, ...[2, 3], ...[4]));
|
|
assertEquals(10, sum(1, 2, ...[3, 4]));
|
|
assertEquals(10, sum(...new Set([1, 2, 3, 4])));
|
|
assertEquals(10, sum(...(function*() {
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
yield 4;
|
|
})()));
|
|
|
|
// nested spreads
|
|
function makeArray() {
|
|
var result = [];
|
|
for (var i = 0; i < arguments.length; ++i) {
|
|
result.push(arguments[i]);
|
|
}
|
|
return result;
|
|
}
|
|
assertEquals(10, sum(...makeArray(...[1, 2, 3, 4])));
|
|
assertEquals("test!!!", sum(...makeArray(..."test!!!")));
|
|
|
|
// Interleaved spread/unspread args
|
|
assertEquals(36, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
|
|
assertEquals(45, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
|
|
|
|
// Methods
|
|
var O = {
|
|
returnThis: returnThis,
|
|
countArgs: countArgs,
|
|
sum: sum,
|
|
makeArray: makeArray,
|
|
|
|
nested: {
|
|
returnThis: returnThis,
|
|
countArgs: countArgs,
|
|
sum: sum,
|
|
makeArray: makeArray
|
|
}
|
|
};
|
|
|
|
// Test this argument
|
|
assertEquals(O, O.returnThis(..."test"));
|
|
assertEquals(O, O["returnThis"](..."test"));
|
|
assertEquals(O.nested, O.nested.returnThis(..."test"));
|
|
assertEquals(O.nested, O.nested["returnThis"](..."test"));
|
|
|
|
// Test argument counting with different iterables
|
|
assertEquals(0, O.countArgs(...""));
|
|
assertEquals(4, O.countArgs(..."test"));
|
|
assertEquals(4, O.countArgs(..."tes", ..."t"));
|
|
assertEquals(4, O.countArgs("t", ..."es", "t"));
|
|
assertEquals(4, O.countArgs("tes", ..."t!!"));
|
|
|
|
assertEquals(1, O.countArgs(...[1]));
|
|
assertEquals(2, O.countArgs(...[1, 2]));
|
|
assertEquals(3, O.countArgs(...[1, 2, 3]));
|
|
assertEquals(4, O.countArgs(...[1, 2, 3, 4]));
|
|
assertEquals(5, O.countArgs(...[1, 2, 3, 4, 5]));
|
|
assertEquals(6, O.countArgs(...[1, 2, 3, 4, 5, 6]));
|
|
|
|
assertEquals(1, O.countArgs(...new Set([1])));
|
|
assertEquals(2, O.countArgs(...new Set([1, 2])));
|
|
assertEquals(3, O.countArgs(...new Set([1, 2, 3])));
|
|
assertEquals(4, O.countArgs(...new Set([1, 2, 3, 4])));
|
|
assertEquals(5, O.countArgs(...new Set([1, 2, 3, 4, 5])));
|
|
assertEquals(6, O.countArgs(...new Set([1, 2, 3, 4, 5, 6])));
|
|
|
|
assertEquals(3, O.countArgs(
|
|
...(function*(){ yield 1; yield 2; yield 3; })()));
|
|
|
|
// Test values
|
|
assertEquals(void 0, O.sum(...""));
|
|
assertEquals(void 0, O.sum(...[]));
|
|
assertEquals(void 0, O.sum(...new Set));
|
|
assertEquals(void 0, O.sum(...(function*() { })()));
|
|
|
|
assertEquals("test", O.sum(..."test"));
|
|
assertEquals(10, O.sum(...[1, 2, 3, 4]));
|
|
assertEquals(10, O.sum(...[1, 2, 3], 4));
|
|
assertEquals(10, O.sum(1, ...[2, 3], 4));
|
|
assertEquals(10, O.sum(1, ...[2, 3], ...[4]));
|
|
assertEquals(10, O.sum(1, 2, ...[3, 4]));
|
|
assertEquals(10, O.sum(...new Set([1, 2, 3, 4])));
|
|
assertEquals(10, O.sum(...(function*() {
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
yield 4;
|
|
})()));
|
|
|
|
// nested spreads
|
|
assertEquals(10, O.sum(...O.makeArray(...[1, 2, 3, 4])));
|
|
assertEquals("test!!!", O.sum(...O.makeArray(..."test!!!")));
|
|
|
|
// Interleaved spread/unspread args
|
|
assertEquals(36, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
|
|
assertEquals(45, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
|
|
};
|
|
testSpreadCallsStrict();
|
|
%OptimizeFunctionOnNextCall(testSpreadCallsStrict);
|
|
testSpreadCallsStrict();
|
|
|
|
|
|
(function testSpreadCallsSloppy() {
|
|
// Test this argument
|
|
function returnThis() { return this; }
|
|
assertEquals(this, returnThis(..."test"));
|
|
|
|
function countArgs() { return arguments.length; }
|
|
|
|
// Test argument counting with different iterables
|
|
assertEquals(0, countArgs(...""));
|
|
assertEquals(4, countArgs(..."test"));
|
|
assertEquals(4, countArgs(..."tes", ..."t"));
|
|
assertEquals(4, countArgs("t", ..."es", "t"));
|
|
assertEquals(4, countArgs("tes", ..."t!!"));
|
|
|
|
assertEquals(1, countArgs(...[1]));
|
|
assertEquals(2, countArgs(...[1, 2]));
|
|
assertEquals(3, countArgs(...[1, 2, 3]));
|
|
assertEquals(4, countArgs(...[1, 2, 3, 4]));
|
|
assertEquals(5, countArgs(...[1, 2, 3, 4, 5]));
|
|
assertEquals(6, countArgs(...[1, 2, 3, 4, 5, 6]));
|
|
|
|
assertEquals(1, countArgs(...new Set([1])));
|
|
assertEquals(2, countArgs(...new Set([1, 2])));
|
|
assertEquals(3, countArgs(...new Set([1, 2, 3])));
|
|
assertEquals(4, countArgs(...new Set([1, 2, 3, 4])));
|
|
assertEquals(5, countArgs(...new Set([1, 2, 3, 4, 5])));
|
|
assertEquals(6, countArgs(...new Set([1, 2, 3, 4, 5, 6])));
|
|
|
|
assertEquals(3, countArgs(...(function*(){
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
})()));
|
|
|
|
// Test values
|
|
function sum() {
|
|
var sum = arguments[0];
|
|
for (var i = 1; i < arguments.length; ++i) {
|
|
sum += arguments[i];
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
assertThrows(function() {
|
|
sum(...0);
|
|
}, TypeError);
|
|
assertEquals(void 0, sum(...""));
|
|
assertEquals(void 0, sum(...[]));
|
|
assertEquals(void 0, sum(...new Set));
|
|
assertEquals(void 0, sum(...(function*() { })()));
|
|
|
|
assertEquals("test", sum(..."test"));
|
|
assertEquals(10, sum(...[1, 2, 3, 4]));
|
|
assertEquals(10, sum(...[1, 2, 3], 4));
|
|
assertEquals(10, sum(1, ...[2, 3], 4));
|
|
assertEquals(10, sum(1, ...[2, 3], ...[4]));
|
|
assertEquals(10, sum(1, 2, ...[3, 4]));
|
|
assertEquals(10, sum(...new Set([1, 2, 3, 4])));
|
|
assertEquals(10, sum(...(function*() {
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
yield 4;
|
|
})()));
|
|
|
|
// nested spreads
|
|
function makeArray() {
|
|
var result = [];
|
|
for (var i = 0; i < arguments.length; ++i) {
|
|
result.push(arguments[i]);
|
|
}
|
|
return result;
|
|
}
|
|
assertEquals(10, sum(...makeArray(...[1, 2, 3, 4])));
|
|
assertEquals("test!!!", sum(...makeArray(..."test!!!")));
|
|
|
|
// Interleaved spread/unspread args
|
|
assertEquals(36, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
|
|
assertEquals(45, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
|
|
|
|
// Methods
|
|
var O = {
|
|
returnThis: returnThis,
|
|
countArgs: countArgs,
|
|
sum: sum,
|
|
makeArray: makeArray,
|
|
|
|
nested: {
|
|
returnThis: returnThis,
|
|
countArgs: countArgs,
|
|
sum: sum,
|
|
makeArray: makeArray
|
|
}
|
|
};
|
|
|
|
// Test this argument
|
|
assertEquals(O, O.returnThis(..."test"));
|
|
assertEquals(O, O["returnThis"](..."test"));
|
|
assertEquals(O.nested, O.nested.returnThis(..."test"));
|
|
assertEquals(O.nested, O.nested["returnThis"](..."test"));
|
|
|
|
// Test argument counting with different iterables
|
|
assertEquals(0, O.countArgs(...""));
|
|
assertEquals(4, O.countArgs(..."test"));
|
|
assertEquals(4, O.countArgs(..."tes", ..."t"));
|
|
assertEquals(4, O.countArgs("t", ..."es", "t"));
|
|
assertEquals(4, O.countArgs("tes", ..."t!!"));
|
|
|
|
assertEquals(1, O.countArgs(...[1]));
|
|
assertEquals(2, O.countArgs(...[1, 2]));
|
|
assertEquals(3, O.countArgs(...[1, 2, 3]));
|
|
assertEquals(4, O.countArgs(...[1, 2, 3, 4]));
|
|
assertEquals(5, O.countArgs(...[1, 2, 3, 4, 5]));
|
|
assertEquals(6, O.countArgs(...[1, 2, 3, 4, 5, 6]));
|
|
|
|
assertEquals(1, O.countArgs(...new Set([1])));
|
|
assertEquals(2, O.countArgs(...new Set([1, 2])));
|
|
assertEquals(3, O.countArgs(...new Set([1, 2, 3])));
|
|
assertEquals(4, O.countArgs(...new Set([1, 2, 3, 4])));
|
|
assertEquals(5, O.countArgs(...new Set([1, 2, 3, 4, 5])));
|
|
assertEquals(6, O.countArgs(...new Set([1, 2, 3, 4, 5, 6])));
|
|
|
|
assertEquals(3, O.countArgs(...(function*(){
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
})()));
|
|
|
|
// Test values
|
|
assertEquals(void 0, O.sum(...""));
|
|
assertEquals(void 0, O.sum(...[]));
|
|
assertEquals(void 0, O.sum(...new Set));
|
|
assertEquals(void 0, O.sum(...(function*() { })()));
|
|
|
|
assertEquals("test", O.sum(..."test"));
|
|
assertEquals(10, O.sum(...[1, 2, 3, 4]));
|
|
assertEquals(10, O.sum(...[1, 2, 3], 4));
|
|
assertEquals(10, O.sum(1, ...[2, 3], 4));
|
|
assertEquals(10, O.sum(1, ...[2, 3], ...[4]));
|
|
assertEquals(10, O.sum(1, 2, ...[3, 4]));
|
|
assertEquals(10, O.sum(...new Set([1, 2, 3, 4])));
|
|
assertEquals(10, O.sum(...(function*() {
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
yield 4;
|
|
})()));
|
|
|
|
// nested spreads
|
|
assertEquals(10, O.sum(...O.makeArray(...[1, 2, 3, 4])));
|
|
assertEquals("test!!!", O.sum(...O.makeArray(..."test!!!")));
|
|
|
|
// Interleaved spread/unspread args
|
|
assertEquals(36, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
|
|
assertEquals(45, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
|
|
})();
|
|
|
|
|
|
(function testSpreadEvaluationOrder() {
|
|
"use strict";
|
|
var log = "";
|
|
function* gen() { log += "X"; yield 0; log += "Y"; }
|
|
function a() { log += "A"; }
|
|
function b() { log += "B"; return gen(); }
|
|
function* c() { log += 'C1'; yield 1; log += 'C2'; }
|
|
function d() { log += "D"; }
|
|
function e() { log += "E"; }
|
|
function fn() {
|
|
var args = [];
|
|
for (var i = 0; i < arguments.length; ++i) args.push(arguments[i]);
|
|
return args;
|
|
}
|
|
|
|
var result = fn(a(), ...b(), d());
|
|
assertEquals([undefined, 0, undefined], result);
|
|
assertEquals("ABXYD", log);
|
|
|
|
log = "";
|
|
result = fn(...b(), d());
|
|
assertEquals([0, undefined], result);
|
|
assertEquals("BXYD", log);
|
|
|
|
log = "";
|
|
result = fn(a(), ...b());
|
|
assertEquals([undefined, 0], result);
|
|
assertEquals("ABXY", log);
|
|
|
|
log = "";
|
|
result = fn(a(), ...b(), ...c(), d(), e());
|
|
assertEquals([undefined, 0, 1, undefined, undefined], result);
|
|
assertEquals("ABXYC1C2DE", log);
|
|
|
|
log = "";
|
|
result = fn(a(), ...b(), ...c(), d(), e(), ...b(), ...c());
|
|
assertEquals([undefined, 0, 1, undefined, undefined, 0, 1], result);
|
|
assertEquals("ABXYC1C2DEBXYC1C2", log);
|
|
})();
|
|
|
|
(function testArrayPrototypeHoleGetterModifiesIteratorPrototypeNext() {
|
|
function sum() {
|
|
var sum = arguments[0];
|
|
for (var i = 1; i < arguments.length; ++i) {
|
|
sum += arguments[i];
|
|
}
|
|
return sum;
|
|
}
|
|
var a = [1, 2];
|
|
a[3] = 4;
|
|
var called = 0;
|
|
|
|
Object.defineProperty(Array.prototype, 2, {
|
|
get: function() {
|
|
var ai = a[Symbol.iterator]();
|
|
var original_next = ai.__proto__["next"];
|
|
Object.defineProperty(ai.__proto__, "next", {
|
|
get: function() {
|
|
called++;
|
|
return original_next;
|
|
}
|
|
});
|
|
return 3;
|
|
},
|
|
configurable: true
|
|
});
|
|
|
|
assertEquals(10, sum(...a));
|
|
assertEquals(2, called);
|
|
|
|
Object.defineProperty(Array.prototype, 2, {});
|
|
})();
|
|
|
|
(function testArrayHasOtherPrototype() {
|
|
function countArgs() { return arguments.length; }
|
|
var a = [1, 2, 3];
|
|
var b = {};
|
|
Object.defineProperty(b, Symbol.iterator, {
|
|
value: function*() {
|
|
yield 4;
|
|
},
|
|
configurable: true
|
|
});
|
|
|
|
Object.setPrototypeOf(a, b);
|
|
|
|
assertEquals(1, countArgs(...a));
|
|
})();
|
|
|
|
(function testArrayIteratorPrototypeGetter() {
|
|
function countArgs() { return arguments.length; }
|
|
var a = [1, 2, 3];
|
|
var ai = a[Symbol.iterator]();
|
|
var called = 0;
|
|
|
|
var original_next = ai.__proto__["next"];
|
|
|
|
Object.defineProperty(ai.__proto__, "next", {
|
|
get: function() {
|
|
called++;
|
|
return original_next;
|
|
}
|
|
});
|
|
|
|
countArgs(...a);
|
|
|
|
// should be called 4 times; 3 for the values, 1 for the final
|
|
// {value: undefined, done: true} pair
|
|
assertEquals(4, called);
|
|
})();
|
|
|
|
(function testArrayIteratorPrototypeModified() {
|
|
function countArgs() { return arguments.length; }
|
|
var a = [1,2,3];
|
|
var ai = a[Symbol.iterator]();
|
|
Object.defineProperty(ai.__proto__, "next", {
|
|
value: function() {
|
|
return {value: undefined, done: true};
|
|
},
|
|
configurable: true
|
|
});
|
|
|
|
assertEquals(0, countArgs(...a));
|
|
|
|
})();
|
|
|
|
(function testCustomArrayPrototypeIterator() {
|
|
var origIterator =
|
|
Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator);
|
|
Object.defineProperty(Array.prototype, Symbol.iterator, {
|
|
value: function*() {
|
|
yield 1;
|
|
yield 2;
|
|
yield 3;
|
|
},
|
|
configurable: true
|
|
});
|
|
function returnCountStrict() { 'use strict'; return arguments.length; }
|
|
function returnCountSloppy() { return arguments.length; }
|
|
|
|
assertEquals(3, returnCountStrict(...[1]));
|
|
assertEquals(4, returnCountStrict(1, ...[2]));
|
|
assertEquals(5, returnCountStrict(1, ...[2], 3));
|
|
assertEquals(3, returnCountSloppy(...[1]));
|
|
assertEquals(4, returnCountSloppy(1, ...[2]));
|
|
assertEquals(5, returnCountSloppy(1, ...[2], 3));
|
|
|
|
Object.defineProperty(Array.prototype, Symbol.iterator, origIterator);
|
|
})();
|
|
|
|
(function testGetPropertyIteratorCalledExactlyOnce() {
|
|
function countArgs() { return arguments.length; }
|
|
var a = [1, 2, 3];
|
|
var called = 0;
|
|
|
|
Object.defineProperty(Array.prototype, Symbol.iterator, {
|
|
value: function*() {
|
|
yield 1;
|
|
yield 2;
|
|
},
|
|
configurable: true
|
|
});
|
|
|
|
var it = a[Symbol.iterator];
|
|
Object.defineProperty(a, Symbol.iterator, {
|
|
get: function() {
|
|
called++;
|
|
return it;
|
|
}
|
|
});
|
|
|
|
countArgs(...a);
|
|
|
|
assertEquals(1, called);
|
|
})();
|