Chromium Code Reviews| Index: src/runtime.cc |
| diff --git a/src/runtime.cc b/src/runtime.cc |
| index 8e97f08179b4f99a2b61620de13ff593a949e782..683e25a7b235644c2ab9a5a48ea61595f06549fd 100644 |
| --- a/src/runtime.cc |
| +++ b/src/runtime.cc |
| @@ -10925,9 +10925,10 @@ static Handle<JSObject> MaterializeBlockScope( |
| } |
| -// Iterate over the actual scopes visible from a stack frame. All scopes are |
| +// Iterate over the actual scopes visible from a stack frame. The iteration |
| +// proceeds from the innermost visible nested scope outwards. All scopes are |
| // backed by an actual context except the local scope, which is inserted |
| -// "artifically" in the context chain. |
| +// "artificially" in the context chain. |
| class ScopeIterator { |
| public: |
| enum ScopeType { |
|
Kevin Millikin (Chromium)
2011/10/05 08:43:36
Can this be the same as Scope::Type?
Steven
2011/10/06 19:09:27
Almost. The ScopeIterator so far makes a differenc
|
| @@ -10947,28 +10948,12 @@ class ScopeIterator { |
| inlined_frame_index_(inlined_frame_index), |
| function_(JSFunction::cast(frame->function())), |
| context_(Context::cast(frame->context())), |
| - local_done_(false), |
| - at_local_(false) { |
| - |
| - // Check whether the first scope is actually a local scope. |
| - // If there is a stack slot for .result then this local scope has been |
| - // created for evaluating top level code and it is not a real local scope. |
| - // Checking for the existence of .result seems fragile, but the scope info |
| - // saved with the code object does not otherwise have that information. |
| - int index = function_->shared()->scope_info()-> |
| - StackSlotIndex(isolate_->heap()->result_symbol()); |
| - if (index >= 0) { |
| - local_done_ = true; |
| - } else if (context_->IsGlobalContext() || |
| - context_->IsFunctionContext()) { |
| - at_local_ = true; |
| - } else if (context_->closure() != *function_) { |
| - // The context_ is a block or with or catch block from the outer function. |
| - ASSERT(context_->IsWithContext() || |
| - context_->IsCatchContext() || |
| - context_->IsBlockContext()); |
| - at_local_ = true; |
| - } |
| + nested_scope_chain_(4) { |
| + |
| + Handle<SerializedScopeInfo> scope_info(function_->shared()->scope_info()); |
| + int statement_position = |
| + function_->shared()->code()->SourceStatementPosition(frame_->pc()); |
| + scope_info->GetNestedScopeChain(&nested_scope_chain_, statement_position); |
| } |
| // More scopes? |
| @@ -10976,40 +10961,48 @@ class ScopeIterator { |
| // Move to the next scope. |
| void Next() { |
| - // If at a local scope mark the local scope as passed. |
| - if (at_local_) { |
| - at_local_ = false; |
| - local_done_ = true; |
| - |
| - // If the current context is not associated with the local scope the |
| - // current context is the next real scope, so don't move to the next |
| - // context in this case. |
| - if (context_->closure() != *function_) { |
| - return; |
| - } |
| - } |
| - |
| - // The global scope is always the last in the chain. |
| - if (context_->IsGlobalContext()) { |
| + ScopeType scope_type = Type(); |
| + if (scope_type == ScopeTypeGlobal) { |
| + // The global scope is always the last in the chain. |
| + ASSERT(context_->IsGlobalContext()); |
| context_ = Handle<Context>(); |
| return; |
| } |
| - |
| - // Move to the next context. |
| - context_ = Handle<Context>(context_->previous(), isolate_); |
| - |
| - // If passing the local scope indicate that the current scope is now the |
| - // local scope. |
| - if (!local_done_ && |
| - (context_->IsGlobalContext() || context_->IsFunctionContext())) { |
| - at_local_ = true; |
| + if (nested_scope_chain_.is_empty()) { |
| + context_ = Handle<Context>(context_->previous(), isolate_); |
| + } else { |
| + if (nested_scope_chain_.last()->HasContext()) { |
| + context_ = Handle<Context>(context_->previous(), isolate_); |
| + } |
| + nested_scope_chain_.RemoveLast(); |
| } |
| } |
| // Return the type of the current scope. |
| ScopeType Type() { |
| - if (at_local_) { |
| - return ScopeTypeLocal; |
| + if (!nested_scope_chain_.is_empty()) { |
| + Handle<SerializedScopeInfo> scope_info = nested_scope_chain_.last(); |
| + switch (scope_info->ScopeType()) { |
| + case Scope::FUNCTION_SCOPE: |
| + ASSERT(context_->IsFunctionContext() || |
| + !scope_info->HasContext()); |
| + return ScopeTypeLocal; |
| + case Scope::GLOBAL_SCOPE: |
| + ASSERT(context_->IsGlobalContext()); |
| + return ScopeTypeGlobal; |
| + case Scope::WITH_SCOPE: |
| + ASSERT(context_->IsWithContext()); |
| + return ScopeTypeWith; |
| + case Scope::CATCH_SCOPE: |
| + ASSERT(context_->IsCatchContext()); |
| + return ScopeTypeCatch; |
| + case Scope::BLOCK_SCOPE: |
| + ASSERT(!scope_info->HasContext() || |
| + context_->IsBlockContext()); |
| + return ScopeTypeBlock; |
| + case Scope::EVAL_SCOPE: |
| + UNREACHABLE(); |
| + } |
| } |
| if (context_->IsGlobalContext()) { |
| ASSERT(context_->global()->IsGlobalObject()); |
| @@ -11035,6 +11028,7 @@ class ScopeIterator { |
| return Handle<JSObject>(CurrentContext()->global()); |
| case ScopeIterator::ScopeTypeLocal: |
| // Materialize the content of the local scope into a JSObject. |
| + ASSERT(nested_scope_chain_.length() == 1); |
| return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_); |
| case ScopeIterator::ScopeTypeWith: |
| // Return the with object. |
| @@ -11051,13 +11045,30 @@ class ScopeIterator { |
| return Handle<JSObject>(); |
| } |
| + Handle<SerializedScopeInfo> CurrentScopeInfo() { |
| + if (!nested_scope_chain_.is_empty()) { |
| + return nested_scope_chain_.last(); |
| + } else if (context_->IsBlockContext()) { |
| + return Handle<SerializedScopeInfo>( |
| + SerializedScopeInfo::cast(context_->extension())); |
| + } else if (context_->IsFunctionContext()) { |
| + return Handle<SerializedScopeInfo>( |
| + context_->closure()->shared()->scope_info()); |
| + } |
| + return Handle<SerializedScopeInfo>::null(); |
| + } |
| + |
| // Return the context for this scope. For the local context there might not |
| // be an actual context. |
| Handle<Context> CurrentContext() { |
| - if (at_local_ && context_->closure() != *function_) { |
| + if (Type() == ScopeTypeGlobal || |
| + nested_scope_chain_.is_empty()) { |
| + return context_; |
| + } else if (nested_scope_chain_.last()->HasContext()) { |
| + return context_; |
| + } else { |
| return Handle<Context>(); |
| } |
| - return context_; |
| } |
| #ifdef DEBUG |
| @@ -11120,8 +11131,7 @@ class ScopeIterator { |
| int inlined_frame_index_; |
| Handle<JSFunction> function_; |
| Handle<Context> context_; |
| - bool local_done_; |
| - bool at_local_; |
| + List<Handle<SerializedScopeInfo> > nested_scope_chain_; |
| DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); |
| }; |
| @@ -11584,46 +11594,65 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { |
| // Creates a copy of the with context chain. The copy of the context chain is |
| // is linked to the function context supplied. |
| -static Handle<Context> CopyWithContextChain(Isolate* isolate, |
| - Handle<JSFunction> function, |
| - Handle<Context> current, |
| - Handle<Context> base) { |
| - // At the end of the chain. Return the base context to link to. |
| - if (current->IsFunctionContext() || current->IsGlobalContext()) { |
| - return base; |
| +static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, |
| + Handle<JSFunction> function, |
| + Handle<Context> base, |
| + JavaScriptFrame* frame, |
| + int inlined_frame_index) { |
| + HandleScope scope(isolate); |
| + List<Handle<SerializedScopeInfo> > scope_chain; |
| + List<Handle<Context> > context_chain; |
| + |
| + ScopeIterator it(isolate, frame, inlined_frame_index); |
| + for (; it.Type() != ScopeIterator::ScopeTypeGlobal && |
| + it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) { |
| + ASSERT(!it.Done()); |
| + scope_chain.Add(it.CurrentScopeInfo()); |
| + context_chain.Add(it.CurrentContext()); |
| } |
| - // Recursively copy the with and catch contexts. |
| - HandleScope scope(isolate); |
| - Handle<Context> previous(current->previous()); |
| - Handle<Context> new_previous = |
| - CopyWithContextChain(isolate, function, previous, base); |
| - Handle<Context> new_current; |
| - if (current->IsCatchContext()) { |
| - Handle<String> name(String::cast(current->extension())); |
| - Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX)); |
| - new_current = |
| - isolate->factory()->NewCatchContext(function, |
| - new_previous, |
| - name, |
| - thrown_object); |
| - } else if (current->IsBlockContext()) { |
| - Handle<SerializedScopeInfo> scope_info( |
| - SerializedScopeInfo::cast(current->extension())); |
| - new_current = |
| - isolate->factory()->NewBlockContext(function, new_previous, scope_info); |
| - // Copy context slots. |
| - int num_context_slots = scope_info->NumberOfContextSlots(); |
| - for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) { |
| - new_current->set(i, current->get(i)); |
| + // At the end of the chain. Return the base context to link to. |
| + Handle<Context> context = base; |
| + |
| + // Iteratively copy and or materialize the nested contexts. |
| + while (!scope_chain.is_empty()) { |
| + Handle<SerializedScopeInfo> scope_info = scope_chain.RemoveLast(); |
| + Handle<Context> current = context_chain.RemoveLast(); |
| + ASSERT(!(scope_info->HasContext() & current.is_null())); |
| + |
| + if (scope_info->ScopeType() == Scope::CATCH_SCOPE) { |
| + Handle<String> name(String::cast(current->extension())); |
| + Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX)); |
| + context = |
| + isolate->factory()->NewCatchContext(function, |
| + context, |
| + name, |
| + thrown_object); |
| + } else if (scope_info->ScopeType() == Scope::BLOCK_SCOPE) { |
| + // Materialize the contents of the block scope into a JSObject. |
| + Handle<JSObject> block_scope_object = |
| + MaterializeBlockScope(isolate, current); |
| + if (block_scope_object.is_null()) { |
| + return Handle<Context>::null(); |
| + } |
| + // Allocate a new function context for the debug evaluation and set the |
| + // extension object. |
| + Handle<Context> new_context = |
| + isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, |
| + function); |
| + new_context->set_extension(*block_scope_object); |
| + new_context->set_previous(*context); |
| + context = new_context; |
| + } else { |
| + ASSERT(scope_info->ScopeType() == Scope::WITH_SCOPE); |
| + ASSERT(current->IsWithContext()); |
| + Handle<JSObject> extension(JSObject::cast(current->extension())); |
| + context = |
| + isolate->factory()->NewWithContext(function, context, extension); |
| } |
| - } else { |
| - ASSERT(current->IsWithContext()); |
| - Handle<JSObject> extension(JSObject::cast(current->extension())); |
| - new_current = |
| - isolate->factory()->NewWithContext(function, new_previous, extension); |
| } |
| - return scope.CloseAndEscape(new_current); |
| + |
| + return scope.CloseAndEscape(context); |
| } |
| @@ -11761,7 +11790,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { |
| if (scope_info->HasHeapAllocatedLocals()) { |
| function_context = Handle<Context>(frame_context->declaration_context()); |
| } |
| - context = CopyWithContextChain(isolate, go_between, frame_context, context); |
| + context = CopyNestedScopeContextChain(isolate, |
| + go_between, |
| + context, |
| + frame, |
| + inlined_frame_index); |
| if (additional_context->IsJSObject()) { |
| Handle<JSObject> extension = Handle<JSObject>::cast(additional_context); |