|  | // 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); | 
|  | })(); |