v8/test/mjsunit/sealed-array-reduce.js
Simon Zünd 6df0af84e2 Fix flaky Array#reduce mjsunit test
This CL fixes a flaky mjsunit test, that exercises Array#reduce with
sealed arrays in TurboFan. The flake was caused by temporary objects,
whos maps didn't live long enough. The code object of the function
under test holds weakly onto this maps. With a low enough gc interval,
the maps, and thus the code object, get cleaned up before the
{assertOptimized} can execute.

The fix is simply to assign these temporary objects to variables.

Bug: v8:9374
Change-Id: I43da8ba6b0194872b176e27617d9ca7fbfe43ec2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1666989
Auto-Submit: Simon Zünd <szuend@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Commit-Queue: Simon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62269}
2019-06-19 07:26:09 +00:00

1432 lines
38 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);
%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);
})();