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