Commit 65bae443 authored by verwaest's avatar verwaest Committed by Commit bot

Add function-var to variables_ so LookupRecursive doesn't need to special-case it

After parsing a function, if there's no masking declaration in the function scope, DeclareFunctionVar will also bind the function name to a variable. It will either bind it to the const/const-legacy function_ variable, or to a dynamic non-local if the function calls sloppy eval.

Even if the variable is masked or sloppy eval is called, we still declare the function-var. The client immediately sets up the variable by assigning the resulting function to it.

BUG=v8:5209

Review-Url: https://codereview.chromium.org/2274133002
Cr-Commit-Position: refs/heads/master@{#39581}
parent 15b4b218
...@@ -624,10 +624,16 @@ void DeclarationScope::DeclareDefaultFunctionVariables( ...@@ -624,10 +624,16 @@ void DeclarationScope::DeclareDefaultFunctionVariables(
Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) { Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) {
DCHECK(is_function_scope()); DCHECK(is_function_scope());
DCHECK_NULL(function_); DCHECK_NULL(function_);
DCHECK_NULL(variables_.Lookup(name));
VariableKind kind = is_sloppy(language_mode()) ? SLOPPY_FUNCTION_NAME_VARIABLE VariableKind kind = is_sloppy(language_mode()) ? SLOPPY_FUNCTION_NAME_VARIABLE
: NORMAL_VARIABLE; : NORMAL_VARIABLE;
function_ = function_ =
new (zone()) Variable(this, name, CONST, kind, kCreatedInitialized); new (zone()) Variable(this, name, CONST, kind, kCreatedInitialized);
if (calls_sloppy_eval()) {
NonLocal(name, DYNAMIC);
} else {
variables_.Add(function_);
}
return function_; return function_;
} }
...@@ -766,7 +772,15 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name) { ...@@ -766,7 +772,15 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name) {
index = scope_info_->ModuleIndex(name_handle, &mode, &init_flag, index = scope_info_->ModuleIndex(name_handle, &mode, &init_flag,
&maybe_assigned_flag); &maybe_assigned_flag);
} }
if (index < 0) return nullptr; // Nowhere found.
if (index < 0) {
index = scope_info_->FunctionContextSlotIndex(*name_handle);
if (index < 0) return nullptr; // Nowhere found.
Variable* var = AsDeclarationScope()->DeclareFunctionVar(name);
DCHECK_EQ(CONST, var->mode());
var->AllocateTo(VariableLocation::CONTEXT, index);
return variables_.Lookup(name);
}
VariableKind kind = NORMAL_VARIABLE; VariableKind kind = NORMAL_VARIABLE;
if (location == VariableLocation::CONTEXT && if (location == VariableLocation::CONTEXT &&
...@@ -782,22 +796,6 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name) { ...@@ -782,22 +796,6 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name) {
return var; return var;
} }
Variable* DeclarationScope::LookupFunctionVar(const AstRawString* name) {
if (function_ != nullptr && function_->raw_name() == name) {
return function_;
} else if (!scope_info_.is_null()) {
// If we are backed by a scope info, try to lookup the variable there.
int index = scope_info_->FunctionContextSlotIndex(*(name->string()));
if (index < 0) return nullptr;
Variable* var = DeclareFunctionVar(name);
var->AllocateTo(VariableLocation::CONTEXT, index);
return var;
} else {
return nullptr;
}
}
Variable* Scope::Lookup(const AstRawString* name) { Variable* Scope::Lookup(const AstRawString* name) {
for (Scope* scope = this; for (Scope* scope = this;
scope != NULL; scope != NULL;
...@@ -1455,16 +1453,6 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, Scope* outer_scope_end) { ...@@ -1455,16 +1453,6 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, Scope* outer_scope_end) {
// remains the same.) // remains the same.)
if (var != nullptr) return var; if (var != nullptr) return var;
// We did not find a variable locally. Check against the function variable, if
// any.
if (is_function_scope()) {
var = AsDeclarationScope()->LookupFunctionVar(proxy->raw_name());
if (var != nullptr) {
if (calls_sloppy_eval()) return NonLocal(proxy->raw_name(), DYNAMIC);
return var;
}
}
if (outer_scope_ == outer_scope_end) { if (outer_scope_ == outer_scope_end) {
// We may just be trying to find all free variables. In that case, don't // We may just be trying to find all free variables. In that case, don't
// declare them in the outer scope. // declare them in the outer scope.
......
...@@ -638,15 +638,14 @@ class DeclarationScope : public Scope { ...@@ -638,15 +638,14 @@ class DeclarationScope : public Scope {
void DeclareArguments(AstValueFactory* ast_value_factory); void DeclareArguments(AstValueFactory* ast_value_factory);
void DeclareDefaultFunctionVariables(AstValueFactory* ast_value_factory); void DeclareDefaultFunctionVariables(AstValueFactory* ast_value_factory);
// This lookup corresponds to a lookup in the "intermediate" scope sitting
// between this scope and the outer scope. (ECMA-262, 3rd., requires that
// the name of named function literal is kept in an intermediate scope
// in between this scope and the next outer scope.)
Variable* LookupFunctionVar(const AstRawString* name);
// Declare the function variable for a function literal. This variable // Declare the function variable for a function literal. This variable
// is in an intermediate scope between this function scope and the the // is in an intermediate scope between this function scope and the the
// outer scope. Only possible for function scopes; at most one variable. // outer scope. Only possible for function scopes; at most one variable.
//
// This function needs to be called after all other variables have been
// declared in the scope. It will add a variable for {name} to {variables_};
// either the function variable itself, or a non-local in case the function
// calls sloppy eval.
Variable* DeclareFunctionVar(const AstRawString* name); Variable* DeclareFunctionVar(const AstRawString* name);
// Declare a parameter in this scope. When there are duplicated // Declare a parameter in this scope. When there are duplicated
......
...@@ -3662,17 +3662,22 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( ...@@ -3662,17 +3662,22 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
} }
if (function_type == FunctionLiteral::kNamedExpression) { if (function_type == FunctionLiteral::kNamedExpression) {
// Now that we know the language mode, we can create the const assignment Statement* statement;
// in the previously reserved spot. if (function_scope->LookupLocal(function_name) == nullptr) {
DCHECK_EQ(function_scope, scope()); // Now that we know the language mode, we can create the const assignment
Variable* fvar = function_scope->DeclareFunctionVar(function_name); // in the previously reserved spot.
VariableProxy* fproxy = factory()->NewVariableProxy(fvar); DCHECK_EQ(function_scope, scope());
result->Set(kFunctionNameAssignmentIndex, Variable* fvar = function_scope->DeclareFunctionVar(function_name);
factory()->NewExpressionStatement( VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
factory()->NewAssignment(Token::INIT, fproxy, statement = factory()->NewExpressionStatement(
factory()->NewThisFunction(pos), factory()->NewAssignment(Token::INIT, fproxy,
kNoSourcePosition), factory()->NewThisFunction(pos),
kNoSourcePosition)); kNoSourcePosition),
kNoSourcePosition);
} else {
statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
result->Set(kFunctionNameAssignmentIndex, statement);
} }
MarkCollectedTailCallExpressions(); MarkCollectedTailCallExpressions();
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
function f() {
{
function f() { return 42 }
}
function g() { return f }
return g;
}
var g = f();
var inner_f = g();
assertEquals(42, inner_f());
})();
(function() {
var y = 100;
var z = (function y() { return y; });
assertEquals(z, z());
})();
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