LCOV - code coverage report
Current view: top level - test/cctest/parsing - test-preparser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 89 89 100.0 %
Date: 2017-10-20 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/ast/ast.h"
       6             : #include "src/compiler.h"
       7             : #include "src/objects-inl.h"
       8             : #include "src/parsing/parse-info.h"
       9             : #include "src/parsing/parsing.h"
      10             : #include "src/parsing/preparsed-scope-data.h"
      11             : 
      12             : #include "test/cctest/cctest.h"
      13             : #include "test/cctest/scope-test-helper.h"
      14             : #include "test/cctest/unicode-helpers.h"
      15             : 
      16             : namespace {
      17             : 
      18             : enum SkipTests {
      19             :   DONT_SKIP = 0,
      20             :   // Skip if the test function declares itself strict, otherwise don't skip.
      21             :   SKIP_STRICT_FUNCTION = 1,
      22             :   // Skip if there's a "use strict" directive above the test.
      23             :   SKIP_STRICT_OUTER = 1 << 1,
      24             :   SKIP_ARROW = 1 << 2,
      25             :   SKIP_STRICT = SKIP_STRICT_FUNCTION | SKIP_STRICT_OUTER
      26             : };
      27             : 
      28             : enum class PreciseMaybeAssigned { YES, NO };
      29             : 
      30             : enum class Bailout { BAILOUT_IF_OUTER_SLOPPY, NO };
      31             : 
      32             : }  // namespace
      33             : 
      34       23724 : TEST(PreParserScopeAnalysis) {
      35           6 :   i::FLAG_lazy_inner_functions = true;
      36           6 :   i::FLAG_preparser_scope_analysis = true;
      37           6 :   i::FLAG_aggressive_lazy_inner_functions = true;
      38             :   i::Isolate* isolate = CcTest::i_isolate();
      39             :   i::Factory* factory = isolate->factory();
      40             :   i::HandleScope scope(isolate);
      41          12 :   LocalContext env;
      42             : 
      43             :   struct {
      44             :     const char* code;
      45             :     bool strict_outer;
      46             :     bool strict_test_function;
      47             :     bool arrow;
      48             :     std::vector<unsigned> location;  // "Directions" to the relevant scope.
      49             :   } outers[] = {
      50             :       // Normal case (test function at the laziness boundary):
      51             :       {"(function outer() { function test(%s) { %s \n"
      52             :        "function skippable() { } } })();",
      53             :        false,
      54             :        false,
      55             :        false,
      56             :        {0, 0}},
      57             : 
      58             :       {"(function outer() { let test2 = function test(%s) { %s \n"
      59             :        "function skippable() { } } })();",
      60             :        false,
      61             :        false,
      62             :        false,
      63             :        {0, 0}},
      64             : 
      65             :       // Arrow functions (they can never be at the laziness boundary):
      66             :       {"(function outer() { function inner() { (%s) => { %s } \n"
      67             :        "function skippable() { } } })();",
      68             :        false,
      69             :        false,
      70             :        true,
      71             :        {0, 0}},
      72             : 
      73             :       // Repeat the above mentioned cases w/ outer function declaring itself
      74             :       // strict:
      75             :       {"(function outer() { 'use strict'; function test(%s) { %s \n"
      76             :        "function skippable() { } } })();",
      77             :        true,
      78             :        false,
      79             :        false,
      80             :        {0, 0}},
      81             : 
      82             :       {"(function outer() { 'use strict'; function inner() { "
      83             :        "(%s) => { %s } \nfunction skippable() { } } })();",
      84             :        true,
      85             :        false,
      86             :        true,
      87             :        {0, 0}},
      88             : 
      89             :       // ... and with the test function declaring itself strict:
      90             :       {"(function outer() { function test(%s) { 'use strict'; %s \n"
      91             :        "function skippable() { } } })();",
      92             :        false,
      93             :        true,
      94             :        false,
      95             :        {0, 0}},
      96             : 
      97             :       {"(function outer() { function inner() { "
      98             :        "(%s) => { 'use strict'; %s } \nfunction skippable() { } } })();",
      99             :        false,
     100             :        true,
     101             :        true,
     102             :        {0, 0}},
     103             : 
     104             :       // Methods containing skippable functions.
     105             :       {"class MyClass { constructor(%s) { %s \n"
     106             :        "function skippable() { } } }",
     107             :        true,
     108             :        true,
     109             :        false,
     110             :        {0, 0}},
     111             : 
     112             :       {"class MyClass { test(%s) { %s \n"
     113             :        "function skippable() { } } }",
     114             :        true,
     115             :        true,
     116             :        false,
     117             :        // The default constructor is scope 0 inside the class.
     118             :        {0, 1}},
     119             : 
     120             :       // FIXME(marja): Generators and async functions
     121         114 :   };
     122             : 
     123             :   struct Inner {
     124          78 :     Inner(const char* s) : source(s) {}  // NOLINT
     125          60 :     Inner(const char* s, SkipTests skip) : source(s), skip(skip) {}
     126             :     Inner(const char* s, SkipTests skip, PreciseMaybeAssigned precise)
     127          12 :         : source(s), skip(skip), precise_maybe_assigned(precise) {}
     128             : 
     129          24 :     Inner(const char* p, const char* s) : params(p), source(s) {}
     130             :     Inner(const char* p, const char* s, SkipTests skip)
     131          42 :         : params(p), source(s), skip(skip) {}
     132             :     Inner(const char* p, const char* s, SkipTests skip,
     133             :           PreciseMaybeAssigned precise)
     134          24 :         : params(p), source(s), skip(skip), precise_maybe_assigned(precise) {}
     135             :     Inner(const char* p, const char* s, SkipTests skip, Bailout bailout)
     136           6 :         : params(p), source(s), skip(skip), bailout(bailout) {}
     137             : 
     138             :     const char* params = "";
     139             :     const char* source;
     140             :     SkipTests skip = DONT_SKIP;
     141             :     PreciseMaybeAssigned precise_maybe_assigned = PreciseMaybeAssigned::YES;
     142             :     Bailout bailout = Bailout::NO;
     143             :   } inners[] = {
     144             :       // Simple cases
     145             :       {"var1;"},
     146             :       {"var1 = 5;"},
     147             :       {"if (true) {}"},
     148             :       {"function f1() {}"},
     149             :       {"test;"},
     150             :       {"test2;"},
     151             : 
     152             :       // Var declarations and assignments.
     153             :       {"var var1;"},
     154             :       {"var var1; var1 = 5;"},
     155             :       {"if (true) { var var1; }", DONT_SKIP, PreciseMaybeAssigned::NO},
     156             :       {"if (true) { var var1; var1 = 5; }"},
     157             :       {"var var1; function f() { var1; }"},
     158             :       {"var var1; var1 = 5; function f() { var1; }"},
     159             :       {"var var1; function f() { var1 = 5; }"},
     160             :       {"function f1() { f2(); } function f2() {}"},
     161             : 
     162             :       // Let declarations and assignments.
     163             :       {"let var1;"},
     164             :       {"let var1; var1 = 5;"},
     165             :       {"if (true) { let var1; }"},
     166             :       {"if (true) { let var1; var1 = 5; }"},
     167             :       {"let var1; function f() { var1; }"},
     168             :       {"let var1; var1 = 5; function f() { var1; }"},
     169             :       {"let var1; function f() { var1 = 5; }"},
     170             : 
     171             :       // Const declarations.
     172             :       {"const var1 = 5;"},
     173             :       {"if (true) { const var1 = 5; }"},
     174             :       {"const var1 = 5; function f() { var1; }"},
     175             : 
     176             :       // Functions.
     177             :       {"function f1() { let var2; }"},
     178             :       {"var var1 = function f1() { let var2; }"},
     179             :       {"let var1 = function f1() { let var2; }"},
     180             :       {"const var1 = function f1() { let var2; }"},
     181             :       {"var var1 = function() { let var2; }"},
     182             :       {"let var1 = function() { let var2; }"},
     183             :       {"const var1 = function() { let var2; }"},
     184             : 
     185             :       {"function *f1() { let var2; }"},
     186             :       {"let var1 = function *f1() { let var2; }"},
     187             :       {"let var1 = function*() { let var2; }"},
     188             : 
     189             :       {"async function f1() { let var2; }"},
     190             :       {"let var1 = async function f1() { let var2; }"},
     191             :       {"let var1 = async function() { let var2; }"},
     192             : 
     193             :       // Redeclarations.
     194             :       {"var var1; var var1;"},
     195             :       {"var var1; var var1; var1 = 5;"},
     196             :       {"var var1; if (true) { var var1; }"},
     197             :       {"if (true) { var var1; var var1; }"},
     198             :       {"var var1; if (true) { var var1; var1 = 5; }"},
     199             :       {"if (true) { var var1; var var1; var1 = 5; }"},
     200             :       {"var var1; var var1; function f() { var1; }"},
     201             :       {"var var1; var var1; function f() { var1 = 5; }"},
     202             : 
     203             :       // Shadowing declarations.
     204             :       {"var var1; if (true) { var var1; }"},
     205             :       {"var var1; if (true) { let var1; }"},
     206             :       {"let var1; if (true) { let var1; }"},
     207             : 
     208             :       {"var var1; if (true) { const var1 = 0; }"},
     209             :       {"const var1 = 0; if (true) { const var1 = 0; }"},
     210             : 
     211             :       // Variables deeper in the subscopes (scopes without variables inbetween).
     212             :       {"if (true) { if (true) { function f() { var var1 = 5; } } }"},
     213             : 
     214             :       // Arguments and this.
     215             :       {"arguments;"},
     216             :       {"arguments = 5;", SKIP_STRICT},
     217             :       {"if (true) { arguments; }"},
     218             :       {"if (true) { arguments = 5; }", SKIP_STRICT},
     219             :       {"() => { arguments; }"},
     220             :       {"var1, var2, var3", "arguments;"},
     221             :       {"var1, var2, var3", "arguments = 5;", SKIP_STRICT},
     222             :       {"var1, var2, var3", "() => { arguments; }"},
     223             :       {"var1, var2, var3", "() => { arguments = 5; }", SKIP_STRICT},
     224             : 
     225             :       {"this;"},
     226             :       {"if (true) { this; }"},
     227             :       {"() => { this; }"},
     228             : 
     229             :       // Variable called "arguments"
     230             :       {"var arguments;", SKIP_STRICT},
     231             :       {"var arguments; arguments = 5;", SKIP_STRICT},
     232             :       {"if (true) { var arguments; }", SKIP_STRICT, PreciseMaybeAssigned::NO},
     233             :       {"if (true) { var arguments; arguments = 5; }", SKIP_STRICT},
     234             :       {"var arguments; function f() { arguments; }", SKIP_STRICT},
     235             :       {"var arguments; arguments = 5; function f() { arguments; }",
     236             :        SKIP_STRICT},
     237             :       {"var arguments; function f() { arguments = 5; }", SKIP_STRICT},
     238             : 
     239             :       {"let arguments;", SKIP_STRICT},
     240             :       {"let arguments; arguments = 5;", SKIP_STRICT},
     241             :       {"if (true) { let arguments; }", SKIP_STRICT},
     242             :       {"if (true) { let arguments; arguments = 5; }", SKIP_STRICT},
     243             :       {"let arguments; function f() { arguments; }", SKIP_STRICT},
     244             :       {"let arguments; arguments = 5; function f() { arguments; }",
     245             :        SKIP_STRICT},
     246             :       {"let arguments; function f() { arguments = 5; }", SKIP_STRICT},
     247             : 
     248             :       {"const arguments = 5;", SKIP_STRICT},
     249             :       {"if (true) { const arguments = 5; }", SKIP_STRICT},
     250             :       {"const arguments = 5; function f() { arguments; }", SKIP_STRICT},
     251             : 
     252             :       // Destructuring declarations.
     253             :       {"var [var1, var2] = [1, 2];"},
     254             :       {"var [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
     255             :       {"var [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
     256             :       {"var [var1, ...var2] = [1, 2, 3];"},
     257             : 
     258             :       {"var {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
     259             :       {"var {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
     260             :       {"var {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
     261             : 
     262             :       {"let [var1, var2] = [1, 2];"},
     263             :       {"let [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
     264             :       {"let [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
     265             :       {"let [var1, ...var2] = [1, 2, 3];"},
     266             : 
     267             :       {"let {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
     268             :       {"let {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
     269             :       {"let {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
     270             : 
     271             :       {"const [var1, var2] = [1, 2];"},
     272             :       {"const [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
     273             :       {"const [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
     274             :       {"const [var1, ...var2] = [1, 2, 3];"},
     275             : 
     276             :       {"const {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
     277             :       {"const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
     278             :       {"const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
     279             : 
     280             :       // Referencing the function variable.
     281             :       {"test;"},
     282             :       {"function f1() { f1; }"},
     283             :       {"function f1() { function f2() { f1; } }"},
     284             :       {"function arguments() {}", SKIP_STRICT},
     285             :       {"function f1() {} function f1() {}", SKIP_STRICT},
     286             :       {"var f1; function f1() {}"},
     287             : 
     288             :       // Assigning to the function variable.
     289             :       {"test = 3;"},
     290             :       {"function f1() { f1 = 3; }"},
     291             :       {"function f1() { f1; } f1 = 3;"},
     292             :       {"function arguments() {} arguments = 8;", SKIP_STRICT},
     293             :       {"function f1() {} f1 = 3; function f1() {}", SKIP_STRICT},
     294             : 
     295             :       // Evals.
     296             :       {"var var1; eval('');"},
     297             :       {"var var1; function f1() { eval(''); }"},
     298             :       {"let var1; eval('');"},
     299             :       {"let var1; function f1() { eval(''); }"},
     300             :       {"const var1 = 10; eval('');"},
     301             :       {"const var1 = 10; function f1() { eval(''); }"},
     302             : 
     303             :       // Standard for loops.
     304             :       {"for (var var1 = 0; var1 < 10; ++var1) { }"},
     305             :       {"for (let var1 = 0; var1 < 10; ++var1) { }"},
     306             :       {"for (const var1 = 0; var1 < 10; ++var1) { }"},
     307             : 
     308             :       {"for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
     309             :       {"for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
     310             :       {"for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
     311             : 
     312             :       // For of loops
     313             :       {"for (var1 of [1, 2]) { }"},
     314             :       {"for (var var1 of [1, 2]) { }"},
     315             :       {"for (let var1 of [1, 2]) { }"},
     316             :       {"for (const var1 of [1, 2]) { }"},
     317             : 
     318             :       {"for (var1 of [1, 2]) { var1; }"},
     319             :       {"for (var var1 of [1, 2]) { var1; }"},
     320             :       {"for (let var1 of [1, 2]) { var1; }"},
     321             :       {"for (const var1 of [1, 2]) { var1; }"},
     322             : 
     323             :       {"for (var1 of [1, 2]) { var1 = 0; }"},
     324             :       {"for (var var1 of [1, 2]) { var1 = 0; }"},
     325             :       {"for (let var1 of [1, 2]) { var1 = 0; }"},
     326             :       {"for (const var1 of [1, 2]) { var1 = 0; }"},
     327             : 
     328             :       {"for (var1 of [1, 2]) { function foo() { var1; } }"},
     329             :       {"for (var var1 of [1, 2]) { function foo() { var1; } }"},
     330             :       {"for (let var1 of [1, 2]) { function foo() { var1; } }"},
     331             :       {"for (const var1 of [1, 2]) { function foo() { var1; } }"},
     332             : 
     333             :       {"for (var1 of [1, 2]) { function foo() { var1 = 0; } }"},
     334             :       {"for (var var1 of [1, 2]) { function foo() { var1 = 0; } }"},
     335             :       {"for (let var1 of [1, 2]) { function foo() { var1 = 0; } }"},
     336             :       {"for (const var1 of [1, 2]) { function foo() { var1 = 0; } }"},
     337             : 
     338             :       // For in loops
     339             :       {"for (var1 in {a: 6}) { }"},
     340             :       {"for (var var1 in {a: 6}) { }"},
     341             :       {"for (let var1 in {a: 6}) { }"},
     342             :       {"for (const var1 in {a: 6}) { }"},
     343             : 
     344             :       {"for (var1 in {a: 6}) { var1; }"},
     345             :       {"for (var var1 in {a: 6}) { var1; }"},
     346             :       {"for (let var1 in {a: 6}) { var1; }"},
     347             :       {"for (const var1 in {a: 6}) { var1; }"},
     348             : 
     349             :       {"for (var1 in {a: 6}) { var1 = 0; }"},
     350             :       {"for (var var1 in {a: 6}) { var1 = 0; }"},
     351             :       {"for (let var1 in {a: 6}) { var1 = 0; }"},
     352             :       {"for (const var1 in {a: 6}) { var1 = 0; }"},
     353             : 
     354             :       {"for (var1 in {a: 6}) { function foo() { var1; } }"},
     355             :       {"for (var var1 in {a: 6}) { function foo() { var1; } }"},
     356             :       {"for (let var1 in {a: 6}) { function foo() { var1; } }"},
     357             :       {"for (const var1 in {a: 6}) { function foo() { var1; } }"},
     358             : 
     359             :       {"for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     360             :       {"for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     361             :       {"for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     362             :       {"for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     363             : 
     364             :       {"for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     365             :       {"for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     366             :       {"for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     367             :       {"for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
     368             : 
     369             :       // Destructuring loop variable
     370             :       {"for ([var1, var2] of [[1, 1], [2, 2]]) { }"},
     371             :       {"for (var [var1, var2] of [[1, 1], [2, 2]]) { }"},
     372             :       {"for (let [var1, var2] of [[1, 1], [2, 2]]) { }"},
     373             :       {"for (const [var1, var2] of [[1, 1], [2, 2]]) { }"},
     374             : 
     375             :       {"for ([var1, var2] of [[1, 1], [2, 2]]) { var2 = 3; }"},
     376             :       {"for (var [var1, var2] of [[1, 1], [2, 2]]) { var2 = 3; }"},
     377             :       {"for (let [var1, var2] of [[1, 1], [2, 2]]) { var2 = 3; }"},
     378             :       {"for (const [var1, var2] of [[1, 1], [2, 2]]) { var2 = 3; }"},
     379             : 
     380             :       {"for ([var1, var2] of [[1, 1], [2, 2]]) { () => { var2 = 3; } }"},
     381             :       {"for (var [var1, var2] of [[1, 1], [2, 2]]) { () => { var2 = 3; } }"},
     382             :       {"for (let [var1, var2] of [[1, 1], [2, 2]]) { () => { var2 = 3; } }"},
     383             :       {"for (const [var1, var2] of [[1, 1], [2, 2]]) { () => { var2 = 3; } }"},
     384             : 
     385             :       // Skippable function in loop header
     386             :       {"for (let [var1, var2 = function() { }] of [[1]]) { }"},
     387             :       {"for (let [var1, var2 = function() { var1; }] of [[1]]) { }"},
     388             :       {"for (let [var1, var2 = function() { var2; }] of [[1]]) { }"},
     389             :       {"for (let [var1, var2 = function() { var1; var2; }] of [[1]]) { }"},
     390             :       {"for (let [var1, var2 = function() { var1 = 0; }] of [[1]]) { }"},
     391             :       {"for (let [var1, var2 = function() { var2 = 0; }] of [[1]]) { }"},
     392             :       {"for (let [var1, var2 = function() { var1 = 0; var2 = 0; }] of [[1]]) { "
     393             :        "}"},
     394             : 
     395             :       {"for (let [var1, var2 = function() { }] of [[1]]) { function f() { "
     396             :        "var1; } }"},
     397             :       {"for (let [var1, var2 = function() { }] of [[1]]) { function f() { "
     398             :        "var2; } }"},
     399             :       {"for (let [var1, var2 = function() { }] of [[1]]) { function f() { "
     400             :        "var1; var2; } }"},
     401             :       {"for (let [var1, var2 = function() { }] of [[1]]) { function f() { "
     402             :        "var1 = 0; } }"},
     403             :       {"for (let [var1, var2 = function() { }] of [[1]]) { function f() { "
     404             :        "var2 = 0; } }"},
     405             :       {"for (let [var1, var2 = function() { }] of [[1]]) { function f() { "
     406             :        "var1 = 0; var2 = 0; } }"},
     407             :       {"for (let [var1, var2 = function() { var1; }] of [[1]]) { "
     408             :        "function f() { var1; } }"},
     409             :       {"for (let [var1, var2 = function() { var1; }] of [[1]]) { "
     410             :        "function f() { var2; } }"},
     411             :       {"for (let [var1, var2 = function() { var1; }] of [[1]]) { "
     412             :        "function f() { var1; var2; } }"},
     413             :       {"for (let [var1, var2 = function() { var2; }] of [[1]]) { "
     414             :        "function f() { var1; } }"},
     415             :       {"for (let [var1, var2 = function() { var2; }] of [[1]]) { "
     416             :        "function f() { var2; } }"},
     417             :       {"for (let [var1, var2 = function() { var2; }] of [[1]]) { "
     418             :        "function f() { var1; var2; } }"},
     419             : 
     420             :       // Loops without declarations
     421             :       {"var var1 = 0; for ( ; var1 < 2; ++var1) { }"},
     422             :       {"var var1 = 0; for ( ; var1 < 2; ++var1) { function foo() { var1; } }"},
     423             :       {"var var1 = 0; for ( ; var1 > 2; ) { }"},
     424             :       {"var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1; } }"},
     425             :       {"var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1 = 6; } }"},
     426             : 
     427             :       {"var var1 = 0; for(var1; var1 < 2; ++var1) { }"},
     428             :       {"var var1 = 0; for (var1; var1 < 2; ++var1) { function foo() { var1; } "
     429             :        "}"},
     430             :       {"var var1 = 0; for (var1; var1 > 2; ) { }"},
     431             :       {"var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1; } }"},
     432             :       {"var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1 = 6; } }"},
     433             : 
     434             :       // Block functions (potentially sloppy).
     435             :       {"if (true) { function f1() {} }"},
     436             :       {"if (true) { function f1() {} function f1() {} }", SKIP_STRICT},
     437             :       {"if (true) { if (true) { function f1() {} } }"},
     438             :       {"if (true) { if (true) { function f1() {} function f1() {} } }",
     439             :        SKIP_STRICT},
     440             :       {"if (true) { function f1() {} f1 = 3; }"},
     441             : 
     442             :       {"if (true) { function f1() {} function foo() { f1; } }"},
     443             :       {"if (true) { function f1() {} } function foo() { f1; }"},
     444             :       {"if (true) { function f1() {} function f1() {} function foo() { f1; } "
     445             :        "}",
     446             :        SKIP_STRICT},
     447             :       {"if (true) { function f1() {} function f1() {} } function foo() { f1; "
     448             :        "}",
     449             :        SKIP_STRICT},
     450             :       {"if (true) { if (true) { function f1() {} } function foo() { f1; } }"},
     451             :       {"if (true) { if (true) { function f1() {} function f1() {} } function "
     452             :        "foo() { f1; } }",
     453             :        SKIP_STRICT},
     454             :       {"if (true) { function f1() {} f1 = 3; function foo() { f1; } }"},
     455             :       {"if (true) { function f1() {} f1 = 3; } function foo() { f1; }"},
     456             : 
     457             :       {"var f1 = 1; if (true) { function f1() {} }"},
     458             :       {"var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"},
     459             : 
     460             :       {"if (true) { function f1() {} function f2() { f1(); } }"},
     461             : 
     462             :       {"if (true) { function *f1() {} }"},
     463             :       {"if (true) { async function f1() {} }"},
     464             : 
     465             :       // (Potentially sloppy) block function shadowing a catch variable.
     466             :       {"try { } catch(var1) { if (true) { function var1() {} } }"},
     467             : 
     468             :       // Simple parameters.
     469             :       {"var1", ""},
     470             :       {"var1", "var1;"},
     471             :       {"var1", "var1 = 9;"},
     472             :       {"var1", "function f1() { var1; }"},
     473             :       {"var1", "function f1() { var1 = 9; }"},
     474             : 
     475             :       {"var1, var2", ""},
     476             :       {"var1, var2", "var2;"},
     477             :       {"var1, var2", "var2 = 9;"},
     478             :       {"var1, var2", "function f1() { var2; }"},
     479             :       {"var1, var2", "function f1() { var2 = 9; }"},
     480             :       {"var1, var2", "var1;"},
     481             :       {"var1, var2", "var1 = 9;"},
     482             :       {"var1, var2", "function f1() { var1; }"},
     483             :       {"var1, var2", "function f1() { var1 = 9; }"},
     484             : 
     485             :       // Duplicate parameters.
     486             :       {"var1, var1", "", SkipTests(SKIP_STRICT | SKIP_ARROW)},
     487             :       {"var1, var1", "var1;", SkipTests(SKIP_STRICT | SKIP_ARROW)},
     488             :       {"var1, var1", "var1 = 9;", SkipTests(SKIP_STRICT | SKIP_ARROW)},
     489             :       {"var1, var1", "function f1() { var1; }",
     490             :        SkipTests(SKIP_STRICT | SKIP_ARROW)},
     491             :       {"var1, var1", "function f1() { var1 = 9; }",
     492             :        SkipTests(SKIP_STRICT | SKIP_ARROW)},
     493             : 
     494             :       // If the function declares itself strict, non-simple parameters aren't
     495             :       // allowed.
     496             : 
     497             :       // Rest parameter.
     498             :       {"...var2", "", SKIP_STRICT_FUNCTION},
     499             :       {"...var2", "var2;", SKIP_STRICT_FUNCTION},
     500             :       {"...var2", "var2 = 9;", SKIP_STRICT_FUNCTION},
     501             :       {"...var2", "function f1() { var2; }", SKIP_STRICT_FUNCTION},
     502             :       {"...var2", "function f1() { var2 = 9; }", SKIP_STRICT_FUNCTION},
     503             : 
     504             :       {"var1, ...var2", "", SKIP_STRICT_FUNCTION},
     505             :       {"var1, ...var2", "var2;", SKIP_STRICT_FUNCTION},
     506             :       {"var1, ...var2", "var2 = 9;", SKIP_STRICT_FUNCTION},
     507             :       {"var1, ...var2", "function f1() { var2; }", SKIP_STRICT_FUNCTION},
     508             :       {"var1, ...var2", "function f1() { var2 = 9; }", SKIP_STRICT_FUNCTION},
     509             : 
     510             :       // Default parameters.
     511             :       {"var1 = 3", "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO},
     512             :       {"var1, var2 = var1", "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO},
     513             :       {"var1, var2 = 4, ...var3", "", SKIP_STRICT_FUNCTION,
     514             :        PreciseMaybeAssigned::NO},
     515             : 
     516             :       // Destructuring parameters. Because of the search space explosion, we
     517             :       // cannot test all interesting cases. Let's try to test a relevant subset.
     518             :       {"[]", "", SKIP_STRICT_FUNCTION},
     519             :       {"{}", "", SKIP_STRICT_FUNCTION},
     520             : 
     521             :       {"[var1]", "", SKIP_STRICT_FUNCTION},
     522             :       {"{name1: var1}", "", SKIP_STRICT_FUNCTION},
     523             :       {"{var1}", "", SKIP_STRICT_FUNCTION},
     524             : 
     525             :       {"[var1]", "var1;", SKIP_STRICT_FUNCTION},
     526             :       {"{name1: var1}", "var1;", SKIP_STRICT_FUNCTION},
     527             :       {"{name1: var1}", "name1;", SKIP_STRICT_FUNCTION},
     528             :       {"{var1}", "var1;", SKIP_STRICT_FUNCTION},
     529             : 
     530             :       {"[var1]", "var1 = 16;", SKIP_STRICT_FUNCTION},
     531             :       {"{name1: var1}", "var1 = 16;", SKIP_STRICT_FUNCTION},
     532             :       {"{name1: var1}", "name1 = 16;", SKIP_STRICT_FUNCTION},
     533             :       {"{var1}", "var1 = 16;", SKIP_STRICT_FUNCTION},
     534             : 
     535             :       {"[var1]", "() => { var1; }", SKIP_STRICT_FUNCTION},
     536             :       {"{name1: var1}", "() => { var1; }", SKIP_STRICT_FUNCTION},
     537             :       {"{name1: var1}", "() => { name1; }", SKIP_STRICT_FUNCTION},
     538             :       {"{var1}", "() => { var1; }", SKIP_STRICT_FUNCTION},
     539             : 
     540             :       {"[var1, var2, var3]", "", SKIP_STRICT_FUNCTION},
     541             :       {"{name1: var1, name2: var2, name3: var3}", "", SKIP_STRICT_FUNCTION},
     542             :       {"{var1, var2, var3}", "", SKIP_STRICT_FUNCTION},
     543             : 
     544             :       {"[var1, var2, var3]", "() => { var2 = 16;}", SKIP_STRICT_FUNCTION},
     545             :       {"{name1: var1, name2: var2, name3: var3}", "() => { var2 = 16;}",
     546             :        SKIP_STRICT_FUNCTION},
     547             :       {"{name1: var1, name2: var2, name3: var3}", "() => { name2 = 16;}",
     548             :        SKIP_STRICT_FUNCTION},
     549             :       {"{var1, var2, var3}", "() => { var2 = 16;}", SKIP_STRICT_FUNCTION},
     550             : 
     551             :       // Nesting destructuring.
     552             :       {"[var1, [var2, var3], {var4, name5: [var5, var6]}]", "",
     553             :        SKIP_STRICT_FUNCTION},
     554             : 
     555             :       // Complicated params.
     556             :       {"var1, [var2], var3 = 24, [var4, var5] = [2, 4], var6, {var7}, var8, "
     557             :        "{name9: var9, name10: var10}, ...var11",
     558             :        "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO},
     559             : 
     560             :       // Complicated cases from bugs.
     561             :       {"var1 = {} = {}", "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO},
     562             : 
     563             :       // Destructuring rest. Because we can.
     564             :       {"var1, ...[var2]", "", SKIP_STRICT_FUNCTION},
     565             :       {"var1, ...[var2]", "() => { var2; }", SKIP_STRICT_FUNCTION},
     566             :       {"var1, ...{0: var2}", "", SKIP_STRICT_FUNCTION},
     567             :       {"var1, ...{0: var2}", "() => { var2; }", SKIP_STRICT_FUNCTION},
     568             :       {"var1, ...[]", "", SKIP_STRICT_FUNCTION},
     569             :       {"var1, ...{}", "", SKIP_STRICT_FUNCTION},
     570             :       {"var1, ...[var2, var3]", "", SKIP_STRICT_FUNCTION},
     571             :       {"var1, ...{0: var2, 1: var3}", "", SKIP_STRICT_FUNCTION},
     572             : 
     573             :       // Default parameters for destruring parameters.
     574             :       {"[var1, var2] = [2, 4]", "", SKIP_STRICT_FUNCTION,
     575             :        PreciseMaybeAssigned::NO},
     576             :       {"{var1, var2} = {var1: 3, var2: 3}", "", SKIP_STRICT_FUNCTION,
     577             :        PreciseMaybeAssigned::NO},
     578             : 
     579             :       // Default parameters inside destruring parameters.
     580             :       {"[var1 = 4, var2 = var1]", "", SKIP_STRICT_FUNCTION,
     581             :        PreciseMaybeAssigned::NO},
     582             :       {"{var1 = 4, var2 = var1}", "", SKIP_STRICT_FUNCTION,
     583             :        PreciseMaybeAssigned::NO},
     584             : 
     585             :       // Locals shadowing parameters.
     586             :       {"var1, var2", "var var1 = 16; () => { var1 = 17; }"},
     587             : 
     588             :       // Locals shadowing destructuring parameters and the rest parameter.
     589             :       {"[var1, var2]", "var var1 = 16; () => { var1 = 17; }",
     590             :        SKIP_STRICT_FUNCTION},
     591             :       {"{var1, var2}", "var var1 = 16; () => { var1 = 17; }",
     592             :        SKIP_STRICT_FUNCTION},
     593             :       {"var1, var2, ...var3", "var var3 = 16; () => { var3 = 17; }",
     594             :        SKIP_STRICT_FUNCTION},
     595             :       {"var1, var2 = var1", "var var1 = 16; () => { var1 = 17; }",
     596             :        SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO},
     597             : 
     598             :       // Hoisted sloppy block function shadowing a parameter.
     599             :       // FIXME(marja): why is maybe_assigned inaccurate?
     600             :       {"var1, var2", "for (;;) { function var1() { } }", DONT_SKIP,
     601             :        PreciseMaybeAssigned::NO},
     602             : 
     603             :       // Sloppy eval in default parameter.
     604             :       {"var1, var2 = eval(''), var3", "let var4 = 0;", SKIP_STRICT_FUNCTION,
     605             :        Bailout::BAILOUT_IF_OUTER_SLOPPY},
     606             :       {"var1, var2 = eval(''), var3 = eval('')", "let var4 = 0;",
     607             :        SKIP_STRICT_FUNCTION, Bailout::BAILOUT_IF_OUTER_SLOPPY},
     608             : 
     609             :       // Sloppy eval in arrow function parameter list which is inside another
     610             :       // arrow function parameter list.
     611             :       {"var1, var2 = (var3, var4 = eval(''), var5) => { let var6; }, var7",
     612             :        "let var8 = 0;", SKIP_STRICT_FUNCTION, Bailout::BAILOUT_IF_OUTER_SLOPPY},
     613             : 
     614             :       // Sloppy eval in a function body with non-simple parameters.
     615             :       {"var1 = 1, var2 = 2", "eval('');", SKIP_STRICT_FUNCTION},
     616             : 
     617             :       // Catch variable
     618             :       {"try { } catch(var1) { }"},
     619             :       {"try { } catch(var1) { var1; }"},
     620             :       {"try { } catch(var1) { var1 = 3; }"},
     621             :       {"try { } catch(var1) { function f() { var1; } }"},
     622             :       {"try { } catch(var1) { function f() { var1 = 3; } }"},
     623             : 
     624             :       {"try { } catch({var1, var2}) { function f() { var1 = 3; } }"},
     625             :       {"try { } catch([var1, var2]) { function f() { var1 = 3; } }"},
     626             :       {"try { } catch({}) { }"},
     627             :       {"try { } catch([]) { }"},
     628             : 
     629             :       // Shadowing the catch variable
     630             :       {"try { } catch(var1) { var var1 = 3; }"},
     631             :       {"try { } catch(var1) { var var1 = 3; function f() { var1 = 3; } }"},
     632             : 
     633             :       // Classes
     634             :       {"class MyClass {}"},
     635             :       {"var1 = class MyClass {}"},
     636             :       {"var var1 = class MyClass {}"},
     637             :       {"let var1 = class MyClass {}"},
     638             :       {"const var1 = class MyClass {}"},
     639             :       {"var var1 = class {}"},
     640             :       {"let var1 = class {}"},
     641             :       {"const var1 = class {}"},
     642             : 
     643             :       {"class MyClass { constructor() {} }"},
     644             :       {"class MyClass { constructor() { var var1; } }"},
     645             :       {"class MyClass { constructor() { var var1 = 11; } }"},
     646             :       {"class MyClass { constructor() { var var1; function foo() { var1 = 11; "
     647             :        "} } }"},
     648             : 
     649             :       {"class MyClass { m() {} }"},
     650             :       {"class MyClass { m() { var var1; } }"},
     651             :       {"class MyClass { m() { var var1 = 11; } }"},
     652             :       {"class MyClass { m() { var var1; function foo() { var1 = 11; } } }"},
     653             : 
     654             :       {"class MyClass { static m() {} }"},
     655             :       {"class MyClass { static m() { var var1; } }"},
     656             :       {"class MyClass { static m() { var var1 = 11; } }"},
     657             :       {"class MyClass { static m() { var var1; function foo() { var1 = 11; } } "
     658             :        "}"},
     659             : 
     660             :       {"class MyBase {} class MyClass extends MyBase {}"},
     661             :       {"class MyClass extends MyBase { constructor() {} }"},
     662             :       {"class MyClass extends MyBase { constructor() { super(); } }"},
     663             :       {"class MyClass extends MyBase { constructor() { var var1; } }"},
     664             :       {"class MyClass extends MyBase { constructor() { var var1 = 11; } }"},
     665             :       {"class MyClass extends MyBase { constructor() { var var1; function "
     666             :        "foo() { var1 = 11; } } }"},
     667             : 
     668             :       {"class MyClass extends MyBase { m() {} }"},
     669             :       {"class MyClass extends MyBase { m() { super.foo; } }"},
     670             :       {"class MyClass extends MyBase { m() { var var1; } }"},
     671             :       {"class MyClass extends MyBase { m() { var var1 = 11; } }"},
     672             :       {"class MyClass extends MyBase { m() { var var1; function foo() { var1 = "
     673             :        "11; } } }"},
     674             : 
     675             :       {"class MyClass extends MyBase { static m() {} }"},
     676             :       {"class MyClass extends MyBase { static m() { super.foo; } }"},
     677             :       {"class MyClass extends MyBase { static m() { var var1; } }"},
     678             :       {"class MyClass extends MyBase { static m() { var var1 = 11; } }"},
     679             :       {"class MyClass extends MyBase { static m() { var var1; function foo() { "
     680             :        "var1 = 11; } } }"},
     681             :   };
     682             : 
     683          60 :   for (unsigned outer_ix = 0; outer_ix < arraysize(outers); ++outer_ix) {
     684       19224 :     for (unsigned inner_ix = 0; inner_ix < arraysize(inners); ++inner_ix) {
     685       27768 :       if (outers[outer_ix].strict_outer &&
     686        8544 :           (inners[inner_ix].skip & SKIP_STRICT_OUTER)) {
     687        2784 :         continue;
     688             :       }
     689       26508 :       if (outers[outer_ix].strict_test_function &&
     690        8124 :           (inners[inner_ix].skip & SKIP_STRICT_FUNCTION)) {
     691             :         continue;
     692             :       }
     693       16524 :       if (outers[outer_ix].arrow && (inners[inner_ix].skip & SKIP_ARROW)) {
     694             :         continue;
     695             :       }
     696             : 
     697       16494 :       const char* code = outers[outer_ix].code;
     698       16494 :       int code_len = Utf8LengthHelper(code);
     699             : 
     700       16494 :       int params_len = Utf8LengthHelper(inners[inner_ix].params);
     701       16494 :       int source_len = Utf8LengthHelper(inners[inner_ix].source);
     702       16494 :       int len = code_len + params_len + source_len;
     703             : 
     704       16494 :       i::ScopedVector<char> program(len + 1);
     705             :       i::SNPrintF(program, code, inners[inner_ix].params,
     706       16494 :                   inners[inner_ix].source);
     707             : 
     708             :       i::Handle<i::String> source =
     709       16494 :           factory->InternalizeUtf8String(program.start());
     710       32988 :       source->PrintOn(stdout);
     711             :       printf("\n");
     712             : 
     713             :       // First compile with the lazy inner function and extract the scope data.
     714       16494 :       i::Handle<i::Script> script = factory->NewScript(source);
     715       32934 :       i::ParseInfo lazy_info(script);
     716             : 
     717             :       // No need to run scope analysis; preparser scope data is produced when
     718             :       // parsing.
     719       16494 :       CHECK(i::parsing::ParseProgram(&lazy_info, isolate));
     720             : 
     721             :       // Retrieve the scope data we produced.
     722             :       i::Scope* scope_with_data = i::ScopeTestHelper::FindScope(
     723       16494 :           lazy_info.literal()->scope(), outers[outer_ix].location);
     724             :       i::ProducedPreParsedScopeData* produced_data =
     725             :           scope_with_data->AsDeclarationScope()
     726       16494 :               ->produced_preparsed_scope_data();
     727             :       i::MaybeHandle<i::PreParsedScopeData> maybe_produced_data_on_heap =
     728       16494 :           produced_data->Serialize(isolate);
     729       16584 :       if (inners[inner_ix].bailout == Bailout::BAILOUT_IF_OUTER_SLOPPY &&
     730          90 :           !outers[outer_ix].strict_outer) {
     731             :         DCHECK(maybe_produced_data_on_heap.is_null());
     732          54 :         continue;
     733             :       }
     734             :       DCHECK(!maybe_produced_data_on_heap.is_null());
     735             :       i::Handle<i::PreParsedScopeData> produced_data_on_heap =
     736       16440 :           maybe_produced_data_on_heap.ToHandleChecked();
     737             : 
     738             :       // Then parse eagerly and check against the scope data.
     739       16440 :       script = factory->NewScript(source);
     740             : 
     741       32880 :       i::ParseInfo eager_normal(script);
     742             :       eager_normal.set_allow_lazy_parsing(false);
     743             : 
     744       16440 :       CHECK(i::parsing::ParseProgram(&eager_normal, isolate));
     745       16440 :       CHECK(i::Compiler::Analyze(&eager_normal));
     746             : 
     747             :       // Compare the allocation of the variables in two cases: 1) normal scope
     748             :       // allocation 2) allocation based on the preparse data.
     749             : 
     750       32880 :       i::Scope* normal_scope = i::ScopeTestHelper::FindScope(
     751       16440 :           eager_normal.literal()->scope(), outers[outer_ix].location);
     752       16440 :       CHECK_NULL(normal_scope->sibling());
     753       16440 :       CHECK(normal_scope->is_function_scope());
     754             : 
     755       32880 :       i::ParseInfo eager_using_scope_data(script);
     756             :       eager_using_scope_data.set_allow_lazy_parsing(false);
     757             : 
     758       16440 :       CHECK(i::parsing::ParseProgram(&eager_using_scope_data, isolate));
     759             :       // Don't run scope analysis (that would obviously decide the correct
     760             :       // allocation for the variables).
     761             : 
     762       32880 :       i::Scope* unallocated_scope = i::ScopeTestHelper::FindScope(
     763       16440 :           eager_using_scope_data.literal()->scope(), outers[outer_ix].location);
     764       16440 :       CHECK_NULL(unallocated_scope->sibling());
     765       16440 :       CHECK(unallocated_scope->is_function_scope());
     766             : 
     767             :       // Mark all inner functions as "skipped", so that we don't try to restore
     768             :       // data for them. No test should contain eager functions, because we
     769             :       // cannot properly decide whether we have or don't have data for them.
     770       16440 :       i::ScopeTestHelper::MarkInnerFunctionsAsSkipped(unallocated_scope);
     771             :       i::ConsumedPreParsedScopeData* consumed_preparsed_scope_data =
     772             :           lazy_info.consumed_preparsed_scope_data();
     773       16440 :       consumed_preparsed_scope_data->SetData(produced_data_on_heap);
     774       16440 :       consumed_preparsed_scope_data->SkipFunctionDataForTesting();
     775             :       consumed_preparsed_scope_data->RestoreScopeAllocationData(
     776       16440 :           unallocated_scope->AsDeclarationScope());
     777             :       i::ScopeTestHelper::AllocateWithoutVariableResolution(unallocated_scope);
     778             : 
     779             :       i::ScopeTestHelper::CompareScopes(
     780             :           normal_scope, unallocated_scope,
     781       16440 :           inners[inner_ix].precise_maybe_assigned == PreciseMaybeAssigned::YES);
     782             :     }
     783             :   }
     784           6 : }
     785             : 
     786             : // Regression test for
     787             : // https://bugs.chromium.org/p/chromium/issues/detail?id=753896. Should not
     788             : // crash.
     789       23724 : TEST(Regress753896) {
     790           6 :   i::FLAG_preparser_scope_analysis = true;
     791             :   i::Isolate* isolate = CcTest::i_isolate();
     792             :   i::Factory* factory = isolate->factory();
     793             :   i::HandleScope scope(isolate);
     794          12 :   LocalContext env;
     795             : 
     796             :   i::Handle<i::String> source = factory->InternalizeUtf8String(
     797           6 :       "function lazy() { let v = 0; if (true) { var v = 0; } }");
     798           6 :   i::Handle<i::Script> script = factory->NewScript(source);
     799          12 :   i::ParseInfo info(script);
     800             : 
     801             :   // We don't assert that parsing succeeded or that it failed; currently the
     802             :   // error is not detected inside lazy functions, but it might be in the future.
     803           6 :   i::parsing::ParseProgram(&info, isolate);
     804           6 : }
     805             : 
     806       23724 : TEST(ProducingAndConsumingByteData) {
     807           6 :   i::Isolate* isolate = CcTest::i_isolate();
     808             :   i::HandleScope scope(isolate);
     809          12 :   LocalContext env;
     810             : 
     811          12 :   i::Zone zone(isolate->allocator(), ZONE_NAME);
     812             :   i::ProducedPreParsedScopeData::ByteData bytes(&zone);
     813             :   // Write some data.
     814           6 :   bytes.WriteUint32(1983);  // This will be overwritten.
     815           6 :   bytes.WriteUint32(2147483647);
     816           6 :   bytes.WriteUint8(4);
     817           6 :   bytes.WriteUint8(255);
     818           6 :   bytes.WriteUint32(0);
     819           6 :   bytes.WriteUint8(0);
     820           6 :   bytes.OverwriteFirstUint32(2017);
     821           6 :   bytes.WriteUint8(100);
     822             : 
     823           6 :   i::Handle<i::PodArray<uint8_t>> data_on_heap = bytes.Serialize(isolate);
     824             :   i::ConsumedPreParsedScopeData::ByteData bytes_for_reading;
     825             :   i::ConsumedPreParsedScopeData::ByteData::ReadingScope reading_scope(
     826             :       &bytes_for_reading, *data_on_heap);
     827             : 
     828             :   // Read the data back.
     829           6 :   CHECK_EQ(bytes_for_reading.ReadUint32(), 2017);
     830           6 :   CHECK_EQ(bytes_for_reading.ReadUint32(), 2147483647);
     831          12 :   CHECK_EQ(bytes_for_reading.ReadUint8(), 4);
     832          12 :   CHECK_EQ(bytes_for_reading.ReadUint8(), 255);
     833           6 :   CHECK_EQ(bytes_for_reading.ReadUint32(), 0);
     834          12 :   CHECK_EQ(bytes_for_reading.ReadUint8(), 0);
     835          12 :   CHECK_EQ(bytes_for_reading.ReadUint8(), 100);
     836       71160 : }

Generated by: LCOV version 1.10