e7a46253f2
In some cases, PreParser cannot replicate the Scope structure created by Parser. It happens esp. with arrow function parameters, since the relevant information is already lost by the time we figure out it's an arrow function. In these cases, PreParser should bail out of trying to create data for skipping inner functions. Implementation notes: - The arrow function case is more fundamental; the non-arrow case could be hacked together somehow if we implemented tracking is_simple for each param separately; but now that it's possible to bail out consistently from both cases, I don't think the is_simple complication is worth it. - The added mjsunit test cases are based on the test262 test cases which exposed the problem. - cctest/preparser/PreParserScopeAnalysis was exercising similar cases, but the problem didn't show up because the function parameters didn't contain skippable functions. Those test cases have been repurposed for testing the bailout. - Extra precaution: the bailout tests are in a separate file, to guard from the bug that a bailout case results in bailing out of *all* data creation, which would make all skipping tests in the same file useless. BUG=v8:5516 Change-Id: I4324749a5ec602fa5d7dc27647ade0284a6842fe Reviewed-on: https://chromium-review.googlesource.com/599849 Reviewed-by: Adam Klein <adamk@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/master@{#47170}
251 lines
6.1 KiB
JavaScript
251 lines
6.1 KiB
JavaScript
// 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: --experimental-preparser-scope-analysis
|
|
|
|
(function TestBasicSkipping() {
|
|
var result = 0;
|
|
|
|
function lazy(ctxt_alloc_param) {
|
|
var ctxt_alloc_var = 10;
|
|
function skip_me() {
|
|
result = ctxt_alloc_param + ctxt_alloc_var;
|
|
}
|
|
return skip_me;
|
|
}
|
|
// Test that parameters and variables of the outer function get context
|
|
// allocated even if we skip the inner function.
|
|
lazy(9)();
|
|
assertEquals(19, result);
|
|
})();
|
|
|
|
(function TestSkippingFunctionWithEval() {
|
|
var result = 0;
|
|
|
|
function lazy(ctxt_alloc_param) {
|
|
var ctxt_alloc_var = 10;
|
|
function skip_me() {
|
|
eval('result = ctxt_alloc_param + ctxt_alloc_var');
|
|
}
|
|
return skip_me;
|
|
}
|
|
// Test that parameters and variables of the outer function get context
|
|
// allocated even if we skip the inner function.
|
|
lazy(9)();
|
|
assertEquals(19, result);
|
|
})();
|
|
|
|
(function TestCtxtAllocatingNonSimpleParams1() {
|
|
var result = 0;
|
|
|
|
function lazy([other_param1, ctxt_alloc_param, other_param2]) {
|
|
function skip_me() {
|
|
result = ctxt_alloc_param;
|
|
}
|
|
return skip_me;
|
|
}
|
|
// Test that parameters and variables of the outer function get context
|
|
// allocated even if we skip the inner function.
|
|
lazy([30, 29, 28])();
|
|
assertEquals(29, result);
|
|
})();
|
|
|
|
(function TestCtxtAllocatingNonSimpleParams2() {
|
|
var result = 0;
|
|
|
|
function lazy({a: other_param1, b: ctxt_alloc_param, c: other_param2}) {
|
|
function skip_me() {
|
|
result = ctxt_alloc_param;
|
|
}
|
|
return skip_me;
|
|
}
|
|
// Test that parameters and variables of the outer function get context
|
|
// allocated even if we skip the inner function.
|
|
lazy({a: 31, b: 32, c: 33})();
|
|
assertEquals(32, result);
|
|
})();
|
|
|
|
(function TestCtxtAllocatingNonSimpleParams3() {
|
|
var result = 0;
|
|
|
|
function lazy(...ctxt_alloc_param) {
|
|
function skip_me() {
|
|
result = ctxt_alloc_param;
|
|
}
|
|
return skip_me;
|
|
}
|
|
// Test that parameters and variables of the outer function get context
|
|
// allocated even if we skip the inner function.
|
|
lazy(34, 35)();
|
|
assertEquals([34, 35], result);
|
|
})();
|
|
|
|
// Skippable top level functions.
|
|
let result = 0;
|
|
function lazy_top_level(ctxt_alloc_param) {
|
|
let ctxt_alloc_var = 24;
|
|
function skip_me() {
|
|
result = ctxt_alloc_param + ctxt_alloc_var;
|
|
}
|
|
skip_me();
|
|
}
|
|
|
|
lazy_top_level(10);
|
|
assertEquals(34, result);
|
|
|
|
// Tests for using a function name in an inner function.
|
|
var TestUsingNamedExpressionName1 = function this_is_the_name() {
|
|
function inner() {
|
|
this_is_the_name;
|
|
}
|
|
inner();
|
|
}
|
|
TestUsingNamedExpressionName1();
|
|
|
|
function TestUsingNamedExpressionName2() {
|
|
let f = function this_is_the_name() {
|
|
function inner() {
|
|
this_is_the_name;
|
|
}
|
|
inner();
|
|
}
|
|
f();
|
|
}
|
|
TestUsingNamedExpressionName2();
|
|
|
|
function TestSkippedFunctionInsideLoopInitializer() {
|
|
let saved_func;
|
|
for (let i = 0, f = function() { return i }; i < 1; ++i) {
|
|
saved_func = f;
|
|
}
|
|
assertEquals(0, saved_func());
|
|
}
|
|
TestSkippedFunctionInsideLoopInitializer();
|
|
|
|
(function TestSkippedFunctionWithParameters() {
|
|
var result = 0;
|
|
|
|
function lazy(ctxt_alloc_param) {
|
|
var ctxt_alloc_var = 10;
|
|
function skip_me(param1, param2) {
|
|
result = ctxt_alloc_param + ctxt_alloc_var + param1 + param2;
|
|
}
|
|
return skip_me;
|
|
}
|
|
lazy(9)(8, 7);
|
|
assertEquals(34, result);
|
|
})();
|
|
|
|
function TestSkippingDeeperLazyFunctions() {
|
|
let result = 0;
|
|
function inner_lazy(ctxt_alloc_param) {
|
|
let ctxt_alloc_var = 13;
|
|
function skip_me() {
|
|
result = ctxt_alloc_param + ctxt_alloc_var;
|
|
}
|
|
return skip_me;
|
|
}
|
|
let f = inner_lazy(12);
|
|
f();
|
|
assertEquals(25, result);
|
|
}
|
|
|
|
TestSkippingDeeperLazyFunctions();
|
|
|
|
function TestEagerFunctionsBetweenLazyFunctions() {
|
|
let result = 0;
|
|
// We produce one data set for TestEagerFunctionsBetweenLazyFunctions and
|
|
// another one for inner. The variable data for eager belongs to the former
|
|
// data set.
|
|
let ctxt_allocated1 = 3;
|
|
(function eager() {
|
|
let ctxt_allocated2 = 4;
|
|
function inner() {
|
|
result = ctxt_allocated1 + ctxt_allocated2;
|
|
}
|
|
return inner;
|
|
})()();
|
|
assertEquals(7, result);
|
|
}
|
|
|
|
TestEagerFunctionsBetweenLazyFunctions();
|
|
|
|
function TestEagerNotIifeFunctionsBetweenLazyFunctions() {
|
|
let result = 0;
|
|
// We produce one data set for TestEagerFunctionsBetweenLazyFunctions and
|
|
// another one for inner. The variable data for eager belongs to the former
|
|
// data set.
|
|
let ctxt_allocated1 = 3;
|
|
(function eager_not_iife() {
|
|
let ctxt_allocated2 = 4;
|
|
function inner() {
|
|
result = ctxt_allocated1 + ctxt_allocated2;
|
|
}
|
|
return inner;
|
|
}); // Function not called; not an iife.
|
|
// This is just a regression test. We cannot test that the context allocation
|
|
// was done correctly (since there's no way to call eager_not_iife), but code
|
|
// like this used to trigger some DCHECKs.
|
|
}
|
|
|
|
TestEagerNotIifeFunctionsBetweenLazyFunctions();
|
|
|
|
// Regression test for functions inside a lazy arrow function. (Only top-level
|
|
// arrow functions are lazy, so this cannot be wrapped in a function.)
|
|
result = 0;
|
|
let f1 = (ctxt_alloc_param) => {
|
|
let ctxt_alloc_var = 10;
|
|
function inner() {
|
|
result = ctxt_alloc_param + ctxt_alloc_var;
|
|
}
|
|
return inner;
|
|
}
|
|
f1(9)();
|
|
assertEquals(19, result);
|
|
|
|
function TestStrictEvalInParams() {
|
|
"use strict";
|
|
var result = 0;
|
|
|
|
function lazy(a = function() { return 2; }, b = eval('3')) {
|
|
function skip_me() {
|
|
result = a() + b;
|
|
}
|
|
return skip_me;
|
|
}
|
|
lazy()();
|
|
assertEquals(5, result);
|
|
|
|
function not_skippable_either() {}
|
|
}
|
|
|
|
TestStrictEvalInParams();
|
|
|
|
function TestSloppyEvalInFunctionWithComplexParams() {
|
|
var result = 0;
|
|
|
|
function lazy1(ctxt_alloc_param = 2) {
|
|
var ctxt_alloc_var = 3;
|
|
function skip_me() {
|
|
result = ctxt_alloc_param + ctxt_alloc_var;
|
|
}
|
|
eval('');
|
|
return skip_me;
|
|
}
|
|
lazy1()();
|
|
assertEquals(5, result);
|
|
|
|
function lazy2(ctxt_alloc_param = 4) {
|
|
var ctxt_alloc_var = 5;
|
|
function skip_me() {
|
|
eval('result = ctxt_alloc_param + ctxt_alloc_var;');
|
|
}
|
|
return skip_me;
|
|
}
|
|
lazy2()();
|
|
assertEquals(9, result);
|
|
}
|
|
|
|
TestSloppyEvalInFunctionWithComplexParams();
|