Commit 64d9352a authored by marja's avatar marja Committed by Commit bot

Preparsing inner funcs: be less pessimistic about maybe_assigned.

BUG=v8:5501, v8:5678

Review-Url: https://codereview.chromium.org/2539123002
Cr-Commit-Position: refs/heads/master@{#41645}
parent 1e70454f
......@@ -1093,26 +1093,6 @@ bool Scope::RemoveUnresolved(VariableProxy* var) {
return false;
}
bool Scope::RemoveUnresolved(const AstRawString* name) {
if (unresolved_ != nullptr && unresolved_->raw_name() == name) {
VariableProxy* removed = unresolved_;
unresolved_ = unresolved_->next_unresolved();
removed->set_next_unresolved(nullptr);
return true;
}
VariableProxy* current = unresolved_;
while (current != nullptr) {
VariableProxy* next = current->next_unresolved();
if (next != nullptr && next->raw_name() == name) {
current->set_next_unresolved(next->next_unresolved());
next->set_next_unresolved(nullptr);
return true;
}
current = next;
}
return false;
}
Variable* Scope::NewTemporary(const AstRawString* name) {
DeclarationScope* scope = GetClosureScope();
Variable* var = new (zone())
......
......@@ -183,7 +183,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// allocated globally as a "ghost" variable. RemoveUnresolved removes
// such a variable again if it was added; otherwise this is a no-op.
bool RemoveUnresolved(VariableProxy* var);
bool RemoveUnresolved(const AstRawString* name);
// Creates a new temporary variable in this scope's TemporaryScope. The
// name is only used for printing and cannot be used to find the variable.
......
......@@ -269,19 +269,17 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
PreParserExpression PreParser::ExpressionFromIdentifier(
PreParserIdentifier name, int start_position, InferName infer) {
VariableProxy* proxy = nullptr;
if (track_unresolved_variables_) {
AstNodeFactory factory(ast_value_factory());
// Setting the Zone is necessary because zone_ might be the temp Zone, and
// AstValueFactory doesn't know about it.
factory.set_zone(zone());
DCHECK_NOT_NULL(name.string_);
VariableProxy* proxy = scope()->NewUnresolved(
&factory, name.string_, start_position, NORMAL_VARIABLE);
// We don't know whether the preparsed function assigns or not, so we set
// is_assigned pessimistically.
proxy->set_is_assigned();
proxy = scope()->NewUnresolved(&factory, name.string_, start_position,
NORMAL_VARIABLE);
}
return PreParserExpression::FromIdentifier(name, zone());
return PreParserExpression::FromIdentifier(name, proxy, zone());
}
void PreParser::DeclareAndInitializeVariables(
......@@ -289,7 +287,7 @@ void PreParser::DeclareAndInitializeVariables(
const DeclarationDescriptor* declaration_descriptor,
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok) {
if (declaration->pattern.identifiers_ != nullptr) {
if (declaration->pattern.variables_ != nullptr) {
DCHECK(FLAG_lazy_inner_functions);
/* Mimic what Parser does when declaring variables (see
Parser::PatternRewriter::VisitVariableProxy).
......@@ -306,12 +304,13 @@ void PreParser::DeclareAndInitializeVariables(
if (declaration->initializer.IsEmpty() ||
(declaration_descriptor->mode == VariableMode::LET ||
declaration_descriptor->mode == VariableMode::CONST)) {
for (auto identifier : *(declaration->pattern.identifiers_)) {
declaration_descriptor->scope->RemoveUnresolved(identifier);
for (auto variable : *(declaration->pattern.variables_)) {
declaration_descriptor->scope->RemoveUnresolved(variable);
}
}
for (auto identifier : *(declaration->pattern.identifiers_)) {
scope->DeclareVariableName(identifier, declaration_descriptor->mode);
for (auto variable : *(declaration->pattern.variables_)) {
scope->DeclareVariableName(variable->raw_name(),
declaration_descriptor->mode);
}
}
}
......
This diff is collapsed.
......@@ -3302,63 +3302,68 @@ TEST(InnerAssignment) {
{"function x() {}; var x;", true, false},
{"var x; try {} catch (x) { var x = 5; }", true, false},
};
// We set allow_error_in_inner_function to true in cases where our handling of
// assigned variables in lazy inner functions is currently overly pessimistic.
// FIXME(marja): remove it when no longer needed.
struct {
const char* source;
bool assigned;
bool with;
bool allow_error_in_inner_function;
} inners[] = {
// Actual assignments.
{"x = 1;", true, false},
{"x++;", true, false},
{"++x;", true, false},
{"x--;", true, false},
{"--x;", true, false},
{"{ x = 1; }", true, false},
{"'use strict'; { let x; }; x = 0;", true, false},
{"'use strict'; { const x = 1; }; x = 0;", true, false},
{"'use strict'; { function x() {} }; x = 0;", true, false},
{"with ({}) { x = 1; }", true, true},
{"eval('');", true, false},
{"'use strict'; { let y; eval('') }", true, false},
{"function h() { x = 0; }", true, false},
{"(function() { x = 0; })", true, false},
{"(function() { x = 0; })", true, false},
{"with ({}) (function() { x = 0; })", true, true},
{"for (x of [1,2,3]) {}", true, false},
{"for (x in {a: 1}) {}", true, false},
{"for ([x] of [[1],[2],[3]]) {}", true, false},
{"for ([x] in {ab: 1}) {}", true, false},
{"for ([...x] in {ab: 1}) {}", true, false},
{"[x] = [1]", true, false},
{"x = 1;", true, false, false},
{"x++;", true, false, false},
{"++x;", true, false, false},
{"x--;", true, false, false},
{"--x;", true, false, false},
{"{ x = 1; }", true, false, false},
{"'use strict'; { let x; }; x = 0;", true, false, false},
{"'use strict'; { const x = 1; }; x = 0;", true, false, false},
{"'use strict'; { function x() {} }; x = 0;", true, false, false},
{"with ({}) { x = 1; }", true, true, false},
{"eval('');", true, false, false},
{"'use strict'; { let y; eval('') }", true, false, false},
{"function h() { x = 0; }", true, false, false},
{"(function() { x = 0; })", true, false, false},
{"(function() { x = 0; })", true, false, false},
{"with ({}) (function() { x = 0; })", true, true, false},
{"for (x of [1,2,3]) {}", true, false, false},
{"for (x in {a: 1}) {}", true, false, false},
{"for ([x] of [[1],[2],[3]]) {}", true, false, false},
{"for ([x] in {ab: 1}) {}", true, false, false},
{"for ([...x] in {ab: 1}) {}", true, false, false},
{"[x] = [1]", true, false, false},
// Actual non-assignments.
{"", false, false},
{"x;", false, false},
{"var x;", false, false},
{"var x = 8;", false, false},
{"var x; x = 8;", false, false},
{"'use strict'; let x;", false, false},
{"'use strict'; let x = 8;", false, false},
{"'use strict'; let x; x = 8;", false, false},
{"'use strict'; const x = 8;", false, false},
{"function x() {}", false, false},
{"function x() { x = 0; }", false, false},
{"function h(x) { x = 0; }", false, false},
{"'use strict'; { let x; x = 0; }", false, false},
{"{ var x; }; x = 0;", false, false},
{"with ({}) {}", false, true},
{"var x; { with ({}) { x = 1; } }", false, true},
{"try {} catch(x) { x = 0; }", false, false},
{"try {} catch(x) { with ({}) { x = 1; } }", false, true},
{"", false, false, false},
{"x;", false, false, false},
{"var x;", false, false, false},
{"var x = 8;", false, false, false},
{"var x; x = 8;", false, false, false},
{"'use strict'; let x;", false, false, false},
{"'use strict'; let x = 8;", false, false, false},
{"'use strict'; let x; x = 8;", false, false, false},
{"'use strict'; const x = 8;", false, false, false},
{"function x() {}", false, false, false},
{"function x() { x = 0; }", false, false, true},
{"function h(x) { x = 0; }", false, false, false},
{"'use strict'; { let x; x = 0; }", false, false, false},
{"{ var x; }; x = 0;", false, false, false},
{"with ({}) {}", false, true, false},
{"var x; { with ({}) { x = 1; } }", false, true, false},
{"try {} catch(x) { x = 0; }", false, false, true},
{"try {} catch(x) { with ({}) { x = 1; } }", false, true, true},
// Eval approximation.
{"eval('');", true, false},
{"function h() { eval(''); }", true, false},
{"(function() { eval(''); })", true, false},
{"eval('');", true, false, false},
{"function h() { eval(''); }", true, false, false},
{"(function() { eval(''); })", true, false, false},
// Shadowing not recognized because of eval approximation.
{"var x; eval('');", true, false},
{"'use strict'; let x; eval('');", true, false},
{"try {} catch(x) { eval(''); }", true, false},
{"function x() { eval(''); }", true, false},
{"(function(x) { eval(''); })", true, false},
{"var x; eval('');", true, false, false},
{"'use strict'; let x; eval('');", true, false, false},
{"try {} catch(x) { eval(''); }", true, false, false},
{"function x() { eval(''); }", true, false, false},
{"(function(x) { eval(''); })", true, false, false},
};
int prefix_len = Utf8LengthHelper(prefix);
......@@ -3417,9 +3422,8 @@ TEST(InnerAssignment) {
CHECK(var->is_used() || !expected);
bool is_maybe_assigned = var->maybe_assigned() == i::kMaybeAssigned;
if (i::FLAG_lazy_inner_functions) {
// If we parse inner functions lazily, allow being pessimistic about
// maybe_assigned.
CHECK(is_maybe_assigned || (is_maybe_assigned == expected));
CHECK(is_maybe_assigned == expected ||
(is_maybe_assigned && inners[j].allow_error_in_inner_function));
} else {
CHECK_EQ(is_maybe_assigned, expected);
}
......
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