v8/test/mjsunit/es6/tail-call-megatest.js
ishell c67b5096cd [turbofan] Fixing ES6 tail calls in Turbofan.
In case when F inlined normal call to G which tail calls H we should not write translation for G for the tail call site.
Otherwise we will see G in a stack trace inside H.

This CL also adds a "megatest" which tests product of the following cases:
1) tail caller is inlined/not-inlined
2) tail callee is inlined/not-inlined
3) tail caller has an arguments adaptor frame above or not
4) tail callee has an arguments adaptor frame above or not
5) tail callee is a normal/bound/proxy function

Note that tests for not yet supported cases are not run for now.

BUG=v8:4698
LOG=N

Review URL: https://codereview.chromium.org/1709583002

Cr-Commit-Position: refs/heads/master@{#34108}
2016-02-18 10:13:20 +00:00

176 lines
5.0 KiB
JavaScript

// 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: --allow-natives-syntax --harmony-tailcalls --no-turbo-inlining
"use strict";
Error.prepareStackTrace = (error,stack) => {
error.strace = stack;
return error.message + "\n at " + stack.join("\n at ");
}
function CheckStackTrace(expected) {
var e = new Error();
e.stack; // prepare stack trace
var stack = e.strace;
assertEquals("CheckStackTrace", stack[0].getFunctionName());
for (var i = 0; i < expected.length; i++) {
assertEquals(expected[i].name, stack[i + 1].getFunctionName());
}
}
%NeverOptimizeFunction(CheckStackTrace);
function CheckArguments(expected, args) {
args = Array.prototype.slice.call(args);
assertEquals(expected, args);
}
%NeverOptimizeFunction(CheckArguments);
var CAN_INLINE_COMMENT = "// Let it be inlined.";
var DONT_INLINE_COMMENT = (function() {
var line = "// Don't inline. Don't inline. Don't inline. Don't inline.";
for (var i = 0; i < 4; i++) {
line += "\n " + line;
}
return line;
})();
function ident_source(source, ident) {
ident = " ".repeat(ident);
return ident + source.replace(/\n/gi, "\n" + ident);
}
function run_tests() {
function f_template_normal(f_inlinable, f_args) {
var f_comment = f_inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT;
var lines = [
`function f(a) {`,
` ${f_comment}`,
` assertEquals(undefined, this);`,
` CheckArguments([${f_args}], arguments);`,
` CheckStackTrace([f, test]);`,
` %DeoptimizeNow();`,
` CheckArguments([${f_args}], arguments);`,
` CheckStackTrace([f, test]);`,
` return 42;`,
`}`,
];
return lines.join("\n");
}
function f_template_bound(f_inlinable, f_args) {
var f_comment = f_inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT;
var lines = [
`function ff(a) {`,
` ${f_comment}`,
` assertEquals(153, this.a);`,
` CheckArguments([${f_args}], arguments);`,
` CheckStackTrace([ff, test]);`,
` %DeoptimizeNow();`,
` CheckArguments([${f_args}], arguments);`,
` CheckStackTrace([ff, test]);`,
` return 42;`,
`}`,
`var f = ff.bind({a: 153});`,
];
return lines.join("\n");
}
function f_template_proxy(f_inlinable, f_args) {
var f_comment = f_inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT;
var lines = [
`function ff(a) {`,
` ${f_comment}`,
` assertEquals(undefined, this);`,
` CheckArguments([${f_args}], arguments);`,
` CheckStackTrace([f, test]);`,
` %DeoptimizeNow();`,
` CheckArguments([${f_args}], arguments);`,
` CheckStackTrace([f, test]);`,
` return 42;`,
`}`,
`var f = new Proxy(ff, {});`,
];
return lines.join("\n");
}
function g_template(g_inlinable, f_args, g_args) {
var g_comment = g_inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT;
var lines = [
`function g(a) {`,
` ${g_comment}`,
` CheckArguments([${g_args}], arguments);`,
` return f(${f_args});`,
`}`,
];
return lines.join("\n");
}
function test_template(f_source, g_source, g_args,
f_inlinable, g_inlinable) {
f_source = ident_source(f_source, 2);
g_source = ident_source(g_source, 2);
var lines = [
`(function() {`,
f_source,
g_source,
` function test() {`,
` assertEquals(42, g(${g_args}));`,
` }`,
` ${f_inlinable ? "%SetForceInlineFlag(f)" : ""};`,
` ${g_inlinable ? "%SetForceInlineFlag(g)" : ""};`,
``,
` test();`,
` %OptimizeFunctionOnNextCall(test);`,
` try { %OptimizeFunctionOnNextCall(f); } catch(e) {}`,
` try { %OptimizeFunctionOnNextCall(ff); } catch(e) {}`,
` %OptimizeFunctionOnNextCall(g);`,
` test();`,
`})();`,
``,
];
var source = lines.join("\n");
return source;
}
// TODO(v8:4698), TODO(ishell): support all commented cases.
var f_args_variants = ["", "1", "1, 2"];
var g_args_variants = [/*"",*/ "10", /*"10, 20"*/];
var f_inlinable_variants = [/*true,*/ false];
var g_inlinable_variants = [true, false];
var f_variants = [
f_template_normal,
f_template_bound,
f_template_proxy
];
f_variants.forEach((f_template) => {
f_args_variants.forEach((f_args) => {
g_args_variants.forEach((g_args) => {
f_inlinable_variants.forEach((f_inlinable) => {
g_inlinable_variants.forEach((g_inlinable) => {
var f_source = f_template(f_inlinable, f_args);
var g_source = g_template(g_inlinable, f_args, g_args);
var source = test_template(f_source, g_source, g_args,
f_inlinable, g_inlinable);
print("====================");
print(source);
eval(source);
});
});
});
});
});
}
run_tests();