| // 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])); |
| }; |
| %PrepareFunctionForOptimization(testSpreadCallsStrict); |
| 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; |
| |
| // .next method is only accessed during iteration prologue (see |
| // https://github.com/tc39/ecma262/pull/988) |
| let ArrayIteratorPrototype = Array.prototype[Symbol.iterator]().__proto__; |
| let ArrayIteratorPrototypeNextDescriptor = |
| Object.getOwnPropertyDescriptor(ArrayIteratorPrototype, 'next'); |
| 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; |
| }, |
| configurable: true |
| }); |
| return 3; |
| }, |
| configurable: true |
| }); |
| |
| assertEquals(10, sum(...a)); |
| assertEquals(0, called); |
| |
| Object.defineProperty(ArrayIteratorPrototype, 'next', |
| ArrayIteratorPrototypeNextDescriptor); |
| 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); |
| |
| // .next method is only accessed during iteration prologue (see |
| // https://github.com/tc39/ecma262/pull/988) |
| assertEquals(1, 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); |
| })(); |