Commit 32842802 authored by neis's avatar neis Committed by Commit bot

[ast/parsing] Pessimistically assume all top-level variables will be assigned.

A previous CL (https://codereview.chromium.org/2634123002) did that for
let-declared variables.  This CL also does it for var- and function-declared
variables.

BUG=v8:5636

Review-Url: https://codereview.chromium.org/2656753003
Cr-Commit-Position: refs/heads/master@{#42813}
parent bfc8dc12
......@@ -218,6 +218,7 @@ void VariableProxy::BindTo(Variable* var) {
set_var(var);
set_is_resolved();
var->set_is_used();
if (is_assigned()) var->set_maybe_assigned();
}
void VariableProxy::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec,
......
......@@ -1844,7 +1844,6 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
#endif
DCHECK_NOT_NULL(var);
if (proxy->is_assigned()) var->set_maybe_assigned();
if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check();
proxy->BindTo(var);
}
......
......@@ -1480,6 +1480,10 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
bool* ok) {
VariableProxy* proxy =
factory()->NewVariableProxy(variable_name, NORMAL_VARIABLE);
DeclarationScope* target_scope = GetDeclarationScope();
MarkTopLevelVariableAsAssigned(target_scope, proxy);
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, function, scope(), pos);
Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized,
......@@ -1488,7 +1492,6 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
if (is_sloppy_block_function) {
SloppyBlockFunctionStatement* statement =
factory()->NewSloppyBlockFunctionStatement();
DeclarationScope* target_scope = GetDeclarationScope();
target_scope->DeclareSloppyBlockFunction(variable_name, scope(), statement);
return statement;
}
......
......@@ -824,6 +824,20 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
}
}
// Pessimistically assume that top-level variables will be assigned.
//
// Top-level variables in a script can be accessed by other scripts or even
// become global properties. While this does not apply to top-level variables
// in a module (assuming they are not exported), we must still mark these as
// assigned because they might be accessed by a lazily parsed top-level
// function, which, for efficiency, we preparse without variable tracking.
V8_INLINE static void MarkTopLevelVariableAsAssigned(Scope* scope,
VariableProxy* proxy) {
if (scope->is_script_scope() || scope->is_module_scope()) {
proxy->set_is_assigned();
}
}
// Returns true if we have a binary expression between two numeric
// literals. In that case, *x will be changed to an expression which is the
// computed value.
......
......@@ -162,6 +162,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
names_->Add(name, zone());
}
Scope* var_init_scope = descriptor_->scope;
MarkTopLevelVariableAsAssigned(var_init_scope, proxy);
// If there's no initializer, we're done.
if (value == nullptr) return;
......@@ -177,7 +180,6 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// 'v' than the 'v' in the declaration (e.g., if we are inside a
// 'with' statement or 'catch' block). Global var declarations
// also need special treatment.
Scope* var_init_scope = descriptor_->scope;
if (descriptor_->mode == VAR && var_init_scope->is_script_scope()) {
// Global variable declarations must be compiled in a specific
......@@ -220,19 +222,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// But for var declarations we need to do a new lookup.
if (descriptor_->mode == VAR) {
proxy = var_init_scope->NewUnresolved(factory(), name);
// TODO(neis): Set is_assigned on proxy.
} else {
DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(proxy->var());
if (var_init_scope->is_script_scope() ||
var_init_scope->is_module_scope()) {
// We have to pessimistically assume that top-level variables will be
// assigned. This is because they might be accessed by a lazily parsed
// top-level function, which, for efficiency, we preparse without
// variable tracking. In the case of a script (not a module), they
// might also get accessed by another script.
proxy->set_is_assigned();
}
}
// Add break location for destructured sub-pattern.
int pos = IsSubPattern() ? pattern->position() : value->position();
......
......@@ -3525,7 +3525,10 @@ TEST(MaybeAssignedTopLevel) {
const char* prefixes[] = {
"let foo; ", "let foo = 0; ",
"let [foo] = [1]; ", "let {foo} = {foo: 2}; ",
"let {foo=3} = {}; ",
"let {foo=3} = {}; ", "function foo() {}; ",
"var foo; ", "var foo = 0; ",
"var [foo] = [1]; ", "var {foo} = {foo: 2}; ",
"var {foo=3} = {}; ", "function* foo() {}; ",
};
const char* sources[] = {
"function bar() {foo = 42}; ext(bar); ext(foo)",
......
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