f6f5bafe41
The catch variable is a special VAR-mode variable which is not in a declaration scope. Normally creating such a variable is not possible with DeclareVariable, but Parser bypasses it by calling DeclareLocal directly (which doesn't have the hoisting check). PreParser used to cut corners and declare the catch variable as a LET-mode variable to prevent hoisting. But since LET and VAR variables behave differently when deciding whether they block sloppy block function hoisting, that approach doesn't fly. BUG=v8:5516,chromium:771474 Change-Id: Ic6f5f4996416c9fa59132725c8b0b6b570c72f48 Reviewed-on: https://chromium-review.googlesource.com/700634 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/master@{#48308}
355 lines
8.5 KiB
JavaScript
355 lines
8.5 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();
|
|
})();
|