0df0c8e3bc
Use FastJSArrayForRead pattern. Add test of array.reduce, array.reduceRight for non-extensible, sealed, frozen objects similar to mjsunit/array-reduce.js ~3x perf improvement in JSTests/ObjectFreeze micro-benchmark Before: ArrayReduce ArrayReduce-Numbers(Score): 0.0740 ArrayReduceRight ArrayReduceRight-Numbers(Score): 0.0767 After: ArrayReduce ArrayReduce-Numbers(Score): 0.249 ArrayReduceRight ArrayReduceRight-Numbers(Score): 0.261 Bug: v8:6831 Change-Id: I98f54f010256993fcd05bb24be968fb2d0f5c966 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1656851 Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Reviewed-by: Simon Zünd <szuend@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#62158}
1405 lines
37 KiB
JavaScript
1405 lines
37 KiB
JavaScript
// 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);
|
|
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);
|
|
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);
|
|
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);
|
|
done = false;
|
|
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);
|
|
done = false;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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]});
|
|
};
|
|
%PrepareFunctionForOptimization(r);
|
|
assertEquals(r(Object.seal([[0]])), [0]);
|
|
assertEquals(r(Object.seal([[0]])), [0]);
|
|
assertEquals(r(Object.seal([0,,])), 0);
|
|
%OptimizeFunctionOnNextCall(r);
|
|
assertEquals(r(Object.seal([,0,0])), undefined);
|
|
assertOptimized(r);
|
|
})();
|