From d820268c0ba9536f3289206e2d928aa7e9436037 Mon Sep 17 00:00:00 2001 From: rmcilroy Date: Thu, 15 Oct 2015 08:43:55 -0700 Subject: [PATCH] Add support for calculating a scopes maximum nested context chain. Adds Scope::MaxNestedContextChainLength() which calculates the maximum length of the context chain for the given scope. This is used by the interpreter to preallocate the approprate number of context registers when compiling the function. BUG=v8:4280 LOG=N Review URL: https://codereview.chromium.org/1404793004 Cr-Commit-Position: refs/heads/master@{#31309} --- src/interpreter/bytecode-generator.cc | 5 ++--- src/scopes.cc | 19 +++++++++++++++---- src/scopes.h | 11 ++++++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index dc36fb1aa5..a4efcce1da 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -153,11 +153,10 @@ Handle BytecodeGenerator::MakeBytecode(CompilationInfo* info) { builder()->set_parameter_count(info->num_parameters_including_this()); builder()->set_locals_count(scope()->num_stack_slots()); - // TODO(rmcilroy): Set correct context count. - builder()->set_context_count(info->num_heap_slots() > 0 ? 1 : 0); + builder()->set_context_count(scope()->MaxNestedContextChainLength()); // Build function context only if there are context allocated variables. - if (info->num_heap_slots() > 0) { + if (scope()->NeedsContext()) { // Push a new inner context scope for the function. VisitNewLocalFunctionContext(); ContextScope top_context(this, true); diff --git a/src/scopes.cc b/src/scopes.cc index dbcc4b6083..4e6acca5fc 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -765,15 +765,26 @@ int Scope::ContextChainLength(Scope* scope) { int n = 0; for (Scope* s = this; s != scope; s = s->outer_scope_) { DCHECK(s != NULL); // scope must be in the scope chain - if (s->is_with_scope() || s->num_heap_slots() > 0) n++; - // Catch and module scopes always have heap slots. - DCHECK(!s->is_catch_scope() || s->num_heap_slots() > 0); - DCHECK(!s->is_module_scope() || s->num_heap_slots() > 0); + if (s->NeedsContext()) n++; } return n; } +int Scope::MaxNestedContextChainLength() { + int max_context_chain_length = 0; + for (int i = 0; i < inner_scopes_.length(); i++) { + Scope* scope = inner_scopes_[i]; + max_context_chain_length = std::max(scope->MaxNestedContextChainLength(), + max_context_chain_length); + } + if (NeedsContext()) { + max_context_chain_length += 1; + } + return max_context_chain_length; +} + + Scope* Scope::DeclarationScope() { Scope* scope = this; while (!scope->is_declaration_scope()) { diff --git a/src/scopes.h b/src/scopes.h index 26c092fe3e..16581d776f 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -341,7 +341,12 @@ class Scope: public ZoneObject { bool is_nonlinear() const { return scope_nonlinear_; } // Whether this needs to be represented by a runtime context. - bool NeedsContext() const { return num_heap_slots() > 0; } + bool NeedsContext() const { + // Catch and module scopes always have heap slots. + DCHECK(!is_catch_scope() || num_heap_slots() > 0); + DCHECK(!is_module_scope() || num_heap_slots() > 0); + return is_with_scope() || num_heap_slots() > 0; + } bool NeedsHomeObject() const { return scope_uses_super_property_ || @@ -519,6 +524,10 @@ class Scope: public ZoneObject { // The number of contexts between this and scope; zero if this == scope. int ContextChainLength(Scope* scope); + // The maximum number of nested contexts required for this scope and any inner + // scopes. + int MaxNestedContextChainLength(); + // Find the first function, script, eval or (declaration) block scope. This is // the scope where var declarations will be hoisted to in the implementation. Scope* DeclarationScope();