diff options
Diffstat (limited to 'deps/v8/src/scopes.cc')
-rw-r--r-- | deps/v8/src/scopes.cc | 150 |
1 files changed, 101 insertions, 49 deletions
diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index 74d0c2a2e2..5546875c4b 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -119,9 +119,9 @@ Scope::Scope(Type type) temps_(0), params_(0), unresolved_(0), - decls_(0) { + decls_(0), + already_resolved_(false) { SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null()); - ASSERT(!resolved()); } @@ -131,14 +131,14 @@ Scope::Scope(Scope* outer_scope, Type type) temps_(4), params_(4), unresolved_(16), - decls_(4) { + decls_(4), + already_resolved_(false) { SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null()); // At some point we might want to provide outer scopes to // eval scopes (by walking the stack and reading the scope info). // In that case, the ASSERT below needs to be adjusted. ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL)); ASSERT(!HasIllegalRedeclaration()); - ASSERT(!resolved()); } @@ -148,15 +148,34 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) temps_(4), params_(4), unresolved_(16), - decls_(4) { + decls_(4), + already_resolved_(true) { ASSERT(!scope_info.is_null()); SetDefaults(FUNCTION_SCOPE, NULL, scope_info); - ASSERT(resolved()); if (scope_info->HasHeapAllocatedLocals()) { num_heap_slots_ = scope_info_->NumberOfContextSlots(); } + AddInnerScope(inner_scope); +} + +Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name) + : inner_scopes_(1), + variables_(), + temps_(0), + params_(0), + unresolved_(0), + decls_(0), + already_resolved_(true) { + SetDefaults(CATCH_SCOPE, NULL, Handle<SerializedScopeInfo>::null()); AddInnerScope(inner_scope); + ++num_var_or_const_; + Variable* variable = variables_.Declare(this, + catch_variable_name, + Variable::VAR, + true, // Valid left-hand side. + Variable::NORMAL); + AllocateHeapSlot(variable); } @@ -190,30 +209,43 @@ void Scope::SetDefaults(Type type, Scope* Scope::DeserializeScopeChain(CompilationInfo* info, Scope* global_scope) { + // Reconstruct the outer scope chain from a closure's context chain. ASSERT(!info->closure().is_null()); - // If we have a serialized scope info, reuse it. + Context* context = info->closure()->context(); + Scope* current_scope = NULL; Scope* innermost_scope = NULL; - Scope* scope = NULL; - - SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info(); - if (scope_info != SerializedScopeInfo::Empty()) { - JSFunction* current = *info->closure(); - do { - current = current->context()->closure(); - Handle<SerializedScopeInfo> scope_info(current->shared()->scope_info()); - if (*scope_info != SerializedScopeInfo::Empty()) { - scope = new Scope(scope, scope_info); - if (innermost_scope == NULL) innermost_scope = scope; + bool contains_with = false; + while (!context->IsGlobalContext()) { + if (context->IsWithContext()) { + // All the inner scopes are inside a with. + contains_with = true; + for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) { + s->scope_inside_with_ = true; + } + } else { + if (context->IsFunctionContext()) { + SerializedScopeInfo* scope_info = + context->closure()->shared()->scope_info(); + current_scope = + new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info)); } else { - ASSERT(current->context()->IsGlobalContext()); + ASSERT(context->IsCatchContext()); + String* name = String::cast(context->extension()); + current_scope = new Scope(current_scope, Handle<String>(name)); } - } while (!current->context()->IsGlobalContext()); - } + if (contains_with) current_scope->RecordWithStatement(); + if (innermost_scope == NULL) innermost_scope = current_scope; + } - global_scope->AddInnerScope(scope); - if (innermost_scope == NULL) innermost_scope = global_scope; + // Forget about a with when we move to a context for a different function. + if (context->previous()->closure() != context->closure()) { + contains_with = false; + } + context = context->previous(); + } - return innermost_scope; + global_scope->AddInnerScope(current_scope); + return (innermost_scope == NULL) ? global_scope : innermost_scope; } @@ -238,7 +270,7 @@ bool Scope::Analyze(CompilationInfo* info) { void Scope::Initialize(bool inside_with) { - ASSERT(!resolved()); + ASSERT(!already_resolved()); // Add this scope as a new inner scope of the outer scope. if (outer_scope_ != NULL) { @@ -256,11 +288,16 @@ 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 - Variable* var = - variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR, - false, Variable::THIS); - var->set_rewrite(new Slot(var, Slot::PARAMETER, -1)); - receiver_ = var; + if (is_catch_scope()) { + ASSERT(outer_scope() != NULL); + receiver_ = outer_scope()->receiver(); + } else { + Variable* var = + variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR, + false, Variable::THIS); + var->set_rewrite(new Slot(var, Slot::PARAMETER, -1)); + receiver_ = var; + } if (is_function_scope()) { // Declare 'arguments' variable which exists in all functions. @@ -274,11 +311,10 @@ void Scope::Initialize(bool inside_with) { Variable* Scope::LocalLookup(Handle<String> name) { Variable* result = variables_.Lookup(name); - if (result != NULL || !resolved()) { + if (result != NULL || scope_info_.is_null()) { return result; } - // If the scope is resolved, we can find a variable in serialized scope - // info. + // If we have a serialized scope info, we might find the variable there. // // We should never lookup 'arguments' in this scope as it is implicitly // present in every scope. @@ -326,7 +362,7 @@ Variable* Scope::DeclareFunctionVar(Handle<String> name) { void Scope::DeclareParameter(Handle<String> name) { - ASSERT(!resolved()); + ASSERT(!already_resolved()); ASSERT(is_function_scope()); Variable* var = variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); @@ -335,7 +371,7 @@ void Scope::DeclareParameter(Handle<String> name) { Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) { - ASSERT(!resolved()); + ASSERT(!already_resolved()); // This function handles VAR and CONST modes. DYNAMIC variables are // introduces during variable allocation, INTERNAL variables are allocated // explicitly, and TEMPORARY variables are allocated via NewTemporary(). @@ -358,7 +394,7 @@ VariableProxy* Scope::NewUnresolved(Handle<String> name, // Note that we must not share the unresolved variables with // the same name because they may be removed selectively via // RemoveUnresolved(). - ASSERT(!resolved()); + ASSERT(!already_resolved()); VariableProxy* proxy = new VariableProxy(name, false, inside_with, position); unresolved_.Add(proxy); return proxy; @@ -378,7 +414,7 @@ void Scope::RemoveUnresolved(VariableProxy* var) { Variable* Scope::NewTemporary(Handle<String> name) { - ASSERT(!resolved()); + ASSERT(!already_resolved()); Variable* var = new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL); temps_.Add(var); @@ -508,12 +544,22 @@ int Scope::ContextChainLength(Scope* scope) { } +Scope* Scope::DeclarationScope() { + Scope* scope = this; + while (scope->is_catch_scope()) { + scope = scope->outer_scope(); + } + return scope; +} + + #ifdef DEBUG static const char* Header(Scope::Type type) { switch (type) { case Scope::EVAL_SCOPE: return "eval"; case Scope::FUNCTION_SCOPE: return "function"; case Scope::GLOBAL_SCOPE: return "global"; + case Scope::CATCH_SCOPE: return "catch"; } UNREACHABLE(); return NULL; @@ -864,8 +910,10 @@ bool Scope::MustAllocate(Variable* var) { // visible name. if ((var->is_this() || var->name()->length() > 0) && (var->is_accessed_from_inner_scope() || - scope_calls_eval_ || inner_scope_calls_eval_ || - scope_contains_with_)) { + scope_calls_eval_ || + inner_scope_calls_eval_ || + scope_contains_with_ || + is_catch_scope())) { var->set_is_used(true); } // Global variables do not need to be allocated. @@ -874,16 +922,20 @@ bool Scope::MustAllocate(Variable* var) { bool Scope::MustAllocateInContext(Variable* var) { - // If var is accessed from an inner scope, or if there is a - // possibility that it might be accessed from the current or an inner - // scope (through an eval() call), it must be allocated in the - // context. Exception: temporary variables are not allocated in the + // If var is accessed from an inner scope, or if there is a possibility + // that it might be accessed from the current or an inner scope (through + // an eval() call or a runtime with lookup), it must be allocated in the // context. - return - var->mode() != Variable::TEMPORARY && - (var->is_accessed_from_inner_scope() || - scope_calls_eval_ || inner_scope_calls_eval_ || - scope_contains_with_ || var->is_global()); + // + // 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; + return var->is_accessed_from_inner_scope() || + scope_calls_eval_ || + inner_scope_calls_eval_ || + scope_contains_with_ || + var->is_global(); } @@ -1010,7 +1062,7 @@ void Scope::AllocateVariablesRecursively() { // If scope is already resolved, we still need to allocate // variables in inner scopes which might not had been resolved yet. - if (resolved()) return; + if (already_resolved()) return; // The number of slots required for variables. num_stack_slots_ = 0; num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; |