Commit dec61127 authored by marja's avatar marja Committed by Commit bot

[parser] Skipping inner funcs: produce the same scopes / variables for sloppy block funcs.

BUG=v8:5516
R=vogelheim@chromium.org

Review-Url: https://codereview.chromium.org/2670633003
Cr-Commit-Position: refs/heads/master@{#42913}
parent 63dea876
......@@ -66,8 +66,8 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope,
return reinterpret_cast<Variable*>(p->value);
}
void VariableMap::DeclareName(Zone* zone, const AstRawString* name,
VariableMode mode) {
Variable* VariableMap::DeclareName(Zone* zone, const AstRawString* name,
VariableMode mode) {
Entry* p =
ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
ZoneAllocationPolicy(zone));
......@@ -77,6 +77,7 @@ void VariableMap::DeclareName(Zone* zone, const AstRawString* name,
p->value =
mode == VAR ? kDummyPreParserVariable : kDummyPreParserLexicalVariable;
}
return reinterpret_cast<Variable*>(p->value);
}
void VariableMap::Remove(Variable* var) {
......@@ -508,7 +509,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
}
}
bool var_created = false;
Variable* created_variable = nullptr;
// Write in assignments to var for each block-scoped function declaration
auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value);
......@@ -543,9 +544,9 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
if (!should_hoist) continue;
// Declare a var-style binding for the function in the outer scope
if (!var_created) {
var_created = true;
if (factory) {
if (factory) {
DCHECK(!is_being_lazily_parsed_);
if (created_variable == nullptr) {
VariableProxy* proxy =
factory->NewVariableProxy(name, NORMAL_VARIABLE);
auto declaration =
......@@ -554,22 +555,28 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
// allow_harmony_restrictive_generators and
// sloppy_mode_block_scope_function_redefinition.
bool ok = true;
DeclareVariable(declaration, VAR,
Variable::DefaultInitializationFlag(VAR), false,
nullptr, &ok);
created_variable = DeclareVariable(
declaration, VAR, Variable::DefaultInitializationFlag(VAR), false,
nullptr, &ok);
CHECK(ok); // Based on the preceding check, this should not fail
} else {
DeclareVariableName(name, VAR);
}
}
if (factory) {
Expression* assignment = factory->NewAssignment(
Token::ASSIGN, NewUnresolved(factory, name),
delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
Statement* statement =
factory->NewExpressionStatement(assignment, kNoSourcePosition);
delegate->set_statement(statement);
} else {
DCHECK(is_being_lazily_parsed_);
if (created_variable == nullptr) {
created_variable = DeclareVariableName(name, VAR);
if (created_variable != kDummyPreParserVariable &&
created_variable != kDummyPreParserLexicalVariable) {
DCHECK(FLAG_preparser_scope_analysis);
created_variable->set_maybe_assigned();
}
}
}
}
}
......@@ -1063,7 +1070,8 @@ Variable* Scope::DeclareVariable(
return var;
}
void Scope::DeclareVariableName(const AstRawString* name, VariableMode mode) {
Variable* Scope::DeclareVariableName(const AstRawString* name,
VariableMode mode) {
DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_);
DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
......@@ -1094,8 +1102,9 @@ void Scope::DeclareVariableName(const AstRawString* name, VariableMode mode) {
var->set_maybe_assigned();
}
var->set_is_used();
return var;
} else {
variables_.DeclareName(zone(), name, mode);
return variables_.DeclareName(zone(), name, mode);
}
}
......
......@@ -39,7 +39,8 @@ class VariableMap: public ZoneHashMap {
// Records that "name" exists (if not recorded yet) but doesn't create a
// Variable. Useful for preparsing.
void DeclareName(Zone* zone, const AstRawString* name, VariableMode mode);
Variable* DeclareName(Zone* zone, const AstRawString* name,
VariableMode mode);
Variable* Lookup(const AstRawString* name);
void Remove(Variable* var);
......@@ -180,7 +181,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
bool* sloppy_mode_block_scope_function_redefinition,
bool* ok);
void DeclareVariableName(const AstRawString* name, VariableMode mode);
Variable* DeclareVariableName(const AstRawString* name, VariableMode mode);
// Declarations list.
ThreadedList<Declaration>* declarations() { return &decls_; }
......
......@@ -137,6 +137,10 @@ PreParser::PreParseResult PreParser::PreParseFunction(
LazyParsingResult result = ParseStatementListAndLogFunction(
&formals, has_duplicate_parameters, may_abort, ok);
if (is_sloppy(function_scope->language_mode())) {
function_scope->HoistSloppyBlockFunctions(nullptr);
}
if (!IsArrowFunction(kind) && track_unresolved_variables_) {
// Declare arguments after parsing the function since lexical 'arguments'
// masks the arguments object. Declare arguments before declaring the
......@@ -144,10 +148,6 @@ PreParser::PreParseResult PreParser::PreParseFunction(
function_scope->DeclareArguments(ast_value_factory());
}
if (is_sloppy(function_scope->language_mode())) {
function_scope->HoistSloppyBlockFunctions(nullptr);
}
use_counts_ = nullptr;
track_unresolved_variables_ = false;
......
......@@ -9332,8 +9332,12 @@ TEST(PreParserScopeAnalysis) {
{"", "for (let var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (const var1 = 0; var1 < 10; ++var1) { }"},
// FIXME(marja): make the corresponding cases work when foo is a sloppy
// block function.
{"",
"for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"'use strict'; for (var var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"},
......@@ -9343,6 +9347,34 @@ TEST(PreParserScopeAnalysis) {
{"",
"'use strict'; for (const var1 = 0; var1 < 10; ++var1) { function foo() "
"{ var1; } }"},
{"", "if (true) { function f1() {} }"},
{"", "if (true) { function f1() {} function f1() {} }"},
{"", "if (true) { if (true) { function f1() {} } }"},
{"", "if (true) { if (true) { function f1() {} function f1() {} } }"},
{"", "if (true) { function f1() {} f1 = 3; }"},
{"", "if (true) { function f1() {} function foo() { f1; } }"},
{"", "if (true) { function f1() {} } function foo() { f1; }"},
{"",
"if (true) { function f1() {} function f1() {} function foo() { f1; } "
"}"},
{"",
"if (true) { function f1() {} function f1() {} } function foo() { f1; "
"}"},
{"",
"if (true) { if (true) { function f1() {} } function foo() { f1; } }"},
{"",
"if (true) { if (true) { function f1() {} function f1() {} } function "
"foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; function foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; } function foo() { f1; }"},
{"", "function inner2() { if (true) { function f1() {} } }"},
{"", "function inner2() { if (true) { function f1() {} f1 = 3; } }"},
{"", "var f1 = 1; if (true) { function f1() {} }"},
{"", "var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"},
};
for (unsigned i = 0; i < arraysize(inners); ++i) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment