| // Copyright 2009 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // Flags: --allow-natives-syntax --opt --no-lazy-feedback-allocation |
| |
| // TODO(v8:10195): Fix these tests s.t. we assert deoptimization occurs when |
| // expected (e.g. in a %DeoptimizeNow call), then remove |
| // --no-lazy-feedback-allocation. |
| |
| function clone(v) { |
| // Shallow-copies arrays, returns everything else verbatim. |
| if (v instanceof Array) { |
| // Shallow-copy an array. |
| var newArray = new Array(v.length); |
| for (var i in v) { |
| newArray[i] = v[i]; |
| } |
| return newArray; |
| } |
| return v; |
| } |
| |
| |
| // Creates a callback function for reduce/reduceRight that tests the number |
| // of arguments and otherwise behaves as "func", but which also |
| // records all calls in an array on the function (as arrays of arguments |
| // followed by result). |
| function makeRecorder(func, testName) { |
| var record = []; |
| var f = function recorder(a, b, i, s) { |
| assertEquals(4, arguments.length, |
| testName + "(number of arguments: " + arguments.length + ")"); |
| assertEquals("number", typeof(i), testName + "(index must be number)"); |
| assertEquals(s[i], b, testName + "(current argument is at index)"); |
| if (record.length > 0) { |
| var prevRecord = record[record.length - 1]; |
| var prevResult = prevRecord[prevRecord.length - 1]; |
| assertEquals(prevResult, a, |
| testName + "(prev result -> current input)"); |
| } |
| var args = [clone(a), clone(b), i, clone(s)]; |
| var result = func.apply(this, arguments); |
| args.push(clone(result)); |
| record.push(args); |
| return result; |
| }; |
| f.record = record; |
| return f; |
| } |
| |
| |
| function testReduce(type, |
| testName, |
| expectedResult, |
| expectedCalls, |
| array, |
| combine, |
| init) { |
| var rec = makeRecorder(combine); |
| var result; |
| var performsCall; |
| if (arguments.length > 6) { |
| result = array[type](rec, init); |
| } else { |
| result = array[type](rec); |
| } |
| var calls = rec.record; |
| assertEquals(expectedCalls.length, calls.length, |
| testName + " (number of calls)"); |
| for (var i = 0; i < expectedCalls.length; i++) { |
| assertEquals(expectedCalls[i], calls[i], |
| testName + " (call " + (i + 1) + ")"); |
| } |
| assertEquals(expectedResult, result, testName + " (result)"); |
| } |
| |
| |
| function sum(a, b) { return a + b; } |
| function prod(a, b) { return a * b; } |
| function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); } |
| function accumulate(acc, elem, i) { acc[i] = elem; return acc; } |
| |
| // ---- Test Reduce[Left] |
| |
| var simpleArray = [2,4,6] |
| |
| testReduce("reduce", "SimpleReduceSum", 12, |
| [[0, 2, 0, simpleArray, 2], |
| [2, 4, 1, simpleArray, 6], |
| [6, 6, 2, simpleArray, 12]], |
| simpleArray, sum, 0); |
| |
| testReduce("reduce", "SimpleReduceProd", 48, |
| [[1, 2, 0, simpleArray, 2], |
| [2, 4, 1, simpleArray, 8], |
| [8, 6, 2, simpleArray, 48]], |
| simpleArray, prod, 1); |
| |
| testReduce("reduce", "SimpleReduceDec", 246, |
| [[0, 2, 0, simpleArray, 200], |
| [200, 4, 1, simpleArray, 240], |
| [240, 6, 2, simpleArray, 246]], |
| simpleArray, dec, 0); |
| |
| testReduce("reduce", "SimpleReduceAccumulate", simpleArray, |
| [[[], 2, 0, simpleArray, [2]], |
| [[2], 4, 1, simpleArray, [2, 4]], |
| [[2,4], 6, 2, simpleArray, simpleArray]], |
| simpleArray, accumulate, []); |
| |
| |
| testReduce("reduce", "EmptyReduceSum", 0, [], [], sum, 0); |
| testReduce("reduce", "EmptyReduceProd", 1, [], [], prod, 1); |
| testReduce("reduce", "EmptyReduceDec", 0, [], [], dec, 0); |
| testReduce("reduce", "EmptyReduceAccumulate", [], [], [], accumulate, []); |
| |
| testReduce("reduce", "EmptyReduceSumNoInit", 0, [], [0], sum); |
| testReduce("reduce", "EmptyReduceProdNoInit", 1, [], [1], prod); |
| testReduce("reduce", "EmptyReduceDecNoInit", 0, [], [0], dec); |
| testReduce("reduce", "EmptyReduceAccumulateNoInit", [], [], [[]], accumulate); |
| |
| |
| var simpleSparseArray = [,,,2,,4,,6,,]; |
| testReduce("reduce", "SimpleSparseReduceSum", 12, |
| [[0, 2, 3, simpleSparseArray, 2], |
| [2, 4, 5, simpleSparseArray, 6], |
| [6, 6, 7, simpleSparseArray, 12]], |
| simpleSparseArray, sum, 0); |
| |
| testReduce("reduce", "SimpleSparseReduceProd", 48, |
| [[1, 2, 3, simpleSparseArray, 2], |
| [2, 4, 5, simpleSparseArray, 8], |
| [8, 6, 7, simpleSparseArray, 48]], |
| simpleSparseArray, prod, 1); |
| |
| testReduce("reduce", "SimpleSparseReduceDec", 204060, |
| [[0, 2, 3, simpleSparseArray, 200000], |
| [200000, 4, 5, simpleSparseArray, 204000], |
| [204000, 6, 7, simpleSparseArray, 204060]], |
| simpleSparseArray, dec, 0); |
| |
| testReduce("reduce", "SimpleSparseReduceAccumulate", [,,,2,,4,,6], |
| [[[], 2, 3, simpleSparseArray, [,,,2]], |
| [[,,,2], 4, 5, simpleSparseArray, [,,,2,,4]], |
| [[,,,2,,4], 6, 7, simpleSparseArray, [,,,2,,4,,6]]], |
| simpleSparseArray, accumulate, []); |
| |
| |
| testReduce("reduce", "EmptySparseReduceSumNoInit", 0, [], [,,0,,], sum); |
| testReduce("reduce", "EmptySparseReduceProdNoInit", 1, [], [,,1,,], prod); |
| testReduce("reduce", "EmptySparseReduceDecNoInit", 0, [], [,,0,,], dec); |
| testReduce("reduce", "EmptySparseReduceAccumulateNoInit", |
| [], [], [,,[],,], accumulate); |
| |
| |
| var verySparseArray = []; |
| verySparseArray.length = 10000; |
| verySparseArray[2000] = 2; |
| verySparseArray[5000] = 4; |
| verySparseArray[9000] = 6; |
| var verySparseSlice2 = verySparseArray.slice(0, 2001); |
| var verySparseSlice4 = verySparseArray.slice(0, 5001); |
| var verySparseSlice6 = verySparseArray.slice(0, 9001); |
| |
| testReduce("reduce", "VerySparseReduceSum", 12, |
| [[0, 2, 2000, verySparseArray, 2], |
| [2, 4, 5000, verySparseArray, 6], |
| [6, 6, 9000, verySparseArray, 12]], |
| verySparseArray, sum, 0); |
| |
| testReduce("reduce", "VerySparseReduceProd", 48, |
| [[1, 2, 2000, verySparseArray, 2], |
| [2, 4, 5000, verySparseArray, 8], |
| [8, 6, 9000, verySparseArray, 48]], |
| verySparseArray, prod, 1); |
| |
| testReduce("reduce", "VerySparseReduceDec", Infinity, |
| [[0, 2, 2000, verySparseArray, Infinity], |
| [Infinity, 4, 5000, verySparseArray, Infinity], |
| [Infinity, 6, 9000, verySparseArray, Infinity]], |
| verySparseArray, dec, 0); |
| |
| testReduce("reduce", "VerySparseReduceAccumulate", |
| verySparseSlice6, |
| [[[], 2, 2000, verySparseArray, verySparseSlice2], |
| [verySparseSlice2, 4, 5000, verySparseArray, verySparseSlice4], |
| [verySparseSlice4, 6, 9000, verySparseArray, verySparseSlice6]], |
| verySparseArray, accumulate, []); |
| |
| |
| testReduce("reduce", "VerySparseReduceSumNoInit", 12, |
| [[2, 4, 5000, verySparseArray, 6], |
| [6, 6, 9000, verySparseArray, 12]], |
| verySparseArray, sum); |
| |
| testReduce("reduce", "VerySparseReduceProdNoInit", 48, |
| [[2, 4, 5000, verySparseArray, 8], |
| [8, 6, 9000, verySparseArray, 48]], |
| verySparseArray, prod); |
| |
| testReduce("reduce", "VerySparseReduceDecNoInit", Infinity, |
| [[2, 4, 5000, verySparseArray, Infinity], |
| [Infinity, 6, 9000, verySparseArray, Infinity]], |
| verySparseArray, dec); |
| |
| testReduce("reduce", "SimpleSparseReduceAccumulateNoInit", |
| 2, |
| [[2, 4, 5000, verySparseArray, 2], |
| [2, 6, 9000, verySparseArray, 2]], |
| verySparseArray, accumulate); |
| |
| |
| // ---- Test ReduceRight |
| |
| testReduce("reduceRight", "SimpleReduceRightSum", 12, |
| [[0, 6, 2, simpleArray, 6], |
| [6, 4, 1, simpleArray, 10], |
| [10, 2, 0, simpleArray, 12]], |
| simpleArray, sum, 0); |
| |
| testReduce("reduceRight", "SimpleReduceRightProd", 48, |
| [[1, 6, 2, simpleArray, 6], |
| [6, 4, 1, simpleArray, 24], |
| [24, 2, 0, simpleArray, 48]], |
| simpleArray, prod, 1); |
| |
| testReduce("reduceRight", "SimpleReduceRightDec", 246, |
| [[0, 6, 2, simpleArray, 6], |
| [6, 4, 1, simpleArray, 46], |
| [46, 2, 0, simpleArray, 246]], |
| simpleArray, dec, 0); |
| |
| testReduce("reduceRight", "SimpleReduceRightAccumulate", simpleArray, |
| [[[], 6, 2, simpleArray, [,,6]], |
| [[,,6], 4, 1, simpleArray, [,4,6]], |
| [[,4,6], 2, 0, simpleArray, simpleArray]], |
| simpleArray, accumulate, []); |
| |
| |
| testReduce("reduceRight", "EmptyReduceRightSum", 0, [], [], sum, 0); |
| testReduce("reduceRight", "EmptyReduceRightProd", 1, [], [], prod, 1); |
| testReduce("reduceRight", "EmptyReduceRightDec", 0, [], [], dec, 0); |
| testReduce("reduceRight", "EmptyReduceRightAccumulate", [], |
| [], [], accumulate, []); |
| |
| testReduce("reduceRight", "EmptyReduceRightSumNoInit", 0, [], [0], sum); |
| testReduce("reduceRight", "EmptyReduceRightProdNoInit", 1, [], [1], prod); |
| testReduce("reduceRight", "EmptyReduceRightDecNoInit", 0, [], [0], dec); |
| testReduce("reduceRight", "EmptyReduceRightAccumulateNoInit", |
| [], [], [[]], accumulate); |
| |
| |
| testReduce("reduceRight", "SimpleSparseReduceRightSum", 12, |
| [[0, 6, 7, simpleSparseArray, 6], |
| [6, 4, 5, simpleSparseArray, 10], |
| [10, 2, 3, simpleSparseArray, 12]], |
| simpleSparseArray, sum, 0); |
| |
| testReduce("reduceRight", "SimpleSparseReduceRightProd", 48, |
| [[1, 6, 7, simpleSparseArray, 6], |
| [6, 4, 5, simpleSparseArray, 24], |
| [24, 2, 3, simpleSparseArray, 48]], |
| simpleSparseArray, prod, 1); |
| |
| testReduce("reduceRight", "SimpleSparseReduceRightDec", 204060, |
| [[0, 6, 7, simpleSparseArray, 60], |
| [60, 4, 5, simpleSparseArray, 4060], |
| [4060, 2, 3, simpleSparseArray, 204060]], |
| simpleSparseArray, dec, 0); |
| |
| testReduce("reduceRight", "SimpleSparseReduceRightAccumulate", [,,,2,,4,,6], |
| [[[], 6, 7, simpleSparseArray, [,,,,,,,6]], |
| [[,,,,,,,6], 4, 5, simpleSparseArray, [,,,,,4,,6]], |
| [[,,,,,4,,6], 2, 3, simpleSparseArray, [,,,2,,4,,6]]], |
| simpleSparseArray, accumulate, []); |
| |
| |
| testReduce("reduceRight", "EmptySparseReduceRightSumNoInit", |
| 0, [], [,,0,,], sum); |
| testReduce("reduceRight", "EmptySparseReduceRightProdNoInit", |
| 1, [], [,,1,,], prod); |
| testReduce("reduceRight", "EmptySparseReduceRightDecNoInit", |
| 0, [], [,,0,,], dec); |
| testReduce("reduceRight", "EmptySparseReduceRightAccumulateNoInit", |
| [], [], [,,[],,], accumulate); |
| |
| |
| var verySparseSuffix6 = []; |
| verySparseSuffix6[9000] = 6; |
| var verySparseSuffix4 = []; |
| verySparseSuffix4[5000] = 4; |
| verySparseSuffix4[9000] = 6; |
| var verySparseSuffix2 = verySparseSlice6; |
| |
| |
| testReduce("reduceRight", "VerySparseReduceRightSum", 12, |
| [[0, 6, 9000, verySparseArray, 6], |
| [6, 4, 5000, verySparseArray, 10], |
| [10, 2, 2000, verySparseArray, 12]], |
| verySparseArray, sum, 0); |
| |
| testReduce("reduceRight", "VerySparseReduceRightProd", 48, |
| [[1, 6, 9000, verySparseArray, 6], |
| [6, 4, 5000, verySparseArray, 24], |
| [24, 2, 2000, verySparseArray, 48]], |
| verySparseArray, prod, 1); |
| |
| testReduce("reduceRight", "VerySparseReduceRightDec", Infinity, |
| [[0, 6, 9000, verySparseArray, Infinity], |
| [Infinity, 4, 5000, verySparseArray, Infinity], |
| [Infinity, 2, 2000, verySparseArray, Infinity]], |
| verySparseArray, dec, 0); |
| |
| testReduce("reduceRight", "VerySparseReduceRightAccumulate", |
| verySparseSuffix2, |
| [[[], 6, 9000, verySparseArray, verySparseSuffix6], |
| [verySparseSuffix6, 4, 5000, verySparseArray, verySparseSuffix4], |
| [verySparseSuffix4, 2, 2000, verySparseArray, verySparseSuffix2]], |
| verySparseArray, accumulate, []); |
| |
| |
| testReduce("reduceRight", "VerySparseReduceRightSumNoInit", 12, |
| [[6, 4, 5000, verySparseArray, 10], |
| [10, 2, 2000, verySparseArray, 12]], |
| verySparseArray, sum); |
| |
| testReduce("reduceRight", "VerySparseReduceRightProdNoInit", 48, |
| [[6, 4, 5000, verySparseArray, 24], |
| [24, 2, 2000, verySparseArray, 48]], |
| verySparseArray, prod); |
| |
| testReduce("reduceRight", "VerySparseReduceRightDecNoInit", Infinity, |
| [[6, 4, 5000, verySparseArray, Infinity], |
| [Infinity, 2, 2000, verySparseArray, Infinity]], |
| verySparseArray, dec); |
| |
| testReduce("reduceRight", "SimpleSparseReduceRightAccumulateNoInit", |
| 6, |
| [[6, 4, 5000, verySparseArray, 6], |
| [6, 2, 2000, verySparseArray, 6]], |
| verySparseArray, accumulate); |
| |
| |
| // undefined is an element |
| var undefArray = [,,undefined,,undefined,,]; |
| |
| testReduce("reduce", "SparseUndefinedReduceAdd", NaN, |
| [[0, undefined, 2, undefArray, NaN], |
| [NaN, undefined, 4, undefArray, NaN], |
| ], |
| undefArray, sum, 0); |
| |
| testReduce("reduceRight", "SparseUndefinedReduceRightAdd", NaN, |
| [[0, undefined, 4, undefArray, NaN], |
| [NaN, undefined, 2, undefArray, NaN], |
| ], undefArray, sum, 0); |
| |
| testReduce("reduce", "SparseUndefinedReduceAddNoInit", NaN, |
| [[undefined, undefined, 4, undefArray, NaN], |
| ], undefArray, sum); |
| |
| testReduce("reduceRight", "SparseUndefinedReduceRightAddNoInit", NaN, |
| [[undefined, undefined, 2, undefArray, NaN], |
| ], undefArray, sum); |
| |
| |
| // Ignore non-array properties: |
| |
| var arrayPlus = [1,2,,3]; |
| arrayPlus[-1] = NaN; |
| arrayPlus[Math.pow(2,32)] = NaN; |
| arrayPlus[NaN] = NaN; |
| arrayPlus["00"] = NaN; |
| arrayPlus["02"] = NaN; |
| arrayPlus["-0"] = NaN; |
| |
| testReduce("reduce", "ArrayWithNonElementPropertiesReduce", 6, |
| [[0, 1, 0, arrayPlus, 1], |
| [1, 2, 1, arrayPlus, 3], |
| [3, 3, 3, arrayPlus, 6], |
| ], arrayPlus, sum, 0); |
| |
| testReduce("reduceRight", "ArrayWithNonElementPropertiesReduceRight", 6, |
| [[0, 3, 3, arrayPlus, 3], |
| [3, 2, 1, arrayPlus, 5], |
| [5, 1, 0, arrayPlus, 6], |
| ], arrayPlus, sum, 0); |
| |
| // Test passing undefined as initial value (to test missing parameter |
| // detection). |
| [1].reduce((a, b) => { assertEquals(a, undefined); assertEquals(b, 1) }, |
| undefined); |
| [1, 2].reduce((a, b) => { assertEquals(a, 1); assertEquals(b, 2); }); |
| [1].reduce((a, b) => { assertTrue(false); }); |
| |
| // Test error conditions: |
| |
| var exception = false; |
| try { |
| [1].reduce("not a function"); |
| } catch (e) { |
| exception = true; |
| assertTrue(e instanceof TypeError, |
| "reduce callback not a function not throwing TypeError"); |
| assertTrue(e.message.indexOf(" is not a function") >= 0, |
| "reduce non function TypeError type"); |
| } |
| assertTrue(exception); |
| |
| exception = false; |
| try { |
| [1].reduceRight("not a function"); |
| } catch (e) { |
| exception = true; |
| assertTrue(e instanceof TypeError, |
| "reduceRight callback not a function not throwing TypeError"); |
| assertTrue(e.message.indexOf(" is not a function") >= 0, |
| "reduceRight non function TypeError type"); |
| } |
| assertTrue(exception); |
| |
| exception = false; |
| try { |
| [].reduce(sum); |
| } catch (e) { |
| exception = true; |
| assertTrue(e instanceof TypeError, |
| "reduce no initial value not throwing TypeError"); |
| assertEquals("Reduce of empty array with no initial value", e.message, |
| "reduce no initial TypeError type"); |
| } |
| assertTrue(exception); |
| |
| exception = false; |
| try { |
| [].reduceRight(sum); |
| } catch (e) { |
| exception = true; |
| assertTrue(e instanceof TypeError, |
| "reduceRight no initial value not throwing TypeError"); |
| assertEquals("Reduce of empty array with no initial value", e.message, |
| "reduceRight no initial TypeError type"); |
| } |
| assertTrue(exception); |
| |
| exception = false; |
| try { |
| [,,,].reduce(sum); |
| } catch (e) { |
| exception = true; |
| assertTrue(e instanceof TypeError, |
| "reduce sparse no initial value not throwing TypeError"); |
| assertEquals("Reduce of empty array with no initial value", e.message, |
| "reduce no initial TypeError type"); |
| } |
| assertTrue(exception); |
| |
| exception = false; |
| try { |
| [,,,].reduceRight(sum); |
| } catch (e) { |
| exception = true; |
| assertTrue(e instanceof TypeError, |
| "reduceRight sparse no initial value not throwing TypeError"); |
| assertEquals("Reduce of empty array with no initial value", e.message, |
| "reduceRight no initial TypeError type"); |
| } |
| assertTrue(exception); |
| |
| |
| // Array changing length |
| |
| function manipulator(a, b, i, s) { |
| if (s.length % 2) { |
| s[s.length * 3] = i; |
| } else { |
| s.length = s.length >> 1; |
| } |
| return a + b; |
| } |
| |
| var arr = [1, 2, 3, 4]; |
| testReduce("reduce", "ArrayManipulationShort", 3, |
| [[0, 1, 0, [1, 2, 3, 4], 1], |
| [1, 2, 1, [1, 2], 3], |
| ], arr, manipulator, 0); |
| |
| var arr = [1, 2, 3, 4]; |
| testReduce("reduceRight", "RightArrayManipulationShort", 7, |
| [[0, 4, 3, [1, 2, 3, 4], 4], |
| [4, 2, 1, [1, 2], 6], |
| [6, 1, 0, [1], 7], |
| ], arr, manipulator, 0); |
| |
| var arr = [1, 2, 3, 4, 5]; |
| testReduce("reduce", "ArrayManipulationLonger", 10, |
| [[0, 1, 0, [1, 2, 3, 4, 5], 1], |
| [1, 2, 1, [1, 2, 3, 4, 5,,,,,,,,,,, 0], 3], |
| [3, 3, 2, [1, 2, 3, 4, 5,,,,], 6], |
| [6, 4, 3, [1, 2, 3, 4], 10], |
| ], arr, manipulator, 0); |
| |
| function extender(a, b, i, s) { |
| s[s.length] = s.length; |
| return a + b; |
| } |
| |
| var arr = [1, 2, 3, 4]; |
| testReduce("reduce", "ArrayManipulationExtender", 10, |
| [[0, 1, 0, [1, 2, 3, 4], 1], |
| [1, 2, 1, [1, 2, 3, 4, 4], 3], |
| [3, 3, 2, [1, 2, 3, 4, 4, 5], 6], |
| [6, 4, 3, [1, 2, 3, 4, 4, 5, 6], 10], |
| ], arr, extender, 0); |
| |
| var arr = []; |
| Object.defineProperty(arr, "0", { get: function() { delete this[0] }, |
| configurable: true }); |
| assertEquals(undefined, arr.reduce(function(val) { return val })); |
| |
| var arr = []; |
| Object.defineProperty(arr, "0", { get: function() { delete this[0] }, |
| configurable: true}); |
| assertEquals(undefined, arr.reduceRight(function(val) { return val })); |
| |
| |
| (function ReduceRightMaxIndex() { |
| const kMaxIndex = 0xffffffff-1; |
| let array = []; |
| array[kMaxIndex-2] = 'value-2'; |
| array[kMaxIndex-1] = 'value-1'; |
| // Use the maximum array index possible. |
| array[kMaxIndex] = 'value'; |
| // Add the next index which is a normal property and thus will not show up. |
| array[kMaxIndex+1] = 'normal property'; |
| assertThrowsEquals( () => { |
| array.reduceRight((sum, value) => { |
| assertEquals('initial', sum); |
| assertEquals('value', value); |
| // Throw at this point as we would very slowly loop down from kMaxIndex. |
| throw 'do not continue'; |
| }, 'initial') |
| }, 'do not continue'); |
| })(); |
| |
| (function OptimizedReduce() { |
| let f = (a,current) => a + current; |
| let g = function(a) { |
| return a.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [1,2,3,4,5,6,7,8,9,10]; |
| g(a); g(a); |
| let total = g(a); |
| %OptimizeFunctionOnNextCall(g); |
| assertEquals(total, g(a)); |
| })(); |
| |
| (function OptimizedReduceEmpty() { |
| let f = (a,current) => a + current; |
| let g = function(a) { |
| return a.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [1,2,3,4,5,6,7,8,9,10]; |
| g(a); g(a); g(a); |
| %OptimizeFunctionOnNextCall(g); |
| g(a); |
| assertThrows(() => g([])); |
| })(); |
| |
| (function OptimizedReduceLazyDeopt() { |
| let deopt = false; |
| let f = (a,current) => { if (deopt) %DeoptimizeNow(); return a + current; }; |
| let g = function(a) { |
| return a.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [1,2,3,4,5,6,7,8,9,10]; |
| g(a); g(a); |
| let total = g(a); |
| %OptimizeFunctionOnNextCall(g); |
| g(a); |
| deopt = true; |
| assertEquals(total, g(a)); |
| })(); |
| |
| (function OptimizedReduceLazyDeoptMiddleOfIteration() { |
| let deopt = false; |
| let f = (a,current) => { |
| if (current == 6 && deopt) %DeoptimizeNow(); |
| return a + current; |
| }; |
| let g = function(a) { |
| return a.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [11,22,33,45,56,6,77,84,93,101]; |
| g(a); g(a); |
| let total = g(a); |
| %OptimizeFunctionOnNextCall(g); |
| g(a); |
| deopt = true; |
| assertEquals(total, g(a)); |
| })(); |
| |
| (function OptimizedReduceEagerDeoptMiddleOfIteration() { |
| let deopt = false; |
| let array = [11,22,33,45,56,6,77,84,93,101]; |
| let f = (a,current) => { |
| if (current == 6 && deopt) {array[0] = 1.5; } |
| return a + current; |
| }; |
| let g = function() { |
| return array.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| g(); |
| %PrepareFunctionForOptimization(g); |
| deopt = false; |
| array = [11,22,33,45,56,6,77,84,93,101]; |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| assertEquals(total, g()); |
| })(); |
| |
| (function OptimizedReduceEagerDeoptMiddleOfIterationHoley() { |
| let deopt = false; |
| let array = [, ,11,22,,33,45,56,,6,77,84,93,101,]; |
| let f = (a,current) => { |
| if (current == 6 && deopt) {array[0] = 1.5; } |
| return a + current; |
| }; |
| let g = function() { |
| return array.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| g(); |
| %PrepareFunctionForOptimization(g); |
| deopt = false; |
| array = [11,22,33,45,56,6,77,84,93,101]; |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| assertEquals(total, g()); |
| })(); |
| |
| (function TriggerReduceRightPreLoopDeopt() { |
| function f(a) { |
| a.reduceRight((x) => { return x + 1 }); |
| }; |
| %PrepareFunctionForOptimization(f); |
| f([1,2,]); |
| f([1,2,]); |
| %OptimizeFunctionOnNextCall(f); |
| assertThrows(() => f([]), TypeError); |
| })(); |
| |
| (function OptimizedReduceRightEagerDeoptMiddleOfIterationHoley() { |
| let deopt = false; |
| let array = [, ,11,22,,33,45,56,,6,77,84,93,101,]; |
| let f = (a,current) => { |
| if (current == 6 && deopt) {array[array.length-1] = 1.5; } |
| return a + current; |
| }; |
| let g = function() { |
| return array.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| g(); |
| %PrepareFunctionForOptimization(g); |
| deopt = false; |
| array = [11,22,33,45,56,6,77,84,93,101]; |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| assertEquals(total, g()); |
| })(); |
| |
| (function ReduceCatch() { |
| let f = (a,current) => { |
| return a + current; |
| }; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| g(); |
| assertEquals(total, g()); |
| })(); |
| |
| (function ReduceThrow() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceThrow() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| %NeverOptimizeFunction(f); |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceFinally() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| } finally { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceFinallyNoInline() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| %NeverOptimizeFunction(f); |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| } finally { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceNonCallableOpt() { |
| let done = false; |
| let f = (a, current) => { |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| return array.reduce(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); g(); |
| assertEquals(6, g()); |
| f = null; |
| assertThrows(() => g()); |
| })(); |
| |
| (function ReduceCatchInlineDeopt() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) { |
| %DeoptimizeNow(); |
| throw "x"; |
| } |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceFinallyInlineDeopt() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) { |
| %DeoptimizeNow(); |
| throw "x"; |
| } |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduce(f); |
| } catch (e) { |
| } finally { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function OptimizedReduceRight() { |
| let count = 0; |
| let f = (a,current,i) => a + current * ++count; |
| let g = function(a) { |
| count = 0; |
| return a.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [1,2,3,4,5,6,7,8,9,10]; |
| g(a); g(a); |
| let total = g(a); |
| %OptimizeFunctionOnNextCall(g); |
| assertEquals(total, g(a)); |
| })(); |
| |
| (function OptimizedReduceEmpty() { |
| let count = 0; |
| let f = (a,current,i) => a + current * ++count; |
| let g = function(a) { |
| count = 0; |
| return a.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [1,2,3,4,5,6,7,8,9,10]; |
| g(a); g(a); g(a); |
| %OptimizeFunctionOnNextCall(g); |
| g(a); |
| assertThrows(() => g([])); |
| })(); |
| |
| (function OptimizedReduceLazyDeopt() { |
| let deopt = false; |
| let f = (a,current) => { if (deopt) %DeoptimizeNow(); return a + current; }; |
| let g = function(a) { |
| return a.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [1,2,3,4,5,6,7,8,9,10]; |
| g(a); g(a); |
| let total = g(a); |
| %OptimizeFunctionOnNextCall(g); |
| g(a); |
| deopt = true; |
| assertEquals(total, g(a)); |
| })(); |
| |
| (function OptimizedReduceLazyDeoptMiddleOfIteration() { |
| let deopt = false; |
| let f = (a,current) => { |
| if (current == 6 && deopt) %DeoptimizeNow(); |
| return a + current; |
| }; |
| let g = function(a) { |
| return a.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| let a = [11,22,33,45,56,6,77,84,93,101]; |
| g(a); g(a); |
| let total = g(a); |
| %OptimizeFunctionOnNextCall(g); |
| g(a); |
| deopt = true; |
| assertEquals(total, g(a)); |
| })(); |
| |
| (function OptimizedReduceEagerDeoptMiddleOfIteration() { |
| let deopt = false; |
| let array = [11,22,33,45,56,6,77,84,93,101]; |
| let f = (a,current) => { |
| if (current == 6 && deopt) {array[9] = 1.5; } |
| return a + current; |
| }; |
| let g = function() { |
| return array.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| g(); |
| %PrepareFunctionForOptimization(g); |
| deopt = false; |
| array = [11,22,33,45,56,6,77,84,93,101]; |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| deopt = true; |
| assertEquals(total, g()); |
| })(); |
| |
| (function ReduceCatch() { |
| let f = (a,current) => { |
| return a + current; |
| }; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| g(); |
| assertEquals(total, g()); |
| })(); |
| |
| (function ReduceThrow() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceThrow() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| %NeverOptimizeFunction(f); |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceFinally() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| } finally { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceFinallyNoInline() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) throw "x"; |
| return a + current; |
| }; |
| %NeverOptimizeFunction(f); |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| } finally { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceNonCallableOpt() { |
| let done = false; |
| let f = (a, current) => { |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| return array.reduceRight(f); |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); g(); |
| assertEquals(6, g()); |
| f = null; |
| assertThrows(() => g()); |
| })(); |
| |
| (function ReduceCatchInlineDeopt() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) { |
| %DeoptimizeNow(); |
| throw "x"; |
| } |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceFinallyInlineDeopt() { |
| let done = false; |
| let f = (a, current) => { |
| if (done) { |
| %DeoptimizeNow(); |
| throw "x"; |
| } |
| return a + current; |
| }; |
| let array = [1,2,3]; |
| let g = function() { |
| try { |
| return array.reduceRight(f); |
| } catch (e) { |
| } finally { |
| if (done) return null; |
| } |
| }; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| let total = g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| done = false; |
| %PrepareFunctionForOptimization(g); |
| g(); g(); |
| %OptimizeFunctionOnNextCall(g); |
| g(); |
| assertEquals(6, g()); |
| done = true; |
| assertEquals(null, g()); |
| })(); |
| |
| (function ReduceHoleyArrayWithDefaultAccumulator() { |
| var holey = new Array(10); |
| function reduce(a) { |
| let callback = function(accumulator, currentValue) { |
| return currentValue; |
| }; |
| return a.reduce(callback, 13); |
| }; |
| %PrepareFunctionForOptimization(reduce); |
| assertEquals(13, reduce(holey)); |
| assertEquals(13, reduce(holey)); |
| assertEquals(13, reduce(holey)); |
| %OptimizeFunctionOnNextCall(reduce); |
| assertEquals(13, reduce(holey)); |
| })(); |
| |
| (function ReduceRightHoleyArrayWithDefaultAccumulator() { |
| var holey = new Array(10); |
| function reduce(a) { |
| let callback = function(accumulator, currentValue) { |
| return currentValue; |
| }; |
| return a.reduceRight(callback, 13); |
| }; |
| %PrepareFunctionForOptimization(reduce); |
| assertEquals(13, reduce(holey)); |
| assertEquals(13, reduce(holey)); |
| assertEquals(13, reduce(holey)); |
| %OptimizeFunctionOnNextCall(reduce); |
| assertEquals(13, reduce(holey)); |
| })(); |
| |
| (function ReduceHoleyArrayOneElementWithDefaultAccumulator() { |
| var holey = new Array(10); |
| holey[1] = 5; |
| function reduce(a) { |
| let callback = function(accumulator, currentValue) { |
| return currentValue + accumulator; |
| }; |
| return a.reduce(callback, 13); |
| }; |
| %PrepareFunctionForOptimization(reduce); |
| assertEquals(18, reduce(holey)); |
| assertEquals(18, reduce(holey)); |
| assertEquals(18, reduce(holey)); |
| %OptimizeFunctionOnNextCall(reduce); |
| assertEquals(18, reduce(holey)); |
| })(); |
| |
| (function ReduceRightHoleyArrayOneElementWithDefaultAccumulator() { |
| var holey = new Array(10); |
| holey[1] = 5; |
| function reduce(a) { |
| let callback = function(accumulator, currentValue) { |
| return currentValue + accumulator; |
| }; |
| return a.reduceRight(callback, 13); |
| }; |
| %PrepareFunctionForOptimization(reduce); |
| assertEquals(18, reduce(holey)); |
| assertEquals(18, reduce(holey)); |
| assertEquals(18, reduce(holey)); |
| %OptimizeFunctionOnNextCall(reduce); |
| assertEquals(18, reduce(holey)); |
| })(); |
| |
| (function ReduceMixedHoleyArrays() { |
| function r(a) { |
| return a.reduce((acc, i) => {acc[0]}); |
| }; |
| %PrepareFunctionForOptimization(r); |
| r([[0]]); |
| r([[0]]); |
| r([0,,]); |
| %OptimizeFunctionOnNextCall(r); |
| r([,0,0]); |
| })(); |