Index: src/scopes.cc |
diff --git a/src/scopes.cc b/src/scopes.cc |
index 8b623f90ce908ac548bfd8ea46bdcf088121bbcf..b130033a779b0ffb32107b810d7f4d5e51217d62 100644 |
--- a/src/scopes.cc |
+++ b/src/scopes.cc |
@@ -77,6 +77,7 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type, |
internals_(4, zone), |
temps_(4, zone), |
params_(4, zone), |
+ param_positions_(4, zone), |
unresolved_(16, zone), |
decls_(4, zone), |
module_descriptor_( |
@@ -100,6 +101,7 @@ Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, |
internals_(4, zone), |
temps_(4, zone), |
params_(4, zone), |
+ param_positions_(4, zone), |
unresolved_(16, zone), |
decls_(4, zone), |
module_descriptor_(NULL), |
@@ -126,6 +128,7 @@ Scope::Scope(Zone* zone, Scope* inner_scope, |
internals_(0, zone), |
temps_(0, zone), |
params_(0, zone), |
+ param_positions_(0, zone), |
unresolved_(0, zone), |
decls_(0, zone), |
module_descriptor_(NULL), |
@@ -150,6 +153,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope, |
Handle<ScopeInfo> scope_info, |
FunctionKind function_kind) { |
outer_scope_ = outer_scope; |
+ function_body_ = nullptr; |
scope_type_ = scope_type; |
function_kind_ = function_kind; |
block_scope_is_class_scope_ = false; |
@@ -194,6 +198,12 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope, |
block_scope_is_class_scope_ = scope_info->block_scope_is_class_scope(); |
function_kind_ = scope_info->function_kind(); |
} |
+ if (scope_type == FUNCTION_BODY_SCOPE) { |
+ DCHECK_NOT_NULL(outer_scope); |
+ DCHECK(outer_scope->is_function_scope()); |
+ DCHECK_NULL(outer_scope->function_body_); |
+ outer_scope->function_body_ = this; |
+ } |
} |
@@ -317,7 +327,7 @@ void Scope::Initialize() { |
// instead load them directly from the stack. Currently, the only |
// such parameter is 'this' which is passed on the stack when |
// invoking scripts |
- if (is_declaration_scope()) { |
+ if (is_declaration_scope() && !is_function_body_scope()) { |
DCHECK(!subclass_constructor || is_function_scope()); |
Variable* var = variables_.Declare( |
this, ast_value_factory_->this_string(), |
@@ -359,6 +369,12 @@ Scope* Scope::FinalizeBlockScope() { |
if (num_var_or_const() > 0) return this; |
+ // If this is the function body scope of a function scope, remove the parent |
+ // function body. |
+ if (outer_scope_->function_body_ == this) { |
+ outer_scope_->function_body_ = nullptr; |
+ } |
+ |
// Remove this scope from outer scope. |
for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) { |
if (outer_scope_->inner_scopes_[i] == this) { |
@@ -464,7 +480,7 @@ Variable* Scope::Lookup(const AstRawString* name) { |
Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode, |
- bool is_rest, bool* is_duplicate) { |
+ int pos, bool is_rest, bool* is_duplicate) { |
DCHECK(!already_resolved()); |
DCHECK(is_function_scope()); |
Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL, |
@@ -477,6 +493,7 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode, |
// TODO(wingo): Avoid O(n^2) check. |
*is_duplicate = IsDeclaredParameter(name); |
params_.Add(var, zone()); |
+ param_positions_.Add(pos, zone()); |
return var; |
} |
@@ -496,6 +513,17 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
} |
+Variable* Scope::RedeclareLocal(const AstRawString* name, VariableMode mode, |
+ InitializationFlag init_flag, |
+ Variable::Kind kind, |
+ MaybeAssignedFlag maybe_assigned_flag, |
+ int declaration_group_start) { |
+ variables_.Remove(const_cast<AstRawString*>(name), name->hash()); |
+ return DeclareLocal(name, mode, init_flag, kind, maybe_assigned_flag, |
+ declaration_group_start); |
+} |
+ |
+ |
Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { |
DCHECK(is_script_scope()); |
return variables_.Declare(this, |
@@ -543,7 +571,14 @@ Variable* Scope::NewTemporary(const AstRawString* name) { |
void Scope::AddDeclaration(Declaration* declaration) { |
- decls_.Add(declaration, zone()); |
+ Scope* target = this; |
+ if (is_function_body_scope() && |
+ (declaration->mode() == VAR || declaration->IsFunctionDeclaration())) { |
+ // Add `var` declarations to outer scope, to make allocation simpler |
+ target = outer_scope(); |
+ DCHECK(target->is_function_scope()); |
+ } |
+ target->decls_.Add(declaration, zone()); |
} |
@@ -718,7 +753,9 @@ bool Scope::HasLazyCompilableOuterContext() const { |
outer = outer->DeclarationScope(); |
bool found_non_trivial_declarations = false; |
for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) { |
- if (scope->is_with_scope() && !found_non_trivial_declarations) return false; |
+ if ((scope->is_function_body_scope() || scope->is_with_scope()) && |
+ !found_non_trivial_declarations) |
+ return false; |
if (scope->is_block_scope() && !scope->decls_.is_empty()) return false; |
if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) { |
found_non_trivial_declarations = true; |
@@ -819,6 +856,8 @@ static const char* Header(ScopeType scope_type) { |
case BLOCK_SCOPE: return "block"; |
case WITH_SCOPE: return "with"; |
case ARROW_SCOPE: return "arrow"; |
+ case FUNCTION_BODY_SCOPE: |
+ return "function body"; |
} |
UNREACHABLE(); |
return NULL; |
@@ -1021,7 +1060,6 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, |
*binding_kind = DYNAMIC_LOOKUP; |
return NULL; |
} |
- |
// Try to find the variable in this scope. |
Variable* var = LookupLocal(proxy->raw_name()); |
@@ -1078,7 +1116,6 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, |
bool Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, |
AstNodeFactory* factory) { |
DCHECK(info->script_scope()->is_script_scope()); |
- |
// If the proxy is already resolved there's nothing to do |
// (functions and consts may be resolved by the parser). |
if (proxy->is_resolved()) return true; |
@@ -1356,7 +1393,11 @@ bool Scope::HasArgumentsParameter(Isolate* isolate) { |
void Scope::AllocateStackSlot(Variable* var) { |
- if (is_block_scope()) { |
+ if (is_function_body_scope()) { |
+ // Function body variables need to be allocated in the "real" function |
+ // scope, but can't be resolved from it |
+ outer_scope()->AllocateStackSlot(var); |
+ } else if (is_block_scope()) { |
DeclarationScope()->AllocateStackSlot(var); |
} else { |
var->AllocateTo(Variable::LOCAL, num_stack_slots_++); |
@@ -1365,6 +1406,8 @@ void Scope::AllocateStackSlot(Variable* var) { |
void Scope::AllocateHeapSlot(Variable* var) { |
+ DCHECK(!is_function_body_scope() || var->scope() == outer_scope()); |
+ if (is_function_body_scope()) return outer_scope()->AllocateHeapSlot(var); |
var->AllocateTo(Variable::CONTEXT, num_heap_slots_++); |
} |
@@ -1434,7 +1477,8 @@ void Scope::AllocateParameterLocals(Isolate* isolate) { |
void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) { |
- DCHECK(var->scope() == this); |
+ DCHECK(var->scope() == this || |
+ (is_function_body_scope() && var->scope() == outer_scope())); |
DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) || |
!var->IsStackLocal()); |
if (var->IsUnallocated() && MustAllocate(var)) { |
@@ -1539,12 +1583,14 @@ void Scope::AllocateModules() { |
int Scope::StackLocalCount() const { |
+ DCHECK(!function_body() || function_body()->num_stack_slots() == 0); |
return num_stack_slots() - |
(function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); |
} |
int Scope::ContextLocalCount() const { |
+ DCHECK(!function_body() || function_body()->num_heap_slots() == 0); |
if (num_heap_slots() == 0) return 0; |
return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
(function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); |