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}
This commit is contained in:
rmcilroy 2015-10-15 08:43:55 -07:00 committed by Commit bot
parent 41e0965c9c
commit d820268c0b
3 changed files with 27 additions and 8 deletions

View File

@ -153,11 +153,10 @@ Handle<BytecodeArray> 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);

View File

@ -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()) {

View File

@ -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();