| Index: test/cctest/test-parsing.cc
|
| diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
|
| index dd3dc0625bb890b50983f67f4bdd29f2d718306e..0babb13711165b386d8881506f636413dddb01e2 100644
|
| --- a/test/cctest/test-parsing.cc
|
| +++ b/test/cctest/test-parsing.cc
|
| @@ -8405,3 +8405,118 @@ TEST(ArgumentsRedeclaration) {
|
| RunParserSyncTest(context_data, data, kSuccess);
|
| }
|
| }
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +class ScopeTestHelper {
|
| + public:
|
| + static bool MustAllocateInContext(Variable* var) {
|
| + return var->scope()->MustAllocateInContext(var);
|
| + }
|
| +};
|
| +} // namespace internal
|
| +} // namespace v8
|
| +
|
| +// Test that lazily parsed inner functions don't result in overly pessimistic
|
| +// context allocations.
|
| +TEST(NoPessimisticContextAllocation) {
|
| + i::FLAG_lazy_inner_functions = true;
|
| + i::Isolate* isolate = CcTest::i_isolate();
|
| + i::Factory* factory = isolate->factory();
|
| + i::HandleScope scope(isolate);
|
| + LocalContext env;
|
| +
|
| + const char* prefix = "(function outer() { var my_var; ";
|
| + const char* suffix = " })();";
|
| + int prefix_len = Utf8LengthHelper(prefix);
|
| + int suffix_len = Utf8LengthHelper(suffix);
|
| +
|
| + struct {
|
| + const char* source;
|
| + bool ctxt_allocate;
|
| + } inners[] = {
|
| + // Context allocating because we need to:
|
| + {"function inner() { my_var; }", true},
|
| + {"function inner() { eval(\"foo\"); }", true},
|
| + // No pessimistic context allocation:
|
| + {"function inner() { var my_var; my_var; }", false},
|
| + {"function inner() { var my_var; }", false},
|
| + {"function inner() { let my_var; my_var; }", false},
|
| + {"function inner() { let my_var; }", false},
|
| + {"function inner() { const my_var = 0; my_var; }", false},
|
| + {"function inner() { const my_var = 0; }", false},
|
| + {"function inner() { var [a, myvar] = [1, 2]; myvar; }", false},
|
| + {"function inner() { let [a, myvar] = [1, 2]; myvar; }", false},
|
| + {"function inner() { const [a, myvar] = [1, 2]; myvar; }", false},
|
| + {"function inner() { var {a: myvar} = {a: 3}; myvar; }", false},
|
| + {"function inner() { let {a: myvar} = {a: 3}; myvar; }", false},
|
| + {"function inner() { const {a: myvar} = {a: 3}; myvar; }", false},
|
| + {"function inner() { var {myvar} = {myvar: 3}; myvar; }", false},
|
| + {"function inner() { let {myvar} = {myvar: 3}; myvar; }", false},
|
| + {"function inner() { const {myvar} = {myvar: 3}; myvar; }", false},
|
| + {"function inner(my_var) { my_var; }", false},
|
| + {"function inner(my_var) { }", false},
|
| + {"function inner(...my_var) { my_var; }", false},
|
| + {"function inner(...my_var) { }", false},
|
| + {"function inner([a, my_var, b]) { my_var; }", false},
|
| + {"function inner([a, my_var, b]) { }", false},
|
| + {"function inner({x: my_var}) { my_var; }", false},
|
| + {"function inner({x: my_var}) { }", false},
|
| + {"function inner({my_var}) { my_var; }", false},
|
| + {"function inner({my_var}) { }", false},
|
| + {"my_var => my_var; ", false},
|
| + {"my_var => { }", false},
|
| + {"(...my_var) => my_var;", false},
|
| + {"(...my_var) => { }", false},
|
| + {"([a, my_var, b]) => my_var;", false},
|
| + {"([a, my_var, b]) => { }", false},
|
| + {"({x: my_var}) => my_var;", false},
|
| + {"({x: my_var}) => { }", false},
|
| + {"({my_var}) => my_var;", false},
|
| + {"({my_var}) => { }", false},
|
| + {"function inner() { try { } catch (my_var) { } }", false},
|
| + {"function inner() { class my_var {}; }", false},
|
| + // In the following cases we still context allocate pessimistically:
|
| + {"function inner() { function my_var() {} my_var; }", true},
|
| + {"function inner() { if (true) { function my_var() {} } my_var; }",
|
| + true},
|
| + {"function inner() { try { } catch (my_var) { my_var; } }", true},
|
| + {"function inner() { for (my_var of {}) { my_var; } }", true},
|
| + {"function inner() { for (my_var of {}) { } }", true},
|
| + {"function inner() { for (my_var in []) { my_var; } }", true},
|
| + {"function inner() { for (my_var in []) { } }", true},
|
| + {"function inner() { class my_var {}; my_var }", true},
|
| + };
|
| +
|
| + for (unsigned i = 0; i < arraysize(inners); ++i) {
|
| + const char* inner = inners[i].source;
|
| + int inner_len = Utf8LengthHelper(inner);
|
| + int len = prefix_len + inner_len + suffix_len;
|
| + i::ScopedVector<char> program(len + 1);
|
| + i::SNPrintF(program, "%s%s%s", prefix, inner, suffix);
|
| + i::Handle<i::String> source =
|
| + factory->InternalizeUtf8String(program.start());
|
| + source->PrintOn(stdout);
|
| + printf("\n");
|
| +
|
| + i::Handle<i::Script> script = factory->NewScript(source);
|
| + i::Zone zone(isolate->allocator(), ZONE_NAME);
|
| + i::ParseInfo info(&zone, script);
|
| +
|
| + i::Parser parser(&info);
|
| + CHECK(parser.Parse(&info));
|
| + CHECK(i::Compiler::Analyze(&info));
|
| + CHECK(info.literal() != NULL);
|
| +
|
| + i::Scope* scope = info.literal()->scope()->inner_scope();
|
| + DCHECK_NOT_NULL(scope);
|
| + DCHECK_NULL(scope->sibling());
|
| + DCHECK(scope->is_function_scope());
|
| + const i::AstRawString* var_name =
|
| + info.ast_value_factory()->GetOneByteString("my_var");
|
| + i::Variable* var = scope->Lookup(var_name);
|
| + CHECK_EQ(inners[i].ctxt_allocate,
|
| + i::ScopeTestHelper::MustAllocateInContext(var));
|
| + }
|
| +}
|
|
|