Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 3e9c6c695456d0e66bdbf015ed9445aa92935f3c..c3918e634c0f060c49870744f6d4eb2def7a7d5c 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -11216,48 +11216,28 @@ class ScopeIterator { |
inlined_frame_index_(inlined_frame_index), |
function_(JSFunction::cast(frame->function())), |
context_(Context::cast(frame->context())), |
- nested_scope_chain_(4) { |
+ local_done_(false), |
+ at_local_(false) { |
- // Catch the case when the debugger stops in an internal function. |
- Handle<SharedFunctionInfo> shared_info(function_->shared()); |
- if (shared_info->script() == isolate->heap()->undefined_value()) { |
- while (context_->closure() == *function_) { |
- context_ = Handle<Context>(context_->previous(), isolate_); |
- } |
- return; |
- } |
- |
- // Check whether we are in global code or function code. If there is a stack |
- // slot for .result then this function has been created for evaluating |
- // global code and it is not a real function. |
+ // 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 = shared_info->scope_info()-> |
+ int index = function_->shared()->scope_info()-> |
StackSlotIndex(isolate_->heap()->result_symbol()); |
- |
- // Reparse the code and analyze the scopes. |
- ZoneScope zone_scope(isolate, DELETE_ON_EXIT); |
- Handle<Script> script(Script::cast(shared_info->script())); |
- Scope* scope; |
if (index >= 0) { |
- // Global code |
- CompilationInfo info(script); |
- info.MarkAsGlobal(); |
- CHECK(ParserApi::Parse(&info)); |
- CHECK(Scope::Analyze(&info)); |
- scope = info.function()->scope(); |
- } else { |
- // Function code |
- CompilationInfo info(shared_info); |
- CHECK(ParserApi::Parse(&info)); |
- CHECK(Scope::Analyze(&info)); |
- scope = info.function()->scope(); |
+ 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; |
} |
- |
- // Retrieve the scope chain for the current position. |
- int statement_position = |
- shared_info->code()->SourceStatementPosition(frame_->pc()); |
- scope->GetNestedScopeChain(&nested_scope_chain_, statement_position); |
} |
// More scopes? |
@@ -11265,48 +11245,40 @@ class ScopeIterator { |
// Move to the next scope. |
void Next() { |
- ScopeType scope_type = Type(); |
- if (scope_type == ScopeTypeGlobal) { |
- // The global scope is always the last in the chain. |
- ASSERT(context_->IsGlobalContext()); |
+ // 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()) { |
context_ = Handle<Context>(); |
return; |
} |
- 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(); |
+ |
+ // 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; |
} |
} |
// Return the type of the current scope. |
ScopeType Type() { |
- if (!nested_scope_chain_.is_empty()) { |
- Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); |
- switch (scope_info->Type()) { |
- case FUNCTION_SCOPE: |
- ASSERT(context_->IsFunctionContext() || |
- !scope_info->HasContext()); |
- return ScopeTypeLocal; |
- case GLOBAL_SCOPE: |
- ASSERT(context_->IsGlobalContext()); |
- return ScopeTypeGlobal; |
- case WITH_SCOPE: |
- ASSERT(context_->IsWithContext()); |
- return ScopeTypeWith; |
- case CATCH_SCOPE: |
- ASSERT(context_->IsCatchContext()); |
- return ScopeTypeCatch; |
- case BLOCK_SCOPE: |
- ASSERT(!scope_info->HasContext() || |
- context_->IsBlockContext()); |
- return ScopeTypeBlock; |
- case EVAL_SCOPE: |
- UNREACHABLE(); |
- } |
+ if (at_local_) { |
+ return ScopeTypeLocal; |
} |
if (context_->IsGlobalContext()) { |
ASSERT(context_->global()->IsGlobalObject()); |
@@ -11332,7 +11304,6 @@ 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. |
@@ -11349,28 +11320,13 @@ class ScopeIterator { |
return Handle<JSObject>(); |
} |
- Handle<ScopeInfo> CurrentScopeInfo() { |
- if (!nested_scope_chain_.is_empty()) { |
- return nested_scope_chain_.last(); |
- } else if (context_->IsBlockContext()) { |
- return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); |
- } else if (context_->IsFunctionContext()) { |
- return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); |
- } |
- return Handle<ScopeInfo>::null(); |
- } |
- |
// Return the context for this scope. For the local context there might not |
// be an actual context. |
Handle<Context> CurrentContext() { |
- if (Type() == ScopeTypeGlobal || |
- nested_scope_chain_.is_empty()) { |
- return context_; |
- } else if (nested_scope_chain_.last()->HasContext()) { |
- return context_; |
- } else { |
+ if (at_local_ && context_->closure() != *function_) { |
return Handle<Context>(); |
} |
+ return context_; |
} |
#ifdef DEBUG |
@@ -11432,7 +11388,8 @@ class ScopeIterator { |
int inlined_frame_index_; |
Handle<JSFunction> function_; |
Handle<Context> context_; |
- List<Handle<ScopeInfo> > nested_scope_chain_; |
+ bool local_done_; |
+ bool at_local_; |
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); |
}; |
@@ -11895,65 +11852,45 @@ 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> CopyNestedScopeContextChain(Isolate* isolate, |
- Handle<JSFunction> function, |
- Handle<Context> base, |
- JavaScriptFrame* frame, |
- int inlined_frame_index) { |
- HandleScope scope(isolate); |
- List<Handle<ScopeInfo> > 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()); |
+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; |
} |
- // 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<ScopeInfo> scope_info = scope_chain.RemoveLast(); |
- Handle<Context> current = context_chain.RemoveLast(); |
- ASSERT(!(scope_info->HasContext() & current.is_null())); |
- |
- if (scope_info->Type() == 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->Type() == 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->Type() == WITH_SCOPE); |
- ASSERT(current->IsWithContext()); |
- Handle<JSObject> extension(JSObject::cast(current->extension())); |
- context = |
- isolate->factory()->NewWithContext(function, context, extension); |
+ // 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<ScopeInfo> scope_info(ScopeInfo::cast(current->extension())); |
+ new_current = |
+ isolate->factory()->NewBlockContext(function, new_previous, scope_info); |
+ // Copy context slots. |
+ int num_context_slots = scope_info->ContextLength(); |
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) { |
+ new_current->set(i, current->get(i)); |
} |
+ } else { |
+ ASSERT(current->IsWithContext()); |
+ Handle<JSObject> extension(JSObject::cast(current->extension())); |
+ new_current = |
+ isolate->factory()->NewWithContext(function, new_previous, extension); |
} |
- |
- return scope.CloseAndEscape(context); |
+ return scope.CloseAndEscape(new_current); |
} |
@@ -12088,11 +12025,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { |
if (scope_info->HasContext()) { |
function_context = Handle<Context>(frame_context->declaration_context()); |
} |
- context = CopyNestedScopeContextChain(isolate, |
- go_between, |
- context, |
- frame, |
- inlined_frame_index); |
+ context = CopyWithContextChain(isolate, go_between, frame_context, context); |
if (additional_context->IsJSObject()) { |
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context); |