v8/test/mjsunit/skipping-inner-functions.js
Marja Hölttä dd18faf2cb [parser] Skipping inner funcs: Fix default ctors in PreParser.
Parser creates a FunctionState for default ctors, which affects the
next_function_is_likely_called logic. PreParser needs to match that logic, so
that Parser and PreParser agree about which functions are skippable.

BUG=v8:5515, chromium:773576

Change-Id: I96cb6f5aa68e74389a863355f70a34693a2d1329
Reviewed-on: https://chromium-review.googlesource.com/712579
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48511}
2017-10-12 18:30:01 +00:00

368 lines
8.9 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: --preparser-scope-analysis --enable-slow-asserts
(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.
var 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();
function TestSkippableFunctionInForOfHeader() {
var c;
function inner() {
for (let [a, b = c = function() { return a; }] of [[10]]) {
}
}
inner();
var result = c();
assertEquals(10, result);
}
TestSkippableFunctionInForOfHeader();
function TestSkippableFunctionInForOfBody() {
var c;
function inner() {
for (let [a, b] of [[10, 11]]) {
c = function f() {
return a + b;
}
}
}
inner();
var result = c();
assertEquals(21, result);
}
TestSkippableFunctionInForOfBody();
function TestSkippableFunctionInForOfHeaderAndBody() {
var c1;
var c2;
function inner() {
for (let [a, b = c1 = function() { return a; }] of [[10]]) {
c2 = function f() {
return a + 1;
}
}
}
inner();
var result = c1() + c2();
assertEquals(21, result);
}
TestSkippableFunctionInForOfHeaderAndBody();
(function TestSkippableGeneratorInSloppyBlock() {
var result = 0;
function lazy(ctxt_alloc_param) {
var ctxt_alloc_var = 10;
{
function *skip_me() {
result = ctxt_alloc_param + ctxt_alloc_var;
yield 3;
}
return skip_me;
}
}
// Test that parameters and variables of the outer function get context
// allocated even if we skip the inner function.
assertEquals(3, lazy(9)().next().value);
assertEquals(19, result);
})();
(function TestRestoringDataToAsyncArrowFunctionWithNonSimpleParams_1() {
// Regression test for
// https://bugs.chromium.org/p/chromium/issues/detail?id=765532
function lazy() {
// The arrow function is not skippable, but we need to traverse its scopes
// and restore data to them.
async(a=0) => { const d = 0; }
function skippable() {}
}
lazy();
})();
(function TestRestoringDataToAsyncArrowFunctionWithNonSimpleParams_2() {
// Regression test for
// https://bugs.chromium.org/p/chromium/issues/detail?id=765532
function lazy() {
// The arrow function is not skippable, but we need to traverse its scopes
// and restore data to them.
async(...a) => { const d = 0; }
function skippable() {}
}
lazy();
})();
(function TestSloppyBlockFunctionShadowingCatchVariable() {
// Regression test for
// https://bugs.chromium.org/p/chromium/issues/detail?id=771474
function lazy() {
try {
} catch (my_var) {
if (false) {
function my_var() { }
}
}
}
lazy();
})();
(function TestLazinessDecisionWithDefaultConstructors() {
// Regression test for
// https://bugs.chromium.org/p/chromium/issues/detail?id=773576
// The problem was that Parser and PreParser treated default constructors
// differently, and that threw off the "next / previous function is likely
// called" logic.
function lazy(p = (function() {}, class {}, function() {}, class { method1() { } })) { }
lazy();
})();