diff options
Diffstat (limited to 'deps/v8/test/mjsunit')
133 files changed, 6102 insertions, 263 deletions
diff --git a/deps/v8/test/mjsunit/array-iteration.js b/deps/v8/test/mjsunit/array-iteration.js index 9d03ed13ce..4de58208b4 100644 --- a/deps/v8/test/mjsunit/array-iteration.js +++ b/deps/v8/test/mjsunit/array-iteration.js @@ -73,6 +73,31 @@ assertEquals(3, count); for (var i in a) assertEquals(2, a[i]); + // Skip over missing properties. + a = { + "0": 0, + "2": 2, + length: 3 + }; + var received = []; + assertArrayEquals([2], + Array.prototype.filter.call(a, function(n) { + received.push(n); + return n == 2; + })); + assertArrayEquals([0, 2], received); + + // Modify array prototype + a = [0, , 2]; + received = []; + assertArrayEquals([2], + Array.prototype.filter.call(a, function(n) { + a.__proto__ = null; + received.push(n); + return n == 2; + })); + assertArrayEquals([0, 2], received); + // Create a new object in each function call when receiver is a // primitive value. See ECMA-262, Annex C. a = []; @@ -131,6 +156,26 @@ a.forEach(function(n) { count++; }); assertEquals(1, count); + // Skip over missing properties. + a = { + "0": 0, + "2": 2, + length: 3 + }; + var received = []; + Array.prototype.forEach.call(a, function(n) { received.push(n); }); + assertArrayEquals([0, 2], received); + + // Modify array prototype + a = [0, , 2]; + received = []; + Array.prototype.forEach.call(a, function(n) { + a.__proto__ = null; + received.push(n); + return n == 2; + }); + assertArrayEquals([0, 2], received); + // Create a new object in each function call when receiver is a // primitive value. See ECMA-262, Annex C. a = []; @@ -194,6 +239,31 @@ assertTrue(a.every(function(n) { count++; return n == 2; })); assertEquals(2, count); + // Skip over missing properties. + a = { + "0": 2, + "2": 2, + length: 3 + }; + var received = []; + assertTrue( + Array.prototype.every.call(a, function(n) { + received.push(n); + return n == 2; + })); + assertArrayEquals([2, 2], received); + + // Modify array prototype + a = [2, , 2]; + received = []; + assertTrue( + Array.prototype.every.call(a, function(n) { + a.__proto__ = null; + received.push(n); + return n == 2; + })); + assertArrayEquals([2, 2], received); + // Create a new object in each function call when receiver is a // primitive value. See ECMA-262, Annex C. a = []; @@ -252,6 +322,31 @@ a = a.map(function(n) { return 2*n; }); for (var i in a) assertEquals(4, a[i]); + // Skip over missing properties. + a = { + "0": 1, + "2": 2, + length: 3 + }; + var received = []; + assertArrayEquals([2, , 4], + Array.prototype.map.call(a, function(n) { + received.push(n); + return n * 2; + })); + assertArrayEquals([1, 2], received); + + // Modify array prototype + a = [1, , 2]; + received = []; + assertArrayEquals([2, , 4], + Array.prototype.map.call(a, function(n) { + a.__proto__ = null; + received.push(n); + return n * 2; + })); + assertArrayEquals([1, 2], received); + // Create a new object in each function call when receiver is a // primitive value. See ECMA-262, Annex C. a = []; diff --git a/deps/v8/test/mjsunit/array-reduce.js b/deps/v8/test/mjsunit/array-reduce.js index 4a4494a72c..171a40f092 100644 --- a/deps/v8/test/mjsunit/array-reduce.js +++ b/deps/v8/test/mjsunit/array-reduce.js @@ -25,6 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax + /** * @fileoverview Test reduce and reduceRight */ @@ -557,3 +559,685 @@ assertEquals(undefined, arr.reduceRight(function(val) { return val })); }, 'initial') }, 'do not continue'); })(); + +(function OptimizedReduce() { + let f = (a,current) => a + current; + let g = function(a) { + return a.reduce(f); + } + let a = [1,2,3,4,5,6,7,8,9,10]; + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + assertEquals(total, g(a)); +})(); + +(function OptimizedReduceEmpty() { + let f = (a,current) => a + current; + let g = function(a) { + return a.reduce(f); + } + let a = [1,2,3,4,5,6,7,8,9,10]; + g(a); g(a); g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + assertThrows(() => g([])); +})(); + +(function OptimizedReduceLazyDeopt() { + let deopt = false; + let f = (a,current) => { if (deopt) %DeoptimizeNow(); return a + current; }; + let g = function(a) { + return a.reduce(f); + } + let a = [1,2,3,4,5,6,7,8,9,10]; + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + deopt = true; + assertEquals(total, g(a)); +})(); + +(function OptimizedReduceLazyDeoptMiddleOfIteration() { + let deopt = false; + let f = (a,current) => { + if (current == 6 && deopt) %DeoptimizeNow(); + return a + current; + }; + let g = function(a) { + return a.reduce(f); + } + let a = [11,22,33,45,56,6,77,84,93,101]; + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + deopt = true; + assertEquals(total, g(a)); +})(); + +(function OptimizedReduceEagerDeoptMiddleOfIteration() { + let deopt = false; + let array = [11,22,33,45,56,6,77,84,93,101]; + let f = (a,current) => { + if (current == 6 && deopt) {array[0] = 1.5; } + return a + current; + }; + let g = function() { + return array.reduce(f); + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + deopt = true; + g(); + deopt = false; + array = [11,22,33,45,56,6,77,84,93,101]; + %OptimizeFunctionOnNextCall(g); + g(); + deopt = true; + assertEquals(total, g()); +})(); + +(function ReduceCatch() { + let f = (a,current) => { + return a + current; + }; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + g(); + assertEquals(total, g()); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + %NeverOptimizeFunction(f); + let array = [1,2,3]; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceFinally() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + } finally { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceFinallyNoInline() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + %NeverOptimizeFunction(f); + let array = [1,2,3]; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + } finally { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceNonCallableOpt() { + let done = false; + let f = (a, current) => { + return a + current; + }; + let array = [1,2,3]; + let g = function() { + return array.reduce(f); + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); g(); + assertEquals(6, g()); + f = null; + assertThrows(() => g()); +})(); + +(function ReduceCatchInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceFinallyInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduce(f); + } catch (e) { + } finally { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function OptimizedReduceRight() { + let count = 0; + let f = (a,current,i) => a + current * ++count; + let g = function(a) { + count = 0; + return a.reduceRight(f); + } + let a = [1,2,3,4,5,6,7,8,9,10]; + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + assertEquals(total, g(a)); +})(); + +(function OptimizedReduceEmpty() { + let count = 0; + let f = (a,current,i) => a + current * ++count; + let g = function(a) { + count = 0; + return a.reduceRight(f); + } + let a = [1,2,3,4,5,6,7,8,9,10]; + g(a); g(a); g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + assertThrows(() => g([])); +})(); + +(function OptimizedReduceLazyDeopt() { + let deopt = false; + let f = (a,current) => { if (deopt) %DeoptimizeNow(); return a + current; }; + let g = function(a) { + return a.reduceRight(f); + } + let a = [1,2,3,4,5,6,7,8,9,10]; + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + deopt = true; + assertEquals(total, g(a)); +})(); + +(function OptimizedReduceLazyDeoptMiddleOfIteration() { + let deopt = false; + let f = (a,current) => { + if (current == 6 && deopt) %DeoptimizeNow(); + return a + current; + }; + let g = function(a) { + return a.reduceRight(f); + } + let a = [11,22,33,45,56,6,77,84,93,101]; + g(a); g(a); + let total = g(a); + %OptimizeFunctionOnNextCall(g); + g(a); + deopt = true; + assertEquals(total, g(a)); +})(); + +(function OptimizedReduceEagerDeoptMiddleOfIteration() { + let deopt = false; + let array = [11,22,33,45,56,6,77,84,93,101]; + let f = (a,current) => { + if (current == 6 && deopt) {array[9] = 1.5; } + return a + current; + }; + let g = function() { + return array.reduceRight(f); + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + deopt = true; + g(); + deopt = false; + array = [11,22,33,45,56,6,77,84,93,101]; + %OptimizeFunctionOnNextCall(g); + g(); + deopt = true; + assertEquals(total, g()); +})(); + +(function ReduceCatch() { + let f = (a,current) => { + return a + current; + }; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + g(); + assertEquals(total, g()); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceThrow() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + %NeverOptimizeFunction(f); + let array = [1,2,3]; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceFinally() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + } finally { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceFinallyNoInline() { + let done = false; + let f = (a, current) => { + if (done) throw "x"; + return a + current; + }; + %NeverOptimizeFunction(f); + let array = [1,2,3]; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + } finally { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceNonCallableOpt() { + let done = false; + let f = (a, current) => { + return a + current; + }; + let array = [1,2,3]; + let g = function() { + return array.reduceRight(f); + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); g(); + assertEquals(6, g()); + f = null; + assertThrows(() => g()); +})(); + +(function ReduceCatchInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceFinallyInlineDeopt() { + let done = false; + let f = (a, current) => { + if (done) { + %DeoptimizeNow(); + throw "x"; + } + return a + current; + }; + let array = [1,2,3]; + let g = function() { + try { + return array.reduceRight(f); + } catch (e) { + } finally { + if (done) return null; + } + } + g(); g(); + let total = g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); + done = false; + g(); g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertEquals(6, g()); + done = true; + assertEquals(null, g()); +})(); + +(function ReduceHoleyArrayWithDefaultAccumulator() { + var __v_12258 = new Array(10); + function __f_3253(a) { + let __f_3252 = function(accumulator, currentValue) { + return currentValue; + } + return a.reduce(__f_3252, 13); + } + assertEquals(13, __f_3253(__v_12258)); + assertEquals(13, __f_3253(__v_12258)); + assertEquals(13, __f_3253(__v_12258)); + %OptimizeFunctionOnNextCall(__f_3253); + assertEquals(13, __f_3253(__v_12258)); +})(); + +(function ReduceRightHoleyArrayWithDefaultAccumulator() { + var __v_12258 = new Array(10); + function __f_3253(a) { + let __f_3252 = function(accumulator, currentValue) { + return currentValue; + } + return a.reduceRight(__f_3252, 13); + } + assertEquals(13, __f_3253(__v_12258)); + assertEquals(13, __f_3253(__v_12258)); + assertEquals(13, __f_3253(__v_12258)); + %OptimizeFunctionOnNextCall(__f_3253); + assertEquals(13, __f_3253(__v_12258)); +})(); + +(function ReduceHoleyArrayOneElementWithDefaultAccumulator() { + var __v_12258 = new Array(10); + __v_12258[1] = 5; + function __f_3253(a) { + let __f_3252 = function(accumulator, currentValue) { + return currentValue + accumulator; + } + return a.reduce(__f_3252, 13); + } + assertEquals(18, __f_3253(__v_12258)); + assertEquals(18, __f_3253(__v_12258)); + assertEquals(18, __f_3253(__v_12258)); + %OptimizeFunctionOnNextCall(__f_3253); + assertEquals(18, __f_3253(__v_12258)); +})(); + +(function ReduceRightHoleyArrayOneElementWithDefaultAccumulator() { + var __v_12258 = new Array(10); + __v_12258[1] = 5; + function __f_3253(a) { + let __f_3252 = function(accumulator, currentValue) { + return currentValue + accumulator; + } + return a.reduceRight(__f_3252, 13); + } + assertEquals(18, __f_3253(__v_12258)); + assertEquals(18, __f_3253(__v_12258)); + assertEquals(18, __f_3253(__v_12258)); + %OptimizeFunctionOnNextCall(__f_3253); + assertEquals(18, __f_3253(__v_12258)); +})(); diff --git a/deps/v8/test/mjsunit/code-coverage-block-noopt.js b/deps/v8/test/mjsunit/code-coverage-block-noopt.js index 3eba9d3f57..ef68e0394d 100644 --- a/deps/v8/test/mjsunit/code-coverage-block-noopt.js +++ b/deps/v8/test/mjsunit/code-coverage-block-noopt.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --no-always-opt --harmony-async-iteration +// Flags: --allow-natives-syntax --no-always-opt // Flags: --no-opt // Files: test/mjsunit/code-coverage-utils.js diff --git a/deps/v8/test/mjsunit/code-coverage-block-opt.js b/deps/v8/test/mjsunit/code-coverage-block-opt.js index bc4a3f1010..e02775bd45 100644 --- a/deps/v8/test/mjsunit/code-coverage-block-opt.js +++ b/deps/v8/test/mjsunit/code-coverage-block-opt.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --no-always-opt --harmony-async-iteration --opt +// Flags: --allow-natives-syntax --no-always-opt --opt // Files: test/mjsunit/code-coverage-utils.js %DebugToggleBlockCoverage(true); @@ -39,7 +39,7 @@ TestCoverage("Partial coverage collection", }(); // 0400 `, [{"start":52,"end":153,"count":0}, - {"start":127,"end":152,"count":1}] + {"start":121,"end":152,"count":1}] ); %DebugToggleBlockCoverage(false); diff --git a/deps/v8/test/mjsunit/code-coverage-block.js b/deps/v8/test/mjsunit/code-coverage-block.js index 3355fd1259..b9d00bce6d 100644 --- a/deps/v8/test/mjsunit/code-coverage-block.js +++ b/deps/v8/test/mjsunit/code-coverage-block.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --no-always-opt --harmony-async-iteration +// Flags: --allow-natives-syntax --no-always-opt // Files: test/mjsunit/code-coverage-utils.js %DebugToggleBlockCoverage(true); @@ -38,20 +38,23 @@ function f(x) { // 0050 } // 0550 f(42); // 0600 f(43); // 0650 -`, -[{"start":0,"end":699,"count":1}, +if (true) { // 0700 + const foo = 'bar'; // 0750 +} else { // 0800 + const bar = 'foo'; // 0850 +} // 0900 +`, +[{"start":0,"end":949,"count":1}, + {"start":801,"end":901,"count":0}, {"start":0,"end":15,"count":11}, {"start":50,"end":551,"count":2}, {"start":115,"end":203,"count":1}, {"start":167,"end":171,"count":0}, - {"start":265,"end":273,"count":1}, - {"start":279,"end":287,"count":1}, - {"start":315,"end":319,"count":1}, - {"start":325,"end":329,"count":1}, + {"start":265,"end":287,"count":1}, + {"start":315,"end":329,"count":1}, {"start":363,"end":367,"count":0}, {"start":413,"end":417,"count":0}, - {"start":472,"end":476,"count":0}] - + {"start":466,"end":476,"count":0}] ); TestCoverage( @@ -82,7 +85,7 @@ TestCoverage( `, [{"start":0,"end":249,"count":1}, {"start":1,"end":201,"count":1}, - {"start":124,"end":129,"count":0}] + {"start":118,"end":129,"count":0}] ); TestCoverage( @@ -109,7 +112,7 @@ function g() {} // 0000 {"start":330,"end":334,"count":0}, {"start":431,"end":503,"count":12}, {"start":470,"end":474,"count":4}, - {"start":480,"end":484,"count":8}] + {"start":474,"end":484,"count":8}] ); TestCoverage( diff --git a/deps/v8/test/mjsunit/compiler/array-multiple-receiver-maps.js b/deps/v8/test/mjsunit/compiler/array-multiple-receiver-maps.js new file mode 100644 index 0000000000..2ef0cc3a01 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/array-multiple-receiver-maps.js @@ -0,0 +1,122 @@ +// Copyright 2018 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 + +function runTest(f, message, mkICTraining, deoptArg) { + function test(f, message, ictraining, deoptArg) { + // Train the call ic to the maps. + let t = ictraining; + + // We put the training data into local variables + // to ensure their maps are kepts alive. If the + // maps die, gc *may* deoptimize {f}, which makes + // the test flaky. + let t1 = t(); + let t2 = t(); + let t3 = t(); + + for (let a of t1) { + f(a.arr, () => a.el); + } + for (let a of t2) { + f(a.arr, () => a.el); + } + %OptimizeFunctionOnNextCall(f); + message += " trained with" + JSON.stringify(t()); + if (deoptArg == undefined) { + // Make sure the optimized function can handle + // all trained maps without deopt. + for (let a of t3) { + f(a.arr, () => a.el); + message += " for args " + JSON.stringify(a); + assertOptimized(f, undefined, message + " should have been optimized"); + } + } else { + // Trigger deopt, causing no-speculation bit to be set. + let a1 = deoptArg; + let a2 = deoptArg; + message += " for args " + JSON.stringify(a1); + f(a1.arr, () => a1.el); + assertUnoptimized(f, undefined, message + " should have been unoptimized"); + %OptimizeFunctionOnNextCall(f); + // No speculation should protect against further deopts. + f(a2.arr, () => a2.el); + assertOptimized(f, undefined, message + " should have been optimized"); + } + } + + // Get function as a string. + var testString = test.toString(); + // Remove the function header.. + testString = testString.replace(new RegExp("[^\n]*"), "let f = " + f.toString() + ";"); + // ..and trailing '}'. + testString = testString.replace(new RegExp("[^\n]*$"), ""); + // Substitute parameters. + testString = testString.replace(new RegExp("ictraining", 'g'), mkICTraining.toString()); + testString = testString.replace(new RegExp("deoptArg", 'g'), + deoptArg ? JSON.stringify(deoptArg) : "undefined"); + + var modTest = new Function("message", testString); + //print(modTest); + modTest(message); +} + +let checks = { + smiReceiver: + { mkTrainingArguments : () => [{arr:[1], el:3}], + deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}] + }, + objectReceiver: + { mkTrainingArguments : () => [{arr:[{}], el:0.1}], + deoptingArguments : [] + }, + multipleSmiReceivers: + { mkTrainingArguments : () => { let b = [1]; b.x=3; return [{arr:[1], el:3}, {arr:b, el:3}] }, + deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}] + }, + multipleSmiReceiversPackedUnpacked: + { mkTrainingArguments : () => { let b = [1]; b[100] = 3; return [{arr:[1], el:3}, {arr:b, el:3}] }, + deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}] + }, + multipleDoubleReceivers: + { mkTrainingArguments : () => { let b = [0.1]; b.x=0.3; return [{arr:[0.1], el:0.3}, {arr:b, el:0.3}] }, + deoptingArguments : [{arr:[{}], el:true}, {arr:[1], el:true}] + }, + multipleDoubleReceiversPackedUnpacked: + { mkTrainingArguments : () => { let b = [0.1]; b[100] = 0.3; return [{arr:[0.1], el:0.3}, {arr:b, el:0.3}] }, + deoptingArguments : [{arr:[{}], el:true}, {arr:[1], el:true}] + }, + multipleMixedReceivers: + { mkTrainingArguments : () => { let b = [0.1]; b.x=0.3; return [{arr:[1], el:0.3}, {arr:[{}], el:true}, {arr:b, el:0.3}] }, + deoptingArguments : [] + }, + multipleMixedReceiversPackedUnpacked: + { mkTrainingArguments : () => { let b = [0.1]; b[100] = 0.3; return [{arr:[1], el:0.3}, {arr:[{}], el:true}, {arr:b, el:0.3}] }, + deoptingArguments : [] + }, +}; + +const functions = { + push_reliable: (a,g) => { let b = g(); return a.push(2, b); }, + push_unreliable: (a,g) => { return a.push(2, g()); }, + pop_reliable: (a,g) => { let b = g(); return a.pop(2, b); }, + pop_unreliable: (a,g) => { return a.pop(2, g()); }, + shift_reliable: (a,g) => { let b = g(); return a.shift(2, b); }, + shift_unreliable: (a,g) => { return a.shift(2, g()); } +} + +Object.keys(checks).forEach( + key => { + let check = checks[key]; + + for (fnc in functions) { + runTest(functions[fnc], "test-reliable-" + key, check.mkTrainingArguments); + // Test each deopting arg separately. + for (let deoptArg of check.deoptingArguments) { + runTest(functions[fnc], "testDeopt-reliable-" + key, check.mkTrainingArguments, deoptArg); + } + } + } +); diff --git a/deps/v8/test/mjsunit/compiler/deopt-array-builtins.js b/deps/v8/test/mjsunit/compiler/deopt-array-builtins.js new file mode 100644 index 0000000000..b737b17ed0 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/deopt-array-builtins.js @@ -0,0 +1,148 @@ +// Copyright 2017 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 + +/* Test MapCheck behavior */ + +(function testForEachMapCheck() { + function f(v,n,o) { + Object.freeze(o); + } + function g() { + [1,2,3].forEach(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + + +(function testFindMapCheck() { + function f(v,n,o) { + Object.freeze(o); + return false; + } + function g() { + [1,2,3].find(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + +(function testMapMapCheck() { + function f(v,n,o) { + Object.freeze(o); + return false; + } + function g() { + [1,2,3].map(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + +(function testFilterMapCheck() { + function f(v,n,o) { + Object.freeze(o); + return true; + } + function g() { + [1,2,3].filter(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + + +/* Test CheckBounds behavior */ + +(function testForEachCheckBounds() { + function f(v,n,o) { + o.length=2; + } + function g() { + [1,2,3].forEach(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + + +(function testFindCheckBounds() { + function f(v,n,o) { + o.length=2; + return false; + } + function g() { + [1,2,3].find(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + +(function testMapCheckBounds() { + function f(v,n,o) { + o.length=2; + return false; + } + function g() { + [1,2,3].map(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + assertOptimized(g); +})(); + +(function testFilterCheckBounds() { + function f(v,n,o) { + o.length = 2; + return true; + } + function g() { + [1,2,3].filter(f); + } + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + g(); + %OptimizeFunctionOnNextCall(g); + g(); + g(); + assertOptimized(g); +})(); diff --git a/deps/v8/test/mjsunit/compiler/deopt-array-push.js b/deps/v8/test/mjsunit/compiler/deopt-array-push.js new file mode 100644 index 0000000000..e34d99a325 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/deopt-array-push.js @@ -0,0 +1,97 @@ +// Copyright 2017 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 + +(function test() { + function foo(a) { a.push(a.length = 2); } + + foo([1]); + foo([1]); + %OptimizeFunctionOnNextCall(foo); + foo([1]); + %OptimizeFunctionOnNextCall(foo); + foo([1]); + assertOptimized(foo); +})(); + +(function testElementTypeCheckSmi() { + function foo(a) { a.push('a'); } + + foo([1]); + foo([1]); + %OptimizeFunctionOnNextCall(foo); + foo([1]); + %OptimizeFunctionOnNextCall(foo); + foo([1]); + assertOptimized(foo); +})(); + +(function testElementTypeCheckDouble() { + function foo(a) { a.push('a'); } + + foo([0.3413312]); + foo([0.3413312]); + %OptimizeFunctionOnNextCall(foo); + foo([0.3413312]); + %OptimizeFunctionOnNextCall(foo); + foo([0.3413312]); + assertOptimized(foo); +})(); +(function test() { + function bar(a) { a.x = 2 }; + %NeverOptimizeFunction(bar); + function foo(a) { a.push(bar(a)); } + + foo(["1"]); + foo(["1"]); + %OptimizeFunctionOnNextCall(foo); + foo(["1"]); + %OptimizeFunctionOnNextCall(foo); + foo(["1"]); + assertOptimized(foo); +})(); + +(function test() { + function foo(a) { a.push(a.length = 2); } + + foo([0.34234]); + foo([0.34234]); + %OptimizeFunctionOnNextCall(foo); + foo([0.34234]); + %OptimizeFunctionOnNextCall(foo); + foo([0.34234]); + assertOptimized(foo); +})(); + +(function test() { + const N = 128 * 1024; + + function foo(a) { a.push(1); } + + foo(new Array(N)); + foo(new Array(N)); + %OptimizeFunctionOnNextCall(foo); + foo(new Array(N)); + %OptimizeFunctionOnNextCall(foo); + foo(new Array(N)); + assertOptimized(foo); +})(); + +(function test() { + function mkArray() { + const N = 128 * 1024; + let a = [0.1]; + a.length = N; + return a; + } + function foo(a) { a.push(0.23441233123); } + foo(mkArray()); + foo(mkArray()); + %OptimizeFunctionOnNextCall(foo); + foo(mkArray()); + %OptimizeFunctionOnNextCall(foo); + foo(mkArray()); + assertOptimized(foo); +})(); diff --git a/deps/v8/test/mjsunit/compiler/escape-analysis-13.js b/deps/v8/test/mjsunit/compiler/escape-analysis-13.js index fca4da618e..5f281aaaa4 100644 --- a/deps/v8/test/mjsunit/compiler/escape-analysis-13.js +++ b/deps/v8/test/mjsunit/compiler/escape-analysis-13.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --turbo-escape --turbo-experimental +// Flags: --allow-natives-syntax --turbo-escape function f() { var x = {}; diff --git a/deps/v8/test/mjsunit/compiler/escape-analysis-15.js b/deps/v8/test/mjsunit/compiler/escape-analysis-15.js index 4f9a40ad5c..1960d74892 100644 --- a/deps/v8/test/mjsunit/compiler/escape-analysis-15.js +++ b/deps/v8/test/mjsunit/compiler/escape-analysis-15.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --turbo-escape --turbo-experimental --no-turbo-load-elimination +// Flags: --allow-natives-syntax --turbo-escape --no-turbo-load-elimination function f(i) { var o1 = {a: 1, b: 2}; diff --git a/deps/v8/test/mjsunit/compiler/escape-analysis-phi-type.js b/deps/v8/test/mjsunit/compiler/escape-analysis-phi-type.js index 806b09b3de..9d033b9640 100644 --- a/deps/v8/test/mjsunit/compiler/escape-analysis-phi-type.js +++ b/deps/v8/test/mjsunit/compiler/escape-analysis-phi-type.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --turbo-escape --turbo-experimental --no-turbo-loop-peeling +// Flags: --allow-natives-syntax --turbo-escape --no-turbo-loop-peeling function f(x) { var o = {a : 0}; diff --git a/deps/v8/test/mjsunit/compiler/materialize-dictionary-properties.js b/deps/v8/test/mjsunit/compiler/materialize-dictionary-properties.js new file mode 100644 index 0000000000..5838a83979 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/materialize-dictionary-properties.js @@ -0,0 +1,18 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function f() { + // Create a non-escaping object. + var o = Object.create(null); + %DeoptimizeNow(); + // Keep it alive. + return o ? 1 : 0; +} + +f(); +f(); +%OptimizeFunctionOnNextCall(f); +assertEquals(1, f()); diff --git a/deps/v8/test/mjsunit/compiler/materialize-mutable-heap-number.js b/deps/v8/test/mjsunit/compiler/materialize-mutable-heap-number.js new file mode 100644 index 0000000000..b6b99afcf4 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/materialize-mutable-heap-number.js @@ -0,0 +1,22 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function C() {} +%CompleteInobjectSlackTracking(new C()); + +function f() { + // Create a non-escaping object. + var o = new C(); + // Add an out-of-object double property. + o.x = 0.5; + %DeoptimizeNow(); + return o.x + 0.25; +} + +f(); +f(); +%OptimizeFunctionOnNextCall(f); +assertEquals(0.75, f()); diff --git a/deps/v8/test/mjsunit/compiler/new-cons-string.js b/deps/v8/test/mjsunit/compiler/new-cons-string.js new file mode 100644 index 0000000000..7f6da7262a --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/new-cons-string.js @@ -0,0 +1,71 @@ +// Copyright 2017 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 --expose-externalize-string + +(function() { + function foo(s) { + return "abcdefghijklm" + s; + } + + assertTrue(isOneByteString(foo("0"))); + assertTrue(isOneByteString(foo("0"))); + %OptimizeFunctionOnNextCall(foo); + assertTrue(isOneByteString(foo("0"))); +})(); + +(function() { + function foo(s) { + return s + "abcdefghijklm"; + } + + assertTrue(isOneByteString(foo("0"))); + assertTrue(isOneByteString(foo("0"))); + %OptimizeFunctionOnNextCall(foo); + assertTrue(isOneByteString(foo("0"))); +})(); + +(function() { + function foo(s) { + return "abcdefghijklm" + s; + } + + assertFalse(isOneByteString(foo("\u1234"))); + assertFalse(isOneByteString(foo("\u1234"))); + %OptimizeFunctionOnNextCall(foo); + assertFalse(isOneByteString(foo("\u1234"))); +})(); + +(function() { + function foo(s) { + return s + "abcdefghijklm"; + } + + assertFalse(isOneByteString(foo("\u1234"))); + assertFalse(isOneByteString(foo("\u1234"))); + %OptimizeFunctionOnNextCall(foo); + assertFalse(isOneByteString(foo("\u1234"))); +})(); + +(function() { + function foo(s) { + return "abcdefghijkl\u1234" + s; + } + + assertFalse(isOneByteString(foo("0"))); + assertFalse(isOneByteString(foo("0"))); + %OptimizeFunctionOnNextCall(foo); + assertFalse(isOneByteString(foo("0"))); +})(); + +(function() { + function foo(s) { + return s + "abcdefghijkl\u1234"; + } + + assertFalse(isOneByteString(foo("0"))); + assertFalse(isOneByteString(foo("0"))); + %OptimizeFunctionOnNextCall(foo); + assertFalse(isOneByteString(foo("0"))); +})(); diff --git a/deps/v8/test/mjsunit/compiler/regress-786521.js b/deps/v8/test/mjsunit/compiler/regress-786521.js new file mode 100644 index 0000000000..2b161270ed --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-786521.js @@ -0,0 +1,23 @@ +// Copyright 2017 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 + +// Provoke type None as result of a SpeculativeNumberMultiply to +// ensure that Turbofan can handle this. + +function inlined(b, x) { + if (b) { + x * 2 * 2 + } +} + +inlined(true, 1); +inlined(true, 2); +inlined(false, 1); + +function foo(b) { inlined(b, "") } +foo(false); foo(false); +%OptimizeFunctionOnNextCall(foo); +foo(true); diff --git a/deps/v8/test/mjsunit/compiler/regress-793863.js b/deps/v8/test/mjsunit/compiler/regress-793863.js new file mode 100644 index 0000000000..883805dff6 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-793863.js @@ -0,0 +1,12 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function f(a) { + return arguments[0]; +} + +%OptimizeFunctionOnNextCall(f); +assertEquals(undefined, f()); diff --git a/deps/v8/test/mjsunit/compiler/regress-796041.js b/deps/v8/test/mjsunit/compiler/regress-796041.js new file mode 100644 index 0000000000..e2c2e11c0b --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-796041.js @@ -0,0 +1,35 @@ +// Copyright 2018 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 + +'use strict'; + +function f(abort, n, a, b) { + if (abort) return; + var x = a ? true : "" + a; + if (!a) { + var dead = n + 1 + 1; + if(!b) { + x = dead; + } + if (x) { + x = false; + } + if (b) { + x = false; + } + } + return x + 1; +} +f(false, 5); f(false, 6); f(false, 7); f(false, 8); + +function g(abort, a, b) { + return f(abort, "abc", a, b); +} + +g(true); g(true); g(true); g(true); + +%OptimizeFunctionOnNextCall(g); +g(false); diff --git a/deps/v8/test/mjsunit/compiler/regress-797596.js b/deps/v8/test/mjsunit/compiler/regress-797596.js new file mode 100644 index 0000000000..4e3594bdb1 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-797596.js @@ -0,0 +1,30 @@ +// Copyright 2017 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: --expose-gc --allow-natives-syntax +var notCallable; +function inferReceiverMapsInDeadCode() { + var obj = { func() {} }; + gc(); + function wrappedCode() { try { code(); } catch (e) {} } + function code() { + obj.a; + try { + Object.defineProperty(obj, "func", { get() {} }); + } catch (neverCaught) {} + for (var i = 0; i < 1; i++) { + try { + notCallable(arguments[i]); + } catch (alwaysCaught) {} + } + } + wrappedCode(); + try { + %OptimizeFunctionOnNextCall(wrappedCode); + wrappedCode(); + } catch (e) {} +} +inferReceiverMapsInDeadCode(); +inferReceiverMapsInDeadCode(); +inferReceiverMapsInDeadCode(); diff --git a/deps/v8/test/mjsunit/compiler/regress-801097.js b/deps/v8/test/mjsunit/compiler/regress-801097.js new file mode 100644 index 0000000000..d488ce4deb --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-801097.js @@ -0,0 +1,19 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function GetFunction() { + var source = "return ((dividend | 0) / (("; + for (var i = 0; i < 0x8000; i++) { + source += "a," + } + source += "a) | 0)) | 0"; + return Function("dividend", source); +} + +var func = GetFunction(); +assertThrows("func();"); +%OptimizeFunctionOnNextCall(func); +assertThrows("func()"); diff --git a/deps/v8/test/mjsunit/compiler/varargs.js b/deps/v8/test/mjsunit/compiler/varargs.js new file mode 100644 index 0000000000..ae636dc0f7 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/varargs.js @@ -0,0 +1,49 @@ +// Copyright 2017 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. + +x = "a"; + +function test_varargs(...args) { + var sum = this.x; + for (i in args) { + sum += "," + args[i]; + } + return sum; +} + +assertEquals("a", test_varargs()); +assertEquals("a,b", test_varargs("b")); +assertEquals("a,b,c", test_varargs("b", "c")); +assertEquals("a,b,c,d", test_varargs("b", "c", "d")); +assertEquals("a,b,c,d,e", test_varargs("b", "c", "d", "e")); + +function forward_varargs(...args) { + return test_varargs(...args); +} + +assertEquals("a", forward_varargs()); +assertEquals("a,b", forward_varargs("b")); +assertEquals("a,b,c", forward_varargs("b", "c")); +assertEquals("a,b,c,d", forward_varargs("b", "c", "d")); +assertEquals("a,b,c,d,e", forward_varargs("b", "c", "d", "e")); + +function forward_varargs_one_arg(x, ...args) { + return test_varargs(x, ...args); +} + +assertEquals("a,undefined", forward_varargs_one_arg()); +assertEquals("a,b", forward_varargs_one_arg("b")); +assertEquals("a,b,c", forward_varargs_one_arg("b", "c")); +assertEquals("a,b,c,d", forward_varargs_one_arg("b", "c", "d")); +assertEquals("a,b,c,d,e", forward_varargs_one_arg("b", "c", "d", "e")); + +function forward_varargs_two_args(x, y, ...args) { + return test_varargs(x, y, ...args); +} + +assertEquals("a,undefined,undefined", forward_varargs_two_args()); +assertEquals("a,b,undefined", forward_varargs_two_args("b")); +assertEquals("a,b,c", forward_varargs_two_args("b", "c")); +assertEquals("a,b,c,d", forward_varargs_two_args("b", "c", "d")); +assertEquals("a,b,c,d,e", forward_varargs_two_args("b", "c", "d", "e")); diff --git a/deps/v8/test/mjsunit/constant-folding-2.js b/deps/v8/test/mjsunit/constant-folding-2.js index da9e5d5469..7586261c92 100644 --- a/deps/v8/test/mjsunit/constant-folding-2.js +++ b/deps/v8/test/mjsunit/constant-folding-2.js @@ -33,8 +33,6 @@ function test(f) { f(); %OptimizeFunctionOnNextCall(f); f(); - // Assert that there has been no deopt. - assertOptimized(f); } test(function add() { @@ -234,6 +232,7 @@ test(function stringCharCodeAt() { assertEquals("NaN", String("abc".charCodeAt(4))); assertEquals(98, "abc".charCodeAt(1.1)); assertEquals("NaN", String("abc".charCodeAt(4.1))); + assertEquals("NaN", String("abc".charCodeAt(1 + 4294967295))); }); test(function stringCharAt() { @@ -242,6 +241,7 @@ test(function stringCharAt() { assertEquals("", "abc".charAt(4)); assertEquals("b", "abc".charAt(1.1)); assertEquals("", "abc".charAt(4.1)); + assertEquals("", String("abc".charAt(1 + 4294967295))); }); diff --git a/deps/v8/test/mjsunit/d8/.gitignore b/deps/v8/test/mjsunit/d8/.gitignore new file mode 100644 index 0000000000..4497115e4c --- /dev/null +++ b/deps/v8/test/mjsunit/d8/.gitignore @@ -0,0 +1 @@ +v8_trace.json diff --git a/deps/v8/test/mjsunit/d8-os.js b/deps/v8/test/mjsunit/d8/d8-os.js index c2d8ec59bc..c2d8ec59bc 100644 --- a/deps/v8/test/mjsunit/d8-os.js +++ b/deps/v8/test/mjsunit/d8/d8-os.js diff --git a/deps/v8/test/mjsunit/d8-performance-now.js b/deps/v8/test/mjsunit/d8/d8-performance-now.js index 3e5485e81d..3e5485e81d 100644 --- a/deps/v8/test/mjsunit/d8-performance-now.js +++ b/deps/v8/test/mjsunit/d8/d8-performance-now.js diff --git a/deps/v8/test/mjsunit/d8-worker-sharedarraybuffer.js b/deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js index 09586c3a11..09586c3a11 100644 --- a/deps/v8/test/mjsunit/d8-worker-sharedarraybuffer.js +++ b/deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js diff --git a/deps/v8/test/mjsunit/d8-worker-spawn-worker.js b/deps/v8/test/mjsunit/d8/d8-worker-spawn-worker.js index a114d8587e..a114d8587e 100644 --- a/deps/v8/test/mjsunit/d8-worker-spawn-worker.js +++ b/deps/v8/test/mjsunit/d8/d8-worker-spawn-worker.js diff --git a/deps/v8/test/mjsunit/d8-worker.js b/deps/v8/test/mjsunit/d8/d8-worker.js index a73d7b1706..a73d7b1706 100644 --- a/deps/v8/test/mjsunit/d8-worker.js +++ b/deps/v8/test/mjsunit/d8/d8-worker.js diff --git a/deps/v8/test/mjsunit/d8/enable-tracing.js b/deps/v8/test/mjsunit/d8/enable-tracing.js new file mode 100644 index 0000000000..5174b41155 --- /dev/null +++ b/deps/v8/test/mjsunit/d8/enable-tracing.js @@ -0,0 +1,8 @@ +// Copyright 2017 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: --enable-tracing --trace-path=test/mjsunit/d8/v8_trace.json + +// Just test that running d8 with --enable-tracing does not crash in a normal +// execution without exceptions or calls to natives. diff --git a/deps/v8/test/mjsunit/deserialize-reference.js b/deps/v8/test/mjsunit/deserialize-reference.js index b032013159..ac4979bd26 100644 --- a/deps/v8/test/mjsunit/deserialize-reference.js +++ b/deps/v8/test/mjsunit/deserialize-reference.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --cache=code --serialize-toplevel +// Flags: --cache=code var a = "123"; assertEquals(a, "123"); diff --git a/deps/v8/test/mjsunit/dictionary-prototypes.js b/deps/v8/test/mjsunit/dictionary-prototypes.js new file mode 100644 index 0000000000..109f8d42a6 --- /dev/null +++ b/deps/v8/test/mjsunit/dictionary-prototypes.js @@ -0,0 +1,409 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function EnsureDictionaryMode(obj, properties=1500) { + for (let i = 0; i < properties; i++) { + obj["x" + i] = 0; + } + assertFalse(%HasFastProperties(obj)); +} + +function EnsureAlmostDictionaryMode(obj) { + for (let i = 0; i < 1020; i++) { + obj["x" + i] = 0; + } +} + +function TestAddingPropertyToDictionaryPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + // The UNINITIALIZED -> PREMONOMORPHIC transition of StoreIC should + // properly invalidate prototype chains. + Bar.prototype.func = function() { ++bar_func_called; } + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToDictionaryPrototype(); + +// Same as TestAddingPropertyToDictionaryPrototype, but using o["foo"] access +// instead of o.foo. +function TestAddingPropertyToDictionaryPrototype2() { + let foo_func_called = 0; + let bar_func_called = 0; + let name = "func"; + + function Foo() {} + Foo.prototype[name] = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o[name](); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + // The UNINITIALIZED -> PREMONOMORPHIC transition of KeyedStoreIC should + // properly invalidate prototype chains. + Bar.prototype[name] = function() { ++bar_func_called; } + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToDictionaryPrototype2(); + +function TestAddingPropertyToDictionaryPrototype_DefineProperty() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + // The runtime should properly invalidate prototype chains. + Object.defineProperty(Bar.prototype, "func", {value: function() { ++bar_func_called; }}); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToDictionaryPrototype_DefineProperty(); + +function TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + // The magic number ensures that the next addition to the dictionary will + // trigger the slow path. + EnsureDictionaryMode(Bar.prototype, 2731); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + // -> slow path for dictionary add + Bar.prototype.func = function() { ++bar_func_called; } + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath(); + +function TestAddingAccessorPropertyToDictionaryPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + Object.defineProperty(Bar.prototype, "func", + {get: function() { return function() { ++bar_func_called; }}}); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingAccessorPropertyToDictionaryPrototype(); + +function TestRemovingPropertyFromDictionaryPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + Bar.prototype.func = function() { ++bar_func_called; } + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Bar. + o.func(); + + // Remove the property from Bar which is a dictionary-mode prototype between + // o and Foo. In the next iteration, it's looked up from Foo. + if (i == 9) { + delete Bar.prototype.func; + } + } + + assertEquals(1, foo_func_called); + assertEquals(10, bar_func_called); +} + +TestRemovingPropertyFromDictionaryPrototype(); + +// Same as TestRemovingPropertyFromDictionaryPrototype, but using o["foo"] access +// instead of o.foo. +function TestRemovingPropertyFromDictionaryPrototype2() { + let foo_func_called = 0; + let bar_func_called = 0; + let name = "func"; + + function Foo() {} + Foo.prototype[name] = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + Bar.prototype[name] = function() { ++bar_func_called; } + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Bar. + o[name](); + + // Remove the property from Bar which is a dictionary-mode prototype between + // o and Foo. In the next iteration, it's looked up from Foo. + if (i == 9) { + delete Bar.prototype[name]; + } + } + + assertEquals(1, foo_func_called); + assertEquals(10, bar_func_called); +} + +TestRemovingPropertyFromDictionaryPrototype2(); + +function TestAddingPropertyToDictionaryPrototype_Monomorphic() { + function DoMonomorphicStoreToPrototype(p, f, do_delete=true) { + p.func = f; + if (do_delete) { + delete p.func; + } + } + + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + + function bar_func() { + ++bar_func_called; + } + DoMonomorphicStoreToPrototype(Bar.prototype, bar_func); + DoMonomorphicStoreToPrototype(Bar.prototype, bar_func); + DoMonomorphicStoreToPrototype(Bar.prototype, bar_func); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + DoMonomorphicStoreToPrototype(Bar.prototype, bar_func, false); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToDictionaryPrototype_Monomorphic(); + +function TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic() { + function DoMonomorphicKeyedStoreToPrototype(p, name, f, do_delete=true) { + p[name] = f; + if (do_delete) { + delete p[name]; + } + } + + let foo_func_called = 0; + let bar_func_called = 0; + let name = "func"; + + function Foo() {} + Foo.prototype[name] = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureDictionaryMode(Bar.prototype); + + function bar_func() { + ++bar_func_called; + } + DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func); + DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func); + DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a dictionary-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func, false); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic(); + +// Like TestAddingPropertyToDictionaryPrototype, except that the prototype isn't +// in dictionary mode yet, but turns to dictionary mode after the interesting +// property is added. +function TestAddingPropertyToAlmostDictionaryPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + EnsureAlmostDictionaryMode(Bar.prototype); + + let o = new Bar(); + for (let i = 0; i < 2; ++i) { + o.x0; + } + assertTrue(%HasFastProperties(Bar.prototype)); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which will now turn permanently into dictionary + // mode. In the next iteration, it's looked up from Bar. + if (i == 9) { + Bar.prototype.func = function() { ++bar_func_called; } + assertFalse(%HasFastProperties(Bar.prototype)); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToAlmostDictionaryPrototype(); + +function TestReconfiguringDataToAccessor() { + let setter_called = 0; + + function Bar() {} + EnsureDictionaryMode(Bar.prototype); + let name = "prop"; + Object.defineProperty(Bar.prototype, name, + {value: 1000, writable: true, configurable: true}); + + for (let i = 0; i < 11; ++i) { + let obj1 = new Bar(); + if (i < 10) { + assertEquals(1000, obj1.prop); + } else { + assertEquals(3000, obj1.prop); + } + + // Add the property into the object. + obj1.prop = 2000; + if (i < 10) { + assertEquals(2000, obj1.prop); + } else { + assertEquals(3000, obj1.prop); + } + + // Make "prop" an accessor property in the prototype. + if (i == 9) { + Object.defineProperty(Bar.prototype, name, + {get: () => 3000, + set: function(val) { ++setter_called; }}); + } + } + assertEquals(1, setter_called); +} + +TestReconfiguringDataToAccessor(); diff --git a/deps/v8/test/mjsunit/es6/array-find.js b/deps/v8/test/mjsunit/es6/array-find.js index 5f6ba4226b..9fed027c8f 100644 --- a/deps/v8/test/mjsunit/es6/array-find.js +++ b/deps/v8/test/mjsunit/es6/array-find.js @@ -234,6 +234,40 @@ assertEquals(22, a.find(function(val) { return 22 === val; }), undefined); // +// Test predicate is called for missing properties +// +(function() { + const obj = { + "0": 0, + "2": 2, + length: 3 + }; + const received = []; + const predicate = (v) => { received.push(v); return false; }; + const found = Array.prototype.find.call(obj, predicate); + assertEquals(undefined, found); + assertArrayEquals([0, undefined, 2], received); +})(); + + +// +// Test predicate modifying array prototype +// +(function() { + const a = [0, , 2]; + const received = []; + const predicate = (v) => { + a.__proto__ = null; + received.push(v); + return false; + }; + const found = Array.prototype.find.call(a, predicate); + assertEquals(undefined, found); + assertArrayEquals([0, undefined, 2], received); +})(); + + +// // Test thisArg // (function() { diff --git a/deps/v8/test/mjsunit/es6/array-findindex.js b/deps/v8/test/mjsunit/es6/array-findindex.js index 716eb4e0db..d335c15108 100644 --- a/deps/v8/test/mjsunit/es6/array-findindex.js +++ b/deps/v8/test/mjsunit/es6/array-findindex.js @@ -234,6 +234,40 @@ assertEquals(3, a.findIndex(function(val) { return 24 === val; })); // +// Test predicate is called for missing properties +// +(function() { + const obj = { + "0": 0, + "2": 2, + length: 3 + }; + const received = []; + const predicate = (v) => { received.push(v); return false; }; + const found = Array.prototype.findIndex.call(obj, predicate); + assertEquals(-1, found); + assertArrayEquals([0, undefined, 2], received); +})(); + + +// +// Test predicate modifying array prototype +// +(function() { + const a = [0, , 2]; + const received = []; + const predicate = (v) => { + a.__proto__ = null; + received.push(v); + return false; + }; + const found = Array.prototype.findIndex.call(a, predicate); + assertEquals(-1, found); + assertArrayEquals([0, undefined, 2], received); +})(); + + +// // Test thisArg // (function() { diff --git a/deps/v8/test/mjsunit/es6/array-iterator-turbo.js b/deps/v8/test/mjsunit/es6/array-iterator-turbo.js index 3a159b6337..489a53dbc7 100644 --- a/deps/v8/test/mjsunit/es6/array-iterator-turbo.js +++ b/deps/v8/test/mjsunit/es6/array-iterator-turbo.js @@ -3,7 +3,7 @@ // found in the LICENSE file. // Flags: --turbo-escape --allow-natives-syntax --no-always-opt -// Flags: --opt --turbo-filter=* +// Flags: --opt --turbo-filter=* --no-force-slow-path "use strict"; diff --git a/deps/v8/test/mjsunit/es6/call-with-spread-modify-next.js b/deps/v8/test/mjsunit/es6/call-with-spread-modify-next.js index d22a1eaec0..3cae94ff9d 100644 --- a/deps/v8/test/mjsunit/es6/call-with-spread-modify-next.js +++ b/deps/v8/test/mjsunit/es6/call-with-spread-modify-next.js @@ -37,6 +37,8 @@ var r2 = testMax(1, 2); - assertEquals(3, called); + // .next() is only loaded once during the iteration prologue (see + // https://github.com/tc39/ecma262/pull/988/ and v8:6861) + assertEquals(1, called); assertEquals(2, r2); })(); diff --git a/deps/v8/test/mjsunit/es6/computed-property-names-object-literals-methods.js b/deps/v8/test/mjsunit/es6/computed-property-names-object-literals-methods.js index 36afbe2ced..24a357258a 100644 --- a/deps/v8/test/mjsunit/es6/computed-property-names-object-literals-methods.js +++ b/deps/v8/test/mjsunit/es6/computed-property-names-object-literals-methods.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration - function ID(x) { return x; } diff --git a/deps/v8/test/mjsunit/es6/destructuring-assignment.js b/deps/v8/test/mjsunit/es6/destructuring-assignment.js index 579c87718b..dee7a0b16d 100644 --- a/deps/v8/test/mjsunit/es6/destructuring-assignment.js +++ b/deps/v8/test/mjsunit/es6/destructuring-assignment.js @@ -513,25 +513,31 @@ assertEquals(oz, [1, 2, 3, 4, 5]); } function FakeNewTarget() {} - assertEquals(undefined, ReturnNewTarget1()); - assertEquals(ReturnNewTarget1, new ReturnNewTarget1()); - assertEquals(FakeNewTarget, - Reflect.construct(ReturnNewTarget1, [], FakeNewTarget)); - - assertEquals(undefined, ReturnNewTarget2()); - assertEquals(ReturnNewTarget2, new ReturnNewTarget2()); - assertEquals(FakeNewTarget, - Reflect.construct(ReturnNewTarget2, [], FakeNewTarget)); - - assertEquals(undefined, ReturnNewTarget3()); - assertEquals(ReturnNewTarget3, new ReturnNewTarget3()); - assertEquals(FakeNewTarget, - Reflect.construct(ReturnNewTarget3, [], FakeNewTarget)); - - assertEquals(undefined, ReturnNewTarget4()); - assertEquals(ReturnNewTarget4, new ReturnNewTarget4()); - assertEquals(FakeNewTarget, - Reflect.construct(ReturnNewTarget4, [], FakeNewTarget)); + + function construct() { + assertEquals(undefined, ReturnNewTarget1()); + assertEquals(ReturnNewTarget1, new ReturnNewTarget1()); + assertEquals(FakeNewTarget, + Reflect.construct(ReturnNewTarget1, [], FakeNewTarget)); + + assertEquals(undefined, ReturnNewTarget2()); + assertEquals(ReturnNewTarget2, new ReturnNewTarget2()); + assertEquals(FakeNewTarget, + Reflect.construct(ReturnNewTarget2, [], FakeNewTarget)); + + assertEquals(undefined, ReturnNewTarget3()); + assertEquals(ReturnNewTarget3, new ReturnNewTarget3()); + assertEquals(FakeNewTarget, + Reflect.construct(ReturnNewTarget3, [], FakeNewTarget)); + + assertEquals(undefined, ReturnNewTarget4()); + assertEquals(ReturnNewTarget4, new ReturnNewTarget4()); + assertEquals(FakeNewTarget, + Reflect.construct(ReturnNewTarget4, [], FakeNewTarget)); + } + construct(); + FakeNewTarget.prototype = 1; + construct(); })(); (function testSuperCall() { diff --git a/deps/v8/test/mjsunit/es6/iteration-semantics.js b/deps/v8/test/mjsunit/es6/iteration-semantics.js index 558fb837e7..40037be6f5 100644 --- a/deps/v8/test/mjsunit/es6/iteration-semantics.js +++ b/deps/v8/test/mjsunit/es6/iteration-semantics.js @@ -220,13 +220,11 @@ assertThrows('fold(sum, 0, unreachable({}))', TypeError); assertThrows('fold(sum, 0, unreachable(false))', TypeError); assertThrows('fold(sum, 0, unreachable(37))', TypeError); -// "next" is looked up each time. -assertThrows('fold(sum, 0, remove_next_after(integers_until(10), 5))', - TypeError); -// It is not called at any other time. +// "next" is looked up only once during the iteration prologue (see +// https://github.com/tc39/ecma262/pull/988) +assertEquals(45, fold(sum, 0, remove_next_after(integers_until(10), 5))); assertEquals(45, fold(sum, 0, remove_next_after(integers_until(10), 10))); -// It is not looked up too many times. assertEquals(45, fold(sum, 0, poison_next_after(integers_until(10), 10))); diff --git a/deps/v8/test/mjsunit/es6/reflect-construct.js b/deps/v8/test/mjsunit/es6/reflect-construct.js index 03e8397a9b..34b6f27373 100644 --- a/deps/v8/test/mjsunit/es6/reflect-construct.js +++ b/deps/v8/test/mjsunit/es6/reflect-construct.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Flags: --allow-unsafe-function-constructor --harmony-async-iteration +// Flags: --allow-unsafe-function-constructor (function testReflectConstructArity() { diff --git a/deps/v8/test/mjsunit/es6/spread-call.js b/deps/v8/test/mjsunit/es6/spread-call.js index cdedd990c8..7403e0726e 100644 --- a/deps/v8/test/mjsunit/es6/spread-call.js +++ b/deps/v8/test/mjsunit/es6/spread-call.js @@ -376,6 +376,11 @@ testSpreadCallsStrict(); a[3] = 4; var called = 0; + // .next method is only accessed during iteration prologue (see + // https://github.com/tc39/ecma262/pull/988) + let ArrayIteratorPrototype = Array.prototype[Symbol.iterator]().__proto__; + let ArrayIteratorPrototypeNextDescriptor = + Object.getOwnPropertyDescriptor(ArrayIteratorPrototype, 'next'); Object.defineProperty(Array.prototype, 2, { get: function() { var ai = a[Symbol.iterator](); @@ -384,7 +389,8 @@ testSpreadCallsStrict(); get: function() { called++; return original_next; - } + }, + configurable: true }); return 3; }, @@ -392,8 +398,10 @@ testSpreadCallsStrict(); }); assertEquals(10, sum(...a)); - assertEquals(2, called); + assertEquals(0, called); + Object.defineProperty(ArrayIteratorPrototype, 'next', + ArrayIteratorPrototypeNextDescriptor); Object.defineProperty(Array.prototype, 2, {}); })(); @@ -430,9 +438,9 @@ testSpreadCallsStrict(); countArgs(...a); - // should be called 4 times; 3 for the values, 1 for the final - // {value: undefined, done: true} pair - assertEquals(4, called); + // .next method is only accessed during iteration prologue (see + // https://github.com/tc39/ecma262/pull/988) + assertEquals(1, called); })(); (function testArrayIteratorPrototypeModified() { diff --git a/deps/v8/test/mjsunit/es6/super-with-spread-modify-next.js b/deps/v8/test/mjsunit/es6/super-with-spread-modify-next.js index 299917dbf1..cd7798b8d1 100644 --- a/deps/v8/test/mjsunit/es6/super-with-spread-modify-next.js +++ b/deps/v8/test/mjsunit/es6/super-with-spread-modify-next.js @@ -48,7 +48,9 @@ var r2 = testArgumentsPoint(1, 2); - assertEquals(3, called); + // .next() is only loaded once during the iteration prologue (see + // https://github.com/tc39/ecma262/pull/988/ and v8:6861) + assertEquals(1, called); assertInstanceof(r2, ArgumentsPoint); assertInstanceof(r2, Point); assertEquals(r2.x, 1); diff --git a/deps/v8/test/mjsunit/es6/typedarray.js b/deps/v8/test/mjsunit/es6/typedarray.js index 93d92097cd..02bd91c1e5 100644 --- a/deps/v8/test/mjsunit/es6/typedarray.js +++ b/deps/v8/test/mjsunit/es6/typedarray.js @@ -341,16 +341,30 @@ function TestTypedArray(constr, elementSize, typicalElement) { // Modified %ArrayIteratorPrototype%.next() method is honoured (v8:5699) const ArrayIteratorPrototype = Object.getPrototypeOf([][Symbol.iterator]()); + const ArrayIteratorPrototypeNextDescriptor = + Object.getOwnPropertyDescriptor(ArrayIteratorPrototype, 'next'); const ArrayIteratorPrototypeNext = ArrayIteratorPrototype.next; ArrayIteratorPrototype.next = function() { return { done: true }; }; genArr = new constr([1, 2, 3]); assertEquals(0, genArr.length); + ArrayIteratorPrototype.next = ArrayIteratorPrototypeNext; - // Modified %ArrayIteratorPrototype%.next() during iteration is honoured as - // well. + // Modified %ArrayIteratorPrototype%.next() is only loaded during the iterator + // prologue. + let nextMethod = ArrayIteratorPrototypeNext; + let getNextCount = 0; + Object.defineProperty(ArrayIteratorPrototype, 'next', { + get() { + getNextCount++; + return nextMethod; + }, + set(v) { nextMethod = v; }, + configurable: true + }); + genArr = new constr(Object.defineProperty([1, , 3], 1, { get() { ArrayIteratorPrototype.next = function() { @@ -359,9 +373,13 @@ function TestTypedArray(constr, elementSize, typicalElement) { return 2; } })); - assertEquals(2, genArr.length); + Object.defineProperty(ArrayIteratorPrototype, 'next', + ArrayIteratorPrototypeNextDescriptor); + assertEquals(1, getNextCount); + assertEquals(3, genArr.length); assertEquals(1, genArr[0]); assertEquals(2, genArr[1]); + assertEquals(3, genArr[2]); ArrayIteratorPrototype.next = ArrayIteratorPrototypeNext; } diff --git a/deps/v8/test/mjsunit/es8/object-entries.js b/deps/v8/test/mjsunit/es8/object-entries.js index c59d81c823..5c7e74e378 100644 --- a/deps/v8/test/mjsunit/es8/object-entries.js +++ b/deps/v8/test/mjsunit/es8/object-entries.js @@ -284,8 +284,8 @@ TestMutateDuringEnumeration(); HOLEY_DOUBLE_ELEMENTS: [ [, , NaN], [ ["2", NaN] ] ], DICTIONARY_ELEMENTS: [ Object.defineProperties({ 10000: "world" }, { - 100: { enumerable: true, value: "hello" }, - 99: { enumerable: false, value: "nope" } + 100: { enumerable: true, value: "hello", configurable: true}, + 99: { enumerable: false, value: "nope", configurable: true} }), [ ["100", "hello"], ["10000", "world" ] ] ], FAST_SLOPPY_ARGUMENTS_ELEMENTS: [ fastSloppyArguments("a", "b", "c"), @@ -298,17 +298,42 @@ TestMutateDuringEnumeration(); [ ["0", "s"], ["1", "t"], ["2", "r"]] ], SLOW_STRING_WRAPPER_ELEMENTS: [ Object.defineProperties(new String("str"), { - 10000: { enumerable: false, value: "X" }, - 9999: { enumerable: true, value: "Y" } + 10000: { enumerable: false, value: "X", configurable: true}, + 9999: { enumerable: true, value: "Y", configurable: true} }), [["0", "s"], ["1", "t"], ["2", "r"], ["9999", "Y"]] ], }; for (let [kind, [object, expected]] of Object.entries(element_kinds)) { let result1 = Object.entries(object); + %HeapObjectVerify(object); + %HeapObjectVerify(result1); assertEquals(expected, result1, `fast Object.entries() with ${kind}`); let proxy = new Proxy(object, {}); let result2 = Object.entries(proxy); + %HeapObjectVerify(result2); assertEquals(result1, result2, `slow Object.entries() with ${kind}`); } + + function makeFastElements(array) { + // Remove all possible getters. + for (let k of Object.getOwnPropertyNames(this)) { + if (k == "length") continue; + delete this[k]; + } + // Make the array large enough to trigger re-checking for compaction. + this[1000] = 1; + // Make the elements fast again. + Array.prototype.unshift.call(this, 1.1); + } + + // Test that changing the elements kind is supported. + for (let [kind, [object, expected]] of Object.entries(element_kinds)) { + if (kind == "FAST_STRING_WRAPPER_ELEMENTS") break; + object.__defineGetter__(1, makeFastElements); + let result1 = Object.entries(object).toString(); + %HeapObjectVerify(object); + %HeapObjectVerify(result1); + } + })(); diff --git a/deps/v8/test/mjsunit/es8/regress/regress-794744.js b/deps/v8/test/mjsunit/es8/regress/regress-794744.js new file mode 100644 index 0000000000..a4dcb5d42a --- /dev/null +++ b/deps/v8/test/mjsunit/es8/regress/regress-794744.js @@ -0,0 +1,8 @@ +// Copyright 2017 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. + +// Object.getOwnPropertyDescriptors loads %FunctionPrototype%.caller, an +// accessor property which inspects the current callstack. Verify that this +// callstack iteration doesn't crash when there are no JS frames on the stack. +Promise.resolve(function () {}).then(Object.getOwnPropertyDescriptors); diff --git a/deps/v8/test/mjsunit/global-prototypes.js b/deps/v8/test/mjsunit/global-prototypes.js new file mode 100644 index 0000000000..98232c2814 --- /dev/null +++ b/deps/v8/test/mjsunit/global-prototypes.js @@ -0,0 +1,354 @@ +// Copyright 2017 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 + + +assertEquals(this.__proto__, Object.prototype); + +function TestAddingPropertyToGlobalPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + delete this.func; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a Global-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + Bar.prototype.func = function() { ++bar_func_called; } + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToGlobalPrototype(); + + +// Same as TestAddingPropertyToGlobalPrototype, but using o["foo"] access +// instead of o.foo. +function TestAddingPropertyToGlobalPrototype2() { + let foo_func_called = 0; + let bar_func_called = 0; + let name = "func"; + + function Foo() {} + Foo.prototype[name] = function() { ++foo_func_called; } + + delete this[name]; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o[name](); + + // Add the property to Bar which is a Global-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + Bar.prototype[name] = function() { ++bar_func_called; } + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToGlobalPrototype2(); + + +function TestAddingPropertyToGlobalPrototype_DefineProperty() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + delete this.func; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a Global-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + Object.defineProperty(Bar.prototype, "func", + { + value: function() { ++bar_func_called; }, + configurable:true + }); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToGlobalPrototype_DefineProperty(); + + +function TestAddingAccessorPropertyToGlobalPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + delete this.func; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a Global-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + Object.defineProperty(Bar.prototype, "func", + { + get: function() { return function() { ++bar_func_called; }}, + configurable: true + }); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingAccessorPropertyToGlobalPrototype(); + + +function TestRemovingPropertyFromGlobalPrototype() { + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + delete this.func; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + Bar.prototype.func = function() { ++bar_func_called; } + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Bar. + o.func(); + + // Remove the property from Bar which is a Global-mode prototype between + // o and Foo. In the next iteration, it's looked up from Foo. + if (i == 9) { + delete Bar.prototype.func; + } + } + + assertEquals(1, foo_func_called); + assertEquals(10, bar_func_called); +} + +TestRemovingPropertyFromGlobalPrototype(); + + +// Same as TestRemovingPropertyFromGlobalPrototype, but using o["foo"] access +// instead of o.foo. +function TestRemovingPropertyFromGlobalPrototype2() { + let foo_func_called = 0; + let bar_func_called = 0; + let name = "func"; + + function Foo() {} + Foo.prototype[name] = function() { ++foo_func_called; } + + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + Bar.prototype[name] = function() { ++bar_func_called; } + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Bar. + o[name](); + + // Remove the property from Bar which is a Global-mode prototype between + // o and Foo. In the next iteration, it's looked up from Foo. + if (i == 9) { + delete Bar.prototype[name]; + } + } + + assertEquals(1, foo_func_called); + assertEquals(10, bar_func_called); +} + +TestRemovingPropertyFromGlobalPrototype2(); + + +function TestAddingPropertyToGlobalPrototype_MonomorphicDot() { + function DoMonomorphicStoreToPrototypeDot(p, f, do_delete=true) { + p.func = f; + if (do_delete) { + delete p.func; + } + } + let foo_func_called = 0; + let bar_func_called = 0; + + function Foo() {} + Foo.prototype.func = function() { ++foo_func_called; } + + delete this.func; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + + function bar_func() { + ++bar_func_called; + } + DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func); + DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func); + DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a Global-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func, false); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToGlobalPrototype_MonomorphicDot(); + + +function TestAddingPropertyToGlobalPrototype_MonomorphicBrackets() { + function DoMonomorphicStoreToPrototypeBrackets(p, name, f, do_delete=true) { + p[name] = f; + if (do_delete) { + delete p[name]; + } + } + let foo_func_called = 0; + let bar_func_called = 0; + let name = "func"; + + function Foo() {} + Foo.prototype[name] = function() { ++foo_func_called; } + + delete this[name]; + this.__proto__ = Foo.prototype; + + function Bar() {} + Bar.prototype = this; + + function bar_func() { + ++bar_func_called; + } + DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func); + DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func); + DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func); + + let o = new Bar(); + + for (let i = 0; i < 11; ++i) { + // First, the property is looked up from Foo. + o.func(); + + // Add the property to Bar which is a Global-mode prototype between o + // and Foo. In the next iteration, it's looked up from Bar. + if (i == 9) { + DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func, false); + } + } + + assertEquals(10, foo_func_called); + assertEquals(1, bar_func_called); +} + +TestAddingPropertyToGlobalPrototype_MonomorphicBrackets(); + + +function TestReconfiguringDataToAccessor() { + let setter_called = 0; + let name = "prop"; + + delete this[name]; + this.__proto__ = Object.prototype; + + function Bar() {} + Bar.prototype = this; + + Object.defineProperty(Bar.prototype, name, {value: 1000, writable: true, configurable: true}); + + for (let i = 0; i < 11; ++i) { + let obj1 = new Bar(); + if (i < 10) { + assertEquals(1000, obj1.prop); + } else { + assertEquals(3000, obj1.prop); + } + + // Add the property into the object. + obj1.prop = 2000; + if (i < 10) { + assertEquals(2000, obj1.prop); + } else { + assertEquals(3000, obj1.prop); + } + + // Make "prop" an accessor property in the prototype. + if (i == 9) { + Object.defineProperty(Bar.prototype, name, + {get: () => 3000, + set: function(val) { ++setter_called; }}); + } + } + assertEquals(1, setter_called); +} + +TestReconfiguringDataToAccessor(); diff --git a/deps/v8/test/mjsunit/harmony/async-for-of-non-iterable.js b/deps/v8/test/mjsunit/harmony/async-for-of-non-iterable.js index c84c9c6884..3394ed394c 100644 --- a/deps/v8/test/mjsunit/harmony/async-for-of-non-iterable.js +++ b/deps/v8/test/mjsunit/harmony/async-for-of-non-iterable.js @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration var done = false; async function f() { diff --git a/deps/v8/test/mjsunit/harmony/async-from-sync-iterator.js b/deps/v8/test/mjsunit/harmony/async-from-sync-iterator.js index d965bd070c..a7b0d1bda4 100644 --- a/deps/v8/test/mjsunit/harmony/async-from-sync-iterator.js +++ b/deps/v8/test/mjsunit/harmony/async-from-sync-iterator.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration --allow-natives-syntax +// Flags: --allow-natives-syntax let testFailed = false; let testFailure; diff --git a/deps/v8/test/mjsunit/harmony/async-generators-basic.js b/deps/v8/test/mjsunit/harmony/async-generators-basic.js index 29441b119b..d7af1836b8 100644 --- a/deps/v8/test/mjsunit/harmony/async-generators-basic.js +++ b/deps/v8/test/mjsunit/harmony/async-generators-basic.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration --allow-natives-syntax +// Flags: --allow-natives-syntax function assertThrowsAsync(run, errorType, message) { var actual; diff --git a/deps/v8/test/mjsunit/harmony/async-generators-resume-return.js b/deps/v8/test/mjsunit/harmony/async-generators-resume-return.js index 7a7efe7801..715c81fc21 100644 --- a/deps/v8/test/mjsunit/harmony/async-generators-resume-return.js +++ b/deps/v8/test/mjsunit/harmony/async-generators-resume-return.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration --allow-natives-syntax +// Flags: --allow-natives-syntax // .return() from state suspendedStart with undefined testAsync(test => { diff --git a/deps/v8/test/mjsunit/harmony/async-generators-return.js b/deps/v8/test/mjsunit/harmony/async-generators-return.js index b0c7febf8c..27cbd4373b 100644 --- a/deps/v8/test/mjsunit/harmony/async-generators-return.js +++ b/deps/v8/test/mjsunit/harmony/async-generators-return.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration --allow-natives-syntax +// Flags: --allow-natives-syntax testAsync(test => { test.plan(2); diff --git a/deps/v8/test/mjsunit/harmony/async-generators-yield.js b/deps/v8/test/mjsunit/harmony/async-generators-yield.js index c999c7006f..feb6339af2 100644 --- a/deps/v8/test/mjsunit/harmony/async-generators-yield.js +++ b/deps/v8/test/mjsunit/harmony/async-generators-yield.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration --allow-natives-syntax +// Flags: --allow-natives-syntax // Yield a thenable which is never settled testAsync(test => { diff --git a/deps/v8/test/mjsunit/harmony/bigint/as-int-n.js b/deps/v8/test/mjsunit/harmony/bigint/as-int-n.js index 08c94245fd..faa7dba866 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/as-int-n.js +++ b/deps/v8/test/mjsunit/harmony/bigint/as-int-n.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-bigint --noopt +// Flags: --harmony-bigint // BigInt.asIntN { @@ -145,6 +145,8 @@ }{ assertThrows(() => BigInt.asIntN(3, 12), TypeError); assertEquals(-4n, BigInt.asIntN(3, "12")); + assertEquals(0x123456789abcdefn, + BigInt.asIntN(64, 0xabcdef0123456789abcdefn)); } // BigInt.asUintN @@ -244,10 +246,9 @@ assertEquals(9223372036854775808n - 42n, BigInt.asUintN(63, -42n)); assertEquals(18446744073709551616n - 42n, BigInt.asUintN(64, -42n)); assertEquals(36893488147419103232n - 42n, BigInt.asUintN(65, -42n)); - // TODO(neis): Enable once we have exponentation. - // assertEquals(2n**127n - 42n, BigInt.asUintN(127, -42n)); - // assertEquals(2n**128n - 42n, BigInt.asUintN(128, -42n)); - // assertEquals(2n**129n - 42n, BigInt.asUintN(129, -42n)); + assertEquals(2n**127n - 42n, BigInt.asUintN(127, -42n)); + assertEquals(2n**128n - 42n, BigInt.asUintN(128, -42n)); + assertEquals(2n**129n - 42n, BigInt.asUintN(129, -42n)); }{ assertEquals(0n, BigInt.asUintN(0, 4294967295n)); assertEquals(1n, BigInt.asUintN(1, 4294967295n)); @@ -274,10 +275,9 @@ BigInt.asUintN(64,-4294967295n)); assertEquals(36893488147419103232n - 4294967295n, BigInt.asUintN(65, -4294967295n)); - // TODO(neis): Enable once we have exponentation. - // assertEquals(2n**127n - 42n, BigInt.asUintN(127, -4294967295n)); - // assertEquals(2n**128n - 42n, BigInt.asUintN(128, -4294967295n)); - // assertEquals(2n**129n - 42n, BigInt.asUintN(129, -4294967295n)); + assertEquals(2n**127n - 4294967295n, BigInt.asUintN(127, -4294967295n)); + assertEquals(2n**128n - 4294967295n, BigInt.asUintN(128, -4294967295n)); + assertEquals(2n**129n - 4294967295n, BigInt.asUintN(129, -4294967295n)); }{ assertEquals(42n, BigInt.asUintN(2**32, 42n)); assertEquals(4294967295n, BigInt.asUintN(2**32, 4294967295n)); diff --git a/deps/v8/test/mjsunit/harmony/bigint/basics.js b/deps/v8/test/mjsunit/harmony/bigint/basics.js index 5ea89009a3..398d670ca8 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/basics.js +++ b/deps/v8/test/mjsunit/harmony/bigint/basics.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --harmony-bigint --no-opt +// Flags: --allow-natives-syntax --harmony-bigint 'use strict' @@ -105,14 +105,6 @@ const six = BigInt(6); assertTrue(typeof 1n === "bigint"); assertFalse(typeof 1n === "BigInt"); assertFalse(typeof 1 === "bigint"); -}{ - // TODO(neis): Enable once --no-opt can be removed. - // - // function Typeof(x) { return typeof x } - // assertEquals(Typeof(zero), "bigint"); - // assertEquals(Typeof(zero), "bigint"); - // %OptimizeFunctionOnNextCall(Typeof); - // assertEquals(Typeof(zero), "bigint"); } // ToString diff --git a/deps/v8/test/mjsunit/harmony/bigint/comparisons.js b/deps/v8/test/mjsunit/harmony/bigint/comparisons.js index 7be5eb7ee5..513ff37d00 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/comparisons.js +++ b/deps/v8/test/mjsunit/harmony/bigint/comparisons.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --harmony-bigint --no-opt +// Flags: --allow-natives-syntax --harmony-bigint 'use strict' diff --git a/deps/v8/test/mjsunit/harmony/bigint/dec.js b/deps/v8/test/mjsunit/harmony/bigint/dec.js index cdf1d96d60..5e1f40b2dd 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/dec.js +++ b/deps/v8/test/mjsunit/harmony/bigint/dec.js @@ -6,9 +6,6 @@ // Flags: --harmony-bigint -// TODO(adamk/jkummerow/neis): Support BigInts in TF unary ops. -// Flags: --noopt - var data = [{ a: "-609648ccf253976b12f6b6c8e20790c17ef6b89ea9f536267783607cf465b1ca", r: "-609648ccf253976b12f6b6c8e20790c17ef6b89ea9f536267783607cf465b1cb" diff --git a/deps/v8/test/mjsunit/harmony/bigint/exp.js b/deps/v8/test/mjsunit/harmony/bigint/exp.js new file mode 100644 index 0000000000..5a4601134f --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/bigint/exp.js @@ -0,0 +1,43 @@ +// Copyright 2017 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 --harmony-bigint + +assertEquals(1n, 0n ** 0n); +assertEquals(0n, 0n ** 1n); +assertEquals(0n, 0n ** 23n); + +assertEquals(1n, 1n ** 0n); +assertEquals(1n, 1n ** 1n); +assertEquals(1n, 99n ** 0n); + +assertEquals(2n, 2n ** 1n); +assertEquals(4n, 2n ** 2n); +assertEquals(8n, 2n ** 3n); +assertEquals(16n, 2n ** 4n); +assertEquals(151115727451828646838272n, 2n ** 77n); + +assertEquals(3n, 3n ** 1n); +assertEquals(9n, 3n ** 2n); +assertEquals(27n, 3n ** 3n); +assertEquals(81n, 3n ** 4n); +assertEquals(243n, 3n ** 5n); +assertEquals(30903154382632612361920641803529n, 3n ** 66n); + +assertEquals(1n, (-2n) ** 0n); +assertEquals(-2n, (-2n) ** 1n); +assertEquals(4n, (-2n) ** 2n); +assertEquals(-8n, (-2n) ** 3n); +assertEquals(16n, (-2n) ** 4n); +assertEquals(-32n, (-2n) ** 5n); + +assertEquals(1n, (-3n) ** 0n); +assertEquals(-3n, (-3n) ** 1n); +assertEquals(9n, (-3n) ** 2n); +assertEquals(-27n, (-3n) ** 3n); +assertEquals(81n, (-3n) ** 4n); +assertEquals(-243n, (-3n) ** 5n); + +assertThrows(() => 3n ** -2n, RangeError); // Negative exponent. +assertThrows(() => 2n ** (1024n ** 4n), RangeError); // Too big. diff --git a/deps/v8/test/mjsunit/harmony/bigint/inc.js b/deps/v8/test/mjsunit/harmony/bigint/inc.js index 2773ed9110..64865a2b32 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/inc.js +++ b/deps/v8/test/mjsunit/harmony/bigint/inc.js @@ -6,9 +6,6 @@ // Flags: --harmony-bigint -// TODO(adamk/jkummerow/neis): Support BigInts in TF unary ops. -// Flags: --noopt - var data = [{ a: "-989c298c6fc3", r: "-989c298c6fc2" diff --git a/deps/v8/test/mjsunit/harmony/bigint/json.js b/deps/v8/test/mjsunit/harmony/bigint/json.js index 10afdfce02..eb0eefc4bb 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/json.js +++ b/deps/v8/test/mjsunit/harmony/bigint/json.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --harmony-bigint --no-opt +// Flags: --allow-natives-syntax --harmony-bigint 'use strict' diff --git a/deps/v8/test/mjsunit/harmony/bigint/neg.js b/deps/v8/test/mjsunit/harmony/bigint/neg.js index 75548f62c3..8cec9cc21b 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/neg.js +++ b/deps/v8/test/mjsunit/harmony/bigint/neg.js @@ -6,9 +6,6 @@ // Flags: --harmony-bigint -// TODO(adamk/jkummerow/neis): Support BigInts in TF unary ops. -// Flags: --noopt - var data = [{ a: "58ad59aa3aa9d04d4c12493966e204ef0500d5f92ecb31", r: "-58ad59aa3aa9d04d4c12493966e204ef0500d5f92ecb31" diff --git a/deps/v8/test/mjsunit/harmony/bigint/not.js b/deps/v8/test/mjsunit/harmony/bigint/not.js index fe23c8f965..7ceaa01e63 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/not.js +++ b/deps/v8/test/mjsunit/harmony/bigint/not.js @@ -6,9 +6,6 @@ // Flags: --harmony-bigint -// TODO(adamk/jkummerow/neis): Support BigInts in TF unary ops. -// Flags: --noopt - var data = [{ a: "3d02c87edc77722299f6559ecca038911f864a4e78c20af80f4a6d9", r: "-3d02c87edc77722299f6559ecca038911f864a4e78c20af80f4a6da" diff --git a/deps/v8/test/mjsunit/harmony/bigint/regressions.js b/deps/v8/test/mjsunit/harmony/bigint/regressions.js index 45c8816fe7..3057fe1230 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/regressions.js +++ b/deps/v8/test/mjsunit/harmony/bigint/regressions.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-bigint --noopt +// Flags: --harmony-bigint var a = 5n; var b = a / -1n; @@ -16,3 +16,5 @@ assertEquals(0n, 5n % 1n); assertEquals(0n, -5n % 1n); assertEquals(0n, 5n % -1n); assertEquals(0n, -5n % -1n); + +assertTrue(0n === 0n); diff --git a/deps/v8/test/mjsunit/harmony/bigint/tonumber.js b/deps/v8/test/mjsunit/harmony/bigint/tonumber.js index 0061d91d67..d2802a79be 100644 --- a/deps/v8/test/mjsunit/harmony/bigint/tonumber.js +++ b/deps/v8/test/mjsunit/harmony/bigint/tonumber.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-bigint --no-opt +// Flags: --harmony-bigint function Check(bigint, number_string) { var number = Number(number_string); diff --git a/deps/v8/test/mjsunit/harmony/bigint/too-big-literal.js b/deps/v8/test/mjsunit/harmony/bigint/too-big-literal.js deleted file mode 100644 index 242700191a..0000000000 --- a/deps/v8/test/mjsunit/harmony/bigint/too-big-literal.js +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 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: --harmony-bigint --no-opt - -const MAX_BIGINT_BITS = 1024 * 1024; // Matches BigInt::kMaxLengthBits -const MAX_BIGINT_CHARS = MAX_BIGINT_BITS / 4; - -const TOO_MANY_ONES = Array(MAX_BIGINT_CHARS + 2).join("1") + "n"; - -const tooBigHex = "0x" + TOO_MANY_ONES; - -assertThrows(tooBigHex, SyntaxError); diff --git a/deps/v8/test/mjsunit/harmony/bigint/turbo.js b/deps/v8/test/mjsunit/harmony/bigint/turbo.js new file mode 100644 index 0000000000..87130ea101 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/bigint/turbo.js @@ -0,0 +1,193 @@ +// Copyright 2017 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 --harmony-bigint + +'use strict' + + +function test(f, {input, check}) { + let result; + try { + result = { value: f(input), exception: false } + } catch(e) { + result = { value: e, exception: true } + } + check(result); +} + +function Test(f, ...cases) { + for (let i = 0; i < cases.length; ++i) { + test(f, cases[i]); + %OptimizeFunctionOnNextCall(f); + for (let j = 0; j < cases.length; ++j) { + test(f, cases[j]); + } + %DeoptimizeFunction(f); + } +} + + +function V(input, expected_value) { + function check(result) { + assertFalse(result.exception, input); + assertEquals(expected_value, result.value); + } + return {input, check}; +} + +function E(input, expected_exception) { + function check(result) { + assertTrue(result.exception, input); + assertInstanceof(result.value, expected_exception); + } + return {input, check}; +} + + +const six = {[Symbol.toPrimitive]() {return 6n}}; + + +//////////////////////////////////////////////////////////////////////////////// +// The first argument to {Test} is the function to test. The other arguments are +// the test cases, basically pairs of input and expected output. {Test} runs the +// function first unoptimized on one of the inputs, and then optimized on all +// inputs. +//////////////////////////////////////////////////////////////////////////////// + + +Test(x => Number(x), + V(1n, 1), V(1, 1), V("", 0), V(1.4, 1.4), V(null, 0), V(six, 6)); + +Test(x => String(x), + V(1n, "1"), V(1, "1"), V(1.4, "1.4"), V(null, "null"), V(six, "6")); + +Test(x => BigInt(x), + V(true, 1n), V(false, 0n), V(42n, 42n), E(NaN, RangeError), V(six, 6n)); + +Test(x => typeof x, + V(1n, "bigint"), V(1, "number"), V(six, "object")); +Test(x => typeof x == "bigint", + V(1n, true), V(1, false), V(six, false)); + +Test(x => !x, + V(0n, true), V(42n, false), V(0x10000000000000000n, false), V(1, false), + V(undefined, true), V(six, false)); +Test(x => !!x, + V(0n, false), V(42n, true), V(0x10000000000000000n, true), V(1, true), + V(undefined, false), V(six, true)); + +Test(x => +x, + E(-3n, TypeError), V(-4, -4), V(1.4, 1.4), V(null, 0), V("5", 5), + E(six, TypeError)); + +Test(x => -x, + V(-3n, 3n), V(-4, 4), V(1.4, -1.4), V(null, -0), V("5", -5), V(six, -6n)); + +Test(x => ~x, + V(-3n, 2n), V(-4, 3), V(1.5, -2), V(null, -1), V("5", -6), V(six, -7n)); + +Test(x => ++x, + V(-3n, -2n), V(-4, -3), V(1.5, 2.5), V(null, 1), V("5", 6), V(six, 7n)); + +Test(x => --x, + V(-3n, -4n), V(-4, -5), V(1.5, 0.5), V(null, -1), V("5", 4), V(six, 5n)); + +Test(x => x++, + V(-3n, -3n), V(-4, -4), V(1.5, 1.5), V(null, 0), V("5", 5), V(six, 6n)); + +Test(x => x--, + V(-3n, -3n), V(-4, -4), V(1.5, 1.5), V(null, 0), V("5", 5), V(six, 6n)); + +Test(x => x + 42, + E(1n, TypeError), V(2, 44), V(null, 42), V("a", "a42"), E(six, TypeError)); +Test(x => x + 42n, + V(1n, 43n), E(2, TypeError), E(null, TypeError), V("a", "a42"), V(six,48n)); + +Test(x => x - 4, + E(1n, TypeError), V(3, -1), V(null, -4), V("a", NaN), E(six, TypeError)); +Test(x => x - 4n, + V(1n, -3n), E(3, TypeError), E(null, TypeError), E("a", TypeError), + V(six, 2n)); + +Test(x => x * 42, + E(2n, TypeError), V(3, 126), V("a", NaN), V(null, 0), E(six, TypeError)); +Test(x => x * 42n, + V(2n, 84n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 252n)); + +Test(x => x / 2, + E(2n, TypeError), V(6, 3), V("a", NaN), V(null, 0), E(six, TypeError)); +Test(x => x / 2n, + V(2n, 1n), E(6, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 3n)); + +Test(x => x % 2, + E(2n, TypeError), V(3, 1), V("a", NaN), V(null, 0), E(six, TypeError)); +Test(x => x % 2n, + V(2n, 0n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 0n)); + +Test(x => x | 5, + E(2n, TypeError), V(3, 7), V("a", 5), V(null, 5), E(six, TypeError)); +Test(x => x | 5n, + V(2n, 7n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 7n)); + +Test(x => x & 5, + E(2n, TypeError), V(3, 1), V("a", 0), V(null, 0), E(six, TypeError)); +Test(x => x & 5n, + V(2n, 0n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 4n)); + +Test(x => x ^ 5, + E(2n, TypeError), V(3, 6), V("a", 5), V(null, 5), E(six, TypeError)); +Test(x => x ^ 5n, + V(2n, 7n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 3n)); + +Test(x => x << 3, + E(2n, TypeError), V(3, 24), V("a", 0), V(null, 0), E(six, TypeError)); +Test(x => x << 3n, + V(2n, 16n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 48n)); + +Test(x => x >> 1, + E(2n, TypeError), V(3, 1), V("a", 0), V(null, 0), E(six, TypeError)); +Test(x => x >> 1n, + V(2n, 1n), E(3, TypeError), E("a", TypeError), E(null, TypeError), + V(six, 3n)); + +Test(x => x >>> 1, + E(2n, TypeError), V(3, 1), V("a", 0), V(null, 0), E(six, TypeError)); +Test(x => x >>> 1n, + E(2n, TypeError), E(3, TypeError), E("a", TypeError), E(null, TypeError), + E(six, TypeError)); + +Test(x => x === 42, + V(1n, false), V(2, false), V(null, false), V("a", false), V(six, false)); +Test(x => x === 42, + V(42n, false), V(42, true), V(null, false), V("42", false), V(six, false)); +Test(x => x === 42n, + V(1n, false), V(2, false), V(null, false), V("a", false), V(six, false)); +Test(x => x === 42n, + V(42n, true), V(42, false), V(null, false), V("42", false), V(six, false)); + +Test(x => x == 42, + V(1n, false), V(2, false), V(null, false), V("a", false), V(six, false)); +Test(x => x == 42, + V(42n, true), V(42, true), V(null, false), V("42", true), V(six, false)); +Test(x => x == 42n, + V(1n, false), V(2, false), V(null, false), V("a", false), V(six, false)); +Test(x => x == 42n, + V(42n, true), V(42, true), V(null, false), V("42", true), V(six, false)); + +Test(x => x < 42, + V(1n, true), V(2, true), V(null, true), V("41", true), V(six, true)); +Test(x => x < 42, + V(42n, false), V(42, false), V(null, true), V("42", false), V(six, true)); +Test(x => x < 42n, + V(1n, true), V(2, true), V(null, true), V("41", true), V(six, true)); +Test(x => x < 42n, + V(42n, false), V(42, false), V(null, true), V("42", false), V(six, true)); diff --git a/deps/v8/test/mjsunit/harmony/for-await-of.js b/deps/v8/test/mjsunit/harmony/for-await-of.js index efcfdab2ea..e23758a5e1 100644 --- a/deps/v8/test/mjsunit/harmony/for-await-of.js +++ b/deps/v8/test/mjsunit/harmony/for-await-of.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration --allow-natives-syntax +// Flags: --allow-natives-syntax let testFailed = false; let testFailure; diff --git a/deps/v8/test/mjsunit/harmony/modules-import-15.js b/deps/v8/test/mjsunit/harmony/modules-import-15.js index ac33cd50b2..32255ce980 100644 --- a/deps/v8/test/mjsunit/harmony/modules-import-15.js +++ b/deps/v8/test/mjsunit/harmony/modules-import-15.js @@ -29,7 +29,8 @@ async function test2() { } catch(e) { assertInstanceof(e, SyntaxError); assertEquals( - "The requested module does not provide an export named 'default'", + "The requested module 'modules-skip-empty.js' does not provide an " + + "export named 'default'", e.message); ran = true; } diff --git a/deps/v8/test/mjsunit/harmony/optional-catch-binding-breaks.js b/deps/v8/test/mjsunit/harmony/optional-catch-binding-breaks.js new file mode 100644 index 0000000000..82be60cda1 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/optional-catch-binding-breaks.js @@ -0,0 +1,65 @@ +// Copyright 2017 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: --harmony-optional-catch-binding + +let state = 'initial'; +x: try { + throw new Error('caught'); + state = 'unreachable'; +} catch { + assertEquals(state, 'initial'); + state = 'caught'; + break x; + state = 'unreachable'; +} +assertEquals(state, 'caught'); + + +state = 'initial'; +x: try { + throw new Error('caught'); + state = 'unreachable'; +} catch { + assertEquals(state, 'initial'); + state = 'caught'; + break x; + state = 'unreachable'; +} finally { + assertEquals(state, 'caught'); + state = 'finally'; +} +assertEquals(state, 'finally'); + + +state = 'initial'; +x: { + y: try { + throw new Error('caught'); + state = 'unreachable'; + } catch { + assertEquals(state, 'initial'); + state = 'caught'; + break x; + state = 'unreachable'; + } finally { + assertEquals(state, 'caught'); + state = 'finally'; + break y; + state = 'unreachable'; + } + assertEquals(state, 'finally'); + state = 'after block'; +} +assertEquals(state, 'after block'); + + +do { + try { + throw new Error(); + } catch { + break; + } + assertUnreachable(); +} while(false); diff --git a/deps/v8/test/mjsunit/harmony/optional-catch-binding.js b/deps/v8/test/mjsunit/harmony/optional-catch-binding.js new file mode 100644 index 0000000000..093288c4e6 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/optional-catch-binding.js @@ -0,0 +1,39 @@ +// Copyright 2017 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: --harmony-optional-catch-binding + +let state = 'initial'; +try { + throw new Error('caught'); + state = 'unreachable'; +} catch { // Note the lack of a binding + assertEquals(state, 'initial'); + state = 'caught'; +} +assertEquals(state, 'caught'); + + +let sigil1 = {}; +try { + throw sigil1; +} catch (e) { + assertEquals(e, sigil1); +} + + +let sigil2 = {}; +let reached = false; +try { + try { + throw sigil1; + } catch { + reached = true; + } finally { + throw sigil2; + } +} catch (e) { + assertEquals(e, sigil2); +} +assertTrue(reached); diff --git a/deps/v8/test/mjsunit/harmony/promise-prototype-finally.js b/deps/v8/test/mjsunit/harmony/promise-prototype-finally.js index 3668ab5538..4e91f2e6d1 100644 --- a/deps/v8/test/mjsunit/harmony/promise-prototype-finally.js +++ b/deps/v8/test/mjsunit/harmony/promise-prototype-finally.js @@ -605,3 +605,13 @@ testAsync(assert => { .then(() => assert.equals(1, value)); }, "PromiseResolve-ordering"); + +(function testIsObject() { + var called = false; + var p = new Proxy(Promise.resolve(), {}); + var oldThen = Promise.prototype.then; + Promise.prototype.then = () => called = true; + Promise.prototype.finally.call(p); + assertTrue(called); + Promise.prototype.then = oldThen; +})(); diff --git a/deps/v8/test/mjsunit/harmony/public-instance-class-fields.js b/deps/v8/test/mjsunit/harmony/public-instance-class-fields.js index acf0f13a99..a82a0ac919 100644 --- a/deps/v8/test/mjsunit/harmony/public-instance-class-fields.js +++ b/deps/v8/test/mjsunit/harmony/public-instance-class-fields.js @@ -52,16 +52,8 @@ b = x; c = 1; hasOwnProperty() { return 1;} - static [x] = 2; - static b = 3; - static d; } - assertEquals(2, C.a); - assertEquals(3, C.b); - assertEquals(undefined, C.d); - assertEquals(undefined, C.c); - let c = new C; assertEquals(undefined, c.a); assertEquals('a', c.b); @@ -270,7 +262,7 @@ let c = new C; assertEquals(1, c.a); assertEquals(undefined, c.b); - assertEquals(undefined, c.c1); + assertEquals(undefined, c[c1]); } { @@ -281,10 +273,10 @@ } class C { - [run(1)] = run(7); - [run(2)] = run(8); + [run(1)] = run(6); + [run(2)] = run(7); [run(3)]() { run(9);} - static [run(4)] = run(6); + [run(4)] = run(8); [run(5)]() { throw new Error('should not execute');}; } @@ -303,10 +295,10 @@ function x() { } class C { - [run(1)] = run(7); - [run(2)] = run(8); + [run(1)] = run(6); + [run(2)] = run(7); [run(3)]() { run(9);} - static [run(4)] = run(6); + [run(4)] = run(8); [run(5)]() { throw new Error('should not execute');}; } @@ -315,7 +307,7 @@ function x() { assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], log); } } -x(); +x()(); { class C {} @@ -637,20 +629,6 @@ x(); } { - function t() { - return class { - ['x'] = 1; - static ['x'] = 2; - } - } - - let klass = t(); - let obj = new klass; - assertEquals(1, obj.x); - assertEquals(2, klass.x); -} - -{ new class { t = 1; constructor(t = this.t) { @@ -674,3 +652,47 @@ x(); } }, ReferenceError); } + +{ + class X { + p = function() { return arguments[0]; } + } + + let x = new X; + assertEquals(1, x.p(1)); +} + +{ + class X { + t = () => { + function p() { return arguments[0]; }; + return p; + } + } + + let x = new X; + let p = x.t(); + assertEquals(1, p(1)); +} + +{ + class X { + t = () => { + function p() { return eval("arguments[0]"); }; + return p; + } + } + + let x = new X; + let p = x.t(); + assertEquals(1, p(1)); +} + +{ + class X { + p = eval("(function() { return arguments[0]; })(1)"); + } + + let x = new X; + assertEquals(1, x.p); +} diff --git a/deps/v8/test/mjsunit/harmony/public-static-class-fields.js b/deps/v8/test/mjsunit/harmony/public-static-class-fields.js index 0477e3dca7..3de3e2d9d2 100644 --- a/deps/v8/test/mjsunit/harmony/public-static-class-fields.js +++ b/deps/v8/test/mjsunit/harmony/public-static-class-fields.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-public-fields +// Flags: --harmony-public-fields --harmony-static-fields "use strict"; @@ -262,7 +262,7 @@ assertEquals(1, C.a); assertEquals(undefined, C.b); - assertEquals(undefined, C.c); + assertEquals(undefined, C[c]); } { @@ -310,7 +310,51 @@ function x() { assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], log); } } -x(); +x()(); + +{ + let log = []; + function run(i) { + log.push(i); + return i; + } + + class C { + [run(1)] = run(7); + [run(2)] = run(8); + [run(3)]() { run(9);} + static [run(4)] = run(6); + [run(5)]() { throw new Error('should not execute');}; + } + + let c = new C; + c[3](); + assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], log); +} + +function y() { + // This tests lazy parsing. + return function() { + let log = []; + function run(i) { + log.push(i); + return i; + } + + class C { + [run(1)] = run(7); + [run(2)] = run(8); + [run(3)]() { run(9);} + static [run(4)] = run(6); + [run(5)]() { throw new Error('should not execute');}; + } + + let c = new C; + c[3](); + assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], log); + } +} +y()(); { class C {} @@ -333,3 +377,83 @@ x(); let obj = new klass; assertEquals(2, klass.x); } + +{ + let x = 'a'; + class C { + a; + b = x; + c = 1; + hasOwnProperty() { return 1;} + static [x] = 2; + static b = 3; + static d; + } + + assertEquals(2, C.a); + assertEquals(3, C.b); + assertEquals(undefined, C.d); + assertEquals(undefined, C.c); + + let c = new C; + assertEquals(undefined, c.a); + assertEquals('a', c.b); + assertEquals(1, c.c); + assertEquals(undefined, c.d); + assertEquals(1, c.hasOwnProperty()); +} + +{ + function t() { + return class { + ['x'] = 1; + static ['x'] = 2; + } + } + + let klass = t(); + let obj = new klass; + assertEquals(1, obj.x); + assertEquals(2, klass.x); +} + + +{ + class X { + static p = function() { return arguments[0]; } + } + + assertEquals(1, X.p(1)); +} + +{ + class X { + static t = () => { + function p() { return arguments[0]; }; + return p; + } + } + + let p = X.t(); + assertEquals(1, p(1)); +} + +{ + class X { + static t = () => { + function p() { return eval("arguments[0]"); }; + return p; + } + } + + let p = X.t(); + assertEquals(1, p(1)); +} + +{ + class X { + static p = eval("(function() { return arguments[0]; })(1)"); + } + + assertEquals(1, X.p); +} diff --git a/deps/v8/test/mjsunit/harmony/regexp-named-captures.js b/deps/v8/test/mjsunit/harmony/regexp-named-captures.js index 1ad29f6b49..72041b99bf 100644 --- a/deps/v8/test/mjsunit/harmony/regexp-named-captures.js +++ b/deps/v8/test/mjsunit/harmony/regexp-named-captures.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-regexp-named-captures +// Flags: --harmony-regexp-named-captures --allow-natives-syntax // Malformed named captures. assertThrows("/(?<>a)/u", SyntaxError); // Empty name. @@ -418,3 +418,124 @@ function toSlowMode(re) { assertEquals("cd", "abcd".replace(re, "$<fth>")); assertEquals("cd", "abcd".replace(re, "$<$1>")); } + +// Tests for 'groups' semantics on the regexp result object. +// https://crbug.com/v8/7192 + +{ + const re = /./; + const result = re.exec("a"); + assertTrue(%SpeciesProtector()); + assertEquals(result.__proto__, Array.prototype); + assertTrue(result.hasOwnProperty('groups')); + assertArrayEquals(["a"], result); + assertEquals(0, result.index); + assertEquals(undefined, result.groups); + + Array.prototype.groups = { a: "b" }; + assertTrue(%SpeciesProtector()); + assertEquals("$<a>", "a".replace(re, "$<a>")); + Array.prototype.groups = undefined; +} + +{ + const re = toSlowMode(/./); + const result = re.exec("a"); + assertTrue(%SpeciesProtector()); + assertEquals(result.__proto__, Array.prototype); + assertTrue(result.hasOwnProperty('groups')); + assertArrayEquals(["a"], result); + assertEquals(0, result.index); + assertEquals(undefined, result.groups); + + Array.prototype.groups = { a: "b" }; + assertTrue(%SpeciesProtector()); + assertEquals("$<a>", "a".replace(re, "$<a>")); + Array.prototype.groups = undefined; +} + +{ + const re = /(?<a>a).|(?<x>x)/; + const result = re.exec("ab"); + assertTrue(%SpeciesProtector()); + assertEquals(result.__proto__, Array.prototype); + assertTrue(result.hasOwnProperty('groups')); + assertArrayEquals(["ab", "a", undefined], result); + assertEquals(0, result.index); + assertEquals({a: "a", x: undefined}, result.groups); + + // a is a matched named capture, b is an unmatched named capture, and z + // is not a named capture. + Array.prototype.groups = { a: "b", x: "y", z: "z" }; + assertTrue(%SpeciesProtector()); + assertEquals("a", "ab".replace(re, "$<a>")); + assertEquals("", "ab".replace(re, "$<x>")); + assertEquals("", "ab".replace(re, "$<z>")); + Array.prototype.groups = undefined; +} + +{ + const re = toSlowMode(/(?<a>a).|(?<x>x)/); + const result = re.exec("ab"); + assertTrue(%SpeciesProtector()); + assertEquals(result.__proto__, Array.prototype); + assertTrue(result.hasOwnProperty('groups')); + assertArrayEquals(["ab", "a", undefined], result); + assertEquals(0, result.index); + assertEquals({a: "a", x: undefined}, result.groups); + + // a is a matched named capture, b is an unmatched named capture, and z + // is not a named capture. + Array.prototype.groups = { a: "b", x: "y", z: "z" }; + assertTrue(%SpeciesProtector()); + assertEquals("a", "ab".replace(re, "$<a>")); + assertEquals("", "ab".replace(re, "$<x>")); + assertEquals("", "ab".replace(re, "$<z>")); + Array.prototype.groups = undefined; +} + +{ + class FakeRegExp extends RegExp { + exec(subject) { + const fake_result = [ "ab", "a" ]; + fake_result.index = 0; + // groups is not set, triggering prototype lookup. + return fake_result; + } + }; + + const re = new FakeRegExp(); + const result = re.exec("ab"); + assertTrue(%SpeciesProtector()); + assertEquals(result.__proto__, Array.prototype); + assertFalse(result.hasOwnProperty('groups')); + + Array.prototype.groups = { a: "b" }; + Array.prototype.groups.__proto__.b = "c"; + assertTrue(%SpeciesProtector()); + assertEquals("b", "ab".replace(re, "$<a>")); + assertEquals("c", "ab".replace(re, "$<b>")); + Array.prototype.groups = undefined; +} + +{ + class FakeRegExp extends RegExp { + exec(subject) { + const fake_result = [ "ab", "a" ]; + fake_result.index = 0; + fake_result.groups = { a: "b" }; + fake_result.groups.__proto__.b = "c"; + return fake_result; + } + }; + + const re = new FakeRegExp(); + const result = re.exec("ab"); + assertTrue(%SpeciesProtector()); + assertEquals(result.__proto__, Array.prototype); + assertTrue(result.hasOwnProperty('groups')); + assertEquals({ a: "b" }, result.groups); + + assertEquals("b", "ab".replace(re, "$<a>")); + assertEquals("c", "ab".replace(re, "$<b>")); +} diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-6322.js b/deps/v8/test/mjsunit/harmony/regress/regress-6322.js index 9c312a35a5..927b56ea79 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-6322.js +++ b/deps/v8/test/mjsunit/harmony/regress/regress-6322.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration - // Crash with --verify-heap (async function() { for await (let { a = class b { } } of [{}]) { } })(); (async function() { var a; for await ({ a = class b { } } of [{}]) { } })(); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-772649.js b/deps/v8/test/mjsunit/harmony/regress/regress-772649.js index d080410226..2ff27670df 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-772649.js +++ b/deps/v8/test/mjsunit/harmony/regress/regress-772649.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --harmony-async-iteration +// Flags: --allow-natives-syntax async function* gen([[notIterable]] = [null]) {} assertThrows(() => gen(), TypeError); diff --git a/deps/v8/test/mjsunit/harmony/sharedarraybuffer.js b/deps/v8/test/mjsunit/harmony/sharedarraybuffer.js index 12e8c9508e..a79574d69f 100644 --- a/deps/v8/test/mjsunit/harmony/sharedarraybuffer.js +++ b/deps/v8/test/mjsunit/harmony/sharedarraybuffer.js @@ -89,9 +89,6 @@ function TestTypedArray(constr, elementSize, typicalElement) { assertEquals("[object " + constr.name + "]", Object.prototype.toString.call(a0)); - // TODO(binji): Should this return false here? It is a view, but it doesn't - // view a SharedArrayBuffer... - assertTrue(SharedArrayBuffer.isView(a0)); assertSame(elementSize, a0.BYTES_PER_ELEMENT); assertSame(30, a0.length); assertSame(30*elementSize, a0.byteLength); diff --git a/deps/v8/test/mjsunit/harmony/symbol-async-iterator.js b/deps/v8/test/mjsunit/harmony/symbol-async-iterator.js index 8a92add635..5b7e6b5f40 100644 --- a/deps/v8/test/mjsunit/harmony/symbol-async-iterator.js +++ b/deps/v8/test/mjsunit/harmony/symbol-async-iterator.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-async-iteration - assertTrue(Symbol.hasOwnProperty('asyncIterator')); assertEquals('symbol', typeof Symbol.asyncIterator); assertInstanceof(Object(Symbol.asyncIterator), Symbol); diff --git a/deps/v8/test/mjsunit/ic-lookup-on-receiver.js b/deps/v8/test/mjsunit/ic-lookup-on-receiver.js new file mode 100644 index 0000000000..8be3779f05 --- /dev/null +++ b/deps/v8/test/mjsunit/ic-lookup-on-receiver.js @@ -0,0 +1,44 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +(function TestLookupOnReceiver() { + let log = []; + + function f(o, v) { + o.x = v; + return o.x; + } + + let p = {}; + Object.defineProperty( + p, "x", + { + get: function() { return 153; }, + set: function(v) { log.push("set"); }, + configurable: true + }); + + let o = Object.create(p); + // Turn o to dictionary mode. + for (let i = 0; i < 2048; i++) { + o["p"+i] = 0; + } + assertFalse(%HasFastProperties(o)); + + for (let i = 0; i < 5; i++) { + log.push(f(o, i)); + } + + Object.defineProperty(o, "x", { value: 0, configurable: true, writable: true}); + + for (let i = 0; i < 5; i++) { + log.push(f(o, 42 + i)); + } + + assertEquals(log, + ["set", 153, "set", 153, "set", 153, "set", 153, "set", 153, + 42, 43, 44, 45, 46]); +})(); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index aa59fb680a..d91ff6f015 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -31,6 +31,7 @@ # tested standalone. 'modules-skip*': [SKIP], 'harmony/modules-skip*': [SKIP], + 'regress/modules-skip*': [SKIP], # All tests in the bug directory are expected to fail. 'bugs/*': [FAIL], @@ -78,13 +79,16 @@ ############################################################################## # No need to waste time for this test. - 'd8-performance-now': [PASS, NO_VARIANTS], + 'd8/d8-performance-now': [PASS, NO_VARIANTS], 'regress/regress-crbug-491062': [PASS, NO_VARIANTS], # Issue 488: this test sometimes times out. # TODO(arm): This seems to flush out a bug on arm with simulator. 'array-constructor': [PASS, SLOW, ['arch == arm and simulator == True', SKIP]], + # Very slow test + 'regress/regress-crbug-808192' : [PASS, NO_VARIANTS, ['arch == arm or arch == arm64 or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips64 or arch == mips', SKIP]], + # Very slow on ARM and MIPS, contains no architecture dependent code. 'unicode-case-overoptimization': [PASS, NO_VARIANTS, ['arch == arm or arch == arm64 or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips64 or arch == mips', SKIP]], 'regress/regress-3976': [PASS, NO_VARIANTS, ['arch == arm or arch == arm64 or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips64 or arch == mips', SKIP]], @@ -109,11 +113,17 @@ # we cannot run several variants of d8-os simultaneously, since all of them # get the same random seed and would generate the same directory name. Besides # that, it doesn't make sense to run several variants of d8-os anyways. - 'd8-os': [PASS, NO_VARIANTS, ['isolates or arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]], + 'd8/d8-os': [PASS, NO_VARIANTS, ['isolates or arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]], 'tools/tickprocessor': [PASS, NO_VARIANTS, ['arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]], 'tools/dumpcpp': [PASS, NO_VARIANTS, ['arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]], ############################################################################## + # This test generates a file in the test directory, so we cannot run several + # variants of the test simultaneously. Additionally the test should not be + # affected by variants. + 'd8/enable-tracing': [PASS, NO_VARIANTS], + + ############################################################################## # Long running test that reproduces memory leak and should be run manually. 'regress/regress-2073': [SKIP], @@ -135,9 +145,9 @@ 'math-floor-of-div-nosudiv': [PASS, SLOW, ['arch not in [arm, arm64, android_arm, android_arm64]', SKIP]], # Too slow for slow variants. - 'asm/embenchen/*': [PASS, SLOW, FAST_VARIANTS], - 'asm/poppler/*': [PASS, SLOW, FAST_VARIANTS], - 'asm/sqlite3/*': [PASS, SLOW, FAST_VARIANTS], + 'asm/embenchen/*': [PASS, SLOW, NO_VARIANTS], + 'asm/poppler/*': [PASS, SLOW, NO_VARIANTS], + 'asm/sqlite3/*': [PASS, SLOW, NO_VARIANTS], # Slow tests. 'copy-on-write-assert': [PASS, SLOW], @@ -162,6 +172,7 @@ 'regexp-modifiers-autogenerated-i18n': [PASS, ['no_i18n == True', FAIL]], # desugaring regexp property class relies on ICU. 'harmony/regexp-property-*': [PASS, ['no_i18n == True', FAIL]], + 'regress/regress-793588': [PASS, ['no_i18n == True', FAIL]], # noi18n build cannot parse characters in supplementary plane. 'harmony/regexp-named-captures': [PASS, ['no_i18n == True', FAIL]], @@ -193,13 +204,19 @@ }], # novfp3 == True ############################################################################## +# TODO(ahaas): Port multiple return values to ARM, MIPS, S390 and PPC +['arch == arm or arch == arm64 or arch == mips or arch == mips64 or arch == mipsel or arch == mips64el or arch == s390 or arch == s390x or arch == ppc or arch == ppc64', { + 'wasm/multi-value': [SKIP], +}], + +############################################################################## ['gc_stress == True', { # Skip tests not suitable for GC stress. 'allocation-site-info': [SKIP], 'array-constructor-feedback': [SKIP], 'array-feedback': [SKIP], 'array-literal-feedback': [SKIP], - 'd8-performance-now': [SKIP], + 'd8/d8-performance-now': [SKIP], 'elements-kind': [SKIP], 'elements-transition-hoisting': [SKIP], 'fast-prototype': [SKIP], @@ -250,7 +267,7 @@ 'regress/regress-inline-getter-near-stack-limit': [PASS, SLOW], # BUG(v8:4779): Crashes flakily with stress mode on arm64. - 'array-splice': [PASS, SLOW, ['arch == arm64', FAST_VARIANTS]], + 'array-splice': [PASS, SLOW, ['arch == arm64', NO_VARIANTS]], # BUG(chromium:751825): Crashes flakily. 'wasm/js-api': [SKIP], @@ -333,6 +350,9 @@ 'unicode-test': [PASS, SLOW], 'wasm/atomics': [PASS, SLOW], 'whitespaces': [PASS, SLOW], + + # BUG(v8:7247). + 'regress/regress-779407': [PASS, SLOW, NO_VARIANTS], }], # 'arch == arm64' ['arch == arm64 and mode == debug and simulator_run', { @@ -578,9 +598,6 @@ 'math-floor-of-div-nosudiv': [PASS, ['mode == debug', SKIP]], 'unicodelctest': [PASS, ['mode == debug', SKIP]], - # BUG(v8:4495). - 'es6/collections': [PASS, ['arch == ia32', FAST_VARIANTS]], - # Setting the timezone and locale with environment variables unavailable 'icu-date-to-string': [SKIP], 'icu-date-lord-howe': [SKIP], @@ -624,14 +641,19 @@ 'regress/regress-336820': [SKIP], 'regress/regress-748069': [SKIP], 'regress/regress-778668': [SKIP], + 'ignition/regress-672027': [PASS, ['tsan', SKIP]], }], # 'gc_fuzzer == True' ############################################################################## ['predictable == True', { # Skip tests that are known to be non-deterministic. - 'd8-worker-sharedarraybuffer': [SKIP], - 'd8-os': [SKIP], + 'd8/d8-worker-sharedarraybuffer': [SKIP], + 'd8/d8-os': [SKIP], + 'harmony/futex': [SKIP], + + # BUG(v8:7166). + 'd8/enable-tracing': [SKIP], }], # 'predictable == True' ############################################################################## @@ -735,16 +757,17 @@ }], # arch != x64 and arch != ia32 ############################################################################## -# BUG(v8:7138). -['arch == arm and not simulator_run and variant == wasm_traps', { - '*': [SKIP], -}], # arch == arm and not simulator_run and variant == wasm_traps - -############################################################################## ['variant == liftoff', { # In the liftoff variant, liftoff compilation happens even though the test # does not explicitly enable it. 'wasm/default-liftoff-setting': [SKIP], }], # variant == liftoff +############################################################################## +['variant == slow_path and gc_stress', { + # Slow tests. + 'regress/regress-crbug-493779': [SKIP], + 'string-replace-gc': [SKIP], +}], # variant == slow_path + ] diff --git a/deps/v8/test/mjsunit/optimized-array-every.js b/deps/v8/test/mjsunit/optimized-array-every.js new file mode 100644 index 0000000000..0cbab7df67 --- /dev/null +++ b/deps/v8/test/mjsunit/optimized-array-every.js @@ -0,0 +1,520 @@ +// Copyright 2017 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 --turbo-inline-array-builtins --opt +// Flags: --no-always-opt + +// Early exit from every functions properly. +(() => { + const a = [1, 2, 3, 4, 5]; + let result = 0; + function earlyExit() { + return a.every(v => { + result += v; + return v < 2; + }); + } + assertFalse(earlyExit()); + earlyExit(); + %OptimizeFunctionOnNextCall(earlyExit); + assertFalse(earlyExit()); + assertEquals(9, result); +})(); + +// Soft-deopt plus early exit. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let result = 0; + function softyPlusEarlyExit(deopt) { + return a.every(v => { + result += v; + if (v === 4 && deopt) { + a.abc = 25; + } + return v < 8; + }); + } + assertFalse(softyPlusEarlyExit(false)); + softyPlusEarlyExit(false); + %OptimizeFunctionOnNextCall(softyPlusEarlyExit); + assertFalse(softyPlusEarlyExit(true)); + assertEquals(36*3, result); +})(); + +// Soft-deopt synced with early exit, which forces the lazy deoptimization +// continuation handler to exit. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let called_values = []; + function softyPlusEarlyExit(deopt) { + called_values = []; + return a.every(v => { + called_values.push(v); + if (v === 4 && deopt) { + a.abc = 25; + return false; + } + return v < 8; + }); + } + assertFalse(softyPlusEarlyExit(false)); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8], called_values); + softyPlusEarlyExit(false); + %OptimizeFunctionOnNextCall(softyPlusEarlyExit); + assertFalse(softyPlusEarlyExit(true)); + assertArrayEquals([1, 2, 3, 4], called_values); +})(); + +// Unknown field access leads to soft-deopt unrelated to every, should still +// lead to correct result. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function eagerDeoptInCalled(deopt) { + return a.every((v, i) => { + if (i === 13 && deopt) { + a.abc = 25; + } + result += v; + return true; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + assertTrue(eagerDeoptInCalled(true)); + eagerDeoptInCalled(); + assertEquals(1625, result); +})(); + +// Length change detected during loop, must cause properly handled eager deopt. +(() => { + let called_values; + function eagerDeoptInCalled(deopt) { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + called_values = []; + return a.every((v,i) => { + called_values.push(v); + a.length = (i === 5 && deopt) ? 8 : 10; + return true; + }); + } + assertTrue(eagerDeoptInCalled()); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], called_values); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + assertTrue(eagerDeoptInCalled()); + assertTrue(eagerDeoptInCalled(true)); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8], called_values); + eagerDeoptInCalled(); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns true. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.every((v, i) => { + if (i === 3 && deopt) { + a[3] = 100; + %DeoptimizeNow(); + } + return true; + }); + } + assertTrue(lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertTrue(lazyChanger(true)); + assertTrue(lazyChanger()); +})(); + +// Lazy deopt from a callback that will always return true and no element is +// found. Verifies the lazy-after-callback continuation builtin. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.every((v, i) => { + if (i === 3 && deopt) { + %DeoptimizeNow(); + } + return true; + }); + } + assertTrue(lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertTrue(lazyChanger(true)); + assertTrue(lazyChanger()); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns true. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.every((v, i) => { + if (i === 2 && deopt) { + a[3] = 100; + %DeoptimizeNow(); + } + return true; + }); + } + assertTrue(lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertTrue(lazyChanger(true)); + assertTrue(lazyChanger()); +})(); + +// Escape analyzed array +(() => { + let result = 0; + function eagerDeoptInCalled(deopt) { + const a_noescape = [0, 1, 2, 3, 4, 5]; + a_noescape.every((v, i) => { + result += v | 0; + if (i === 13 && deopt) { + a_noescape.length = 25; + } + return true; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + eagerDeoptInCalled(true); + eagerDeoptInCalled(); + assertEquals(75, result); +})(); + +// Lazy deopt from runtime call from inlined callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + a.every((v, i) => { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return true; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Lazy deopt from runtime call from non-inline callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + function callback(v, i) { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return true; + } + %NeverOptimizeFunction(callback); + a.every(callback); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Call to a.every is done inside a try-catch block and the callback function +// being called actually throws. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let caught = false; + function lazyDeopt(deopt) { + try { + a.every((v, i) => { + if (i === 1 && deopt) { + throw("a"); + } + return true; + }); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.every is done inside a try-catch block and the callback function +// being called actually throws, but the callback is not inlined. +(() => { + let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let caught = false; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + throw("a"); + } + return true; + } + %NeverOptimizeFunction(callback); + try { + a.every(callback); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.every is done inside a try-catch block and the callback function +// being called throws into a deoptimized caller function. +(function TestThrowIntoDeoptimizedOuter() { + const a = [1, 2, 3, 4]; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + %DeoptimizeFunction(lazyDeopt); + throw "some exception"; + } + return true; + } + %NeverOptimizeFunction(callback); + let result = 0; + try { + result = a.every(callback); + } catch (e) { + assertEquals("some exception", e); + result = "nope"; + } + return result; + } + assertEquals(true, lazyDeopt(false)); + assertEquals(true, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); + assertEquals("nope", lazyDeopt(true)); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertEquals(true, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); +})(); + +// An error generated inside the callback includes every in it's +// stack trace. +(() => { + const re = /Array\.every/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let result = 0; + b.every((v, i) => { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + } + return true; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); +})(); + +// An error generated inside a non-inlined callback function also +// includes every in it's stack trace. +(() => { + const re = /Array\.every/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + function callback(v, i) { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return true; + } + %NeverOptimizeFunction(callback); + b.every(callback); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// An error generated inside a recently deoptimized callback function +// includes every in it's stack trace. +(() => { + const re = /Array\.every/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + b.every((v, i) => { + result += v; + if (i === 1) { + %DeoptimizeNow(); + } else if (i === 2) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return true; + }); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// Verify that various exception edges are handled appropriately. +// The thrown Error object should always indicate it was created from +// an every call stack. +(() => { + const re = /Array\.every/; + const a = [1, 2, 3]; + let result = 0; + function lazyDeopt() { + a.every((v, i) => { + result += i; + if (i === 1) { + %DeoptimizeFunction(lazyDeopt); + throw new Error(); + } + return true; + }); + } + assertThrows(() => lazyDeopt()); + assertThrows(() => lazyDeopt()); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } + %OptimizeFunctionOnNextCall(lazyDeopt); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } +})(); + +// Verify holes are skipped. +(() => { + const a = [1, 2, , 3, 4]; + function withHoles() { + const callback_values = []; + a.every(v => { + callback_values.push(v); + return true; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, 3, 4], withHoles()); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + function withHoles() { + const callback_values = []; + a.every(v => { + callback_values.push(v); + return true; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, 3.5, 4.5], withHoles()); +})(); + +// Ensure that we handle side-effects between load and call. +(() => { + function side_effect(a, b) { if (b) a.foo = 3; return a; } + %NeverOptimizeFunction(side_effect); + + function unreliable(a, b) { + return a.every(x => true, side_effect(a, b)); + } + + let a = [1, 2, 3]; + unreliable(a, false); + unreliable(a, false); + %OptimizeFunctionOnNextCall(unreliable); + unreliable(a, false); + // Now actually do change the map. + unreliable(a, true); +})(); + +// Handle callback is not callable. +(() => { + const a = [1, 2, 3, 4, 5]; + function notCallable() { + return a.every(undefined); + } + + assertThrows(notCallable, TypeError); + try { notCallable(); } catch(e) { } + %OptimizeFunctionOnNextCall(notCallable); + assertThrows(notCallable, TypeError); +})(); + +// Messing with the Array prototype causes deoptimization. +(() => { + const a = [1, 2, 3]; + let result = 0; + function prototypeChanged() { + a.every((v, i) => { + result += v; + return true; + }); + } + prototypeChanged(); + prototypeChanged(); + %OptimizeFunctionOnNextCall(prototypeChanged); + prototypeChanged(); + a.constructor = {}; + prototypeChanged(); + assertUnoptimized(prototypeChanged); + assertEquals(24, result); +})(); diff --git a/deps/v8/test/mjsunit/optimized-array-find.js b/deps/v8/test/mjsunit/optimized-array-find.js new file mode 100644 index 0000000000..abcd2cf704 --- /dev/null +++ b/deps/v8/test/mjsunit/optimized-array-find.js @@ -0,0 +1,460 @@ +// Copyright 2017 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 --turbo-inline-array-builtins --opt +// Flags: --no-always-opt + +// Unknown field access leads to soft-deopt unrelated to find, should still +// lead to correct result. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function eagerDeoptInCalled(deopt) { + return a.find((v, i) => { + if (i === 13 && deopt) { + a.abc = 25; + } + result += v; + return v === 20; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + assertEquals(20, eagerDeoptInCalled(true)); + eagerDeoptInCalled(); + assertEquals(1050, result); +})(); + +// Length change detected during loop, must cause properly handled eager deopt. +(() => { + let called_values; + function eagerDeoptInCalled(deopt) { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + called_values = []; + return a.find((v,i) => { + called_values.push(v); + a.length = (i === 5 && deopt) ? 8 : 10; + return v === 9; + }); + } + assertEquals(9, eagerDeoptInCalled()); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], called_values); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + assertEquals(9, eagerDeoptInCalled()); + assertEquals(undefined, eagerDeoptInCalled(true)); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8, undefined, undefined], + called_values); + eagerDeoptInCalled(); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns true. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.find((v, i) => { + if (i === 3 && deopt) { + a[3] = 100; + %DeoptimizeNow(); + } + return v > 3; + }); + } + assertEquals(4, lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertEquals(4, lazyChanger(true)); + assertEquals(100, lazyChanger()); +})(); + +// Lazy deopt from a callback that will always return false and no element is +// found. Verifies the lazy-after-callback continuation builtin. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.find((v, i) => { + if (i === 3 && deopt) { + %DeoptimizeNow(); + } + return false; + }); + } + assertEquals(undefined, lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertEquals(undefined, lazyChanger(true)); + assertEquals(undefined, lazyChanger()); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns false. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.find((v, i) => { + if (i === 2 && deopt) { + a[3] = 100; + %DeoptimizeNow(); + } + return v > 3; + }); + } + assertEquals(4, lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertEquals(100, lazyChanger(true)); + assertEquals(100, lazyChanger()); +})(); + +// Escape analyzed array +(() => { + let result = 0; + function eagerDeoptInCalled(deopt) { + const a_noescape = [0, 1, 2, 3, 4, 5]; + a_noescape.find((v, i) => { + result += v | 0; + if (i === 13 && deopt) { + a_noescape.length = 25; + } + return false; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + eagerDeoptInCalled(true); + eagerDeoptInCalled(); + assertEquals(75, result); +})(); + +// Lazy deopt from runtime call from inlined callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + a.find((v, i) => { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return false; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Lazy deopt from runtime call from non-inline callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + function callback(v, i) { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return false; + } + %NeverOptimizeFunction(callback); + a.find(callback); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Call to a.find is done inside a try-catch block and the callback function +// being called actually throws. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let caught = false; + function lazyDeopt(deopt) { + try { + a.find((v, i) => { + if (i === 1 && deopt) { + throw("a"); + } + return false; + }); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.find is done inside a try-catch block and the callback function +// being called actually throws, but the callback is not inlined. +(() => { + let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let caught = false; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + throw("a"); + } + return false; + } + %NeverOptimizeFunction(callback); + try { + a.find(callback); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.find is done inside a try-catch block and the callback function +// being called throws into a deoptimized caller function. +(function TestThrowIntoDeoptimizedOuter() { + const a = [1, 2, 3, 4]; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + %DeoptimizeFunction(lazyDeopt); + throw "some exception"; + } + return v === 3; + } + %NeverOptimizeFunction(callback); + let result = 0; + try { + result = a.find(callback); + } catch (e) { + assertEquals("some exception", e); + result = "nope"; + } + return result; + } + assertEquals(3, lazyDeopt(false)); + assertEquals(3, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); + assertEquals("nope", lazyDeopt(true)); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertEquals(3, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); +})(); + +// An error generated inside the callback includes find in it's +// stack trace. +(() => { + const re = /Array\.find/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let result = 0; + b.find((v, i) => { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + } + return false; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); +})(); + +// An error generated inside a non-inlined callback function also +// includes find in it's stack trace. +(() => { + const re = /Array\.find/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + function callback(v, i) { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return false; + } + %NeverOptimizeFunction(callback); + b.find(callback); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// An error generated inside a recently deoptimized callback function +// includes find in it's stack trace. +(() => { + const re = /Array\.find/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + b.find((v, i) => { + result += v; + if (i === 1) { + %DeoptimizeNow(); + } else if (i === 2) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return false; + }); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// Verify that various exception edges are handled appropriately. +// The thrown Error object should always indicate it was created from +// a find call stack. +(() => { + const re = /Array\.find/; + const a = [1, 2, 3]; + let result = 0; + function lazyDeopt() { + a.find((v, i) => { + result += i; + if (i === 1) { + %DeoptimizeFunction(lazyDeopt); + throw new Error(); + } + return false; + }); + } + assertThrows(() => lazyDeopt()); + assertThrows(() => lazyDeopt()); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } + %OptimizeFunctionOnNextCall(lazyDeopt); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } +})(); + +// Messing with the Array prototype causes deoptimization. +(() => { + const a = [1, 2, 3]; + let result = 0; + function prototypeChanged() { + a.find((v, i) => { + result += v; + return false; + }); + } + prototypeChanged(); + prototypeChanged(); + %OptimizeFunctionOnNextCall(prototypeChanged); + prototypeChanged(); + a.constructor = {}; + prototypeChanged(); + assertUnoptimized(prototypeChanged); + assertEquals(24, result); +})(); + +// Verify holes are replaced with undefined. +(() => { + const a = [1, 2, , 3, 4]; + function withHoles() { + const callback_values = []; + a.find(v => { + callback_values.push(v); + return false; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, undefined, 3, 4], withHoles()); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + function withHoles() { + const callback_values = []; + a.find(v => { + callback_values.push(v); + return false; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, undefined, 3.5, 4.5], withHoles()); +})(); + +// Ensure that we handle side-effects between load and call. +(() => { + function side_effect(a, b) { if (b) a.foo = 3; return a; } + %NeverOptimizeFunction(side_effect); + + function unreliable(a, b) { + return a.find(x => false, side_effect(a, b)); + } + + let a = [1, 2, 3]; + unreliable(a, false); + unreliable(a, false); + %OptimizeFunctionOnNextCall(unreliable); + unreliable(a, false); + // Now actually do change the map. + unreliable(a, true); +})(); + +// Handle callback is not callable. +(() => { + const a = [1, 2, 3, 4, 5]; + function notCallable() { + return a.find(undefined); + } + + assertThrows(notCallable, TypeError); + try { notCallable(); } catch(e) { } + %OptimizeFunctionOnNextCall(notCallable); + assertThrows(notCallable, TypeError); +})(); diff --git a/deps/v8/test/mjsunit/optimized-array-findindex.js b/deps/v8/test/mjsunit/optimized-array-findindex.js new file mode 100644 index 0000000000..91f4a6cc60 --- /dev/null +++ b/deps/v8/test/mjsunit/optimized-array-findindex.js @@ -0,0 +1,460 @@ +// Copyright 2017 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 --turbo-inline-array-builtins --opt +// Flags: --no-always-opt + +// Unknown field access leads to soft-deopt unrelated to findIndex, should still +// lead to correct result. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function eagerDeoptInCalled(deopt) { + return a.findIndex((v, i) => { + if (i === 13 && deopt) { + a.abc = 25; + } + result += v; + return v === 20; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + assertEquals(19, eagerDeoptInCalled(true)); + eagerDeoptInCalled(); + assertEquals(1050, result); +})(); + +// Length change detected during loop, must cause properly handled eager deopt. +(() => { + let called_values; + function eagerDeoptInCalled(deopt) { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + called_values = []; + return a.findIndex((v,i) => { + called_values.push(v); + a.length = (i === 5 && deopt) ? 8 : 10; + return v === 9; + }); + } + assertEquals(8, eagerDeoptInCalled()); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], called_values); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + assertEquals(8, eagerDeoptInCalled()); + assertEquals(-1, eagerDeoptInCalled(true)); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8, undefined, undefined], + called_values); + eagerDeoptInCalled(); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns true. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.findIndex((v, i) => { + if (i === 3 && deopt) { + a[3] = 3; + %DeoptimizeNow(); + } + return v > 3; + }); + } + assertEquals(3, lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertEquals(3, lazyChanger(true)); + assertEquals(4, lazyChanger()); +})(); + +// Lazy deopt from a callback that will always return false and no element is +// found. Verifies the lazy-after-callback continuation builtin. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.findIndex((v, i) => { + if (i === 3 && deopt) { + %DeoptimizeNow(); + } + return false; + }); + } + assertEquals(-1, lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertEquals(-1, lazyChanger(true)); + assertEquals(-1, lazyChanger()); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns false. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.findIndex((v, i) => { + if (i === 2 && deopt) { + a[3] = 2; + %DeoptimizeNow(); + } + return v > 3; + }); + } + assertEquals(3, lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertEquals(4, lazyChanger(true)); + assertEquals(4, lazyChanger()); +})(); + +// Escape analyzed array +(() => { + let result = 0; + function eagerDeoptInCalled(deopt) { + const a_noescape = [0, 1, 2, 3, 4, 5]; + a_noescape.findIndex((v, i) => { + result += v | 0; + if (i === 13 && deopt) { + a_noescape.length = 25; + } + return false; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + eagerDeoptInCalled(true); + eagerDeoptInCalled(); + assertEquals(75, result); +})(); + +// Lazy deopt from runtime call from inlined callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + a.findIndex((v, i) => { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return false; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Lazy deopt from runtime call from non-inline callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + function callback(v, i) { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return false; + } + %NeverOptimizeFunction(callback); + a.findIndex(callback); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Call to a.findIndex is done inside a try-catch block and the callback function +// being called actually throws. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let caught = false; + function lazyDeopt(deopt) { + try { + a.findIndex((v, i) => { + if (i === 1 && deopt) { + throw("a"); + } + return false; + }); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.findIndex is done inside a try-catch block and the callback function +// being called actually throws, but the callback is not inlined. +(() => { + let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let caught = false; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + throw("a"); + } + return false; + } + %NeverOptimizeFunction(callback); + try { + a.findIndex(callback); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.findIndex is done inside a try-catch block and the callback function +// being called throws into a deoptimized caller function. +(function TestThrowIntoDeoptimizedOuter() { + const a = [1, 2, 3, 4]; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + %DeoptimizeFunction(lazyDeopt); + throw "some exception"; + } + return v === 3; + } + %NeverOptimizeFunction(callback); + let result = 0; + try { + result = a.findIndex(callback); + } catch (e) { + assertEquals("some exception", e); + result = "nope"; + } + return result; + } + assertEquals(2, lazyDeopt(false)); + assertEquals(2, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); + assertEquals("nope", lazyDeopt(true)); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertEquals(2, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); +})(); + +// An error generated inside the callback includes findIndex in it's +// stack trace. +(() => { + const re = /Array\.findIndex/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let result = 0; + b.findIndex((v, i) => { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + } + return false; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); +})(); + +// An error generated inside a non-inlined callback function also +// includes findIndex in it's stack trace. +(() => { + const re = /Array\.findIndex/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + function callback(v, i) { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return false; + } + %NeverOptimizeFunction(callback); + b.findIndex(callback); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// An error generated inside a recently deoptimized callback function +// includes findIndex in it's stack trace. +(() => { + const re = /Array\.findIndex/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + b.findIndex((v, i) => { + result += v; + if (i === 1) { + %DeoptimizeNow(); + } else if (i === 2) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return false; + }); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// Verify that various exception edges are handled appropriately. +// The thrown Error object should always indicate it was created from +// a findIndex call stack. +(() => { + const re = /Array\.findIndex/; + const a = [1, 2, 3]; + let result = 0; + function lazyDeopt() { + a.findIndex((v, i) => { + result += i; + if (i === 1) { + %DeoptimizeFunction(lazyDeopt); + throw new Error(); + } + return false; + }); + } + assertThrows(() => lazyDeopt()); + assertThrows(() => lazyDeopt()); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } + %OptimizeFunctionOnNextCall(lazyDeopt); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } +})(); + +// Messing with the Array prototype causes deoptimization. +(() => { + const a = [1, 2, 3]; + let result = 0; + function prototypeChanged() { + a.findIndex((v, i) => { + result += v; + return false; + }); + } + prototypeChanged(); + prototypeChanged(); + %OptimizeFunctionOnNextCall(prototypeChanged); + prototypeChanged(); + a.constructor = {}; + prototypeChanged(); + assertUnoptimized(prototypeChanged); + assertEquals(24, result); +})(); + +// Verify holes are replaced with undefined. +(() => { + const a = [1, 2, , 3, 4]; + function withHoles() { + const callback_values = []; + a.findIndex(v => { + callback_values.push(v); + return false; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, undefined, 3, 4], withHoles()); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + function withHoles() { + const callback_values = []; + a.findIndex(v => { + callback_values.push(v); + return false; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, undefined, 3.5, 4.5], withHoles()); +})(); + +// Ensure that we handle side-effects between load and call. +(() => { + function side_effect(a, b) { if (b) a.foo = 3; return a; } + %NeverOptimizeFunction(side_effect); + + function unreliable(a, b) { + return a.findIndex(x => false, side_effect(a, b)); + } + + let a = [1, 2, 3]; + unreliable(a, false); + unreliable(a, false); + %OptimizeFunctionOnNextCall(unreliable); + unreliable(a, false); + // Now actually do change the map. + unreliable(a, true); +})(); + +// Handle callback is not callable. +(() => { + const a = [1, 2, 3, 4, 5]; + function notCallable() { + return a.findIndex(undefined); + } + + assertThrows(notCallable, TypeError); + try { notCallable(); } catch(e) { } + %OptimizeFunctionOnNextCall(notCallable); + assertThrows(notCallable, TypeError); +})(); diff --git a/deps/v8/test/mjsunit/optimized-array-some.js b/deps/v8/test/mjsunit/optimized-array-some.js new file mode 100644 index 0000000000..8d0114aa64 --- /dev/null +++ b/deps/v8/test/mjsunit/optimized-array-some.js @@ -0,0 +1,502 @@ +// Copyright 2017 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 --turbo-inline-array-builtins --opt +// Flags: --no-always-opt + +// Early exit from some functions properly. +(() => { + const a = [1, 2, 3, 4, 5]; + let result = 0; + function earlyExit() { + return a.some(v => { + result += v; + return v > 2; + }); + } + assertTrue(earlyExit()); + earlyExit(); + %OptimizeFunctionOnNextCall(earlyExit); + assertTrue(earlyExit()); + assertEquals(18, result); +})(); + +// Soft-deopt plus early exit. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let result = 0; + function softyPlusEarlyExit(deopt) { + return a.some(v => { + result += v; + if (v === 4 && deopt) { + a.abc = 25; + } + return v > 7; + }); + } + assertTrue(softyPlusEarlyExit(false)); + softyPlusEarlyExit(false); + %OptimizeFunctionOnNextCall(softyPlusEarlyExit); + assertTrue(softyPlusEarlyExit(true)); + assertEquals(36*3, result); +})(); + +// Soft-deopt synced with early exit, which forces the lazy deoptimization +// continuation handler to exit. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let called_values = []; + function softyPlusEarlyExit(deopt) { + called_values = []; + return a.some(v => { + called_values.push(v); + if (v === 4 && deopt) { + a.abc = 25; + return true; + } + return v > 7; + }); + } + assertTrue(softyPlusEarlyExit(false)); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8], called_values); + softyPlusEarlyExit(false); + %OptimizeFunctionOnNextCall(softyPlusEarlyExit); + assertTrue(softyPlusEarlyExit(true)); + assertArrayEquals([1, 2, 3, 4], called_values); +})(); + +// Unknown field access leads to soft-deopt unrelated to some, should still +// lead to correct result. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function eagerDeoptInCalled(deopt) { + return a.some((v, i) => { + if (i === 13 && deopt) { + a.abc = 25; + } + result += v; + return false; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + assertFalse(eagerDeoptInCalled(true)); + eagerDeoptInCalled(); + assertEquals(1625, result); +})(); + +// Length change detected during loop, must cause properly handled eager deopt. +(() => { + let called_values; + function eagerDeoptInCalled(deopt) { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + called_values = []; + return a.some((v,i) => { + called_values.push(v); + a.length = (i === 5 && deopt) ? 8 : 10; + return false; + }); + } + assertFalse(eagerDeoptInCalled()); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], called_values); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + assertFalse(eagerDeoptInCalled()); + assertFalse(eagerDeoptInCalled(true)); + assertArrayEquals([1, 2, 3, 4, 5, 6, 7, 8], called_values); + eagerDeoptInCalled(); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns true. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.some((v, i) => { + if (i === 3 && deopt) { + a[3] = 100; + %DeoptimizeNow(); + } + return false; + }); + } + assertFalse(lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertFalse(lazyChanger(true)); + assertFalse(lazyChanger()); +})(); + +// Lazy deopt from a callback that will always return false and no element is +// found. Verifies the lazy-after-callback continuation builtin. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.some((v, i) => { + if (i === 3 && deopt) { + %DeoptimizeNow(); + } + return false; + }); + } + assertFalse(lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertFalse(lazyChanger(true)); + assertFalse(lazyChanger()); +})(); + +// Lazy deopt from a callback that changes the input array. Deopt in a callback +// execution that returns false. +(() => { + const a = [1, 2, 3, 4, 5]; + function lazyChanger(deopt) { + return a.every((v, i) => { + if (i === 2 && deopt) { + a[3] = 100; + %DeoptimizeNow(); + } + return false; + }); + } + assertFalse(lazyChanger()); + lazyChanger(); + %OptimizeFunctionOnNextCall(lazyChanger); + assertFalse(lazyChanger(true)); + assertFalse(lazyChanger()); +})(); + +// Escape analyzed array +(() => { + let result = 0; + function eagerDeoptInCalled(deopt) { + const a_noescape = [0, 1, 2, 3, 4, 5]; + a_noescape.some((v, i) => { + result += v | 0; + if (i === 13 && deopt) { + a_noescape.length = 25; + } + return false; + }); + } + eagerDeoptInCalled(); + eagerDeoptInCalled(); + %OptimizeFunctionOnNextCall(eagerDeoptInCalled); + eagerDeoptInCalled(); + eagerDeoptInCalled(true); + eagerDeoptInCalled(); + assertEquals(75, result); +})(); + +// Lazy deopt from runtime call from inlined callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + a.some((v, i) => { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return false; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Lazy deopt from runtime call from non-inline callback function. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let result = 0; + function lazyDeopt(deopt) { + function callback(v, i) { + result += i; + if (i === 13 && deopt) { + %DeoptimizeNow(); + } + return false; + } + %NeverOptimizeFunction(callback); + a.some(callback); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + lazyDeopt(true); + lazyDeopt(); + assertEquals(1500, result); +})(); + +// Call to a.some is done inside a try-catch block and the callback function +// being called actually throws. +(() => { + const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25]; + let caught = false; + function lazyDeopt(deopt) { + try { + a.some((v, i) => { + if (i === 1 && deopt) { + throw("a"); + } + return false; + }); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.some is done inside a try-catch block and the callback function +// being called actually throws, but the callback is not inlined. +(() => { + let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let caught = false; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + throw("a"); + } + return false; + } + %NeverOptimizeFunction(callback); + try { + a.some(callback); + } catch (e) { + caught = true; + } + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); + assertDoesNotThrow(() => lazyDeopt(true)); + assertTrue(caught); + lazyDeopt(); +})(); + +// Call to a.some is done inside a try-catch block and the callback function +// being called throws into a deoptimized caller function. +(function TestThrowIntoDeoptimizedOuter() { + const a = [1, 2, 3, 4]; + function lazyDeopt(deopt) { + function callback(v, i) { + if (i === 1 && deopt) { + %DeoptimizeFunction(lazyDeopt); + throw "some exception"; + } + return false; + } + %NeverOptimizeFunction(callback); + let result = 0; + try { + result = a.some(callback); + } catch (e) { + assertEquals("some exception", e); + result = "nope"; + } + return result; + } + assertEquals(false, lazyDeopt(false)); + assertEquals(false, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); + assertEquals("nope", lazyDeopt(true)); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertEquals(false, lazyDeopt(false)); + assertEquals("nope", lazyDeopt(true)); +})(); + +// An error generated inside the callback includes some in it's +// stack trace. +(() => { + const re = /Array\.some/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let result = 0; + b.some((v, i) => { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + } + return false; + }); + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + lazyDeopt(); +})(); + +// An error generated inside a non-inlined callback function also +// includes some in it's stack trace. +(() => { + const re = /Array\.some/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + function callback(v, i) { + result += v; + if (i === 1) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return false; + } + %NeverOptimizeFunction(callback); + b.some(callback); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// An error generated inside a recently deoptimized callback function +// includes some in it's stack trace. +(() => { + const re = /Array\.some/; + function lazyDeopt(deopt) { + const b = [1, 2, 3]; + let did_assert_error = false; + let result = 0; + b.some((v, i) => { + result += v; + if (i === 1) { + %DeoptimizeNow(); + } else if (i === 2) { + const e = new Error(); + assertTrue(re.exec(e.stack) !== null); + did_assert_error = true; + } + return false; + }); + return did_assert_error; + } + lazyDeopt(); + lazyDeopt(); + %OptimizeFunctionOnNextCall(lazyDeopt); + assertTrue(lazyDeopt()); +})(); + +// Verify that various exception edges are handled appropriately. +// The thrown Error object should always indicate it was created from +// a some call stack. +(() => { + const re = /Array\.some/; + const a = [1, 2, 3]; + let result = 0; + function lazyDeopt() { + a.some((v, i) => { + result += i; + if (i === 1) { + %DeoptimizeFunction(lazyDeopt); + throw new Error(); + } + return false; + }); + } + assertThrows(() => lazyDeopt()); + assertThrows(() => lazyDeopt()); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } + %OptimizeFunctionOnNextCall(lazyDeopt); + try { + lazyDeopt(); + } catch (e) { + assertTrue(re.exec(e.stack) !== null); + } +})(); + +// Messing with the Array prototype causes deoptimization. +(() => { + const a = [1, 2, 3]; + let result = 0; + function prototypeChanged() { + a.some((v, i) => { + result += v; + return false; + }); + } + prototypeChanged(); + prototypeChanged(); + %OptimizeFunctionOnNextCall(prototypeChanged); + prototypeChanged(); + a.constructor = {}; + prototypeChanged(); + assertUnoptimized(prototypeChanged); + assertEquals(24, result); +})(); + +// Verify holes are skipped. +(() => { + const a = [1, 2, , 3, 4]; + function withHoles() { + const callback_values = []; + a.some(v => { + callback_values.push(v); + return false; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, 3, 4], withHoles()); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + function withHoles() { + const callback_values = []; + a.some(v => { + callback_values.push(v); + return false; + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, 3.5, 4.5], withHoles()); +})(); + +// Handle callback is not callable. +(() => { + const a = [1, 2, 3, 4, 5]; + function notCallable() { + return a.some(undefined); + } + + assertThrows(notCallable, TypeError); + try { notCallable(); } catch(e) { } + %OptimizeFunctionOnNextCall(notCallable); + assertThrows(notCallable, TypeError); +})(); diff --git a/deps/v8/test/mjsunit/optimized-filter.js b/deps/v8/test/mjsunit/optimized-filter.js index b13edc3b36..3c7d827e0f 100644 --- a/deps/v8/test/mjsunit/optimized-filter.js +++ b/deps/v8/test/mjsunit/optimized-filter.js @@ -417,6 +417,59 @@ } })(); +// Verify holes are skipped. +(() => { + const a = [1, 2, , 3, 4]; + let callback_values = []; + function withHoles() { + callback_values = []; + return a.filter(v => { + callback_values.push(v); + return true; + }); + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, 3, 4], withHoles()); + assertArrayEquals([1, 2, 3, 4], callback_values); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + let callback_values = []; + function withHoles() { + callback_values = []; + return a.filter(v => { + callback_values.push(v); + return true; + }); + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, 3.5, 4.5], withHoles()); + assertArrayEquals([1.5, 2.5, 3.5, 4.5], callback_values); +})(); + +// Ensure that we handle side-effects between load and call. +(() => { + function side_effect(a, b) { if (b) a.foo = 3; return a; } + %NeverOptimizeFunction(side_effect); + + function unreliable(a, b) { + return a.filter(x => x % 2 === 0, side_effect(a, b)); + } + + let a = [1, 2, 3]; + unreliable(a, false); + unreliable(a, false); + %OptimizeFunctionOnNextCall(unreliable); + unreliable(a, false); + // Now actually do change the map. + unreliable(a, true); +})(); + // Messing with the Array species constructor causes deoptimization. (function() { var result = 0; diff --git a/deps/v8/test/mjsunit/optimized-foreach.js b/deps/v8/test/mjsunit/optimized-foreach.js index f3513f3838..1fe54b5e9f 100644 --- a/deps/v8/test/mjsunit/optimized-foreach.js +++ b/deps/v8/test/mjsunit/optimized-foreach.js @@ -343,3 +343,53 @@ var c = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]; assertTrue(re.exec(e.stack) !== null); } })(); + +// Verify holes are skipped. +(() => { + const a = [1, 2, , 3, 4]; + function withHoles() { + const callback_values = []; + a.forEach(v => { + callback_values.push(v); + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, 3, 4], withHoles()); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + function withHoles() { + const callback_values = []; + a.forEach(v => { + callback_values.push(v); + }); + return callback_values; + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, 3.5, 4.5], withHoles()); +})(); + +// Ensure that we handle side-effects between load and call. +(() => { + function side_effect(a, b) { if (b) a.foo = 3; return a; } + %NeverOptimizeFunction(side_effect); + + function unreliable(a, b) { + let sum = 0; + return a.forEach(x => sum += x, side_effect(a, b)); + } + + let a = [1, 2, 3]; + unreliable(a, false); + unreliable(a, false); + %OptimizeFunctionOnNextCall(unreliable); + unreliable(a, false); + // Now actually do change the map. + unreliable(a, true); +})(); diff --git a/deps/v8/test/mjsunit/optimized-map.js b/deps/v8/test/mjsunit/optimized-map.js index d8613e0300..6a3df4d7d4 100644 --- a/deps/v8/test/mjsunit/optimized-map.js +++ b/deps/v8/test/mjsunit/optimized-map.js @@ -468,6 +468,59 @@ var c = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]; assertEquals("hello1", string_results()[0]); })(); +// Verify holes are not visited. +(() => { + const a = [1, 2, , 3, 4]; + let callback_values = []; + function withHoles() { + callback_values = []; + return a.map(v => { + callback_values.push(v); + return v; + }); + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1, 2, , 3, 4], withHoles()); + assertArrayEquals([1, 2, 3, 4], callback_values); +})(); + +(() => { + const a = [1.5, 2.5, , 3.5, 4.5]; + let callback_values = []; + function withHoles() { + callback_values = []; + return a.map(v => { + callback_values.push(v); + return v; + }); + } + withHoles(); + withHoles(); + %OptimizeFunctionOnNextCall(withHoles); + assertArrayEquals([1.5, 2.5, , 3.5, 4.5], withHoles()); + assertArrayEquals([1.5, 2.5, 3.5, 4.5], callback_values); +})(); + +// Ensure that we handle side-effects between load and call. +(() => { + function side_effect(a, b) { if (b) a.foo = 3; return a; } + %NeverOptimizeFunction(side_effect); + + function unreliable(a, b) { + return a.map(x => x * 2, side_effect(a, b)); + } + + let a = [1, 2, 3]; + unreliable(a, false); + unreliable(a, false); + %OptimizeFunctionOnNextCall(unreliable); + unreliable(a, false); + // Now actually do change the map. + unreliable(a, true); +})(); + // Messing with the Array species constructor causes deoptimization. (function() { var result = 0; diff --git a/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-1.js b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-1.js new file mode 100644 index 0000000000..1aa55aa9fb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-1.js @@ -0,0 +1,5 @@ +// Copyright 2018 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. + +export default () diff --git a/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-2.js b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-2.js new file mode 100644 index 0000000000..855aa2e9d7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-2.js @@ -0,0 +1,5 @@ +// Copyright 2018 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. + +export default (...) diff --git a/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-3.js b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-3.js new file mode 100644 index 0000000000..e6d043d2ce --- /dev/null +++ b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-3.js @@ -0,0 +1,5 @@ +// Copyright 2018 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. + +export default (a, ...b) diff --git a/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-4.js b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-4.js new file mode 100644 index 0000000000..fc7968d03d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-4.js @@ -0,0 +1,5 @@ +// Copyright 2018 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. + +export default 1, 2; diff --git a/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-5.js b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-5.js new file mode 100644 index 0000000000..10864c260f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/modules-skip-regress-797581-5.js @@ -0,0 +1,6 @@ +// Copyright 2018 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. + +let x; +export default x = 0; diff --git a/deps/v8/test/mjsunit/regress/regress-2646.js b/deps/v8/test/mjsunit/regress/regress-2646.js index c51a28060c..ef72556e04 100644 --- a/deps/v8/test/mjsunit/regress/regress-2646.js +++ b/deps/v8/test/mjsunit/regress/regress-2646.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --heap-stats - var expectedItemsCount = 10000, itemSize = 5, heap = new ArrayBuffer(expectedItemsCount * itemSize * 8), diff --git a/deps/v8/test/mjsunit/regress/regress-370827.js b/deps/v8/test/mjsunit/regress/regress-370827.js index 5536d5196b..e6d5185e70 100644 --- a/deps/v8/test/mjsunit/regress/regress-370827.js +++ b/deps/v8/test/mjsunit/regress/regress-370827.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --expose-gc --heap-stats +// Flags: --allow-natives-syntax --expose-gc function g(dummy, x) { var start = ""; diff --git a/deps/v8/test/mjsunit/regress/regress-599717.js b/deps/v8/test/mjsunit/regress/regress-599717.js index 94a41ce4d3..51831860e9 100644 --- a/deps/v8/test/mjsunit/regress/regress-599717.js +++ b/deps/v8/test/mjsunit/regress/regress-599717.js @@ -15,7 +15,7 @@ function __f_61(stdlib, foreign, buffer) { } var ok = false; try { - var __v_12 = new ArrayBuffer(1 << 30); + var __v_12 = new ArrayBuffer(2147483648); ok = true; } catch (e) { // Can happen on 32 bit systems. diff --git a/deps/v8/test/mjsunit/regress/regress-791334.js b/deps/v8/test/mjsunit/regress/regress-791334.js new file mode 100644 index 0000000000..9f2748fdad --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-791334.js @@ -0,0 +1,8 @@ +// Copyright 2017 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. + +// MODULE + +let foo = () => { return this }; +assertEquals(undefined, foo()); diff --git a/deps/v8/test/mjsunit/regress/regress-791958.js b/deps/v8/test/mjsunit/regress/regress-791958.js new file mode 100644 index 0000000000..443ef6e359 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-791958.js @@ -0,0 +1,15 @@ +// Copyright 2017 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 + +obj = {m: print}; +function foo() { + for (var x = -536870912; x != -536870903; ++x) { + obj.m(-x >= 1000000 ? x % 1000000 : y); + } +} +foo(); +%OptimizeFunctionOnNextCall(foo); +foo(); diff --git a/deps/v8/test/mjsunit/regress/regress-793588.js b/deps/v8/test/mjsunit/regress/regress-793588.js new file mode 100644 index 0000000000..6ad7a76e2a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-793588.js @@ -0,0 +1,13 @@ +// Copyright 2017 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: --harmony-regexp-property + +assertNull(/a\P{Any}a/u.exec("a\u{d83d}a")); +assertEquals(["a\u{d83d}a"], /a\p{Any}a/u.exec("a\u{d83d}a")); +assertEquals(["a\u{d83d}a"], /(?:a\P{Any}a|a\p{Any}a)/u.exec("a\u{d83d}a")); +assertNull(/a[\P{Any}]a/u.exec("a\u{d83d}a")); +assertEquals(["a\u{d83d}a"], /a[^\P{Any}]a/u.exec("a\u{d83d}a")); +assertEquals(["a\u{d83d}a"], /a[^\P{Any}x]a/u.exec("a\u{d83d}a")); +assertNull(/a[^\P{Any}x]a/u.exec("axa")); diff --git a/deps/v8/test/mjsunit/regress/regress-796427.js b/deps/v8/test/mjsunit/regress/regress-796427.js new file mode 100644 index 0000000000..c09688d1ec --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-796427.js @@ -0,0 +1,7 @@ +// Copyright 2017 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: --stack-size=150 + +assertThrows(() => "" + { toString: Object.prototype.toLocaleString }, RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-797481.js b/deps/v8/test/mjsunit/regress/regress-797481.js new file mode 100644 index 0000000000..7963dbd3b7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-797481.js @@ -0,0 +1,10 @@ +// Copyright 2017 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: --stack-size=100 + +const a = /x/; + +a.exec = RegExp.prototype.test; +assertThrows(() => RegExp.prototype.test.call(a), RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-797581.js b/deps/v8/test/mjsunit/regress/regress-797581.js new file mode 100644 index 0000000000..17ac0ea50d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-797581.js @@ -0,0 +1,29 @@ +// Copyright 2018 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 --harmony-dynamic-import + +function TryToLoadModule(filename, expect_error, token) { + let caught_error; + + function SetError(e) { + caught_error = e; + } + + import(filename).catch(SetError); + %RunMicrotasks(); + + if (expect_error) { + assertTrue(caught_error instanceof SyntaxError); + assertEquals("Unexpected token " + token, caught_error.message); + } else { + assertEquals(undefined, caught_error); + } +} + +TryToLoadModule("modules-skip-regress-797581-1.js", true, ")"); +TryToLoadModule("modules-skip-regress-797581-2.js", true, ")"); +TryToLoadModule("modules-skip-regress-797581-3.js", true, "..."); +TryToLoadModule("modules-skip-regress-797581-4.js", true, ","); +TryToLoadModule("modules-skip-regress-797581-5.js", false); diff --git a/deps/v8/test/mjsunit/regress/regress-800538.js b/deps/v8/test/mjsunit/regress/regress-800538.js new file mode 100644 index 0000000000..bc420d676c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-800538.js @@ -0,0 +1,6 @@ +// Copyright 2018 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. + +RegExp.prototype.__defineGetter__("global", () => true); +assertEquals("/()/g", /()/.toString()); diff --git a/deps/v8/test/mjsunit/regress/regress-801171.js b/deps/v8/test/mjsunit/regress/regress-801171.js new file mode 100644 index 0000000000..4bd85eeafc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-801171.js @@ -0,0 +1,20 @@ +// Copyright 2018 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. + +let called_custom_unicode_getter = false; +const re = /./; + +function f() { + re.__defineGetter__("unicode", function() { + called_custom_unicode_getter = true; + }); + return 2; +} + +assertEquals(["","",], re[Symbol.split]("abc", { valueOf: f })); + +// The spec mandates retrieving the regexp instance's flags before +// ToUint(limit), i.e. the unicode getter must still be unmodified when +// flags are retrieved. +assertFalse(called_custom_unicode_getter); diff --git a/deps/v8/test/mjsunit/regress/regress-801772.js b/deps/v8/test/mjsunit/regress/regress-801772.js new file mode 100644 index 0000000000..06597e251a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-801772.js @@ -0,0 +1,9 @@ +// Copyright 2018 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. + +function foo(f) { f(); } + +foo(function arguments() { + function skippable() { } +}); diff --git a/deps/v8/test/mjsunit/regress/regress-802060.js b/deps/v8/test/mjsunit/regress/regress-802060.js new file mode 100644 index 0000000000..e975615484 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-802060.js @@ -0,0 +1,24 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function assertEquals(expected, found) { + found.length !== expected.length; +} +assertEquals([], []) +assertEquals("a", "a"); +assertEquals([], []); +function f() { + assertEquals(0, undefined); +} +try { + f(); +} catch (e) { +} +%OptimizeFunctionOnNextCall(f); +try { + f(); +} catch (e) { +} diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-789764.js b/deps/v8/test/mjsunit/regress/regress-crbug-789764.js new file mode 100644 index 0000000000..c377e644fc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-789764.js @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +// Original repro (used to crash): +_v3 = ({ _v7 = (function outer() { + for ([...[]][function inner() {}] in []) { + } + })} = {}) => { +}; +_v3(); + +// Smaller repro (used to crash): +a = (b = !function outer() { for (function inner() {}.foo in []) {} }) => {}; +a(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-791245-1.js b/deps/v8/test/mjsunit/regress/regress-crbug-791245-1.js new file mode 100644 index 0000000000..0d51f8a4a0 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-791245-1.js @@ -0,0 +1,18 @@ +// Copyright 2017 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 + +const s = new Map; + +function foo(s) { + const i = s[Symbol.iterator](); + i.next(); + return i; +} + +console.log(foo(s)); +console.log(foo(s)); +%OptimizeFunctionOnNextCall(foo); +console.log(foo(s)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-791245-2.js b/deps/v8/test/mjsunit/regress/regress-crbug-791245-2.js new file mode 100644 index 0000000000..6734ed2baa --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-791245-2.js @@ -0,0 +1,18 @@ +// Copyright 2017 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 + +const s = new Set; + +function foo(s) { + const i = s[Symbol.iterator](); + i.next(); + return i; +} + +console.log(foo(s)); +console.log(foo(s)); +%OptimizeFunctionOnNextCall(foo); +console.log(foo(s)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-795922.js b/deps/v8/test/mjsunit/regress/regress-crbug-795922.js new file mode 100644 index 0000000000..da2b36740e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-795922.js @@ -0,0 +1,9 @@ +// Copyright 2017 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. + +assertThrows( + // Should throw a syntax error, but not crash. + "({ __proto__: null, __proto__: 1 })", + SyntaxError +); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-798644.js b/deps/v8/test/mjsunit/regress/regress-crbug-798644.js new file mode 100644 index 0000000000..c878a6fda8 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-798644.js @@ -0,0 +1,21 @@ +// Copyright 2018 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 + +let arr = []; +// Make the array large enough to trigger re-checking for compaction. +arr[1000] = 0x1234; + +arr.__defineGetter__(256, function () { + // Remove the getter so we can compact the array. + delete arr[256]; + // Trigger compaction. + arr.unshift(1.1); +}); + +let results = Object.entries(arr); +%HeapObjectVerify(results); +%HeapObjectVerify(arr); +let str = results.toString(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-800077.js b/deps/v8/test/mjsunit/regress/regress-crbug-800077.js new file mode 100644 index 0000000000..13679073fe --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-800077.js @@ -0,0 +1,6 @@ +// Copyright 2018 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. + +var sample = new Float64Array(1); +Reflect.has(sample, undefined); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-800810.js b/deps/v8/test/mjsunit/regress/regress-crbug-800810.js new file mode 100644 index 0000000000..22ac38833e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-800810.js @@ -0,0 +1,13 @@ +// Copyright 2018 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. + +var array = []; +Object.defineProperty(array , 506519, {}); +Object.defineProperty(array , 3, { + get: function () { + Object.defineProperty(array , undefined, { + }) + } +}); +array.includes(61301); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-807096.js b/deps/v8/test/mjsunit/regress/regress-crbug-807096.js new file mode 100644 index 0000000000..845120db6a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-807096.js @@ -0,0 +1,27 @@ +// Copyright 2018 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 --no-lazy + +// For regression testing, it's important that these functions are: +// 1) toplevel +// 2) arrow functions with single-expression bodies +// 3) eagerly compiled + +let f = ({a = (({b = {a = c} = { + a: 0x1234 +}}) => 1)({})}, c) => 1; + +assertThrows(() => f({}), ReferenceError); + +let g = ({a = (async ({b = {a = c} = { + a: 0x1234 +}}) => 1)({})}, c) => a; + +testAsync(assert => { + assert.plan(1); + g({}).catch(e => { + assert.equals("ReferenceError", e.name); + }); +}); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-808192.js b/deps/v8/test/mjsunit/regress/regress-crbug-808192.js new file mode 100644 index 0000000000..3336c0043e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-808192.js @@ -0,0 +1,32 @@ +// Copyright 2018 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. + +// TODO(cbruni): enable always opt once v8:7438 +// Flags: --expose-gc --no-always-opt + +const f = eval(`(function f(i) { + if (i == 0) { + class Derived extends Object { + constructor() { + super(); + ${"this.a=1;".repeat(0x3fffe-8)} + } + } + return Derived; + } + + class DerivedN extends f(i-1) { + constructor() { + super(); + ${"this.a=1;".repeat(0x40000-8)} + } + } + + return DerivedN; +})`); + +let a = new (f(0x7ff))(); +a.a = 1; +gc(); +assertEquals(1, a.a); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-813427.js b/deps/v8/test/mjsunit/regress/regress-crbug-813427.js new file mode 100644 index 0000000000..95fa015de2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-813427.js @@ -0,0 +1,49 @@ +// Copyright 2018 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 + +// Create {count} property assignments. +function createPropertiesAssignment(count) { + let result = ""; + for (let i = 0; i < count; i++) { + result += "this.p"+i+" = undefined;"; + } + return result; +} + +function testSubclassProtoProperties(count) { + const MyClass = eval(`(class MyClass { + constructor() { + ${createPropertiesAssignment(count)} + } + });`); + + class BaseClass {}; + class SubClass extends BaseClass { + constructor() { + super() + } + }; + + const boundMyClass = MyClass.bind(); + %HeapObjectVerify(boundMyClass); + + SubClass.__proto__ = boundMyClass; + var instance = new SubClass(); + + %HeapObjectVerify(instance); + // Create some more instances to complete in-object slack tracking. + let results = []; + for (let i = 0; i < 4000; i++) { + results.push(new SubClass()); + } + var instance = new SubClass(); + %HeapObjectVerify(instance); +} + + +for (let count = 0; count < 10; count++) { + testSubclassProtoProperties(count); +} diff --git a/deps/v8/test/mjsunit/regress/regress-v8-7245.js b/deps/v8/test/mjsunit/regress/regress-v8-7245.js new file mode 100644 index 0000000000..c1a9df2bb3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-v8-7245.js @@ -0,0 +1,6 @@ +// Copyright 2017 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. + +const { revoke } = Proxy.revocable({}, {}); +assertEquals("", revoke.name); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-791810.js b/deps/v8/test/mjsunit/regress/wasm/regress-791810.js new file mode 100644 index 0000000000..cd6c4e2728 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-791810.js @@ -0,0 +1,21 @@ +// Copyright 2017 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. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction('test', kSig_i_i) + .addBody([ + kExprGetLocal, 0x00, // get_local 0 + kExprBlock, kWasmStmt, // block + kExprBr, 0x00, // br depth=0 + kExprEnd, // end + kExprBlock, kWasmStmt, // block + kExprBr, 0x00, // br depth=0 + kExprEnd, // end + kExprBr, 0x00, // br depth=0 + ]) + .exportFunc(); +builder.instantiate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-793551.js b/deps/v8/test/mjsunit/regress/wasm/regress-793551.js new file mode 100644 index 0000000000..8aa0241923 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-793551.js @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction('test', kSig_i_i) + .addBody([ + // body: + kExprGetLocal, 0, // get_local 0 + kExprGetLocal, 0, // get_local 0 + kExprLoop, kWasmStmt, // loop + kExprBr, 0, // br depth=0 + kExprEnd, // end + kExprUnreachable, // unreachable + ]) + .exportFunc(); +builder.instantiate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-797846.js b/deps/v8/test/mjsunit/regress/wasm/regress-797846.js new file mode 100644 index 0000000000..6a4fd5c5f7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-797846.js @@ -0,0 +1,14 @@ +// Copyright 2017 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. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +// We need a module with one valid function. +const builder = new WasmModuleBuilder(); +builder.addFunction('test', kSig_v_v).addBody([]); + +const buffer = builder.toBuffer(); +assertPromiseResult( + WebAssembly.compile(buffer), _ => Realm.createAllowCrossRealmAccess()); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-800756.js b/deps/v8/test/mjsunit/regress/wasm/regress-800756.js new file mode 100644 index 0000000000..2d29997cef --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-800756.js @@ -0,0 +1,15 @@ +// Copyright 2018 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. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addMemory(16, 32); +builder.addFunction(undefined, kSig_i_iii).addBody([ + kExprI32Const, 0, // i32.const 0 + kExprI32LoadMem8S, 0, 0, // i32.load8_s offset=0 align=0 + kExprI32Eqz, // i32.eqz +]); +builder.instantiate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-801850.js b/deps/v8/test/mjsunit/regress/wasm/regress-801850.js new file mode 100644 index 0000000000..ad6ff4c432 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-801850.js @@ -0,0 +1,11 @@ +// Copyright 2018 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. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +var builder = new WasmModuleBuilder(); +let module = new WebAssembly.Module(builder.toBuffer()); +var worker = new Worker('onmessage = function() {};'); +worker.postMessage(module) diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-802244.js b/deps/v8/test/mjsunit/regress/wasm/regress-802244.js new file mode 100644 index 0000000000..0b8decb637 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-802244.js @@ -0,0 +1,22 @@ +// Copyright 2018 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. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction(undefined, kSig_v_iii).addBody([ + kExprI32Const, 0x41, // i32.const 0x41 + kExprLoop, 0x7c, // loop f64 + kExprGetLocal, 0x00, // get_local 0 + kExprGetLocal, 0x01, // get_local 1 + kExprBrIf, 0x01, // br_if depth=1 + kExprGetLocal, 0x00, // get_local 0 + kExprI32Rol, // i32.rol + kExprBrIf, 0x00, // br_if depth=0 + kExprUnreachable, // unreachable + kExprEnd, // end + kExprUnreachable, // unreachable +]); +builder.instantiate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-808980.js b/deps/v8/test/mjsunit/regress/wasm/regress-808980.js new file mode 100644 index 0000000000..884572b895 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-808980.js @@ -0,0 +1,28 @@ +// Copyright 2018 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 --throws + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); +let kTableSize = 3; + +var builder = new WasmModuleBuilder(); +var sig_index1 = builder.addType(kSig_i_v); +builder.addFunction('main', kSig_i_ii).addBody([ + kExprGetLocal, + 0, + kExprCallIndirect, + sig_index1, + kTableZero +]).exportAs('main'); +builder.setFunctionTableBounds(kTableSize, kTableSize); +var m1_bytes = builder.toBuffer(); +var m1 = new WebAssembly.Module(m1_bytes); + +var serialized_m1 = %SerializeWasmModule(m1); +var m1_clone = %DeserializeWasmModule(serialized_m1, m1_bytes); +var i1 = new WebAssembly.Instance(m1_clone); + +i1.exports.main(123123); diff --git a/deps/v8/test/mjsunit/serialize-after-execute.js b/deps/v8/test/mjsunit/serialize-after-execute.js new file mode 100644 index 0000000000..a3e6bc82ae --- /dev/null +++ b/deps/v8/test/mjsunit/serialize-after-execute.js @@ -0,0 +1,15 @@ +// Copyright 2017 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: --cache=after-execute + +function g() { + function h() { + function k() { return 0; }; + return k; + } + return h(); +} + +g(); diff --git a/deps/v8/test/mjsunit/serialize-embedded-error.js b/deps/v8/test/mjsunit/serialize-embedded-error.js index 473c931b30..320fe475b0 100644 --- a/deps/v8/test/mjsunit/serialize-embedded-error.js +++ b/deps/v8/test/mjsunit/serialize-embedded-error.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// --serialize-toplevel --cache=code +// --cache=code var caught = false; try { diff --git a/deps/v8/test/mjsunit/serialize-ic.js b/deps/v8/test/mjsunit/serialize-ic.js index 8e5cd2fd50..74821a9ec3 100644 --- a/deps/v8/test/mjsunit/serialize-ic.js +++ b/deps/v8/test/mjsunit/serialize-ic.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --cache=code --serialize-toplevel +// Flags: --cache=code var foo = []; foo[0] = "bar"; diff --git a/deps/v8/test/mjsunit/testcfg.py b/deps/v8/test/mjsunit/testcfg.py index ff84bc3be5..bc9d69ff33 100644 --- a/deps/v8/test/mjsunit/testcfg.py +++ b/deps/v8/test/mjsunit/testcfg.py @@ -31,7 +31,6 @@ import re from testrunner.local import testsuite from testrunner.objects import testcase -FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") FILES_PATTERN = re.compile(r"//\s+Files:(.*)") ENV_PATTERN = re.compile(r"//\s+Environment Variables:(.*)") SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME") @@ -39,11 +38,7 @@ MODULE_PATTERN = re.compile(r"^// MODULE$", flags=re.MULTILINE) NO_HARNESS_PATTERN = re.compile(r"^// NO HARNESS$", flags=re.MULTILINE) -class MjsunitTestSuite(testsuite.TestSuite): - - def __init__(self, name, root): - super(MjsunitTestSuite, self).__init__(name, root) - +class TestSuite(testsuite.TestSuite): def ListTests(self, context): tests = [] for dirname, dirs, files in os.walk(self.root, followlinks=True): @@ -56,19 +51,19 @@ class MjsunitTestSuite(testsuite.TestSuite): fullpath = os.path.join(dirname, filename) relpath = fullpath[len(self.root) + 1 : -3] testname = relpath.replace(os.path.sep, "/") - test = testcase.TestCase(self, testname) + test = self._create_test(testname) tests.append(test) return tests - def GetParametersForTestCase(self, testcase, context): - source = self.GetSourceForTest(testcase) + def _test_class(self): + return TestCase - flags = testcase.flags + context.mode_flags - env = self._get_env(source) - flags_match = re.findall(FLAGS_PATTERN, source) - for match in flags_match: - flags += match.strip().split() +class TestCase(testcase.TestCase): + def __init__(self, *args, **kwargs): + super(TestCase, self).__init__(*args, **kwargs) + + source = self.get_source() files_list = [] # List of file names to append to command arguments. files_match = FILES_PATTERN.search(source); @@ -79,28 +74,32 @@ class MjsunitTestSuite(testsuite.TestSuite): files_match = FILES_PATTERN.search(source, files_match.end()) else: break - files = [ os.path.normpath(os.path.join(self.root, '..', '..', f)) + files = [ os.path.normpath(os.path.join(self.suite.root, '..', '..', f)) for f in files_list ] - testfilename = os.path.join(self.root, testcase.path + self.suffix()) + testfilename = os.path.join(self.suite.root, + self.path + self._get_suffix()) if SELF_SCRIPT_PATTERN.search(source): files = ( ["-e", "TEST_FILE_NAME=\"%s\"" % testfilename.replace("\\", "\\\\")] + files) - if not context.no_harness and not NO_HARNESS_PATTERN.search(source): - files.append(os.path.join(self.root, "mjsunit.js")) + if NO_HARNESS_PATTERN.search(source): + mjsunit_files = [] + else: + mjsunit_files = [os.path.join(self.suite.root, "mjsunit.js")] + files_suffix = [] if MODULE_PATTERN.search(source): - files.append("--module") - files.append(testfilename) - - all_files = list(files) - if context.isolates: - all_files += ["--isolate"] + files + files_suffix.append("--module") + files_suffix.append(testfilename) - return all_files, flags, env + self._source_files = files + self._source_flags = self._parse_source_flags(source) + self._mjsunit_files = mjsunit_files + self._files_suffix = files_suffix + self._env = self._parse_source_env(source) - def _get_env(self, source): + def _parse_source_env(self, source): env_match = ENV_PATTERN.search(source) env = {} if env_match: @@ -109,11 +108,25 @@ class MjsunitTestSuite(testsuite.TestSuite): env[var] = value return env - def GetSourceForTest(self, testcase): - filename = os.path.join(self.root, testcase.path + self.suffix()) - with open(filename) as f: - return f.read() + def _get_source_flags(self): + return self._source_flags + + def _get_files_params(self, ctx): + files = list(self._source_files) + if not ctx.no_harness: + files += self._mjsunit_files + files += self._files_suffix + if ctx.isolates: + files += ['--isolate'] + files + + return files + + def _get_cmd_env(self): + return self._env + + def _get_source_path(self): + return os.path.join(self.suite.root, self.path + self._get_suffix()) def GetSuite(name, root): - return MjsunitTestSuite(name, root) + return TestSuite(name, root) diff --git a/deps/v8/test/mjsunit/wasm/errors.js b/deps/v8/test/mjsunit/wasm/errors.js index 89066d671a..a90236459f 100644 --- a/deps/v8/test/mjsunit/wasm/errors.js +++ b/deps/v8/test/mjsunit/wasm/errors.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --expose-wasm +// Flags: --expose-wasm --allow-natives-syntax 'use strict'; @@ -170,3 +170,19 @@ function assertConversionError(bytes, imports, msg) { kExprI64Const, 0 ]).exportFunc().end().toBuffer(), {}, "invalid type"); })(); + + +(function InternalDebugTrace() { + var builder = new WasmModuleBuilder(); + var sig = builder.addType(kSig_i_dd); + builder.addImport("mod", "func", sig); + builder.addFunction("main", sig) + .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprCallFunction, 0]) + .exportAs("main") + var main = builder.instantiate({ + mod: { + func: ()=>{%DebugTrace();} + } + }).exports.main; + main(); +})(); diff --git a/deps/v8/test/mjsunit/wasm/grow-memory-detaching.js b/deps/v8/test/mjsunit/wasm/grow-memory-detaching.js new file mode 100644 index 0000000000..da6516afd7 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/grow-memory-detaching.js @@ -0,0 +1,65 @@ +// Copyright 2016 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: --expose-wasm + +load("test/mjsunit/wasm/wasm-constants.js"); +load("test/mjsunit/wasm/wasm-module-builder.js"); + +let module = (() => { + let builder = new WasmModuleBuilder(); + builder.addMemory(1, kV8MaxPages, false); + builder.addFunction("grow_memory", kSig_i_i) + .addBody([kExprGetLocal, 0, kExprGrowMemory, kMemoryZero]) + .exportFunc(); + builder.exportMemoryAs("memory"); + return builder.toModule(); +})(); + +(function TestDetachingViaAPI() { + print("TestDetachingViaAPI..."); + let memory = new WebAssembly.Memory({initial: 1, maximum: 100}); + let growMem = (pages) => memory.grow(pages); + + let b1 = memory.buffer; + assertEquals(kPageSize, b1.byteLength); + + growMem(0); + let b2 = memory.buffer; + assertFalse(b1 === b2); + assertEquals(0, b1.byteLength); + assertEquals(kPageSize, b2.byteLength); + + growMem(1); + let b3 = memory.buffer; + assertFalse(b1 === b3); + assertFalse(b2 === b3); + assertEquals(0, b1.byteLength); + assertEquals(0, b2.byteLength); + assertEquals(2 * kPageSize, b3.byteLength); +})(); + +(function TestDetachingViaBytecode() { + print("TestDetachingViaBytecode..."); + let instance = new WebAssembly.Instance(module); + let growMem = instance.exports.grow_memory; + let memory = instance.exports.memory; + + let b1 = memory.buffer; + assertEquals(kPageSize, b1.byteLength); + + growMem(0); + let b2 = memory.buffer; + assertFalse(b1 === b2); + assertEquals(0, b1.byteLength); + assertEquals(kPageSize, b2.byteLength); + + growMem(1); + let b3 = memory.buffer; + assertFalse(b1 === b3); + assertFalse(b2 === b3); + assertEquals(0, b1.byteLength); + assertEquals(0, b2.byteLength); + assertEquals(2 * kPageSize, b3.byteLength); +})(); diff --git a/deps/v8/test/mjsunit/wasm/indirect-tables.js b/deps/v8/test/mjsunit/wasm/indirect-tables.js index 4c6d9c9f3b..88d1bb719a 100644 --- a/deps/v8/test/mjsunit/wasm/indirect-tables.js +++ b/deps/v8/test/mjsunit/wasm/indirect-tables.js @@ -602,6 +602,47 @@ function js_div(a, b) { return (a / b) | 0; } /signature mismatch/); })(); +(function IndirectCallIntoOtherInstance() { + print("IndirectCallIntoOtherInstance..."); + var mem_1 = new WebAssembly.Memory({initial: 1}); + var mem_2 = new WebAssembly.Memory({initial: 1}); + var view_1 = new Int32Array(mem_1.buffer); + var view_2 = new Int32Array(mem_2.buffer); + view_1[0] = 1; + view_2[0] = 1000; + + let builder = new WasmModuleBuilder(); + let sig = builder.addType(kSig_i_v); + builder.addFunction('main', kSig_i_i) + .addBody([kExprGetLocal, 0, kExprCallIndirect, sig, kTableZero]) + .exportAs('main'); + builder.addImportedMemory('', 'memory', 1); + + builder.setFunctionTableBounds(1, 1); + builder.addExportOfKind('table', kExternalTable); + + let module1 = new WebAssembly.Module(builder.toBuffer()); + let instance1 = new WebAssembly.Instance(module1, {'':{memory:mem_1}}); + + builder = new WasmModuleBuilder(); + builder.addFunction('main', kSig_i_v).addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0]); + builder.addImportedTable('', 'table'); + builder.addFunctionTableInit(0, false, [0], true); + builder.addImportedMemory('', 'memory', 1); + + + let module2 = new WebAssembly.Module(builder.toBuffer()); + let instance2 = new WebAssembly.Instance(module2, { + '': { + table: instance1.exports.table, + memory: mem_2 + } + }); + + assertEquals(instance1.exports.main(0), 1000); +})(); + + (function ImportedFreestandingTable() { print("ImportedFreestandingTable..."); @@ -665,42 +706,40 @@ function js_div(a, b) { return (a / b) | 0; } test(1, 3); })(); -(function IndirectCallIntoOtherInstance() { - print("IndirectCallIntoOtherInstance..."); - var mem_1 = new WebAssembly.Memory({initial: 1}); - var mem_2 = new WebAssembly.Memory({initial: 1}); - var view_1 = new Int32Array(mem_1.buffer); - var view_2 = new Int32Array(mem_2.buffer); - view_1[0] = 1; - view_2[0] = 1000; - - let builder = new WasmModuleBuilder(); - let sig = builder.addType(kSig_i_v); - builder.addFunction('main', kSig_i_i) - .addBody([kExprGetLocal, 0, kExprCallIndirect, sig, kTableZero]) - .exportAs('main'); - builder.addImportedMemory('', 'memory', 1); - builder.setFunctionTableBounds(1, 1); - builder.addExportOfKind('table', kExternalTable); - - let module1 = new WebAssembly.Module(builder.toBuffer()); - let instance1 = new WebAssembly.Instance(module1, {'':{memory:mem_1}}); - - builder = new WasmModuleBuilder(); - builder.addFunction('main', kSig_i_v).addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0]); - builder.addImportedTable('', 'table'); - builder.addFunctionTableInit(0, false, [0], true); - builder.addImportedMemory('', 'memory', 1); +// Remove this test when v8:7232 is addressed comprehensively. +(function TablesAreImmutableInWasmCallstacks() { + print('TablesAreImmutableInWasmCallstacks...'); + let table = new WebAssembly.Table({initial:2, element:'anyfunc'}); + let builder = new WasmModuleBuilder(); + builder.addImport('', 'mutator', kSig_v_v); + builder.addFunction('main', kSig_v_v) + .addBody([ + kExprCallFunction, 0 + ]).exportAs('main'); - let module2 = new WebAssembly.Module(builder.toBuffer()); - let instance2 = new WebAssembly.Instance(module2, { + let module = new WebAssembly.Module(builder.toBuffer()); + let instance = new WebAssembly.Instance(module, { '': { - table: instance1.exports.table, - memory: mem_2 + 'mutator': () => {table.set(0, null);} } }); - assertEquals(instance1.exports.main(0), 1000); + table.set(0, instance.exports.main); + + try { + instance.exports.main(); + assertUnreached(); + } catch (e) { + assertTrue(e instanceof RangeError); + } + try { + instance.exports.main(); + assertUnreached(); + } catch (e) { + assertTrue(e instanceof RangeError); + } + table.set(0, null); + assertEquals(null, table.get(0)); })(); diff --git a/deps/v8/test/mjsunit/wasm/lazy-compilation.js b/deps/v8/test/mjsunit/wasm/lazy-compilation.js index 3d840398a8..fc41fbd622 100644 --- a/deps/v8/test/mjsunit/wasm/lazy-compilation.js +++ b/deps/v8/test/mjsunit/wasm/lazy-compilation.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --wasm-lazy-compilation +// Flags: --wasm-lazy-compilation --allow-natives-syntax load('test/mjsunit/wasm/wasm-constants.js'); load('test/mjsunit/wasm/wasm-module-builder.js'); @@ -46,6 +46,10 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); instance2.exports.call_store(3); assertEquals(3, mem1[0]); assertEquals(0, mem2[0]); + %FreezeWasmLazyCompilation(instance1); + %FreezeWasmLazyCompilation(instance2); + instance2.exports.call_store(7); + assertEquals(7, mem1[0]); })(); (function exportImportedFunction() { @@ -60,4 +64,37 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); const instance2 = builder2.instantiate({A: instance1.exports}); instance2.exports.foo(); + %FreezeWasmLazyCompilation(instance1); + %FreezeWasmLazyCompilation(instance2); + instance2.exports.foo(); +})(); + +(function exportImportedFunctionWithDifferentMemory() { + print(arguments.callee.name); + const builder1 = new WasmModuleBuilder(); + builder1.addMemory(1, 1, true); + builder1.addFunction('store', kSig_v_i) + .addBody([ + kExprI32Const, 0, // i32.const 1 + kExprGetLocal, 0, // get_local 0 + kExprI32StoreMem, 0, 0, // i32.store offset=0 align=0 + ]) + .exportFunc(); + const instance1 = builder1.instantiate(); + const mem1 = new Int32Array(instance1.exports.memory.buffer); + + const builder2 = new WasmModuleBuilder(); + builder2.addMemory(1, 1, true); + const imp_idx = builder2.addImport('A', 'store', kSig_v_i); + builder2.addExport('exp_store', imp_idx); + const instance2 = builder2.instantiate({A: instance1.exports}); + const mem2 = new Int32Array(instance2.exports.memory.buffer); + + instance2.exports.exp_store(3); + assertEquals(3, mem1[0]); + assertEquals(0, mem2[0]); + %FreezeWasmLazyCompilation(instance1); + %FreezeWasmLazyCompilation(instance2); + instance2.exports.exp_store(7); + assertEquals(7, mem1[0]); })(); diff --git a/deps/v8/test/mjsunit/wasm/many-parameters.js b/deps/v8/test/mjsunit/wasm/many-parameters.js index 03d7e09ef3..a56619a6ad 100644 --- a/deps/v8/test/mjsunit/wasm/many-parameters.js +++ b/deps/v8/test/mjsunit/wasm/many-parameters.js @@ -12,10 +12,13 @@ let type_const = [wasmI32Const, wasmF32Const, wasmF64Const]; function f(values, shift, num_const_params, ...args) { assertEquals( values.length + num_const_params, args.length, 'number of arguments'); + const expected = idx => + idx < values.length ? values[(idx + shift) % values.length] : idx; + const msg = 'shifted by ' + shift + ': ' + + 'expected [' + args.map((_, i) => expected(i)).join(', ') + '], got [' + + args.join(', ') + ']'; args.forEach((arg_val, idx) => { - const expected = - idx < values.length ? values[(idx + shift) % values.length] : idx; - assertEquals(expected, arg_val, 'arg #' + idx + ', shifted by ' + shift); + assertEquals(expected(idx), arg_val, 'arg #' + idx + ', ' + msg); }); } diff --git a/deps/v8/test/mjsunit/wasm/module-memory.js b/deps/v8/test/mjsunit/wasm/module-memory.js index f5b5981436..e9d2bb954d 100644 --- a/deps/v8/test/mjsunit/wasm/module-memory.js +++ b/deps/v8/test/mjsunit/wasm/module-memory.js @@ -172,3 +172,26 @@ function testOOBThrows() { } testOOBThrows(); + +function testAddressSpaceLimit() { + // 1TiB, see wasm-memory.h + const kMaxAddressSpace = 1 * 1024 * 1024 * 1024 * 1024; + const kAddressSpacePerMemory = 8 * 1024 * 1024 * 1024; + + try { + let memories = []; + let address_space = 0; + while (address_space <= kMaxAddressSpace + 1) { + memories.push(new WebAssembly.Memory({initial: 1})); + address_space += kAddressSpacePerMemory; + } + } catch (e) { + assertTrue(e instanceof RangeError); + return; + } + failWithMessage("allocated too much memory"); +} + +if(%IsWasmTrapHandlerEnabled()) { + testAddressSpaceLimit(); +} diff --git a/deps/v8/test/mjsunit/wasm/shared-memory.js b/deps/v8/test/mjsunit/wasm/shared-memory.js index fa51a8307f..bbe89a3fe5 100644 --- a/deps/v8/test/mjsunit/wasm/shared-memory.js +++ b/deps/v8/test/mjsunit/wasm/shared-memory.js @@ -7,20 +7,23 @@ load("test/mjsunit/wasm/wasm-constants.js"); load("test/mjsunit/wasm/wasm-module-builder.js"); -function assertMemoryIsValid(memory) { +function assertMemoryIsValid(memory, shared) { assertSame(WebAssembly.Memory.prototype, memory.__proto__); assertSame(WebAssembly.Memory, memory.constructor); assertTrue(memory instanceof Object); assertTrue(memory instanceof WebAssembly.Memory); + if (shared) { + assertTrue(memory.buffer instanceof SharedArrayBuffer); + // Assert that the buffer is frozen when memory is shared. + assertTrue(Object.isFrozen(memory.buffer)); + } } (function TestConstructorWithShared() { print("TestConstructorWithShared"); let memory = new WebAssembly.Memory({ initial: 0, maximum: 10, shared: true}); - assertMemoryIsValid(memory); - // Assert that the buffer is frozen when memory is shared. - assertTrue(Object.isFrozen(memory.buffer)); + assertMemoryIsValid(memory, true); })(); (function TestConstructorWithUndefinedShared() { @@ -36,7 +39,7 @@ function assertMemoryIsValid(memory) { // For numeric values, shared = true. let memory = new WebAssembly.Memory({ initial: 0, maximum: 10, shared: 2098665}); - assertMemoryIsValid(memory); + assertMemoryIsValid(memory, true); })(); (function TestConstructorWithEmptyStringShared() { @@ -101,3 +104,29 @@ function assertMemoryIsValid(memory) { assertThrows(() => new WebAssembly.Instance(module, {m: {imported_mem: memory}}), WebAssembly.LinkError); })(); + +(function TestInstantiateWithSharedDefined() { + print("TestInstantiateWithSharedDefined"); + let builder = new WasmModuleBuilder(); + builder.addMemory(2, 10, true, "shared"); + let module = new WebAssembly.Module(builder.toBuffer()); + let instance = new WebAssembly.Instance(module); + assertMemoryIsValid(instance.exports.memory, true); +})(); + +(function TestAtomicOpWithSharedMemoryDefined() { + print("TestAtomicOpWithSharedMemoryDefined"); + let builder = new WasmModuleBuilder(); + builder.addMemory(2, 10, false, "shared"); + builder.addFunction("main", kSig_i_ii) + .addBody([ + kExprGetLocal, 0, + kExprGetLocal, 1, + kAtomicPrefix, + kExprI32AtomicAdd, 2, 0]) + .exportFunc(); + let module = new WebAssembly.Module(builder.toBuffer()); + let instance = new WebAssembly.Instance(module); + assertEquals(0, instance.exports.main(0, 0x11111111)); + assertEquals(0x11111111, instance.exports.main(0, 0x11111111)); +})(); diff --git a/deps/v8/test/mjsunit/wasm/trap-location.js b/deps/v8/test/mjsunit/wasm/trap-location.js index 0c646c92cd..c4a0f4d787 100644 --- a/deps/v8/test/mjsunit/wasm/trap-location.js +++ b/deps/v8/test/mjsunit/wasm/trap-location.js @@ -86,7 +86,7 @@ let buffer = builder.toBuffer(); // Test async compilation and instantiation. assertPromiseResult(WebAssembly.instantiate(buffer), pair => { - testTrapLocations(pair.instance, 6); + testTrapLocations(pair.instance, 5); }); // Test sync compilation and instantiation. diff --git a/deps/v8/test/mjsunit/wasm/wasm-module-builder.js b/deps/v8/test/mjsunit/wasm/wasm-module-builder.js index d21067b36e..c00c2c8226 100644 --- a/deps/v8/test/mjsunit/wasm/wasm-module-builder.js +++ b/deps/v8/test/mjsunit/wasm/wasm-module-builder.js @@ -121,9 +121,25 @@ class WasmFunctionBuilder { return this; } + getNumLocals() { + let total_locals = 0; + for (let l of this.locals || []) { + for (let type of ["i32", "i64", "f32", "f64", "s128"]) { + total_locals += l[type + "_count"] || 0; + } + } + return total_locals; + } + addLocals(locals, names) { - this.locals = locals; - this.local_names = names; + const old_num_locals = this.getNumLocals(); + if (!this.locals) this.locals = [] + this.locals.push(locals); + if (names) { + if (!this.local_names) this.local_names = []; + const missing_names = old_num_locals - this.local_names.length; + this.local_names.push(...new Array(missing_names), ...names); + } return this; } @@ -409,7 +425,6 @@ class WasmModuleBuilder { } section.emit_u32v(wasm.memory.min); if (has_max) section.emit_u32v(wasm.memory.max); - if (wasm.memory.shared) section.emit_u8(1); }); } @@ -538,9 +553,7 @@ class WasmModuleBuilder { for (let func of wasm.functions) { // Function body length will be patched later. let local_decls = []; - let l = func.locals; - if (l !== undefined) { - let local_decls_count = 0; + for (let l of func.locals || []) { if (l.i32_count > 0) { local_decls.push({count: l.i32_count, type: kWasmI32}); } |