v8/test/mjsunit/harmony/do-expressions.js
Ross McIlroy 05207b098a [Interpreter] Replace --ignition flag with a --stress-fullcodegen
Removes the --ignition flag which is now on by default. Adds a
--stress-fullcodegen flag which enables running all functions supported
by fullcodegen to be compiled by fullcodegen.

This will enable moving parser internalization later when we are not
stressing fullcodegen or compiling asm.js functions.

BUG=v8:5203, v8:6409, v8:6589

Change-Id: I7fa68016d4e734755434ec0b4e749ef65ffa7f4e
Reviewed-on: https://chromium-review.googlesource.com/565569
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46635}
2017-07-13 13:05:00 +00:00

307 lines
7.1 KiB
JavaScript

// Copyright 2015 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-do-expressions --allow-natives-syntax --no-always-opt
// Flags: --opt --no-stress-fullcodegen
function returnValue(v) { return v; }
function MyError() {}
var global = this;
function TestBasic() {
// Looping and lexical declarations
assertEquals(512, returnValue(do {
let n = 2;
for (let i = 0; i < 4; i++) n <<= 2;
}));
// Strings do the right thing
assertEquals("spooky halloween", returnValue(do {
"happy halloween".replace('happy', 'spooky');
}));
// Do expressions with no completion produce an undefined value
assertEquals(undefined, returnValue(do {}));
assertEquals(undefined, returnValue(do { var x = 99; }));
assertEquals(undefined, returnValue(do { function f() {}; }));
assertEquals(undefined, returnValue(do { let z = 33; }));
// Propagation of exception
assertThrows(function() {
(do {
throw new MyError();
"potatoes";
});
}, MyError);
assertThrows(function() {
return do {
throw new MyError();
"potatoes";
};
}, MyError);
// Return value within do-block overrides `return |do-expression|`
assertEquals("inner-return", (function() {
return "outer-return" + do {
return "inner-return";
"";
};
})());
var count = 0, n = 1;
// Breaking out |do-expression|
assertEquals(3, (function() {
for (var i = 0; i < 10; ++i) (count += 2 * do { if (i === 3) break; ++n });
return i;
})());
// (2 * 2) + (2 * 3) + (2 * 4)
assertEquals(18, count);
// Continue in |do-expression|
count = 0, n = 1;
assertEquals([1, 3, 5, 7, 9], (function() {
var values = [];
for (var i = 0; i < 10; ++i) {
count += 2 * (do {
if ((i & 1) === 0) continue;
values.push(i);
++n;
}) + 1;
}
// (2*2) + 1 + (2*3) + 1 + (2*4) + 1 + (2*5) + 1 + (2*6) + 1
return values;
})());
assertEquals(count, 45);
assertThrows("(do { break; });", SyntaxError);
assertThrows("(do { continue; });", SyntaxError);
// Real-world use case for desugaring
var array = [1, 2, 3, 4, 5], iterable = [6, 7, 8,9];
assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], do {
for (var element of iterable) array.push(element);
array;
});
// Nested do-expressions
assertEquals(125, do { (do { (do { 5 * 5 * 5 }) }) });
// Directives are not honoured
(do {
"use strict";
foo = 80;
assertEquals(foo, 80);
});
// Non-empty operand stack testing
var O = {
method1() {
let x = 256;
return x + do {
for (var i = 0; i < 4; ++i) x += i;
} + 17;
},
method2() {
let x = 256;
this.reset();
return x + do {
for (var i = 0; i < this.length(); ++i) x += this.index() * 2;
};
},
_index: 0,
index() {
return ++this._index;
},
_length: 4,
length() { return this._length; },
reset() { this._index = 0; }
};
assertEquals(535, O["method" + do { 1 } + ""]());
assertEquals(532, O["method" + do { ({ valueOf() { return "2"; } }); }]());
assertEquals(532, O[
do { let s = ""; for (let c of "method") s += c; } + "2"]());
}
TestBasic();
function TestDeoptimization1() {
function f(v) {
return 88 + do {
v.a * v.b + v.c;
};
}
var o1 = {};
o1.a = 10;
o1.b = 5;
o1.c = 50;
var o2 = {};
o2.c = 100;
o2.a = 10;
o2.b = 10;
assertEquals(188, f(o1));
assertEquals(188, f(o1));
%OptimizeFunctionOnNextCall(f);
assertEquals(188, f(o1));
assertOptimized(f);
assertEquals(288, f(o2));
assertUnoptimized(f);
assertEquals(288, f(o2));
}
TestDeoptimization1();
function TestInParameterInitializers() {
var first_name = "George";
var last_name = "Jetson";
function fn1(name = do { first_name + " " + last_name }) {
return name;
}
assertEquals("George Jetson", fn1());
var _items = [1, 2, 3, NaN, 4, 5];
function fn2(items = do {
let items = [];
for (var el of _items) {
if (el !== el) {
items;
break;
}
items.push(el), items;
}
}) {
return items;
}
assertEquals([1, 2, 3], fn2());
function thrower() { throw new MyError(); }
function fn3(exception = do { try { thrower(); } catch (e) { e } }) {
return exception;
}
assertDoesNotThrow(fn3);
assertInstanceof(fn3(), MyError);
function fn4(exception = do { throw new MyError() }) {}
function catcher(fn) {
try {
fn();
assertUnreachable("fn() initializer should throw");
} catch (e) {
assertInstanceof(e, MyError);
}
}
catcher(fn4);
}
TestInParameterInitializers();
function TestWithEval() {
(function sloppy1() {
assertEquals(do { eval("var x = 5"), x }, 5);
assertEquals(x, 5);
})();
assertThrows(function strict1() {
"use strict";
(do { eval("var x = 5"), x }, 5);
}, ReferenceError);
assertThrows(function strict2() {
(do { eval("'use strict'; var x = 5"), x }, 5);
}, ReferenceError);
}
TestWithEval();
function TestHoisting() {
(do { var a = 1; });
assertEquals(a, 1);
assertEquals(global.a, undefined);
(do {
for (let it of [1, 2, 3, 4, 5]) {
var b = it;
}
});
assertEquals(b, 5);
assertEquals(global.b, undefined);
{
let x = 1
// TODO(caitp): ensure VariableStatements in |do-expressions| in parameter
// initializers, are evaluated in the same VariableEnvironment as they would
// be for eval().
// function f1(a = do { var x = 2 }, b = x) { return b }
// assertEquals(1, f1())
// function f2(a = x, b = do { var x = 2 }) { return a }
// assertEquals(1, f2())
function f3({a = do { var x = 2 }, b = x}) { return b }
assertEquals(2, f3({}))
function f4({a = x, b = do { var x = 2 }}) { return b }
assertEquals(undefined, f4({}))
function f5(a = do { var y = 0 }) {}
assertThrows(() => y, ReferenceError)
}
// TODO(caitp): Always block-scope function declarations in |do| expressions
//(do {
// assertEquals(true, inner_func());
// function inner_func() { return true; }
//});
//assertThrows(function() { return innerFunc(); }, ReferenceError);
}
TestHoisting();
// v8:4661
function tryFinallySimple() { (do { try {} finally {} }); }
tryFinallySimple();
tryFinallySimple();
tryFinallySimple();
tryFinallySimple();
var finallyRanCount = 0;
function tryFinallyDoExpr() {
return (do {
try {
throw "BOO";
} catch (e) {
"Caught: " + e + " (" + finallyRanCount + ")"
} finally {
++finallyRanCount;
}
});
}
assertEquals("Caught: BOO (0)", tryFinallyDoExpr());
assertEquals(1, finallyRanCount);
assertEquals("Caught: BOO (1)", tryFinallyDoExpr());
assertEquals(2, finallyRanCount);
assertEquals("Caught: BOO (2)", tryFinallyDoExpr());
assertEquals(3, finallyRanCount);
assertEquals("Caught: BOO (3)", tryFinallyDoExpr());
assertEquals(4, finallyRanCount);
function TestOSR() {
var numbers = do {
let nums = [];
for (let i = 0; i < 1000; ++i) {
let value = (Math.random() * 100) | 0;
nums.push(value === 0 ? 1 : value), nums;
}
};
assertEquals(numbers.length, 1000);
}
for (var i = 0; i < 64; ++i) TestOSR();