| Index: src/scopes.cc
|
| diff --git a/src/scopes.cc b/src/scopes.cc
|
| index 390a0b6e11ba8f1ccd4081fda789f582c8bc1554..658194c0b4bf3d72f18a9fb28790ebefc2d73861 100644
|
| --- a/src/scopes.cc
|
| +++ b/src/scopes.cc
|
| @@ -207,9 +207,17 @@ void Scope::SetDefaults(Type type,
|
| outer_scope_is_eval_scope_ = false;
|
| force_eager_compilation_ = false;
|
| num_var_or_const_ = 0;
|
| + num_stack_allocs_ = 0;
|
| num_stack_slots_ = 0;
|
| num_heap_slots_ = 0;
|
| scope_info_ = scope_info;
|
| + if (!scope_info_.is_null()) {
|
| + source_beg_statement_pos_ = scope_info_->SourceBegStatementPos();
|
| + source_end_statement_pos_ = scope_info_->SourceEndStatementPos();
|
| + } else {
|
| + source_beg_statement_pos_ = -1;
|
| + source_end_statement_pos_ = -1;
|
| + }
|
| }
|
|
|
|
|
| @@ -294,7 +302,7 @@ void Scope::Initialize(bool inside_with) {
|
| // 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_catch_scope()) {
|
| + if (is_catch_scope() || is_with_scope()) {
|
| ASSERT(outer_scope() != NULL);
|
| receiver_ = outer_scope()->receiver();
|
| } else {
|
| @@ -547,11 +555,16 @@ bool Scope::HasTrivialOuterContext() const {
|
| }
|
|
|
|
|
| +bool Scope::HasContext() const {
|
| + return num_heap_slots() > 0 || is_with_scope();
|
| +}
|
| +
|
| +
|
| int Scope::ContextChainLength(Scope* scope) {
|
| int n = 0;
|
| for (Scope* s = this; s != scope; s = s->outer_scope_) {
|
| ASSERT(s != NULL); // scope must be in the scope chain
|
| - if (s->num_heap_slots() > 0) n++;
|
| + if (s->HasContext()) n++;
|
| }
|
| return n;
|
| }
|
| @@ -559,7 +572,7 @@ int Scope::ContextChainLength(Scope* scope) {
|
|
|
| Scope* Scope::DeclarationScope() {
|
| Scope* scope = this;
|
| - while (scope->is_catch_scope()) {
|
| + while (scope->is_catch_scope() || scope->is_with_scope()) {
|
| scope = scope->outer_scope();
|
| }
|
| return scope;
|
| @@ -573,6 +586,7 @@ static const char* Header(Scope::Type type) {
|
| case Scope::FUNCTION_SCOPE: return "function";
|
| case Scope::GLOBAL_SCOPE: return "global";
|
| case Scope::CATCH_SCOPE: return "catch";
|
| + case Scope::WITH_SCOPE: return "with";
|
| }
|
| UNREACHABLE();
|
| return NULL;
|
| @@ -664,6 +678,8 @@ void Scope::Print(int n) {
|
| PrintF("%d stack slots\n", num_stack_slots_); }
|
| if (num_heap_slots_ > 0) { Indent(n1, "// ");
|
| PrintF("%d heap slots\n", num_heap_slots_); }
|
| + if (num_stack_allocs_ > 0) { Indent(n1, "// ");
|
| + PrintF("%d stack allocs\n", num_stack_allocs_); }
|
|
|
| // Print locals.
|
| PrettyPrinter printer;
|
| @@ -753,7 +769,9 @@ Variable* Scope::LookupRecursive(Handle<String> name,
|
| var = function_;
|
|
|
| } else if (outer_scope_ != NULL) {
|
| - var = outer_scope_->LookupRecursive(name, true, invalidated_local);
|
| + var = outer_scope_->LookupRecursive(name,
|
| + inner_lookup || is_function_scope(),
|
| + invalidated_local);
|
| // We may have found a variable in an outer scope. However, if
|
| // the current scope is inside a 'with', the actual variable may
|
| // be a property introduced via the 'with' statement. Then, the
|
| @@ -943,7 +961,7 @@ bool Scope::MustAllocateInContext(Variable* var) {
|
| // Exceptions: temporary variables are never allocated in a context;
|
| // catch-bound variables are always allocated in a context.
|
| if (var->mode() == Variable::TEMPORARY) return false;
|
| - if (is_catch_scope()) return true;
|
| + if (is_catch_scope() && !DeclarationScope()->is_function_scope()) return true;
|
| return var->is_accessed_from_inner_scope() ||
|
| scope_calls_eval_ ||
|
| inner_scope_calls_eval_ ||
|
| @@ -964,7 +982,9 @@ bool Scope::HasArgumentsParameter() {
|
|
|
|
|
| void Scope::AllocateStackSlot(Variable* var) {
|
| - var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
|
| + Scope* scope = DeclarationScope();
|
| + var->set_rewrite(NewSlot(var, Slot::LOCAL, scope->num_stack_allocs_++));
|
| + num_stack_slots_++;
|
| }
|
|
|
|
|
| @@ -1070,43 +1090,47 @@ void Scope::AllocateNonParameterLocals() {
|
|
|
|
|
| void Scope::AllocateVariablesRecursively() {
|
| - // Allocate variables for inner scopes.
|
| - for (int i = 0; i < inner_scopes_.length(); i++) {
|
| - inner_scopes_[i]->AllocateVariablesRecursively();
|
| - }
|
| -
|
| // If scope is already resolved, we still need to allocate
|
| // variables in inner scopes which might not had been resolved yet.
|
| - if (already_resolved()) return;
|
| - // The number of slots required for variables.
|
| - num_stack_slots_ = 0;
|
| - num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
|
| -
|
| - // Allocate variables for this scope.
|
| - // Parameters must be allocated first, if any.
|
| - if (is_function_scope()) AllocateParameterLocals();
|
| - AllocateNonParameterLocals();
|
| -
|
| - // Allocate context if necessary.
|
| - bool must_have_local_context = false;
|
| - if (scope_calls_eval_ || scope_contains_with_) {
|
| - // The context for the eval() call or 'with' statement in this scope.
|
| - // Unless we are in the global or an eval scope, we need a local
|
| - // context even if we didn't statically allocate any locals in it,
|
| - // and the compiler will access the context variable. If we are
|
| - // not in an inner scope, the scope is provided from the outside.
|
| - must_have_local_context = is_function_scope();
|
| - }
|
| + if (!already_resolved()) {
|
| + // The number of slots required for variables.
|
| + num_stack_slots_ = 0;
|
| + num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
|
| +
|
| + // Allocate variables for this scope.
|
| + // Parameters must be allocated first, if any.
|
| + if (is_function_scope()) AllocateParameterLocals();
|
| + AllocateNonParameterLocals();
|
| +
|
| + // Allocate context if necessary.
|
| + bool must_have_local_context = false;
|
| + if (scope_calls_eval_ || scope_contains_with_) {
|
| + // The context for the eval() call or 'with' statement in this scope.
|
| + // Unless we are in the global or an eval scope, we need a local
|
| + // context even if we didn't statically allocate any locals in it,
|
| + // and the compiler will access the context variable. If we are
|
| + // not in an inner scope, the scope is provided from the outside.
|
| + must_have_local_context = is_function_scope();
|
| + }
|
| +
|
| + // If we didn't allocate any locals in the local context, then we only
|
| + // need the minimal number of slots if we must have a local context.
|
| + if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
|
| + !must_have_local_context) {
|
| + num_heap_slots_ = 0;
|
| + }
|
|
|
| - // If we didn't allocate any locals in the local context, then we only
|
| - // need the minimal number of slots if we must have a local context.
|
| - if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
|
| - !must_have_local_context) {
|
| - num_heap_slots_ = 0;
|
| + // Allocation done.
|
| + ASSERT(num_heap_slots_ == 0 ||
|
| + num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
|
| }
|
|
|
| - // Allocation done.
|
| - ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
|
| + // Allocate variables for inner scopes. Must be done after parameters and
|
| + // local variables to allow reservation of stack slots for variables from
|
| + // nested blocks.
|
| + for (int i = 0; i < inner_scopes_.length(); i++) {
|
| + inner_scopes_[i]->AllocateVariablesRecursively();
|
| + }
|
| }
|
|
|
| } } // namespace v8::internal
|
|
|