diff options
Diffstat (limited to 'deps/v8/test/mjsunit/sealed-array-reduce.js')
-rw-r--r-- | deps/v8/test/mjsunit/sealed-array-reduce.js | 1431 |
1 files changed, 1431 insertions, 0 deletions
diff --git a/deps/v8/test/mjsunit/sealed-array-reduce.js b/deps/v8/test/mjsunit/sealed-array-reduce.js new file mode 100644 index 0000000000..a572aa2cc4 --- /dev/null +++ b/deps/v8/test/mjsunit/sealed-array-reduce.js @@ -0,0 +1,1431 @@ +// Copyright 2019 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 --opt --no-always-opt + +/** + * @fileoverview Test reduce and reduceRight + */ + +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; + 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 Number(a) + Number(b); } +function prod(a, b) { return Number(a) * Number(b); } +function dec(a, b, i, arr) { return Number(a) + Number(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]; +Object.seal(simpleArray); + +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, []); + +var emptyArray = []; +Object.seal(emptyArray); + +testReduce("reduce", "EmptyReduceSum", 0, [], emptyArray, sum, 0); +testReduce("reduce", "EmptyReduceProd", 1, [], emptyArray, prod, 1); +testReduce("reduce", "EmptyReduceDec", 0, [], emptyArray, dec, 0); +testReduce("reduce", "EmptyReduceAccumulate", [], [], emptyArray, accumulate, []); + +testReduce("reduce", "EmptyReduceSumNoInit", 0, emptyArray, [0], sum); +testReduce("reduce", "EmptyReduceProdNoInit", 1, emptyArray, [1], prod); +testReduce("reduce", "EmptyReduceDecNoInit", 0, emptyArray, [0], dec); +testReduce("reduce", "EmptyReduceAccumulateNoInit", [], emptyArray, [[]], accumulate); + + +var simpleSparseArray = [,,,'2',,4,,6,,]; +Object.seal(simpleSparseArray); + +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); +Object.seal(verySparseArray); + +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,,]; +Object.seal(undefArray); + +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; +Object.seal(arrayPlus); + +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). +Object.seal(['1']).reduce((a, b) => { assertEquals(a, undefined); assertEquals(b, '1') }, + undefined); +Object.seal(['1', 2]).reduce((a, b) => { assertEquals(a, '1'); assertEquals(b, 2); }); +Object.seal(['1']).reduce((a, b) => { assertTrue(false); }); + +// Test error conditions: + +var exception = false; +try { + Object.seal(['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 { + Object.seal(['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 { + Object.seal([]).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 { + Object.seal([]).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 { + Object.seal([,,,]).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 { + Object.seal([,,,]).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 extender(a, b, i, s) { + s[s.length] = s.length; + return Number(a) + Number(b); +} + +var arr = [1, '2', 3, 4]; +Object.seal(arr); +testReduce("reduce", "ArrayManipulationExtender", 10, + [[0, 1, 0, [1, '2', 3, 4], 1], + [1, '2', 1, [1, '2', 3, 4], 3], + [3, 3, 2, [1, '2', 3, 4], 6], + [6, 4, 3, [1, '2', 3, 4], 10], + ], arr, extender, 0); + +var arr = []; +Object.defineProperty(arr, "0", { get: function() { delete this[0] }, + configurable: true }); +assertEquals(undefined, Object.seal(arr).reduce(function(val) { return val })); + +var arr = []; +Object.defineProperty(arr, "0", { get: function() { delete this[0] }, + configurable: true}); +assertEquals(undefined, Object.seal(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( () => { + Object.seal(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 + Number(current); + let g = function(a) { + return a.reduce(f); + }; + %PrepareFunctionForOptimization(g); + let a = [1,'2',3,4,5,6,7,8,9,10]; + Object.seal(a); + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + assertEquals(total, g(a)); + assertOptimized(g); +})(); + +(function OptimizedReduceEmpty() { + let f = (a,current) => a + Number(current); + let g = function(a) { + return a.reduce(f); + }; + %PrepareFunctionForOptimization(g); + let a = [1,'2',3,4,5,6,7,8,9,10]; + Object.seal(a); + g(a); g(a); g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + assertOptimized(g); + assertThrows(() => g([])); + assertUnoptimized(g); +})(); + +(function OptimizedReduceLazyDeopt() { + let deopt = false; + let f = (a,current) => { if (deopt) %DeoptimizeNow(); return a + Number(current); }; + let g = function(a) { + return a.reduce(f); + }; + %PrepareFunctionForOptimization(g); + let a = [1,'2',3,4,5,6,7,8,9,10]; + Object.seal(a); + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + assertOptimized(g); + deopt = true; + assertEquals(total, g(a)); + assertOptimized(g); +})(); + +(function OptimizedReduceLazyDeoptMiddleOfIteration() { + let deopt = false; + let f = (a,current) => { + if (current == 6 && deopt) %DeoptimizeNow(); + return a + Number(current); + }; + let g = function(a) { + return a.reduce(f); + }; + %PrepareFunctionForOptimization(g); + let a = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(a); + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + assertOptimized(g); + deopt = true; + assertEquals(total, g(a)); + assertOptimized(g); +})(); + +(function OptimizedReduceEagerDeoptMiddleOfIteration() { + let deopt = false; + let array = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(array); + let f = (a,current) => { + if (current == 6 && deopt) {array[0] = 1.5; } + return a + Number(current); + }; + let g = function() { + return array.reduce(f); + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); + deopt = true; + g(); + assertOptimized(g); + %PrepareFunctionForOptimization(g); + deopt = false; + array = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(array); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); + deopt = true; + assertEquals(total, g()); + assertOptimized(g); +})(); + +(function OptimizedReduceEagerDeoptMiddleOfIterationHoley() { + let deopt = false; + let array = [, ,11,'22',,33,45,56,,6,77,84,93,101,]; + Object.seal(array); + let f = (a,current) => { + if (current == 6 && deopt) {array[0] = 1.5; } + return a + Number(current); + }; + let g = function() { + return array.reduce(f); + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); + deopt = true; + g(); + assertOptimized(g); + %PrepareFunctionForOptimization(g); + deopt = false; + array = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(array); + %OptimizeFunctionOnNextCall(g); + g(); + assertUnoptimized(g); + deopt = true; + assertEquals(total, g()); + assertUnoptimized(g); +})(); + +(function TriggerReduceRightPreLoopDeopt() { + function f(a) { + a.reduceRight((x) => { return Number(x) + 1 }); + }; + %PrepareFunctionForOptimization(f); + var arr = Object.seal([1, '2', ]); + f(arr); + f(arr); + %OptimizeFunctionOnNextCall(f); + assertThrows(() => f([]), TypeError); + assertUnoptimized(f); +})(); + +(function OptimizedReduceRightEagerDeoptMiddleOfIterationHoley() { + let deopt = false; + let array = [, ,11,'22',,33,45,56,,6,77,84,93,101,]; + Object.seal(array); + let f = (a,current) => { + if (current == 6 && deopt) {array[array.length-1] = 1.5; } + return a + Number(current); + }; + let g = function() { + return array.reduceRight(f); + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); + deopt = true; + g(); + assertOptimized(g); + %PrepareFunctionForOptimization(g); + deopt = false; + array = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(array); + %OptimizeFunctionOnNextCall(g); + g(); + assertUnoptimized(g); + deopt = true; + assertEquals(total, g()); + assertUnoptimized(g); +})(); + +(function ReduceCatch() { + let f = (a,current) => { + return a + current; + }; + let g = function() { + try { + return Object.seal(array).reduce(f); + } catch (e) { + } + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + g(); + assertEquals(total, g()); + assertOptimized(g); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + %PrepareFunctionForOptimization(g); + %OptimizeFunctionOnNextCall(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + %NeverOptimizeFunction(f); + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + %PrepareFunctionForOptimization(g); + done = false; + %OptimizeFunctionOnNextCall(g); + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceFinally() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceFinallyNoInline() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + %NeverOptimizeFunction(f); + let array = [1, '2', 3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceNonCallableOpt() { + let done = false; + let f = (a, current) => { + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + let g = function() { + return array.reduce(f); + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); g(); + assertEquals(6, g()); + assertOptimized(g); + f = null; + assertThrows(() => g()); + assertOptimized(g); +})(); + +(function ReduceCatchInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + Number(current); + }; + let array = [1,2,3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceFinallyInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function OptimizedReduceRight() { + let count = 0; + let f = (a,current,i) => a + Number(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]; + Object.seal(a); + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + assertEquals(total, g(a)); + assertOptimized(g); +})(); + +(function OptimizedReduceEmpty() { + let count = 0; + let f = (a,current,i) => a + Number(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]; + Object.seal(a); + g(a); g(a); g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + assertOptimized(g); + assertThrows(() => g([])); + assertUnoptimized(g); +})(); + +(function OptimizedReduceLazyDeopt() { + let deopt = false; + let f = (a,current) => { if (deopt) %DeoptimizeNow(); return a + Number(current); }; + let g = function(a) { + return a.reduceRight(f); + }; + %PrepareFunctionForOptimization(g); + let a = [1,'2',3,4,5,6,7,8,9,10]; + Object.seal(a); + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + deopt = true; + assertEquals(total, g(a)); + assertOptimized(g); +})(); + +(function OptimizedReduceLazyDeoptMiddleOfIteration() { + let deopt = false; + let f = (a,current) => { + if (current == 6 && deopt) %DeoptimizeNow(); + return a + Number(current); + }; + let g = function(a) { + return a.reduceRight(f); + }; + %PrepareFunctionForOptimization(g); + let a = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(a); + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + deopt = true; + assertEquals(total, g(a)); + assertOptimized(g); +})(); + +(function OptimizedReduceEagerDeoptMiddleOfIteration() { + let deopt = false; + let array = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(array); + let f = (a,current) => { + if (current == 6 && deopt) {array[9] = 1.5; } + return a + Number(current); + }; + let g = function() { + return array.reduceRight(f); + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); + deopt = true; + %PrepareFunctionForOptimization(g); + g(); + deopt = false; + array = [11,'22',33,45,56,6,77,84,93,101]; + Object.seal(array); + %OptimizeFunctionOnNextCall(g); + g(); + deopt = true; + assertEquals(total, g()); + assertOptimized(g); +})(); + +(function ReduceCatch() { + let f = (a,current) => { + return a + Number(current); + }; + let g = function() { + try { + return Object.seal(array).reduceRight(f); + } catch (e) { + } + }; + %PrepareFunctionForOptimization(g); + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + g(); + assertEquals(total, g()); + assertOptimized(g); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = true; + assertEquals(null, g()); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + %NeverOptimizeFunction(f); + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceFinally() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + let array = [1, '2', 3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceFinallyNoInline() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + Number(current); + }; + %NeverOptimizeFunction(f); + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = true; + assertEquals(null, g()); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceNonCallableOpt() { + let done = false; + let f = (a, current) => { + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); +})(); + +(function ReduceCatchInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceFinallyInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + Number(current); + }; + let array = [1,'2',3]; + Object.seal(array); + 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()); + assertOptimized(g); + done = false; + %PrepareFunctionForOptimization(g); + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + assertOptimized(g); +})(); + +(function ReduceHoleyArrayWithDefaultAccumulator() { + var holey = new Array(10); + Object.seal(holey); + 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)); + assertOptimized(reduce); +})(); + +(function ReduceRightHoleyArrayWithDefaultAccumulator() { + var holey = new Array(10); + Object.seal(holey); + 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)); + assertOptimized(reduce); +})(); + +(function ReduceHoleyArrayOneElementWithDefaultAccumulator() { + var holey = new Array(10); + holey[1] = '5'; + Object.seal(holey); + function reduce(a) { + let callback = function(accumulator, currentValue) { + return Number(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)); + assertOptimized(reduce); +})(); + +(function ReduceRightHoleyArrayOneElementWithDefaultAccumulator() { + var holey = new Array(10); + holey[1] = '5'; + Object.seal(holey); + function reduce(a) { + let callback = function(accumulator, currentValue) { + return Number(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)); + assertOptimized(reduce); +})(); + +(function ReduceMixedHoleyArrays() { + function r(a) { + return a.reduce((acc, i) => {acc[0]}); + }; + + // Hold on to the objects, otherwise their maps might be garbage + // collected and {r} will get deoptmized before the {assertOptimized}. + const object1 = Object.seal([[0]]); + const object2 = Object.seal([0,,]); + const object3 = Object.seal([,0,0]); + + %PrepareFunctionForOptimization(r); + assertEquals(r(object1), [0]); + assertEquals(r(object1), [0]); + assertEquals(r(object2), 0); + %OptimizeFunctionOnNextCall(r); + assertEquals(r(object3), undefined); + assertOptimized(r); +})(); |