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 : }
|