| // 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(); |
| })(); |
| |
| (function TestOneByteTwoByteMismatch() { |
| // Regression test for |
| // https://bugs.chromium.org/p/v8/issues/detail?id=7428 |
| |
| let name = 'weird_string\u2653'.slice(0, 12); |
| let o = {}; |
| o[name] = null; |
| var x; |
| eval('x = function weird_string() { function skip() {} };'); |
| x(); |
| })(); |