| Index: src/runtime.cc
|
| diff --git a/src/runtime.cc b/src/runtime.cc
|
| index df225b63f3fcc66734c27563908ee261584cd2ad..694c87234bb7aea2e88cf211de664a097bf8a948 100644
|
| --- a/src/runtime.cc
|
| +++ b/src/runtime.cc
|
| @@ -10219,11 +10219,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
|
| isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
|
|
|
| // Fill in the values of the locals.
|
| + int first_stack_index = info.first_stack_index();
|
| int i = 0;
|
| for (; i < info.number_of_stack_slots(); ++i) {
|
| // Use the value from the stack.
|
| locals->set(i * 2, *info.LocalName(i));
|
| - locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
|
| + locals->set(i * 2 + 1,
|
| + frame_inspector.GetExpression(i + first_stack_index));
|
| }
|
| if (i < info.NumberOfLocals()) {
|
| // Get the context containing declarations.
|
| @@ -10456,12 +10458,14 @@ static Handle<JSObject> MaterializeLocalScope(
|
| }
|
|
|
| // Second fill all stack locals.
|
| + int first_stack_index = scope_info.first_stack_index();
|
| for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
|
| + int index = i + first_stack_index;
|
| RETURN_IF_EMPTY_HANDLE_VALUE(
|
| isolate,
|
| SetProperty(local_scope,
|
| scope_info.stack_slot_name(i),
|
| - Handle<Object>(frame_inspector.GetExpression(i)),
|
| + Handle<Object>(frame_inspector.GetExpression(index)),
|
| NONE,
|
| kNonStrictMode),
|
| Handle<JSObject>());
|
| @@ -10568,6 +10572,88 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
|
| }
|
|
|
|
|
| +
|
| +// Create a plain JSObject which materializes the local scope for the specified
|
| +// frame.
|
| +static Handle<JSObject> MaterializeLocalScope(
|
| + Isolate* isolate,
|
| + Handle<Context> context,
|
| + Handle<SerializedScopeInfo> serialized_scope_info,
|
| + JavaScriptFrame* frame,
|
| + int inlined_frame_index) {
|
| + Handle<JSFunction> function(JSFunction::cast(frame->function()));
|
| + ScopeInfo<> scope_info(*serialized_scope_info);
|
| + FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
|
| +
|
| + // Allocate and initialize a JSObject with all the arguments, stack locals
|
| + // heap locals and extension properties of the debugged function.
|
| + Handle<JSObject> local_scope =
|
| + isolate->factory()->NewJSObject(isolate->object_function());
|
| +
|
| + // First fill all parameters.
|
| + for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
|
| + RETURN_IF_EMPTY_HANDLE_VALUE(
|
| + isolate,
|
| + SetProperty(local_scope,
|
| + scope_info.parameter_name(i),
|
| + Handle<Object>(frame_inspector.GetParameter(i)),
|
| + NONE,
|
| + kNonStrictMode),
|
| + Handle<JSObject>());
|
| + }
|
| +
|
| + // Second fill all stack locals.
|
| + int first_stack_index = scope_info.first_stack_index();
|
| + for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
|
| + int index = i + first_stack_index;
|
| + RETURN_IF_EMPTY_HANDLE_VALUE(
|
| + isolate,
|
| + SetProperty(local_scope,
|
| + scope_info.stack_slot_name(i),
|
| + Handle<Object>(frame_inspector.GetExpression(index)),
|
| + NONE,
|
| + kNonStrictMode),
|
| + Handle<JSObject>());
|
| + }
|
| +
|
| + if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
|
| + // Third fill all context locals.
|
| + Handle<Context> frame_context(Context::cast(frame->context()));
|
| + Handle<Context> function_context(frame_context->declaration_context());
|
| + if (!CopyContextLocalsToScopeObject(isolate,
|
| + serialized_scope_info, scope_info,
|
| + function_context, local_scope)) {
|
| + return Handle<JSObject>();
|
| + }
|
| +
|
| + // Finally copy any properties from the function context extension.
|
| + // These will be variables introduced by eval.
|
| + if (function_context->closure() == *function) {
|
| + if (function_context->has_extension() &&
|
| + !function_context->IsGlobalContext()) {
|
| + Handle<JSObject> ext(JSObject::cast(function_context->extension()));
|
| + Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
|
| + for (int i = 0; i < keys->length(); i++) {
|
| + // Names of variables introduced by eval are strings.
|
| + ASSERT(keys->get(i)->IsString());
|
| + Handle<String> key(String::cast(keys->get(i)));
|
| + RETURN_IF_EMPTY_HANDLE_VALUE(
|
| + isolate,
|
| + SetProperty(local_scope,
|
| + key,
|
| + GetProperty(ext, key),
|
| + NONE,
|
| + kNonStrictMode),
|
| + Handle<JSObject>());
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + return local_scope;
|
| +}
|
| +
|
| +
|
| // Iterate over the actual scopes visible from a stack frame. All scopes are
|
| // backed by an actual context except the local scope, which is inserted
|
| // "artifically" in the context chain.
|
| @@ -10589,66 +10675,74 @@ class ScopeIterator {
|
| inlined_frame_index_(inlined_frame_index),
|
| function_(JSFunction::cast(frame->function())),
|
| context_(Context::cast(frame->context())),
|
| - local_done_(false),
|
| - at_local_(false) {
|
| + local_scope_chain_(4) {
|
|
|
| - // Check whether the first scope is actually a local scope.
|
| - if (context_->IsGlobalContext()) {
|
| - // 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());
|
| - at_local_ = index < 0;
|
| - } else if (context_->IsFunctionContext()) {
|
| - at_local_ = true;
|
| - } else if (context_->closure() != *function_) {
|
| - // The context_ is a with or catch block from the outer function.
|
| - ASSERT(context_->IsWithContext() || context_->IsCatchContext());
|
| - at_local_ = true;
|
| - }
|
| + Handle<SerializedScopeInfo> scope_info(function_->shared()->scope_info());
|
| + int statement_position =
|
| + function_->code()->SourceStatementPosition(frame_->pc());
|
| + scope_info->GetLocalScopeChain(&local_scope_chain_, statement_position);
|
| +
|
| + if (!local_scope_chain_.is_empty()) return;
|
| }
|
|
|
| // More scopes?
|
| bool Done() { return context_.is_null(); }
|
|
|
| - // 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;
|
| - }
|
| - }
|
| -
|
| + private:
|
| + void AdvanceContext() {
|
| // The global scope is always the last in the chain.
|
| if (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;
|
| + public:
|
| + // Move to the next scope.
|
| + void Next() {
|
| + // Move to the next scope.
|
| + if (local_scope_chain_.is_empty()) {
|
| + AdvanceContext();
|
| + } else {
|
| + if (local_scope_chain_.last()->HasContext()) {
|
| + AdvanceContext();
|
| + }
|
| + local_scope_chain_.RemoveLast();
|
| }
|
| }
|
|
|
| // Return the type of the current scope.
|
| int Type() {
|
| - if (at_local_) {
|
| - return ScopeTypeLocal;
|
| + if (!local_scope_chain_.is_empty()) {
|
| + Handle<SerializedScopeInfo> scope_info = local_scope_chain_.last();
|
| + if (scope_info->ScopeType() == Scope::FUNCTION_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 =
|
| + scope_info->StackSlotIndex(isolate_->heap()->result_symbol());
|
| + if (index >= 0) {
|
| + ASSERT(context_->IsGlobalContext());
|
| + return ScopeTypeGlobal;
|
| + }
|
| + ASSERT(context_->IsFunctionContext() ||
|
| + !scope_info->HasContext());
|
| + return ScopeTypeLocal;
|
| + } else if (scope_info->ScopeType() == Scope::GLOBAL_SCOPE) {
|
| + ASSERT(context_->IsGlobalContext());
|
| + return ScopeTypeGlobal;
|
| + } else if (scope_info->ScopeType() == Scope::CATCH_SCOPE) {
|
| + ASSERT(context_->IsCatchContext() ||
|
| + !scope_info->HasContext());
|
| + return ScopeTypeCatch;
|
| + } else {
|
| + ASSERT(scope_info->ScopeType() == Scope::WITH_SCOPE);
|
| + ASSERT(context_->IsWithContext());
|
| + return ScopeTypeWith;
|
| + }
|
| }
|
| if (context_->IsGlobalContext()) {
|
| ASSERT(context_->global()->IsGlobalObject());
|
| @@ -10668,15 +10762,31 @@ class ScopeIterator {
|
| Handle<JSObject> ScopeObject() {
|
| switch (Type()) {
|
| case ScopeIterator::ScopeTypeGlobal:
|
| + if (CurrentContext().is_null()) {
|
| + return Handle<JSObject>();
|
| + }
|
| return Handle<JSObject>(CurrentContext()->global());
|
| case ScopeIterator::ScopeTypeLocal:
|
| // Materialize the content of the local scope into a JSObject.
|
| - return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
|
| + ASSERT(local_scope_chain_.length() == 1);
|
| + return MaterializeLocalScope(isolate_,
|
| + CurrentContext(),
|
| + local_scope_chain_.last(),
|
| + frame_,
|
| + inlined_frame_index_);
|
| case ScopeIterator::ScopeTypeWith:
|
| // Return the with object.
|
| return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
|
| case ScopeIterator::ScopeTypeCatch:
|
| - return MaterializeCatchScope(isolate_, CurrentContext());
|
| + if (local_scope_chain_.is_empty()) {
|
| + return MaterializeCatchScope(isolate_, CurrentContext());
|
| + } else {
|
| + return MaterializeLocalScope(isolate_,
|
| + CurrentContext(),
|
| + local_scope_chain_.last(),
|
| + frame_,
|
| + inlined_frame_index_);
|
| + }
|
| case ScopeIterator::ScopeTypeClosure:
|
| // Materialize the content of the closure scope into a JSObject.
|
| return MaterializeClosure(isolate_, CurrentContext());
|
| @@ -10688,10 +10798,14 @@ class ScopeIterator {
|
| // 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 ||
|
| + local_scope_chain_.is_empty()) {
|
| + return context_;
|
| + } else if (local_scope_chain_.last()->HasContext()) {
|
| + return context_;
|
| + } else {
|
| return Handle<Context>();
|
| }
|
| - return context_;
|
| }
|
|
|
| #ifdef DEBUG
|
| @@ -10754,8 +10868,7 @@ class ScopeIterator {
|
| int inlined_frame_index_;
|
| Handle<JSFunction> function_;
|
| Handle<Context> context_;
|
| - bool local_done_;
|
| - bool at_local_;
|
| + List<Handle<SerializedScopeInfo> > local_scope_chain_;
|
|
|
| DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
|
| };
|
|
|