Debugger: refactor ScopeIterator, FrameInspector and DebugEvaluate.
authoryangguo <yangguo@chromium.org>
Tue, 4 Aug 2015 12:08:56 +0000 (05:08 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 4 Aug 2015 12:10:13 +0000 (12:10 +0000)
This is a pure refactor and does not change functionality.

R=ulan@chromium.org

Review URL: https://codereview.chromium.org/1264993002

Cr-Commit-Position: refs/heads/master@{#29995}

16 files changed:
BUILD.gn
src/debug/debug-evaluate.cc [new file with mode: 0644]
src/debug/debug-evaluate.h [new file with mode: 0644]
src/debug/debug-frames.cc [new file with mode: 0644]
src/debug/debug-frames.h [new file with mode: 0644]
src/debug/debug-scopes.cc [new file with mode: 0644]
src/debug/debug-scopes.h [new file with mode: 0644]
src/globals.h
src/isolate.h
src/objects.h
src/runtime/runtime-debug.cc
src/runtime/runtime-liveedit.cc
src/runtime/runtime.h
src/scopeinfo.cc
test/cctest/test-debug.cc
tools/gyp/v8.gyp

index d194d63256cdeecbe177cc13719aa865f08d91b3..20878cda52da86ce669d23cc3da95a866530f418 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -834,6 +834,12 @@ source_set("v8_base") {
     "src/dateparser-inl.h",
     "src/dateparser.cc",
     "src/dateparser.h",
+    "src/debug/debug-evaluate.cc",
+    "src/debug/debug-evaluate.h",
+    "src/debug/debug-frames.cc",
+    "src/debug/debug-frames.h",
+    "src/debug/debug-scopes.cc",
+    "src/debug/debug-scopes.h",
     "src/debug/debug.cc",
     "src/debug/debug.h",
     "src/debug/liveedit.cc",
diff --git a/src/debug/debug-evaluate.cc b/src/debug/debug-evaluate.cc
new file mode 100644 (file)
index 0000000..509d97a
--- /dev/null
@@ -0,0 +1,319 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/debug/debug-evaluate.h"
+
+#include "src/accessors.h"
+#include "src/contexts.h"
+#include "src/debug/debug.h"
+#include "src/debug/debug-frames.h"
+#include "src/debug/debug-scopes.h"
+#include "src/isolate.h"
+
+namespace v8 {
+namespace internal {
+
+
+static inline bool IsDebugContext(Isolate* isolate, Context* context) {
+  // Try to unwrap script context if it exist.
+  if (context->IsScriptContext()) context = context->previous();
+  DCHECK_NOT_NULL(context);
+  return context == *isolate->debug()->debug_context();
+}
+
+
+MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
+                                          Handle<String> source,
+                                          bool disable_break,
+                                          Handle<Object> context_extension) {
+  // Handle the processing of break.
+  DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+  // Enter the top context from before the debugger was invoked.
+  SaveContext save(isolate);
+  SaveContext* top = &save;
+  while (top != NULL && IsDebugContext(isolate, *top->context())) {
+    top = top->prev();
+  }
+  if (top != NULL) isolate->set_context(*top->context());
+
+  // Get the native context now set to the top context from before the
+  // debugger was invoked.
+  Handle<Context> context = isolate->native_context();
+  Handle<JSObject> receiver(context->global_proxy());
+  Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
+  return Evaluate(isolate, outer_info, context, context_extension, receiver,
+                  source);
+}
+
+
+MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
+                                         StackFrame::Id frame_id,
+                                         int inlined_jsframe_index,
+                                         Handle<String> source,
+                                         bool disable_break,
+                                         Handle<Object> context_extension) {
+  // Handle the processing of break.
+  DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+  // Get the frame where the debugging is performed.
+  JavaScriptFrameIterator it(isolate, frame_id);
+  JavaScriptFrame* frame = it.frame();
+
+  // Traverse the saved contexts chain to find the active context for the
+  // selected frame.
+  SaveContext* save =
+      DebugFrameHelper::FindSavedContextForFrame(isolate, frame);
+  SaveContext savex(isolate);
+  isolate->set_context(*(save->context()));
+
+  // Materialize stack locals and the arguments object.
+  ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
+  if (isolate->has_pending_exception()) return MaybeHandle<Object>();
+
+  Handle<Object> receiver(frame->receiver(), isolate);
+  MaybeHandle<Object> maybe_result = Evaluate(
+      isolate, context_builder.outer_info(),
+      context_builder.innermost_context(), context_extension, receiver, source);
+  if (!maybe_result.is_null()) context_builder.UpdateValues();
+  return maybe_result;
+}
+
+
+// Compile and evaluate source for the given context.
+MaybeHandle<Object> DebugEvaluate::Evaluate(
+    Isolate* isolate, Handle<SharedFunctionInfo> outer_info,
+    Handle<Context> context, Handle<Object> context_extension,
+    Handle<Object> receiver, Handle<String> source) {
+  if (context_extension->IsJSObject()) {
+    Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
+    Handle<JSFunction> closure(context->closure(), isolate);
+    context = isolate->factory()->NewWithContext(closure, context, extension);
+  }
+
+  Handle<JSFunction> eval_fun;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
+                             Compiler::GetFunctionFromEval(
+                                 source, outer_info, context, SLOPPY,
+                                 NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
+                             Object);
+
+  Handle<Object> result;
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
+      Object);
+
+  // Skip the global proxy as it has no properties and always delegates to the
+  // real global object.
+  if (result->IsJSGlobalProxy()) {
+    PrototypeIterator iter(isolate, result);
+    // TODO(verwaest): This will crash when the global proxy is detached.
+    result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+  }
+
+  return result;
+}
+
+
+DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
+                                              JavaScriptFrame* frame,
+                                              int inlined_jsframe_index)
+    : isolate_(isolate),
+      frame_(frame),
+      inlined_jsframe_index_(inlined_jsframe_index) {
+  FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
+  Handle<JSFunction> function =
+      handle(JSFunction::cast(frame_inspector.GetFunction()));
+  Handle<Context> outer_context = handle(function->context(), isolate);
+  outer_info_ = handle(function->shared());
+  Handle<Context> inner_context;
+
+  bool stop = false;
+  for (ScopeIterator it(isolate, &frame_inspector);
+       !it.Failed() && !it.Done() && !stop; it.Next()) {
+    ScopeIterator::ScopeType scope_type = it.Type();
+
+    if (scope_type == ScopeIterator::ScopeTypeLocal) {
+      Handle<Context> parent_context =
+          it.HasContext() ? it.CurrentContext() : outer_context;
+
+      // The "this" binding, if any, can't be bound via "with".  If we need
+      // to, add another node onto the outer context to bind "this".
+      parent_context = MaterializeReceiver(parent_context, function);
+
+      Handle<JSObject> materialized_function = NewJSObjectWithNullProto();
+
+      frame_inspector.MaterializeStackLocals(materialized_function, function);
+
+      MaterializeArgumentsObject(materialized_function, function);
+
+      Handle<Context> with_context = isolate->factory()->NewWithContext(
+          function, parent_context, materialized_function);
+
+      ContextChainElement context_chain_element;
+      context_chain_element.original_context = it.CurrentContext();
+      context_chain_element.materialized_object = materialized_function;
+      context_chain_element.scope_info = it.CurrentScopeInfo();
+      context_chain_.Add(context_chain_element);
+
+      stop = true;
+      RecordContextsInChain(&inner_context, with_context, with_context);
+    } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
+               scope_type == ScopeIterator::ScopeTypeWith) {
+      Handle<Context> cloned_context =
+          Handle<Context>::cast(FixedArray::CopySize(
+              it.CurrentContext(), it.CurrentContext()->length()));
+
+      ContextChainElement context_chain_element;
+      context_chain_element.original_context = it.CurrentContext();
+      context_chain_element.cloned_context = cloned_context;
+      context_chain_.Add(context_chain_element);
+
+      RecordContextsInChain(&inner_context, cloned_context, cloned_context);
+    } else if (scope_type == ScopeIterator::ScopeTypeBlock) {
+      Handle<JSObject> materialized_object = NewJSObjectWithNullProto();
+      frame_inspector.MaterializeStackLocals(materialized_object,
+                                             it.CurrentScopeInfo());
+      if (it.HasContext()) {
+        Handle<Context> cloned_context =
+            Handle<Context>::cast(FixedArray::CopySize(
+                it.CurrentContext(), it.CurrentContext()->length()));
+        Handle<Context> with_context = isolate->factory()->NewWithContext(
+            function, cloned_context, materialized_object);
+
+        ContextChainElement context_chain_element;
+        context_chain_element.original_context = it.CurrentContext();
+        context_chain_element.cloned_context = cloned_context;
+        context_chain_element.materialized_object = materialized_object;
+        context_chain_element.scope_info = it.CurrentScopeInfo();
+        context_chain_.Add(context_chain_element);
+
+        RecordContextsInChain(&inner_context, cloned_context, with_context);
+      } else {
+        Handle<Context> with_context = isolate->factory()->NewWithContext(
+            function, outer_context, materialized_object);
+
+        ContextChainElement context_chain_element;
+        context_chain_element.materialized_object = materialized_object;
+        context_chain_element.scope_info = it.CurrentScopeInfo();
+        context_chain_.Add(context_chain_element);
+
+        RecordContextsInChain(&inner_context, with_context, with_context);
+      }
+    } else {
+      stop = true;
+    }
+  }
+  if (innermost_context_.is_null()) {
+    innermost_context_ = outer_context;
+  }
+  DCHECK(!innermost_context_.is_null());
+}
+
+
+void DebugEvaluate::ContextBuilder::UpdateValues() {
+  for (int i = 0; i < context_chain_.length(); i++) {
+    ContextChainElement element = context_chain_[i];
+    if (!element.original_context.is_null() &&
+        !element.cloned_context.is_null()) {
+      Handle<Context> cloned_context = element.cloned_context;
+      cloned_context->CopyTo(
+          Context::MIN_CONTEXT_SLOTS, *element.original_context,
+          Context::MIN_CONTEXT_SLOTS,
+          cloned_context->length() - Context::MIN_CONTEXT_SLOTS);
+    }
+    if (!element.materialized_object.is_null()) {
+      // Write back potential changes to materialized stack locals to the
+      // stack.
+      FrameInspector(frame_, inlined_jsframe_index_, isolate_)
+          .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
+                                                   element.scope_info);
+    }
+  }
+}
+
+
+Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() {
+  Handle<JSObject> result =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+  Handle<Map> new_map =
+      Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
+  Map::SetPrototype(new_map, isolate_->factory()->null_value());
+  JSObject::MigrateToMap(result, new_map);
+  return result;
+}
+
+
+void DebugEvaluate::ContextBuilder::RecordContextsInChain(
+    Handle<Context>* inner_context, Handle<Context> first,
+    Handle<Context> last) {
+  if (!inner_context->is_null()) {
+    (*inner_context)->set_previous(*last);
+  } else {
+    innermost_context_ = last;
+  }
+  *inner_context = first;
+}
+
+
+void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject(
+    Handle<JSObject> target, Handle<JSFunction> function) {
+  // Do not materialize the arguments object for eval or top-level code.
+  // Skip if "arguments" is already taken.
+  if (!function->shared()->is_function()) return;
+  Maybe<bool> maybe = JSReceiver::HasOwnProperty(
+      target, isolate_->factory()->arguments_string());
+  DCHECK(maybe.IsJust());
+  if (maybe.FromJust()) return;
+
+  // FunctionGetArguments can't throw an exception.
+  Handle<JSObject> arguments =
+      Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
+  Handle<String> arguments_str = isolate_->factory()->arguments_string();
+  JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
+                                           NONE)
+      .Check();
+}
+
+
+Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver(
+    Handle<Context> target, Handle<JSFunction> function) {
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+  Handle<Object> receiver;
+  switch (scope_info->scope_type()) {
+    case FUNCTION_SCOPE: {
+      VariableMode mode;
+      VariableLocation location;
+      InitializationFlag init_flag;
+      MaybeAssignedFlag maybe_assigned_flag;
+
+      // Don't bother creating a fake context node if "this" is in the context
+      // already.
+      if (ScopeInfo::ContextSlotIndex(
+              scope_info, isolate_->factory()->this_string(), &mode, &location,
+              &init_flag, &maybe_assigned_flag) >= 0) {
+        return target;
+      }
+      receiver = handle(frame_->receiver(), isolate_);
+      break;
+    }
+    case MODULE_SCOPE:
+      receiver = isolate_->factory()->undefined_value();
+      break;
+    case SCRIPT_SCOPE:
+      receiver = handle(function->global_proxy(), isolate_);
+      break;
+    default:
+      // For eval code, arrow functions, and the like, there's no "this" binding
+      // to materialize.
+      return target;
+  }
+
+  return isolate_->factory()->NewCatchContext(
+      function, target, isolate_->factory()->this_string(), receiver);
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/debug/debug-evaluate.h b/src/debug/debug-evaluate.h
new file mode 100644 (file)
index 0000000..49a7fce
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_DEBUG_DEBUG_EVALUATE_H_
+#define V8_DEBUG_DEBUG_EVALUATE_H_
+
+#include "src/frames.h"
+#include "src/objects.h"
+
+namespace v8 {
+namespace internal {
+
+class DebugEvaluate : public AllStatic {
+ public:
+  static MaybeHandle<Object> Global(Isolate* isolate, Handle<String> source,
+                                    bool disable_break,
+                                    Handle<Object> context_extension);
+
+  // Evaluate a piece of JavaScript in the context of a stack frame for
+  // debugging.  Things that need special attention are:
+  // - Parameters and stack-allocated locals need to be materialized.  Altered
+  //   values need to be written back to the stack afterwards.
+  // - The arguments object needs to materialized.
+  static MaybeHandle<Object> Local(Isolate* isolate, StackFrame::Id frame_id,
+                                   int inlined_jsframe_index,
+                                   Handle<String> source, bool disable_break,
+                                   Handle<Object> context_extension);
+
+ private:
+  // This class builds a context chain for evaluation of expressions
+  // in debugger.
+  // The scope chain leading up to a breakpoint where evaluation occurs
+  // looks like:
+  // - [a mix of with, catch and block scopes]
+  //    - [function stack + context]
+  //      - [outer context]
+  // The builder materializes all stack variables into properties of objects;
+  // the expression is then evaluated as if it is inside a series of 'with'
+  // statements using those objects. To this end, the builder builds a new
+  // context chain, based on a scope chain:
+  //   - every With and Catch scope begets a cloned context
+  //   - Block scope begets one or two contexts:
+  //       - if a block has context-allocated varaibles, its context is cloned
+  //       - stack locals are materizalized as a With context
+  //   - Local scope begets a With context for materizalized locals, chained to
+  //     original function context. Original function context is the end of
+  //     the chain.
+  class ContextBuilder {
+   public:
+    ContextBuilder(Isolate* isolate, JavaScriptFrame* frame,
+                   int inlined_jsframe_index);
+
+    void UpdateValues();
+
+    Handle<Context> innermost_context() const { return innermost_context_; }
+    Handle<SharedFunctionInfo> outer_info() const { return outer_info_; }
+
+   private:
+    struct ContextChainElement {
+      Handle<Context> original_context;
+      Handle<Context> cloned_context;
+      Handle<JSObject> materialized_object;
+      Handle<ScopeInfo> scope_info;
+    };
+
+    void RecordContextsInChain(Handle<Context>* inner_context,
+                               Handle<Context> first, Handle<Context> last);
+
+    Handle<JSObject> NewJSObjectWithNullProto();
+
+    // Helper function to find or create the arguments object for
+    // Runtime_DebugEvaluate.
+    void MaterializeArgumentsObject(Handle<JSObject> target,
+                                    Handle<JSFunction> function);
+
+    Handle<Context> MaterializeReceiver(Handle<Context> target,
+                                        Handle<JSFunction> function);
+
+    Handle<SharedFunctionInfo> outer_info_;
+    Handle<Context> innermost_context_;
+    List<ContextChainElement> context_chain_;
+    Isolate* isolate_;
+    JavaScriptFrame* frame_;
+    int inlined_jsframe_index_;
+  };
+
+  static MaybeHandle<Object> Evaluate(Isolate* isolate,
+                                      Handle<SharedFunctionInfo> outer_info,
+                                      Handle<Context> context,
+                                      Handle<Object> context_extension,
+                                      Handle<Object> receiver,
+                                      Handle<String> source);
+};
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_DEBUG_DEBUG_EVALUATE_H_
diff --git a/src/debug/debug-frames.cc b/src/debug/debug-frames.cc
new file mode 100644 (file)
index 0000000..aeceb58
--- /dev/null
@@ -0,0 +1,217 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/debug/debug-frames.h"
+
+namespace v8 {
+namespace internal {
+
+FrameInspector::FrameInspector(JavaScriptFrame* frame,
+                               int inlined_jsframe_index, Isolate* isolate)
+    : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
+  has_adapted_arguments_ = frame_->has_adapted_arguments();
+  is_bottommost_ = inlined_jsframe_index == 0;
+  is_optimized_ = frame_->is_optimized();
+  // Calculate the deoptimized frame.
+  if (frame->is_optimized()) {
+    // TODO(turbofan): Revisit once we support deoptimization.
+    if (frame->LookupCode()->is_turbofanned() &&
+        frame->function()->shared()->asm_function() &&
+        !FLAG_turbo_asm_deoptimization) {
+      is_optimized_ = false;
+      return;
+    }
+
+    deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
+        frame, inlined_jsframe_index, isolate);
+  }
+}
+
+
+FrameInspector::~FrameInspector() {
+  // Get rid of the calculated deoptimized frame if any.
+  if (deoptimized_frame_ != NULL) {
+    Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
+  }
+}
+
+
+int FrameInspector::GetParametersCount() {
+  return is_optimized_ ? deoptimized_frame_->parameters_count()
+                       : frame_->ComputeParametersCount();
+}
+
+
+int FrameInspector::expression_count() {
+  return deoptimized_frame_->expression_count();
+}
+
+
+Object* FrameInspector::GetFunction() {
+  return is_optimized_ ? deoptimized_frame_->GetFunction() : frame_->function();
+}
+
+
+Object* FrameInspector::GetParameter(int index) {
+  return is_optimized_ ? deoptimized_frame_->GetParameter(index)
+                       : frame_->GetParameter(index);
+}
+
+
+Object* FrameInspector::GetExpression(int index) {
+  // TODO(turbofan): Revisit once we support deoptimization.
+  if (frame_->LookupCode()->is_turbofanned() &&
+      frame_->function()->shared()->asm_function() &&
+      !FLAG_turbo_asm_deoptimization) {
+    return isolate_->heap()->undefined_value();
+  }
+  return is_optimized_ ? deoptimized_frame_->GetExpression(index)
+                       : frame_->GetExpression(index);
+}
+
+
+int FrameInspector::GetSourcePosition() {
+  return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
+                       : frame_->LookupCode()->SourcePosition(frame_->pc());
+}
+
+
+bool FrameInspector::IsConstructor() {
+  return is_optimized_ && !is_bottommost_
+             ? deoptimized_frame_->HasConstructStub()
+             : frame_->IsConstructor();
+}
+
+
+Object* FrameInspector::GetContext() {
+  return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
+}
+
+
+// To inspect all the provided arguments the frame might need to be
+// replaced with the arguments frame.
+void FrameInspector::SetArgumentsFrame(JavaScriptFrame* frame) {
+  DCHECK(has_adapted_arguments_);
+  frame_ = frame;
+  is_optimized_ = frame_->is_optimized();
+  DCHECK(!is_optimized_);
+}
+
+
+// Create a plain JSObject which materializes the local scope for the specified
+// frame.
+void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
+                                            Handle<ScopeInfo> scope_info) {
+  HandleScope scope(isolate_);
+  // First fill all parameters.
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    // Do not materialize the parameter if it is shadowed by a context local.
+    Handle<String> name(scope_info->ParameterName(i));
+    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
+
+    Handle<Object> value(i < GetParametersCount()
+                             ? GetParameter(i)
+                             : isolate_->heap()->undefined_value(),
+                         isolate_);
+    DCHECK(!value->IsTheHole());
+
+    JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
+  }
+
+  // Second fill all stack locals.
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    if (scope_info->LocalIsSynthetic(i)) continue;
+    Handle<String> name(scope_info->StackLocalName(i));
+    Handle<Object> value(GetExpression(scope_info->StackLocalIndex(i)),
+                         isolate_);
+    if (value->IsTheHole()) value = isolate_->factory()->undefined_value();
+
+    JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
+  }
+}
+
+
+void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
+                                            Handle<JSFunction> function) {
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+  MaterializeStackLocals(target, scope_info);
+}
+
+
+void FrameInspector::UpdateStackLocalsFromMaterializedObject(
+    Handle<JSObject> target, Handle<ScopeInfo> scope_info) {
+  if (is_optimized_) {
+    // Optimized frames are not supported. Simply give up.
+    return;
+  }
+
+  HandleScope scope(isolate_);
+
+  // Parameters.
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    // Shadowed parameters were not materialized.
+    Handle<String> name(scope_info->ParameterName(i));
+    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
+
+    DCHECK(!frame_->GetParameter(i)->IsTheHole());
+    Handle<Object> value =
+        Object::GetPropertyOrElement(target, name).ToHandleChecked();
+    frame_->SetParameterValue(i, *value);
+  }
+
+  // Stack locals.
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    if (scope_info->LocalIsSynthetic(i)) continue;
+    int index = scope_info->StackLocalIndex(i);
+    if (frame_->GetExpression(index)->IsTheHole()) continue;
+    Handle<Object> value =
+        Object::GetPropertyOrElement(
+            target, handle(scope_info->StackLocalName(i), isolate_))
+            .ToHandleChecked();
+    frame_->SetExpression(index, *value);
+  }
+}
+
+
+bool FrameInspector::ParameterIsShadowedByContextLocal(
+    Handle<ScopeInfo> info, Handle<String> parameter_name) {
+  VariableMode mode;
+  VariableLocation location;
+  InitializationFlag init_flag;
+  MaybeAssignedFlag maybe_assigned_flag;
+  return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &location,
+                                     &init_flag, &maybe_assigned_flag) != -1;
+}
+
+
+SaveContext* DebugFrameHelper::FindSavedContextForFrame(
+    Isolate* isolate, JavaScriptFrame* frame) {
+  SaveContext* save = isolate->save_context();
+  while (save != NULL && !save->IsBelowFrame(frame)) {
+    save = save->prev();
+  }
+  DCHECK(save != NULL);
+  return save;
+}
+
+
+int DebugFrameHelper::FindIndexedNonNativeFrame(JavaScriptFrameIterator* it,
+                                                int index) {
+  int count = -1;
+  for (; !it->done(); it->Advance()) {
+    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+    it->frame()->Summarize(&frames);
+    for (int i = frames.length() - 1; i >= 0; i--) {
+      // Omit functions from native and extension scripts.
+      if (!frames[i].function()->IsSubjectToDebugging()) continue;
+      if (++count == index) return i;
+    }
+  }
+  return -1;
+}
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/debug/debug-frames.h b/src/debug/debug-frames.h
new file mode 100644 (file)
index 0000000..86e817d
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_DEBUG_DEBUG_FRAMES_H_
+#define V8_DEBUG_DEBUG_FRAMES_H_
+
+#include "src/deoptimizer.h"
+#include "src/frames.h"
+#include "src/isolate.h"
+#include "src/objects.h"
+
+namespace v8 {
+namespace internal {
+
+class FrameInspector {
+ public:
+  FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
+                 Isolate* isolate);
+
+  ~FrameInspector();
+
+  int GetParametersCount();
+  int expression_count();
+  Object* GetFunction();
+  Object* GetParameter(int index);
+  Object* GetExpression(int index);
+  int GetSourcePosition();
+  bool IsConstructor();
+  Object* GetContext();
+
+  JavaScriptFrame* GetArgumentsFrame() { return frame_; }
+  void SetArgumentsFrame(JavaScriptFrame* frame);
+
+  void MaterializeStackLocals(Handle<JSObject> target,
+                              Handle<ScopeInfo> scope_info);
+
+  void MaterializeStackLocals(Handle<JSObject> target,
+                              Handle<JSFunction> function);
+
+  void UpdateStackLocalsFromMaterializedObject(Handle<JSObject> object,
+                                               Handle<ScopeInfo> scope_info);
+
+ private:
+  bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
+                                         Handle<String> parameter_name);
+
+  JavaScriptFrame* frame_;
+  DeoptimizedFrameInfo* deoptimized_frame_;
+  Isolate* isolate_;
+  bool is_optimized_;
+  bool is_bottommost_;
+  bool has_adapted_arguments_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameInspector);
+};
+
+
+class DebugFrameHelper : public AllStatic {
+ public:
+  static SaveContext* FindSavedContextForFrame(Isolate* isolate,
+                                               JavaScriptFrame* frame);
+  // Advances the iterator to the frame that matches the index and returns the
+  // inlined frame index, or -1 if not found.  Skips native JS functions.
+  static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index);
+
+  // Helper functions for wrapping and unwrapping stack frame ids.
+  static Smi* WrapFrameId(StackFrame::Id id) {
+    DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
+    return Smi::FromInt(id >> 2);
+  }
+
+  static StackFrame::Id UnwrapFrameId(int wrapped) {
+    return static_cast<StackFrame::Id>(wrapped << 2);
+  }
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_DEBUG_DEBUG_FRAMES_H_
diff --git a/src/debug/debug-scopes.cc b/src/debug/debug-scopes.cc
new file mode 100644 (file)
index 0000000..e3b4e2c
--- /dev/null
@@ -0,0 +1,769 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/debug/debug-scopes.h"
+
+#include "src/debug/debug.h"
+#include "src/globals.h"
+#include "src/parser.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
+                             bool ignore_nested_scopes)
+    : isolate_(isolate),
+      frame_inspector_(frame_inspector),
+      nested_scope_chain_(4),
+      seen_script_scope_(false),
+      failed_(false) {
+  if (!frame_inspector->GetContext()->IsContext() ||
+      !frame_inspector->GetFunction()->IsJSFunction()) {
+    // Optimized frame, context or function cannot be materialized. Give up.
+    return;
+  }
+
+  context_ = Handle<Context>(Context::cast(frame_inspector->GetContext()));
+
+  // Catch the case when the debugger stops in an internal function.
+  Handle<JSFunction> function = GetFunction();
+  Handle<SharedFunctionInfo> shared_info(function->shared());
+  Handle<ScopeInfo> scope_info(shared_info->scope_info());
+  if (shared_info->script() == isolate->heap()->undefined_value()) {
+    while (context_->closure() == *function) {
+      context_ = Handle<Context>(context_->previous(), isolate_);
+    }
+    return;
+  }
+
+  // Currently it takes too much time to find nested scopes due to script
+  // parsing. Sometimes we want to run the ScopeIterator as fast as possible
+  // (for example, while collecting async call stacks on every
+  // addEventListener call), even if we drop some nested scopes.
+  // Later we may optimize getting the nested scopes (cache the result?)
+  // and include nested scopes into the "fast" iteration case as well.
+
+  if (!ignore_nested_scopes && shared_info->HasDebugInfo()) {
+    // The source position at return is always the end of the function,
+    // which is not consistent with the current scope chain. Therefore all
+    // nested with, catch and block contexts are skipped, and we can only
+    // inspect the function scope.
+    // This can only happen if we set a break point inside right before the
+    // return, which requires a debug info to be available.
+    Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
+
+    // PC points to the instruction after the current one, possibly a break
+    // location as well. So the "- 1" to exclude it from the search.
+    Address call_pc = GetFrame()->pc() - 1;
+
+    // Find the break point where execution has stopped.
+    BreakLocation location =
+        BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
+
+    ignore_nested_scopes = location.IsReturn();
+  }
+
+  if (ignore_nested_scopes) {
+    if (scope_info->HasContext()) {
+      context_ = Handle<Context>(context_->declaration_context(), isolate_);
+    } else {
+      while (context_->closure() == *function) {
+        context_ = Handle<Context>(context_->previous(), isolate_);
+      }
+    }
+    if (scope_info->scope_type() == FUNCTION_SCOPE ||
+        scope_info->scope_type() == ARROW_SCOPE) {
+      nested_scope_chain_.Add(scope_info);
+    }
+  } else {
+    // Reparse the code and analyze the scopes.
+    Handle<Script> script(Script::cast(shared_info->script()));
+    Scope* scope = NULL;
+
+    // Check whether we are in global, eval or function code.
+    Handle<ScopeInfo> scope_info(shared_info->scope_info());
+    Zone zone;
+    if (scope_info->scope_type() != FUNCTION_SCOPE &&
+        scope_info->scope_type() != ARROW_SCOPE) {
+      // Global or eval code.
+      ParseInfo info(&zone, script);
+      if (scope_info->scope_type() == SCRIPT_SCOPE) {
+        info.set_global();
+      } else {
+        DCHECK(scope_info->scope_type() == EVAL_SCOPE);
+        info.set_eval();
+        info.set_context(Handle<Context>(function->context()));
+      }
+      if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
+        scope = info.function()->scope();
+      }
+      RetrieveScopeChain(scope, shared_info);
+    } else {
+      // Function code
+      ParseInfo info(&zone, function);
+      if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
+        scope = info.function()->scope();
+      }
+      RetrieveScopeChain(scope, shared_info);
+    }
+  }
+}
+
+
+ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
+    : isolate_(isolate),
+      frame_inspector_(NULL),
+      context_(function->context()),
+      seen_script_scope_(false),
+      failed_(false) {
+  if (function->IsBuiltin()) context_ = Handle<Context>();
+}
+
+
+MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
+  // Calculate the size of the result.
+  Handle<FixedArray> details =
+      isolate_->factory()->NewFixedArray(kScopeDetailsSize);
+  // Fill in scope details.
+  details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
+  Handle<JSObject> scope_object;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject);
+  details->set(kScopeDetailsObjectIndex, *scope_object);
+  return isolate_->factory()->NewJSArrayWithElements(details);
+}
+
+
+void ScopeIterator::Next() {
+  DCHECK(!failed_);
+  ScopeType scope_type = Type();
+  if (scope_type == ScopeTypeGlobal) {
+    // The global scope is always the last in the chain.
+    DCHECK(context_->IsNativeContext());
+    context_ = Handle<Context>();
+    return;
+  }
+  if (scope_type == ScopeTypeScript) {
+    seen_script_scope_ = true;
+    if (context_->IsScriptContext()) {
+      context_ = Handle<Context>(context_->previous(), isolate_);
+    }
+    if (!nested_scope_chain_.is_empty()) {
+      DCHECK_EQ(nested_scope_chain_.last()->scope_type(), SCRIPT_SCOPE);
+      nested_scope_chain_.RemoveLast();
+      DCHECK(nested_scope_chain_.is_empty());
+    }
+    CHECK(context_->IsNativeContext());
+    return;
+  }
+  if (nested_scope_chain_.is_empty()) {
+    context_ = Handle<Context>(context_->previous(), isolate_);
+  } else {
+    if (nested_scope_chain_.last()->HasContext()) {
+      DCHECK(context_->previous() != NULL);
+      context_ = Handle<Context>(context_->previous(), isolate_);
+    }
+    nested_scope_chain_.RemoveLast();
+  }
+}
+
+
+// Return the type of the current scope.
+ScopeIterator::ScopeType ScopeIterator::Type() {
+  DCHECK(!failed_);
+  if (!nested_scope_chain_.is_empty()) {
+    Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
+    switch (scope_info->scope_type()) {
+      case FUNCTION_SCOPE:
+      case ARROW_SCOPE:
+        DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
+        return ScopeTypeLocal;
+      case MODULE_SCOPE:
+        DCHECK(context_->IsModuleContext());
+        return ScopeTypeModule;
+      case SCRIPT_SCOPE:
+        DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
+        return ScopeTypeScript;
+      case WITH_SCOPE:
+        DCHECK(context_->IsWithContext());
+        return ScopeTypeWith;
+      case CATCH_SCOPE:
+        DCHECK(context_->IsCatchContext());
+        return ScopeTypeCatch;
+      case BLOCK_SCOPE:
+        DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
+        return ScopeTypeBlock;
+      case EVAL_SCOPE:
+        UNREACHABLE();
+    }
+  }
+  if (context_->IsNativeContext()) {
+    DCHECK(context_->global_object()->IsGlobalObject());
+    // If we are at the native context and have not yet seen script scope,
+    // fake it.
+    return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
+  }
+  if (context_->IsFunctionContext()) {
+    return ScopeTypeClosure;
+  }
+  if (context_->IsCatchContext()) {
+    return ScopeTypeCatch;
+  }
+  if (context_->IsBlockContext()) {
+    return ScopeTypeBlock;
+  }
+  if (context_->IsModuleContext()) {
+    return ScopeTypeModule;
+  }
+  if (context_->IsScriptContext()) {
+    return ScopeTypeScript;
+  }
+  DCHECK(context_->IsWithContext());
+  return ScopeTypeWith;
+}
+
+
+MaybeHandle<JSObject> ScopeIterator::ScopeObject() {
+  DCHECK(!failed_);
+  switch (Type()) {
+    case ScopeIterator::ScopeTypeGlobal:
+      return Handle<JSObject>(CurrentContext()->global_object());
+    case ScopeIterator::ScopeTypeScript:
+      return MaterializeScriptScope();
+    case ScopeIterator::ScopeTypeLocal:
+      // Materialize the content of the local scope into a JSObject.
+      DCHECK(nested_scope_chain_.length() == 1);
+      return MaterializeLocalScope();
+    case ScopeIterator::ScopeTypeWith:
+      // Return the with object.
+      return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
+    case ScopeIterator::ScopeTypeCatch:
+      return MaterializeCatchScope();
+    case ScopeIterator::ScopeTypeClosure:
+      // Materialize the content of the closure scope into a JSObject.
+      return MaterializeClosure();
+    case ScopeIterator::ScopeTypeBlock:
+      return MaterializeBlockScope();
+    case ScopeIterator::ScopeTypeModule:
+      return MaterializeModuleScope();
+  }
+  UNREACHABLE();
+  return Handle<JSObject>();
+}
+
+
+bool ScopeIterator::HasContext() {
+  ScopeType type = Type();
+  if (type == ScopeTypeBlock || type == ScopeTypeLocal) {
+    if (!nested_scope_chain_.is_empty()) {
+      return nested_scope_chain_.last()->HasContext();
+    }
+  }
+  return true;
+}
+
+
+bool ScopeIterator::SetVariableValue(Handle<String> variable_name,
+                                     Handle<Object> new_value) {
+  DCHECK(!failed_);
+  switch (Type()) {
+    case ScopeIterator::ScopeTypeGlobal:
+      break;
+    case ScopeIterator::ScopeTypeLocal:
+      return SetLocalVariableValue(variable_name, new_value);
+    case ScopeIterator::ScopeTypeWith:
+      break;
+    case ScopeIterator::ScopeTypeCatch:
+      return SetCatchVariableValue(variable_name, new_value);
+    case ScopeIterator::ScopeTypeClosure:
+      return SetClosureVariableValue(variable_name, new_value);
+    case ScopeIterator::ScopeTypeScript:
+      return SetScriptVariableValue(variable_name, new_value);
+    case ScopeIterator::ScopeTypeBlock:
+      return SetBlockVariableValue(variable_name, new_value);
+    case ScopeIterator::ScopeTypeModule:
+      // TODO(2399): should we implement it?
+      break;
+  }
+  return false;
+}
+
+
+Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
+  DCHECK(!failed_);
+  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();
+}
+
+
+Handle<Context> ScopeIterator::CurrentContext() {
+  DCHECK(!failed_);
+  if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
+      nested_scope_chain_.is_empty()) {
+    return context_;
+  } else if (nested_scope_chain_.last()->HasContext()) {
+    return context_;
+  } else {
+    return Handle<Context>();
+  }
+}
+
+#ifdef DEBUG
+// Debug print of the content of the current scope.
+void ScopeIterator::DebugPrint() {
+  OFStream os(stdout);
+  DCHECK(!failed_);
+  switch (Type()) {
+    case ScopeIterator::ScopeTypeGlobal:
+      os << "Global:\n";
+      CurrentContext()->Print(os);
+      break;
+
+    case ScopeIterator::ScopeTypeLocal: {
+      os << "Local:\n";
+      GetFunction()->shared()->scope_info()->Print();
+      if (!CurrentContext().is_null()) {
+        CurrentContext()->Print(os);
+        if (CurrentContext()->has_extension()) {
+          Handle<Object> extension(CurrentContext()->extension(), isolate_);
+          if (extension->IsJSContextExtensionObject()) {
+            extension->Print(os);
+          }
+        }
+      }
+      break;
+    }
+
+    case ScopeIterator::ScopeTypeWith:
+      os << "With:\n";
+      CurrentContext()->extension()->Print(os);
+      break;
+
+    case ScopeIterator::ScopeTypeCatch:
+      os << "Catch:\n";
+      CurrentContext()->extension()->Print(os);
+      CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
+      break;
+
+    case ScopeIterator::ScopeTypeClosure:
+      os << "Closure:\n";
+      CurrentContext()->Print(os);
+      if (CurrentContext()->has_extension()) {
+        Handle<Object> extension(CurrentContext()->extension(), isolate_);
+        if (extension->IsJSContextExtensionObject()) {
+          extension->Print(os);
+        }
+      }
+      break;
+
+    case ScopeIterator::ScopeTypeScript:
+      os << "Script:\n";
+      CurrentContext()
+          ->global_object()
+          ->native_context()
+          ->script_context_table()
+          ->Print(os);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+  PrintF("\n");
+}
+#endif
+
+
+void ScopeIterator::RetrieveScopeChain(Scope* scope,
+                                       Handle<SharedFunctionInfo> shared_info) {
+  if (scope != NULL) {
+    int source_position = frame_inspector_->GetSourcePosition();
+    scope->GetNestedScopeChain(isolate_, &nested_scope_chain_, source_position);
+  } else {
+    // A failed reparse indicates that the preparser has diverged from the
+    // parser or that the preparse data given to the initial parse has been
+    // faulty. We fail in debug mode but in release mode we only provide the
+    // information we get from the context chain but nothing about
+    // completely stack allocated scopes or stack allocated locals.
+    // Or it could be due to stack overflow.
+    DCHECK(isolate_->has_pending_exception());
+    failed_ = true;
+  }
+}
+
+
+MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() {
+  Handle<GlobalObject> global(CurrentContext()->global_object());
+  Handle<ScriptContextTable> script_contexts(
+      global->native_context()->script_context_table());
+
+  Handle<JSObject> script_scope =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+
+  for (int context_index = 0; context_index < script_contexts->used();
+       context_index++) {
+    Handle<Context> context =
+        ScriptContextTable::GetContext(script_contexts, context_index);
+    Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+    CopyContextLocalsToScopeObject(scope_info, context, script_scope);
+  }
+  return script_scope;
+}
+
+
+MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() {
+  Handle<JSFunction> function = GetFunction();
+
+  Handle<JSObject> local_scope =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+  frame_inspector_->MaterializeStackLocals(local_scope, function);
+
+  Handle<Context> frame_context(Context::cast(frame_inspector_->GetContext()));
+
+  HandleScope scope(isolate_);
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  if (!scope_info->HasContext()) return local_scope;
+
+  // Third fill all context locals.
+  Handle<Context> function_context(frame_context->declaration_context());
+  CopyContextLocalsToScopeObject(scope_info, function_context, local_scope);
+
+  // 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->IsNativeContext()) {
+      Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+      Handle<FixedArray> keys;
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate_, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
+          JSObject);
+
+      for (int i = 0; i < keys->length(); i++) {
+        // Names of variables introduced by eval are strings.
+        DCHECK(keys->get(i)->IsString());
+        Handle<String> key(String::cast(keys->get(i)));
+        Handle<Object> value;
+        ASSIGN_RETURN_ON_EXCEPTION(
+            isolate_, value, Object::GetPropertyOrElement(ext, key), JSObject);
+        RETURN_ON_EXCEPTION(isolate_,
+                            Runtime::SetObjectProperty(isolate_, local_scope,
+                                                       key, value, SLOPPY),
+                            JSObject);
+      }
+    }
+  }
+
+  return local_scope;
+}
+
+
+// Create a plain JSObject which materializes the closure content for the
+// context.
+Handle<JSObject> ScopeIterator::MaterializeClosure() {
+  Handle<Context> context = CurrentContext();
+  DCHECK(context->IsFunctionContext());
+
+  Handle<SharedFunctionInfo> shared(context->closure()->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  // Allocate and initialize a JSObject with all the content of this function
+  // closure.
+  Handle<JSObject> closure_scope =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+
+  // Fill all context locals to the context extension.
+  CopyContextLocalsToScopeObject(scope_info, context, closure_scope);
+
+  // Finally copy any properties from the function context extension. This will
+  // be variables introduced by eval.
+  if (context->has_extension()) {
+    Handle<JSObject> ext(JSObject::cast(context->extension()));
+    DCHECK(ext->IsJSContextExtensionObject());
+    Handle<FixedArray> keys =
+        JSReceiver::GetKeys(ext, JSReceiver::OWN_ONLY).ToHandleChecked();
+
+    for (int i = 0; i < keys->length(); i++) {
+      HandleScope scope(isolate_);
+      // Names of variables introduced by eval are strings.
+      DCHECK(keys->get(i)->IsString());
+      Handle<String> key(String::cast(keys->get(i)));
+      Handle<Object> value = Object::GetProperty(ext, key).ToHandleChecked();
+      JSObject::SetOwnPropertyIgnoreAttributes(closure_scope, key, value, NONE)
+          .Check();
+    }
+  }
+
+  return closure_scope;
+}
+
+
+// Create a plain JSObject which materializes the scope for the specified
+// catch context.
+Handle<JSObject> ScopeIterator::MaterializeCatchScope() {
+  Handle<Context> context = CurrentContext();
+  DCHECK(context->IsCatchContext());
+  Handle<String> name(String::cast(context->extension()));
+  Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
+                               isolate_);
+  Handle<JSObject> catch_scope =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+  JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
+                                           NONE)
+      .Check();
+  return catch_scope;
+}
+
+
+// Create a plain JSObject which materializes the block scope for the specified
+// block context.
+Handle<JSObject> ScopeIterator::MaterializeBlockScope() {
+  Handle<JSObject> block_scope =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+
+  Handle<Context> context = Handle<Context>::null();
+  if (!nested_scope_chain_.is_empty()) {
+    Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
+    frame_inspector_->MaterializeStackLocals(block_scope, scope_info);
+    if (scope_info->HasContext()) context = CurrentContext();
+  } else {
+    context = CurrentContext();
+  }
+
+  if (!context.is_null()) {
+    Handle<ScopeInfo> scope_info_from_context(
+        ScopeInfo::cast(context->extension()));
+    // Fill all context locals.
+    CopyContextLocalsToScopeObject(scope_info_from_context, context,
+                                   block_scope);
+  }
+  return block_scope;
+}
+
+
+// Create a plain JSObject which materializes the module scope for the specified
+// module context.
+MaybeHandle<JSObject> ScopeIterator::MaterializeModuleScope() {
+  Handle<Context> context = CurrentContext();
+  DCHECK(context->IsModuleContext());
+  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+
+  // Allocate and initialize a JSObject with all the members of the debugged
+  // module.
+  Handle<JSObject> module_scope =
+      isolate_->factory()->NewJSObject(isolate_->object_function());
+
+  // Fill all context locals.
+  CopyContextLocalsToScopeObject(scope_info, context, module_scope);
+
+  return module_scope;
+}
+
+
+// Set the context local variable value.
+bool ScopeIterator::SetContextLocalValue(Handle<ScopeInfo> scope_info,
+                                         Handle<Context> context,
+                                         Handle<String> variable_name,
+                                         Handle<Object> new_value) {
+  for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
+    Handle<String> next_name(scope_info->ContextLocalName(i));
+    if (String::Equals(variable_name, next_name)) {
+      VariableMode mode;
+      VariableLocation location;
+      InitializationFlag init_flag;
+      MaybeAssignedFlag maybe_assigned_flag;
+      int context_index =
+          ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &location,
+                                      &init_flag, &maybe_assigned_flag);
+      context->set(context_index, *new_value);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
+                                          Handle<Object> new_value) {
+  JavaScriptFrame* frame = GetFrame();
+  // Optimized frames are not supported.
+  if (frame->is_optimized()) return false;
+
+  Handle<JSFunction> function(frame->function());
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  bool default_result = false;
+
+  // Parameters.
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    HandleScope scope(isolate_);
+    if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
+      frame->SetParameterValue(i, *new_value);
+      // Argument might be shadowed in heap context, don't stop here.
+      default_result = true;
+    }
+  }
+
+  // Stack locals.
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    HandleScope scope(isolate_);
+    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
+      frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
+      return true;
+    }
+  }
+
+  if (scope_info->HasContext()) {
+    // Context locals.
+    Handle<Context> frame_context(Context::cast(frame->context()));
+    Handle<Context> function_context(frame_context->declaration_context());
+    if (SetContextLocalValue(scope_info, function_context, variable_name,
+                             new_value)) {
+      return true;
+    }
+
+    // Function context extension. These are variables introduced by eval.
+    if (function_context->closure() == *function) {
+      if (function_context->has_extension() &&
+          !function_context->IsNativeContext()) {
+        Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+
+        Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
+        DCHECK(maybe.IsJust());
+        if (maybe.FromJust()) {
+          // We don't expect this to do anything except replacing
+          // property value.
+          Runtime::SetObjectProperty(isolate_, ext, variable_name, new_value,
+                                     SLOPPY)
+              .Assert();
+          return true;
+        }
+      }
+    }
+  }
+
+  return default_result;
+}
+
+
+bool ScopeIterator::SetBlockVariableValue(Handle<String> variable_name,
+                                          Handle<Object> new_value) {
+  Handle<ScopeInfo> scope_info = CurrentScopeInfo();
+  JavaScriptFrame* frame = GetFrame();
+
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    HandleScope scope(isolate_);
+    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
+      frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
+      return true;
+    }
+  }
+
+  if (HasContext()) {
+    return SetContextLocalValue(scope_info, CurrentContext(), variable_name,
+                                new_value);
+  }
+  return false;
+}
+
+
+// This method copies structure of MaterializeClosure method above.
+bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
+                                            Handle<Object> new_value) {
+  Handle<Context> context = CurrentContext();
+  DCHECK(context->IsFunctionContext());
+
+  // Context locals to the context extension.
+  Handle<SharedFunctionInfo> shared(context->closure()->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+  if (SetContextLocalValue(scope_info, context, variable_name, new_value)) {
+    return true;
+  }
+
+  // Properties from the function context extension. This will
+  // be variables introduced by eval.
+  if (context->has_extension()) {
+    Handle<JSObject> ext(JSObject::cast(context->extension()));
+    DCHECK(ext->IsJSContextExtensionObject());
+    Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
+    DCHECK(maybe.IsJust());
+    if (maybe.FromJust()) {
+      // We don't expect this to do anything except replacing property value.
+      JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
+                                               NONE)
+          .Check();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
+                                           Handle<Object> new_value) {
+  Handle<Context> context = CurrentContext();
+  Handle<ScriptContextTable> script_contexts(
+      context->global_object()->native_context()->script_context_table());
+  ScriptContextTable::LookupResult lookup_result;
+  if (ScriptContextTable::Lookup(script_contexts, variable_name,
+                                 &lookup_result)) {
+    Handle<Context> script_context = ScriptContextTable::GetContext(
+        script_contexts, lookup_result.context_index);
+    script_context->set(lookup_result.slot_index, *new_value);
+    return true;
+  }
+
+  return false;
+}
+
+
+bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
+                                          Handle<Object> new_value) {
+  Handle<Context> context = CurrentContext();
+  DCHECK(context->IsCatchContext());
+  Handle<String> name(String::cast(context->extension()));
+  if (!String::Equals(name, variable_name)) {
+    return false;
+  }
+  context->set(Context::THROWN_OBJECT_INDEX, *new_value);
+  return true;
+}
+
+
+void ScopeIterator::CopyContextLocalsToScopeObject(
+    Handle<ScopeInfo> scope_info, Handle<Context> context,
+    Handle<JSObject> scope_object) {
+  Isolate* isolate = scope_info->GetIsolate();
+  int local_count = scope_info->ContextLocalCount();
+  if (local_count == 0) return;
+  // Fill all context locals to the context extension.
+  int first_context_var = scope_info->StackLocalCount();
+  int start = scope_info->ContextLocalNameEntriesIndex();
+  for (int i = 0; i < local_count; ++i) {
+    if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
+    int context_index = Context::MIN_CONTEXT_SLOTS + i;
+    Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
+    // Reflect variables under TDZ as undefined in scope object.
+    if (value->IsTheHole()) continue;
+    // This should always succeed.
+    // TODO(verwaest): Use AddDataProperty instead.
+    JSObject::SetOwnPropertyIgnoreAttributes(
+        scope_object, handle(String::cast(scope_info->get(i + start))), value,
+        ::NONE)
+        .Check();
+  }
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/debug/debug-scopes.h b/src/debug/debug-scopes.h
new file mode 100644 (file)
index 0000000..0247cc4
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_DEBUG_DEBUG_SCOPES_H_
+#define V8_DEBUG_DEBUG_SCOPES_H_
+
+#include "src/debug/debug-frames.h"
+#include "src/frames.h"
+
+namespace v8 {
+namespace internal {
+
+// Iterate over the actual scopes visible from a stack frame or from a closure.
+// 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 "artificially" in the context chain.
+class ScopeIterator {
+ public:
+  enum ScopeType {
+    ScopeTypeGlobal = 0,
+    ScopeTypeLocal,
+    ScopeTypeWith,
+    ScopeTypeClosure,
+    ScopeTypeCatch,
+    ScopeTypeBlock,
+    ScopeTypeScript,
+    ScopeTypeModule
+  };
+
+  static const int kScopeDetailsTypeIndex = 0;
+  static const int kScopeDetailsObjectIndex = 1;
+  static const int kScopeDetailsSize = 2;
+
+  ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
+                bool ignore_nested_scopes = false);
+
+  ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
+
+  MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails();
+
+  // More scopes?
+  bool Done() {
+    DCHECK(!failed_);
+    return context_.is_null();
+  }
+
+  bool Failed() { return failed_; }
+
+  // Move to the next scope.
+  void Next();
+
+  // Return the type of the current scope.
+  ScopeType Type();
+
+  // Return the JavaScript object with the content of the current scope.
+  MaybeHandle<JSObject> ScopeObject();
+
+  bool HasContext();
+
+  // Set variable value and return true on success.
+  bool SetVariableValue(Handle<String> variable_name, Handle<Object> new_value);
+
+  Handle<ScopeInfo> CurrentScopeInfo();
+
+  // Return the context for this scope. For the local context there might not
+  // be an actual context.
+  Handle<Context> CurrentContext();
+
+#ifdef DEBUG
+  // Debug print of the content of the current scope.
+  void DebugPrint();
+#endif
+
+ private:
+  Isolate* isolate_;
+  FrameInspector* const frame_inspector_;
+  Handle<Context> context_;
+  List<Handle<ScopeInfo> > nested_scope_chain_;
+  bool seen_script_scope_;
+  bool failed_;
+
+  inline JavaScriptFrame* GetFrame() {
+    return frame_inspector_->GetArgumentsFrame();
+  }
+
+  inline Handle<JSFunction> GetFunction() {
+    return Handle<JSFunction>(
+        JSFunction::cast(frame_inspector_->GetFunction()));
+  }
+
+  void RetrieveScopeChain(Scope* scope, Handle<SharedFunctionInfo> shared_info);
+
+  MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScriptScope();
+  MUST_USE_RESULT MaybeHandle<JSObject> MaterializeLocalScope();
+  MUST_USE_RESULT MaybeHandle<JSObject> MaterializeModuleScope();
+  Handle<JSObject> MaterializeClosure();
+  Handle<JSObject> MaterializeCatchScope();
+  Handle<JSObject> MaterializeBlockScope();
+
+  bool SetLocalVariableValue(Handle<String> variable_name,
+                             Handle<Object> new_value);
+  bool SetBlockVariableValue(Handle<String> variable_name,
+                             Handle<Object> new_value);
+  bool SetClosureVariableValue(Handle<String> variable_name,
+                               Handle<Object> new_value);
+  bool SetScriptVariableValue(Handle<String> variable_name,
+                              Handle<Object> new_value);
+  bool SetCatchVariableValue(Handle<String> variable_name,
+                             Handle<Object> new_value);
+  bool SetContextLocalValue(Handle<ScopeInfo> scope_info,
+                            Handle<Context> context,
+                            Handle<String> variable_name,
+                            Handle<Object> new_value);
+
+  void CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
+                                      Handle<Context> context,
+                                      Handle<JSObject> scope_object);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_DEBUG_DEBUG_SCOPES_H_
index 7ab6fdbd5f5cced8ce0b66a40d267950f6b9f2fb..486794df366e98aad5ea35c49a4eed83c1471b7f 100644 (file)
@@ -423,7 +423,6 @@ class CodeGenerator;
 class CodeStub;
 class Context;
 class Debug;
-class Debugger;
 class DebugInfo;
 class Descriptor;
 class DescriptorArray;
index fe1f51b5c64f33969b52a2b579a261c7329d8e44..1451cf58c8ec07c8382d158ccd62cfe0ea81c8b9 100644 (file)
@@ -83,7 +83,6 @@ typedef void* ExternalReferenceRedirectorPointer();
 
 
 class Debug;
-class Debugger;
 class PromiseOnStack;
 class Redirection;
 class Simulator;
index 94d11737a6fcd7e9139a1bc64bf7081b03b791a7..72b1f06c8d84d0acec917f0366d867cdd3759e71 100644 (file)
@@ -3965,12 +3965,6 @@ class ScopeInfo : public FixedArray {
 
   FunctionKind function_kind();
 
-  // Copies all the context locals into an object used to materialize a scope.
-  static void CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
-                                             Handle<Context> context,
-                                             Handle<JSObject> scope_object);
-
-
   static Handle<ScopeInfo> Create(Isolate* isolate, Zone* zone, Scope* scope);
   static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);
 
@@ -4106,6 +4100,8 @@ class ScopeInfo : public FixedArray {
   class ContextLocalInitFlag:  public BitField<InitializationFlag,   3, 1> {};
   class ContextLocalMaybeAssignedFlag
       : public BitField<MaybeAssignedFlag, 4, 1> {};
+
+  friend class ScopeIterator;
 };
 
 
index c3862f08d927e8dbf6d51bb5b0141b60b09bd8fa..f747f35184eb71dfba3f032fc9167f0c6a556ea4 100644 (file)
@@ -4,12 +4,11 @@
 
 #include "src/v8.h"
 
-#include "src/accessors.h"
 #include "src/arguments.h"
-#include "src/compiler.h"
 #include "src/debug/debug.h"
-#include "src/deoptimizer.h"
-#include "src/parser.h"
+#include "src/debug/debug-evaluate.h"
+#include "src/debug/debug-frames.h"
+#include "src/debug/debug-scopes.h"
 #include "src/runtime/runtime.h"
 #include "src/runtime/runtime-utils.h"
 
@@ -35,18 +34,6 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
 }
 
 
-// Helper functions for wrapping and unwrapping stack frame ids.
-static Smi* WrapFrameId(StackFrame::Id id) {
-  DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
-  return Smi::FromInt(id >> 2);
-}
-
-
-static StackFrame::Id UnwrapFrameId(int wrapped) {
-  return static_cast<StackFrame::Id>(wrapped << 2);
-}
-
-
 // Adds a JavaScript function as a debug event listener.
 // args[0]: debug event listener function to set or null or undefined for
 //          clearing the event listener function
@@ -475,94 +462,6 @@ RUNTIME_FUNCTION(Runtime_GetFrameCount) {
 }
 
 
-class FrameInspector {
- public:
-  FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
-                 Isolate* isolate)
-      : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
-    has_adapted_arguments_ = frame_->has_adapted_arguments();
-    is_bottommost_ = inlined_jsframe_index == 0;
-    is_optimized_ = frame_->is_optimized();
-    // Calculate the deoptimized frame.
-    if (frame->is_optimized()) {
-      // TODO(turbofan): Revisit once we support deoptimization.
-      if (frame->LookupCode()->is_turbofanned() &&
-          frame->function()->shared()->asm_function() &&
-          !FLAG_turbo_asm_deoptimization) {
-        is_optimized_ = false;
-        return;
-      }
-
-      deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
-          frame, inlined_jsframe_index, isolate);
-    }
-  }
-
-  ~FrameInspector() {
-    // Get rid of the calculated deoptimized frame if any.
-    if (deoptimized_frame_ != NULL) {
-      Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
-    }
-  }
-
-  int GetParametersCount() {
-    return is_optimized_ ? deoptimized_frame_->parameters_count()
-                         : frame_->ComputeParametersCount();
-  }
-  int expression_count() { return deoptimized_frame_->expression_count(); }
-  Object* GetFunction() {
-    return is_optimized_ ? deoptimized_frame_->GetFunction()
-                         : frame_->function();
-  }
-  Object* GetParameter(int index) {
-    return is_optimized_ ? deoptimized_frame_->GetParameter(index)
-                         : frame_->GetParameter(index);
-  }
-  Object* GetExpression(int index) {
-    // TODO(turbofan): Revisit once we support deoptimization.
-    if (frame_->LookupCode()->is_turbofanned() &&
-        frame_->function()->shared()->asm_function() &&
-        !FLAG_turbo_asm_deoptimization) {
-      return isolate_->heap()->undefined_value();
-    }
-    return is_optimized_ ? deoptimized_frame_->GetExpression(index)
-                         : frame_->GetExpression(index);
-  }
-  int GetSourcePosition() {
-    return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
-                         : frame_->LookupCode()->SourcePosition(frame_->pc());
-  }
-  bool IsConstructor() {
-    return is_optimized_ && !is_bottommost_
-               ? deoptimized_frame_->HasConstructStub()
-               : frame_->IsConstructor();
-  }
-  Object* GetContext() {
-    return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
-  }
-  JavaScriptFrame* GetArgumentsFrame() { return frame_; }
-
-  // To inspect all the provided arguments the frame might need to be
-  // replaced with the arguments frame.
-  void SetArgumentsFrame(JavaScriptFrame* frame) {
-    DCHECK(has_adapted_arguments_);
-    frame_ = frame;
-    is_optimized_ = frame_->is_optimized();
-    DCHECK(!is_optimized_);
-  }
-
- private:
-  JavaScriptFrame* frame_;
-  DeoptimizedFrameInfo* deoptimized_frame_;
-  Isolate* isolate_;
-  bool is_optimized_;
-  bool is_bottommost_;
-  bool has_adapted_arguments_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameInspector);
-};
-
-
 static const int kFrameDetailsFrameIdIndex = 0;
 static const int kFrameDetailsReceiverIndex = 1;
 static const int kFrameDetailsFunctionIndex = 2;
@@ -575,34 +474,6 @@ static const int kFrameDetailsFlagsIndex = 8;
 static const int kFrameDetailsFirstDynamicIndex = 9;
 
 
-static SaveContext* FindSavedContextForFrame(Isolate* isolate,
-                                             JavaScriptFrame* frame) {
-  SaveContext* save = isolate->save_context();
-  while (save != NULL && !save->IsBelowFrame(frame)) {
-    save = save->prev();
-  }
-  DCHECK(save != NULL);
-  return save;
-}
-
-
-// Advances the iterator to the frame that matches the index and returns the
-// inlined frame index, or -1 if not found.  Skips native JS functions.
-int Runtime::FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) {
-  int count = -1;
-  for (; !it->done(); it->Advance()) {
-    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
-    it->frame()->Summarize(&frames);
-    for (int i = frames.length() - 1; i >= 0; i--) {
-      // Omit functions from native and extension scripts.
-      if (!frames[i].function()->IsSubjectToDebugging()) continue;
-      if (++count == index) return i;
-    }
-  }
-  return -1;
-}
-
-
 // Return an array with frame details
 // args[0]: number: break id
 // args[1]: number: frame index
@@ -638,7 +509,8 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
 
   JavaScriptFrameIterator it(isolate, id);
   // Inlined frame index in optimized frame, starting from outer function.
-  int inlined_jsframe_index = Runtime::FindIndexedNonNativeFrame(&it, index);
+  int inlined_jsframe_index =
+      DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
   if (inlined_jsframe_index == -1) return heap->undefined_value();
 
   FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
@@ -646,10 +518,12 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
 
   // Traverse the saved contexts chain to find the active context for the
   // selected frame.
-  SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
+  SaveContext* save =
+      DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame());
 
   // Get the frame id.
-  Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
+  Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()),
+                          isolate);
 
   // Find source position in unoptimized code.
   int position = frame_inspector.GetSourcePosition();
@@ -866,929 +740,6 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
 }
 
 
-static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
-                                              Handle<String> parameter_name) {
-  VariableMode mode;
-  VariableLocation location;
-  InitializationFlag init_flag;
-  MaybeAssignedFlag maybe_assigned_flag;
-  return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &location,
-                                     &init_flag, &maybe_assigned_flag) != -1;
-}
-
-
-static Handle<Context> MaterializeReceiver(Isolate* isolate,
-                                           Handle<Context> target,
-                                           Handle<JSFunction> function,
-                                           JavaScriptFrame* frame) {
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-  Handle<Object> receiver;
-  switch (scope_info->scope_type()) {
-    case FUNCTION_SCOPE: {
-      VariableMode mode;
-      VariableLocation location;
-      InitializationFlag init_flag;
-      MaybeAssignedFlag maybe_assigned_flag;
-
-      // Don't bother creating a fake context node if "this" is in the context
-      // already.
-      if (ScopeInfo::ContextSlotIndex(
-              scope_info, isolate->factory()->this_string(), &mode, &location,
-              &init_flag, &maybe_assigned_flag) >= 0) {
-        return target;
-      }
-      receiver = handle(frame->receiver(), isolate);
-      break;
-    }
-    case MODULE_SCOPE:
-      receiver = isolate->factory()->undefined_value();
-      break;
-    case SCRIPT_SCOPE:
-      receiver = handle(function->global_proxy(), isolate);
-      break;
-    default:
-      // For eval code, arrow functions, and the like, there's no "this" binding
-      // to materialize.
-      return target;
-  }
-
-  return isolate->factory()->NewCatchContext(
-      function, target, isolate->factory()->this_string(), receiver);
-}
-
-
-// Create a plain JSObject which materializes the local scope for the specified
-// frame.
-static void MaterializeStackLocalsWithFrameInspector(
-    Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info,
-    FrameInspector* frame_inspector) {
-  // First fill all parameters.
-  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
-    // Do not materialize the parameter if it is shadowed by a context local.
-    Handle<String> name(scope_info->ParameterName(i));
-    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
-
-    DCHECK_NOT_NULL(frame_inspector);
-
-    HandleScope scope(isolate);
-    Handle<Object> value(i < frame_inspector->GetParametersCount()
-                             ? frame_inspector->GetParameter(i)
-                             : isolate->heap()->undefined_value(),
-                         isolate);
-    DCHECK(!value->IsTheHole());
-
-    JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
-  }
-
-  // Second fill all stack locals.
-  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    if (scope_info->LocalIsSynthetic(i)) continue;
-    Handle<String> name(scope_info->StackLocalName(i));
-    Handle<Object> value(
-        frame_inspector->GetExpression(scope_info->StackLocalIndex(i)),
-        isolate);
-    if (value->IsTheHole()) {
-      value = isolate->factory()->undefined_value();
-    }
-
-    JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
-  }
-}
-
-static void MaterializeStackLocalsWithFrameInspector(
-    Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
-    FrameInspector* frame_inspector) {
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  MaterializeStackLocalsWithFrameInspector(isolate, target, scope_info,
-                                           frame_inspector);
-}
-
-
-static void UpdateStackLocalsFromMaterializedObject(
-    Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info,
-    JavaScriptFrame* frame, int inlined_jsframe_index) {
-  if (inlined_jsframe_index != 0 || frame->is_optimized()) {
-    // Optimized frames are not supported. Simply give up.
-    return;
-  }
-
-  // Parameters.
-  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
-    // Shadowed parameters were not materialized.
-    Handle<String> name(scope_info->ParameterName(i));
-    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
-
-    DCHECK(!frame->GetParameter(i)->IsTheHole());
-    HandleScope scope(isolate);
-    Handle<Object> value =
-        Object::GetPropertyOrElement(target, name).ToHandleChecked();
-    frame->SetParameterValue(i, *value);
-  }
-
-  // Stack locals.
-  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    if (scope_info->LocalIsSynthetic(i)) continue;
-    int index = scope_info->StackLocalIndex(i);
-    if (frame->GetExpression(index)->IsTheHole()) continue;
-    HandleScope scope(isolate);
-    Handle<Object> value = Object::GetPropertyOrElement(
-                               target, handle(scope_info->StackLocalName(i),
-                                              isolate)).ToHandleChecked();
-    frame->SetExpression(index, *value);
-  }
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
-    Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
-    Handle<Context> frame_context) {
-  HandleScope scope(isolate);
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  if (!scope_info->HasContext()) return target;
-
-  // Third fill all context locals.
-  Handle<Context> function_context(frame_context->declaration_context());
-  ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context,
-                                            target);
-
-  // 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->IsNativeContext()) {
-      Handle<JSObject> ext(JSObject::cast(function_context->extension()));
-      Handle<FixedArray> keys;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
-          JSObject);
-
-      for (int i = 0; i < keys->length(); i++) {
-        // Names of variables introduced by eval are strings.
-        DCHECK(keys->get(i)->IsString());
-        Handle<String> key(String::cast(keys->get(i)));
-        Handle<Object> value;
-        ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
-        RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
-                                         isolate, target, key, value, SLOPPY),
-                            JSObject);
-      }
-    }
-  }
-
-  return target;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScriptScope(
-    Handle<GlobalObject> global) {
-  Isolate* isolate = global->GetIsolate();
-  Handle<ScriptContextTable> script_contexts(
-      global->native_context()->script_context_table());
-
-  Handle<JSObject> script_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  for (int context_index = 0; context_index < script_contexts->used();
-       context_index++) {
-    Handle<Context> context =
-        ScriptContextTable::GetContext(script_contexts, context_index);
-    Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-    ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
-                                              script_scope);
-  }
-  return script_scope;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
-    Isolate* isolate, FrameInspector* frame_inspector) {
-  Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
-
-  Handle<JSObject> local_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-  MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
-                                           frame_inspector);
-
-  Handle<Context> frame_context(Context::cast(frame_inspector->GetContext()));
-
-  return MaterializeLocalContext(isolate, local_scope, function, frame_context);
-}
-
-
-// Set the context local variable value.
-static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
-                                 Handle<Context> context,
-                                 Handle<String> variable_name,
-                                 Handle<Object> new_value) {
-  for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
-    Handle<String> next_name(scope_info->ContextLocalName(i));
-    if (String::Equals(variable_name, next_name)) {
-      VariableMode mode;
-      VariableLocation location;
-      InitializationFlag init_flag;
-      MaybeAssignedFlag maybe_assigned_flag;
-      int context_index =
-          ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &location,
-                                      &init_flag, &maybe_assigned_flag);
-      context->set(context_index, *new_value);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-
-static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
-                                  Handle<String> variable_name,
-                                  Handle<Object> new_value) {
-  // Optimized frames are not supported.
-  if (frame->is_optimized()) return false;
-
-  Handle<JSFunction> function(frame->function());
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  bool default_result = false;
-
-  // Parameters.
-  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
-    HandleScope scope(isolate);
-    if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
-      frame->SetParameterValue(i, *new_value);
-      // Argument might be shadowed in heap context, don't stop here.
-      default_result = true;
-    }
-  }
-
-  // Stack locals.
-  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    HandleScope scope(isolate);
-    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
-      frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
-      return true;
-    }
-  }
-
-  if (scope_info->HasContext()) {
-    // Context locals.
-    Handle<Context> frame_context(Context::cast(frame->context()));
-    Handle<Context> function_context(frame_context->declaration_context());
-    if (SetContextLocalValue(isolate, scope_info, function_context,
-                             variable_name, new_value)) {
-      return true;
-    }
-
-    // Function context extension. These are variables introduced by eval.
-    if (function_context->closure() == *function) {
-      if (function_context->has_extension() &&
-          !function_context->IsNativeContext()) {
-        Handle<JSObject> ext(JSObject::cast(function_context->extension()));
-
-        Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
-        DCHECK(maybe.IsJust());
-        if (maybe.FromJust()) {
-          // We don't expect this to do anything except replacing
-          // property value.
-          Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
-                                     SLOPPY).Assert();
-          return true;
-        }
-      }
-    }
-  }
-
-  return default_result;
-}
-
-
-static bool SetBlockVariableValue(Isolate* isolate,
-                                  Handle<Context> block_context,
-                                  Handle<ScopeInfo> scope_info,
-                                  JavaScriptFrame* frame,
-                                  Handle<String> variable_name,
-                                  Handle<Object> new_value) {
-  if (frame != nullptr) {
-    for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-      HandleScope scope(isolate);
-      if (String::Equals(handle(scope_info->StackLocalName(i)),
-                         variable_name)) {
-        frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
-        return true;
-      }
-    }
-  }
-  if (!block_context.is_null()) {
-    return SetContextLocalValue(block_context->GetIsolate(), scope_info,
-                                block_context, variable_name, new_value);
-  }
-  return false;
-}
-
-
-// Create a plain JSObject which materializes the closure content for the
-// context.
-static Handle<JSObject> MaterializeClosure(Isolate* isolate,
-                                           Handle<Context> context) {
-  DCHECK(context->IsFunctionContext());
-
-  Handle<SharedFunctionInfo> shared(context->closure()->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  // Allocate and initialize a JSObject with all the content of this function
-  // closure.
-  Handle<JSObject> closure_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  // Fill all context locals to the context extension.
-  ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, closure_scope);
-
-  // Finally copy any properties from the function context extension. This will
-  // be variables introduced by eval.
-  if (context->has_extension()) {
-    Handle<JSObject> ext(JSObject::cast(context->extension()));
-    DCHECK(ext->IsJSContextExtensionObject());
-    Handle<FixedArray> keys =
-        JSReceiver::GetKeys(ext, JSReceiver::OWN_ONLY).ToHandleChecked();
-
-    for (int i = 0; i < keys->length(); i++) {
-      HandleScope scope(isolate);
-      // Names of variables introduced by eval are strings.
-      DCHECK(keys->get(i)->IsString());
-      Handle<String> key(String::cast(keys->get(i)));
-      Handle<Object> value = Object::GetProperty(ext, key).ToHandleChecked();
-      JSObject::SetOwnPropertyIgnoreAttributes(closure_scope, key, value, NONE)
-          .Check();
-    }
-  }
-
-  return closure_scope;
-}
-
-
-// This method copies structure of MaterializeClosure method above.
-static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
-                                    Handle<String> variable_name,
-                                    Handle<Object> new_value) {
-  DCHECK(context->IsFunctionContext());
-
-  Handle<SharedFunctionInfo> shared(context->closure()->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  // Context locals to the context extension.
-  if (SetContextLocalValue(isolate, scope_info, context, variable_name,
-                           new_value)) {
-    return true;
-  }
-
-  // Properties from the function context extension. This will
-  // be variables introduced by eval.
-  if (context->has_extension()) {
-    Handle<JSObject> ext(JSObject::cast(context->extension()));
-    DCHECK(ext->IsJSContextExtensionObject());
-    Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
-    DCHECK(maybe.IsJust());
-    if (maybe.FromJust()) {
-      // We don't expect this to do anything except replacing property value.
-      JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
-                                               NONE).Check();
-      return true;
-    }
-  }
-
-  return false;
-}
-
-
-static bool SetScriptVariableValue(Handle<Context> context,
-                                   Handle<String> variable_name,
-                                   Handle<Object> new_value) {
-  Handle<ScriptContextTable> script_contexts(
-      context->global_object()->native_context()->script_context_table());
-  ScriptContextTable::LookupResult lookup_result;
-  if (ScriptContextTable::Lookup(script_contexts, variable_name,
-                                 &lookup_result)) {
-    Handle<Context> script_context = ScriptContextTable::GetContext(
-        script_contexts, lookup_result.context_index);
-    script_context->set(lookup_result.slot_index, *new_value);
-    return true;
-  }
-
-  return false;
-}
-
-
-// Create a plain JSObject which materializes the scope for the specified
-// catch context.
-static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
-                                              Handle<Context> context) {
-  DCHECK(context->IsCatchContext());
-  Handle<String> name(String::cast(context->extension()));
-  Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
-                               isolate);
-  Handle<JSObject> catch_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-  JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
-                                           NONE).Check();
-  return catch_scope;
-}
-
-
-static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
-                                  Handle<String> variable_name,
-                                  Handle<Object> new_value) {
-  DCHECK(context->IsCatchContext());
-  Handle<String> name(String::cast(context->extension()));
-  if (!String::Equals(name, variable_name)) {
-    return false;
-  }
-  context->set(Context::THROWN_OBJECT_INDEX, *new_value);
-  return true;
-}
-
-
-// Create a plain JSObject which materializes the block scope for the specified
-// block context.
-static Handle<JSObject> MaterializeBlockScope(Isolate* isolate,
-                                              Handle<ScopeInfo> scope_info,
-                                              Handle<Context> context,
-                                              FrameInspector* frame_inspector) {
-  Handle<JSObject> block_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  if (frame_inspector != nullptr) {
-    MaterializeStackLocalsWithFrameInspector(isolate, block_scope, scope_info,
-                                             frame_inspector);
-  }
-
-  if (!context.is_null()) {
-    Handle<ScopeInfo> scope_info_from_context(
-        ScopeInfo::cast(context->extension()));
-    // Fill all context locals.
-    ScopeInfo::CopyContextLocalsToScopeObject(scope_info_from_context, context,
-                                              block_scope);
-  }
-
-  return block_scope;
-}
-
-
-// Create a plain JSObject which materializes the module scope for the specified
-// module context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
-    Isolate* isolate, Handle<Context> context) {
-  DCHECK(context->IsModuleContext());
-  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-
-  // Allocate and initialize a JSObject with all the members of the debugged
-  // module.
-  Handle<JSObject> module_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  // Fill all context locals.
-  ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, module_scope);
-
-  return module_scope;
-}
-
-
-// Iterate over the actual scopes visible from a stack frame or from a closure.
-// 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 "artificially" in the context chain.
-class ScopeIterator {
- public:
-  enum ScopeType {
-    ScopeTypeGlobal = 0,
-    ScopeTypeLocal,
-    ScopeTypeWith,
-    ScopeTypeClosure,
-    ScopeTypeCatch,
-    ScopeTypeBlock,
-    ScopeTypeScript,
-    ScopeTypeModule
-  };
-
-  ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
-                bool ignore_nested_scopes = false)
-      : isolate_(isolate),
-        frame_inspector_(frame_inspector),
-        nested_scope_chain_(4),
-        seen_script_scope_(false),
-        failed_(false) {
-    if (!frame_inspector->GetContext()->IsContext() ||
-        !frame_inspector->GetFunction()->IsJSFunction()) {
-      // Optimized frame, context or function cannot be materialized. Give up.
-      return;
-    }
-
-    context_ = Handle<Context>(Context::cast(frame_inspector->GetContext()));
-
-    // Catch the case when the debugger stops in an internal function.
-    Handle<SharedFunctionInfo> shared_info(function()->shared());
-    Handle<ScopeInfo> scope_info(shared_info->scope_info());
-    if (shared_info->script() == isolate->heap()->undefined_value()) {
-      while (context_->closure() == function()) {
-        context_ = Handle<Context>(context_->previous(), isolate_);
-      }
-      return;
-    }
-
-    // Currently it takes too much time to find nested scopes due to script
-    // parsing. Sometimes we want to run the ScopeIterator as fast as possible
-    // (for example, while collecting async call stacks on every
-    // addEventListener call), even if we drop some nested scopes.
-    // Later we may optimize getting the nested scopes (cache the result?)
-    // and include nested scopes into the "fast" iteration case as well.
-
-    if (!ignore_nested_scopes && shared_info->HasDebugInfo()) {
-      // The source position at return is always the end of the function,
-      // which is not consistent with the current scope chain. Therefore all
-      // nested with, catch and block contexts are skipped, and we can only
-      // inspect the function scope.
-      // This can only happen if we set a break point inside right before the
-      // return, which requires a debug info to be available.
-      Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
-
-      // PC points to the instruction after the current one, possibly a break
-      // location as well. So the "- 1" to exclude it from the search.
-      Address call_pc = frame()->pc() - 1;
-
-      // Find the break point where execution has stopped.
-      BreakLocation location =
-          BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
-
-      ignore_nested_scopes = location.IsReturn();
-    }
-
-    if (ignore_nested_scopes) {
-      if (scope_info->HasContext()) {
-        context_ = Handle<Context>(context_->declaration_context(), isolate_);
-      } else {
-        while (context_->closure() == function()) {
-          context_ = Handle<Context>(context_->previous(), isolate_);
-        }
-      }
-      if (scope_info->scope_type() == FUNCTION_SCOPE ||
-          scope_info->scope_type() == ARROW_SCOPE) {
-        nested_scope_chain_.Add(scope_info);
-      }
-    } else {
-      // Reparse the code and analyze the scopes.
-      Handle<Script> script(Script::cast(shared_info->script()));
-      Scope* scope = NULL;
-
-      // Check whether we are in global, eval or function code.
-      Handle<ScopeInfo> scope_info(shared_info->scope_info());
-      Zone zone;
-      if (scope_info->scope_type() != FUNCTION_SCOPE &&
-          scope_info->scope_type() != ARROW_SCOPE) {
-        // Global or eval code.
-        ParseInfo info(&zone, script);
-        if (scope_info->scope_type() == SCRIPT_SCOPE) {
-          info.set_global();
-        } else {
-          DCHECK(scope_info->scope_type() == EVAL_SCOPE);
-          info.set_eval();
-          info.set_context(Handle<Context>(function()->context()));
-        }
-        if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
-          scope = info.function()->scope();
-        }
-        RetrieveScopeChain(scope, shared_info);
-      } else {
-        // Function code
-        ParseInfo info(&zone, Handle<JSFunction>(function()));
-        if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
-          scope = info.function()->scope();
-        }
-        RetrieveScopeChain(scope, shared_info);
-      }
-    }
-  }
-
-  ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
-      : isolate_(isolate),
-        frame_inspector_(NULL),
-        context_(function->context()),
-        seen_script_scope_(false),
-        failed_(false) {
-    if (function->IsBuiltin()) context_ = Handle<Context>();
-  }
-
-  // More scopes?
-  bool Done() {
-    DCHECK(!failed_);
-    return context_.is_null();
-  }
-
-  bool Failed() { return failed_; }
-
-  // Move to the next scope.
-  void Next() {
-    DCHECK(!failed_);
-    ScopeType scope_type = Type();
-    if (scope_type == ScopeTypeGlobal) {
-      // The global scope is always the last in the chain.
-      DCHECK(context_->IsNativeContext());
-      context_ = Handle<Context>();
-      return;
-    }
-    if (scope_type == ScopeTypeScript) {
-      seen_script_scope_ = true;
-      if (context_->IsScriptContext()) {
-        context_ = Handle<Context>(context_->previous(), isolate_);
-      }
-      if (!nested_scope_chain_.is_empty()) {
-        DCHECK_EQ(nested_scope_chain_.last()->scope_type(), SCRIPT_SCOPE);
-        nested_scope_chain_.RemoveLast();
-        DCHECK(nested_scope_chain_.is_empty());
-      }
-      CHECK(context_->IsNativeContext());
-      return;
-    }
-    if (nested_scope_chain_.is_empty()) {
-      context_ = Handle<Context>(context_->previous(), isolate_);
-    } else {
-      if (nested_scope_chain_.last()->HasContext()) {
-        DCHECK(context_->previous() != NULL);
-        context_ = Handle<Context>(context_->previous(), isolate_);
-      }
-      nested_scope_chain_.RemoveLast();
-    }
-  }
-
-  // Return the type of the current scope.
-  ScopeType Type() {
-    DCHECK(!failed_);
-    if (!nested_scope_chain_.is_empty()) {
-      Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
-      switch (scope_info->scope_type()) {
-        case FUNCTION_SCOPE:
-        case ARROW_SCOPE:
-          DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
-          return ScopeTypeLocal;
-        case MODULE_SCOPE:
-          DCHECK(context_->IsModuleContext());
-          return ScopeTypeModule;
-        case SCRIPT_SCOPE:
-          DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
-          return ScopeTypeScript;
-        case WITH_SCOPE:
-          DCHECK(context_->IsWithContext());
-          return ScopeTypeWith;
-        case CATCH_SCOPE:
-          DCHECK(context_->IsCatchContext());
-          return ScopeTypeCatch;
-        case BLOCK_SCOPE:
-          DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
-          return ScopeTypeBlock;
-        case EVAL_SCOPE:
-          UNREACHABLE();
-      }
-    }
-    if (context_->IsNativeContext()) {
-      DCHECK(context_->global_object()->IsGlobalObject());
-      // If we are at the native context and have not yet seen script scope,
-      // fake it.
-      return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
-    }
-    if (context_->IsFunctionContext()) {
-      return ScopeTypeClosure;
-    }
-    if (context_->IsCatchContext()) {
-      return ScopeTypeCatch;
-    }
-    if (context_->IsBlockContext()) {
-      return ScopeTypeBlock;
-    }
-    if (context_->IsModuleContext()) {
-      return ScopeTypeModule;
-    }
-    if (context_->IsScriptContext()) {
-      return ScopeTypeScript;
-    }
-    DCHECK(context_->IsWithContext());
-    return ScopeTypeWith;
-  }
-
-  // Return the JavaScript object with the content of the current scope.
-  MaybeHandle<JSObject> ScopeObject() {
-    DCHECK(!failed_);
-    switch (Type()) {
-      case ScopeIterator::ScopeTypeGlobal:
-        return Handle<JSObject>(CurrentContext()->global_object());
-      case ScopeIterator::ScopeTypeScript:
-        return MaterializeScriptScope(
-            Handle<GlobalObject>(CurrentContext()->global_object()));
-      case ScopeIterator::ScopeTypeLocal:
-        // Materialize the content of the local scope into a JSObject.
-        DCHECK(nested_scope_chain_.length() == 1);
-        return MaterializeLocalScope(isolate_, frame_inspector_);
-      case ScopeIterator::ScopeTypeWith:
-        // Return the with object.
-        return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
-      case ScopeIterator::ScopeTypeCatch:
-        return MaterializeCatchScope(isolate_, CurrentContext());
-      case ScopeIterator::ScopeTypeClosure:
-        // Materialize the content of the closure scope into a JSObject.
-        return MaterializeClosure(isolate_, CurrentContext());
-      case ScopeIterator::ScopeTypeBlock: {
-        if (!nested_scope_chain_.is_empty()) {
-          // this is a block scope on the stack.
-          Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
-          Handle<Context> context = scope_info->HasContext()
-                                        ? CurrentContext()
-                                        : Handle<Context>::null();
-          return MaterializeBlockScope(isolate_, scope_info, context,
-                                       frame_inspector_);
-        } else {
-          return MaterializeBlockScope(isolate_, Handle<ScopeInfo>::null(),
-                                       CurrentContext(), nullptr);
-        }
-      }
-      case ScopeIterator::ScopeTypeModule:
-        return MaterializeModuleScope(isolate_, CurrentContext());
-    }
-    UNREACHABLE();
-    return Handle<JSObject>();
-  }
-
-  bool HasContext() {
-    ScopeType type = Type();
-    if (type == ScopeTypeBlock || type == ScopeTypeLocal) {
-      if (!nested_scope_chain_.is_empty()) {
-        return nested_scope_chain_.last()->HasContext();
-      }
-    }
-    return true;
-  }
-
-  bool SetVariableValue(Handle<String> variable_name,
-                        Handle<Object> new_value) {
-    DCHECK(!failed_);
-    switch (Type()) {
-      case ScopeIterator::ScopeTypeGlobal:
-        break;
-      case ScopeIterator::ScopeTypeLocal:
-        return SetLocalVariableValue(isolate_, frame(), variable_name,
-                                     new_value);
-      case ScopeIterator::ScopeTypeWith:
-        break;
-      case ScopeIterator::ScopeTypeCatch:
-        return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
-                                     new_value);
-      case ScopeIterator::ScopeTypeClosure:
-        return SetClosureVariableValue(isolate_, CurrentContext(),
-                                       variable_name, new_value);
-      case ScopeIterator::ScopeTypeScript:
-        return SetScriptVariableValue(CurrentContext(), variable_name,
-                                      new_value);
-      case ScopeIterator::ScopeTypeBlock:
-        return SetBlockVariableValue(
-            isolate_, HasContext() ? CurrentContext() : Handle<Context>::null(),
-            CurrentScopeInfo(), frame(), variable_name, new_value);
-      case ScopeIterator::ScopeTypeModule:
-        // TODO(2399): should we implement it?
-        break;
-    }
-    return false;
-  }
-
-  Handle<ScopeInfo> CurrentScopeInfo() {
-    DCHECK(!failed_);
-    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() {
-    DCHECK(!failed_);
-    if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
-        nested_scope_chain_.is_empty()) {
-      return context_;
-    } else if (nested_scope_chain_.last()->HasContext()) {
-      return context_;
-    } else {
-      return Handle<Context>();
-    }
-  }
-
-#ifdef DEBUG
-  // Debug print of the content of the current scope.
-  void DebugPrint() {
-    OFStream os(stdout);
-    DCHECK(!failed_);
-    switch (Type()) {
-      case ScopeIterator::ScopeTypeGlobal:
-        os << "Global:\n";
-        CurrentContext()->Print(os);
-        break;
-
-      case ScopeIterator::ScopeTypeLocal: {
-        os << "Local:\n";
-        function()->shared()->scope_info()->Print();
-        if (!CurrentContext().is_null()) {
-          CurrentContext()->Print(os);
-          if (CurrentContext()->has_extension()) {
-            Handle<Object> extension(CurrentContext()->extension(), isolate_);
-            if (extension->IsJSContextExtensionObject()) {
-              extension->Print(os);
-            }
-          }
-        }
-        break;
-      }
-
-      case ScopeIterator::ScopeTypeWith:
-        os << "With:\n";
-        CurrentContext()->extension()->Print(os);
-        break;
-
-      case ScopeIterator::ScopeTypeCatch:
-        os << "Catch:\n";
-        CurrentContext()->extension()->Print(os);
-        CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
-        break;
-
-      case ScopeIterator::ScopeTypeClosure:
-        os << "Closure:\n";
-        CurrentContext()->Print(os);
-        if (CurrentContext()->has_extension()) {
-          Handle<Object> extension(CurrentContext()->extension(), isolate_);
-          if (extension->IsJSContextExtensionObject()) {
-            extension->Print(os);
-          }
-        }
-        break;
-
-      case ScopeIterator::ScopeTypeScript:
-        os << "Script:\n";
-        CurrentContext()
-            ->global_object()
-            ->native_context()
-            ->script_context_table()
-            ->Print(os);
-        break;
-
-      default:
-        UNREACHABLE();
-    }
-    PrintF("\n");
-  }
-#endif
-
- private:
-  Isolate* isolate_;
-  FrameInspector* const frame_inspector_;
-  Handle<Context> context_;
-  List<Handle<ScopeInfo> > nested_scope_chain_;
-  bool seen_script_scope_;
-  bool failed_;
-
-  inline JavaScriptFrame* frame() {
-    return frame_inspector_->GetArgumentsFrame();
-  }
-
-  inline JSFunction* function() {
-    return JSFunction::cast(frame_inspector_->GetFunction());
-  }
-
-  void RetrieveScopeChain(Scope* scope,
-                          Handle<SharedFunctionInfo> shared_info) {
-    if (scope != NULL) {
-      int source_position = frame_inspector_->GetSourcePosition();
-      scope->GetNestedScopeChain(isolate_, &nested_scope_chain_,
-                                 source_position);
-    } else {
-      // A failed reparse indicates that the preparser has diverged from the
-      // parser or that the preparse data given to the initial parse has been
-      // faulty. We fail in debug mode but in release mode we only provide the
-      // information we get from the context chain but nothing about
-      // completely stack allocated scopes or stack allocated locals.
-      // Or it could be due to stack overflow.
-      DCHECK(isolate_->has_pending_exception());
-      failed_ = true;
-    }
-  }
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
-};
-
-
 RUNTIME_FUNCTION(Runtime_GetScopeCount) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 2);
@@ -1798,7 +749,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeCount) {
   CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
 
   // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
   JavaScriptFrameIterator it(isolate, id);
   JavaScriptFrame* frame = it.frame();
   FrameInspector frame_inspector(frame, 0, isolate);
@@ -1825,7 +776,7 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
   CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
 
   // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
   JavaScriptFrameIterator frame_it(isolate, id);
   RUNTIME_ASSERT(!frame_it.done());
 
@@ -1840,28 +791,6 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
 }
 
 
-static const int kScopeDetailsTypeIndex = 0;
-static const int kScopeDetailsObjectIndex = 1;
-static const int kScopeDetailsSize = 2;
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
-    Isolate* isolate, ScopeIterator* it) {
-  // Calculate the size of the result.
-  int details_size = kScopeDetailsSize;
-  Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
-
-  // Fill in scope details.
-  details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
-  Handle<JSObject> scope_object;
-  ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
-                             JSObject);
-  details->set(kScopeDetailsObjectIndex, *scope_object);
-
-  return isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
 // Return an array with scope details
 // args[0]: number: break id
 // args[1]: number: frame index
@@ -1882,7 +811,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
   CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
 
   // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
   JavaScriptFrameIterator frame_it(isolate, id);
   JavaScriptFrame* frame = frame_it.frame();
   FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
@@ -1898,7 +827,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
   }
   Handle<JSObject> details;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
-                                     MaterializeScopeDetails(isolate, &it));
+                                     it.MaterializeScopeDetails());
   return *details;
 }
 
@@ -1928,7 +857,7 @@ RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
   }
 
   // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
   JavaScriptFrameIterator frame_it(isolate, id);
   JavaScriptFrame* frame = frame_it.frame();
   FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
@@ -1938,7 +867,7 @@ RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
   for (; !it.Done(); it.Next()) {
     Handle<JSObject> details;
     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
-                                       MaterializeScopeDetails(isolate, &it));
+                                       it.MaterializeScopeDetails());
     result.Add(details);
   }
 
@@ -1987,7 +916,7 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
 
   Handle<JSObject> details;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
-                                     MaterializeScopeDetails(isolate, &it));
+                                     it.MaterializeScopeDetails());
   return *details;
 }
 
@@ -2032,7 +961,7 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
     CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
 
     // Get the frame where the debugging is performed.
-    StackFrame::Id id = UnwrapFrameId(wrapped_id);
+    StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
     JavaScriptFrameIterator frame_it(isolate, id);
     JavaScriptFrame* frame = frame_it.frame();
     FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
@@ -2305,7 +1234,7 @@ RUNTIME_FUNCTION(Runtime_PrepareStep) {
   if (wrapped_frame_id == 0) {
     frame_id = StackFrame::NO_ID;
   } else {
-    frame_id = UnwrapFrameId(wrapped_frame_id);
+    frame_id = DebugFrameHelper::UnwrapFrameId(wrapped_frame_id);
   }
 
   // Get the step action and check validity.
@@ -2347,254 +1276,6 @@ RUNTIME_FUNCTION(Runtime_ClearStepping) {
 }
 
 
-// Helper function to find or create the arguments object for
-// Runtime_DebugEvaluate.
-static void MaterializeArgumentsObject(Isolate* isolate,
-                                       Handle<JSObject> target,
-                                       Handle<JSFunction> function) {
-  // Do not materialize the arguments object for eval or top-level code.
-  // Skip if "arguments" is already taken.
-  if (!function->shared()->is_function()) return;
-  Maybe<bool> maybe = JSReceiver::HasOwnProperty(
-      target, isolate->factory()->arguments_string());
-  DCHECK(maybe.IsJust());
-  if (maybe.FromJust()) return;
-
-  // FunctionGetArguments can't throw an exception.
-  Handle<JSObject> arguments =
-      Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
-  Handle<String> arguments_str = isolate->factory()->arguments_string();
-  JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
-                                           NONE).Check();
-}
-
-
-// Compile and evaluate source for the given context.
-static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
-                                         Handle<SharedFunctionInfo> outer_info,
-                                         Handle<Context> context,
-                                         Handle<Object> context_extension,
-                                         Handle<Object> receiver,
-                                         Handle<String> source) {
-  if (context_extension->IsJSObject()) {
-    Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
-    Handle<JSFunction> closure(context->closure(), isolate);
-    context = isolate->factory()->NewWithContext(closure, context, extension);
-  }
-
-  Handle<JSFunction> eval_fun;
-  ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
-                             Compiler::GetFunctionFromEval(
-                                 source, outer_info, context, SLOPPY,
-                                 NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
-                             Object);
-
-  Handle<Object> result;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
-      Object);
-
-  // Skip the global proxy as it has no properties and always delegates to the
-  // real global object.
-  if (result->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate, result);
-    // TODO(verwaest): This will crash when the global proxy is detached.
-    result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-  }
-
-  return result;
-}
-
-
-static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
-  Handle<JSObject> result =
-      isolate->factory()->NewJSObject(isolate->object_function());
-  Handle<Map> new_map =
-      Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
-  Map::SetPrototype(new_map, isolate->factory()->null_value());
-  JSObject::MigrateToMap(result, new_map);
-  return result;
-}
-
-
-namespace {
-
-// This class builds a context chain for evaluation of expressions
-// in debugger.
-// The scope chain leading up to a breakpoint where evaluation occurs
-// looks like:
-// - [a mix of with, catch and block scopes]
-//    - [function stack + context]
-//      - [outer context]
-// The builder materializes all stack variables into properties of objects;
-// the expression is then evaluated as if it is inside a series of 'with'
-// statements using those objects. To this end, the builder builds a new
-// context chain, based on a scope chain:
-//   - every With and Catch scope begets a cloned context
-//   - Block scope begets one or two contexts:
-//       - if a block has context-allocated varaibles, its context is cloned
-//       - stack locals are materizalized as a With context
-//   - Local scope begets a With context for materizalized locals, chained to
-//     original function context. Original function context is the end of
-//     the chain.
-class EvaluationContextBuilder {
- public:
-  EvaluationContextBuilder(Isolate* isolate, JavaScriptFrame* frame,
-                           int inlined_jsframe_index)
-      : isolate_(isolate),
-        frame_(frame),
-        inlined_jsframe_index_(inlined_jsframe_index) {
-    FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
-    Handle<JSFunction> function =
-        handle(JSFunction::cast(frame_inspector.GetFunction()));
-    Handle<Context> outer_context = handle(function->context(), isolate);
-    outer_info_ = handle(function->shared());
-    Handle<Context> inner_context;
-
-    bool stop = false;
-    for (ScopeIterator it(isolate, &frame_inspector);
-         !it.Failed() && !it.Done() && !stop; it.Next()) {
-      ScopeIterator::ScopeType scope_type = it.Type();
-
-      if (scope_type == ScopeIterator::ScopeTypeLocal) {
-        Handle<Context> parent_context =
-            it.HasContext() ? it.CurrentContext() : outer_context;
-
-        // The "this" binding, if any, can't be bound via "with".  If we need
-        // to, add another node onto the outer context to bind "this".
-        parent_context =
-            MaterializeReceiver(isolate, parent_context, function, frame);
-
-        Handle<JSObject> materialized_function =
-            NewJSObjectWithNullProto(isolate);
-
-        MaterializeStackLocalsWithFrameInspector(isolate, materialized_function,
-                                                 function, &frame_inspector);
-
-        MaterializeArgumentsObject(isolate, materialized_function, function);
-
-        Handle<Context> with_context = isolate->factory()->NewWithContext(
-            function, parent_context, materialized_function);
-
-        ContextChainElement context_chain_element;
-        context_chain_element.original_context = it.CurrentContext();
-        context_chain_element.materialized_object = materialized_function;
-        context_chain_element.scope_info = it.CurrentScopeInfo();
-        context_chain_.Add(context_chain_element);
-
-        stop = true;
-        RecordContextsInChain(&inner_context, with_context, with_context);
-      } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
-                 scope_type == ScopeIterator::ScopeTypeWith) {
-        Handle<Context> cloned_context =
-            Handle<Context>::cast(FixedArray::CopySize(
-                it.CurrentContext(), it.CurrentContext()->length()));
-
-        ContextChainElement context_chain_element;
-        context_chain_element.original_context = it.CurrentContext();
-        context_chain_element.cloned_context = cloned_context;
-        context_chain_.Add(context_chain_element);
-
-        RecordContextsInChain(&inner_context, cloned_context, cloned_context);
-      } else if (scope_type == ScopeIterator::ScopeTypeBlock) {
-        Handle<JSObject> materialized_object =
-            NewJSObjectWithNullProto(isolate);
-        MaterializeStackLocalsWithFrameInspector(isolate, materialized_object,
-                                                 it.CurrentScopeInfo(),
-                                                 &frame_inspector);
-        if (it.HasContext()) {
-          Handle<Context> cloned_context =
-              Handle<Context>::cast(FixedArray::CopySize(
-                  it.CurrentContext(), it.CurrentContext()->length()));
-          Handle<Context> with_context = isolate->factory()->NewWithContext(
-              function, cloned_context, materialized_object);
-
-          ContextChainElement context_chain_element;
-          context_chain_element.original_context = it.CurrentContext();
-          context_chain_element.cloned_context = cloned_context;
-          context_chain_element.materialized_object = materialized_object;
-          context_chain_element.scope_info = it.CurrentScopeInfo();
-          context_chain_.Add(context_chain_element);
-
-          RecordContextsInChain(&inner_context, cloned_context, with_context);
-        } else {
-          Handle<Context> with_context = isolate->factory()->NewWithContext(
-              function, outer_context, materialized_object);
-
-          ContextChainElement context_chain_element;
-          context_chain_element.materialized_object = materialized_object;
-          context_chain_element.scope_info = it.CurrentScopeInfo();
-          context_chain_.Add(context_chain_element);
-
-          RecordContextsInChain(&inner_context, with_context, with_context);
-        }
-      } else {
-        stop = true;
-      }
-    }
-    if (innermost_context_.is_null()) {
-      innermost_context_ = outer_context;
-    }
-    DCHECK(!innermost_context_.is_null());
-  }
-
-  void UpdateVariables() {
-    for (int i = 0; i < context_chain_.length(); i++) {
-      ContextChainElement element = context_chain_[i];
-      if (!element.original_context.is_null() &&
-          !element.cloned_context.is_null()) {
-        Handle<Context> cloned_context = element.cloned_context;
-        cloned_context->CopyTo(
-            Context::MIN_CONTEXT_SLOTS, *element.original_context,
-            Context::MIN_CONTEXT_SLOTS,
-            cloned_context->length() - Context::MIN_CONTEXT_SLOTS);
-      }
-      if (!element.materialized_object.is_null()) {
-        // Write back potential changes to materialized stack locals to the
-        // stack.
-        UpdateStackLocalsFromMaterializedObject(
-            isolate_, element.materialized_object, element.scope_info, frame_,
-            inlined_jsframe_index_);
-      }
-    }
-  }
-
-  Handle<Context> innermost_context() const { return innermost_context_; }
-  Handle<SharedFunctionInfo> outer_info() const { return outer_info_; }
-
- private:
-  struct ContextChainElement {
-    Handle<Context> original_context;
-    Handle<Context> cloned_context;
-    Handle<JSObject> materialized_object;
-    Handle<ScopeInfo> scope_info;
-  };
-
-  void RecordContextsInChain(Handle<Context>* inner_context,
-                             Handle<Context> first, Handle<Context> last) {
-    if (!inner_context->is_null()) {
-      (*inner_context)->set_previous(*last);
-    } else {
-      innermost_context_ = last;
-    }
-    *inner_context = first;
-  }
-
-  Handle<SharedFunctionInfo> outer_info_;
-  Handle<Context> innermost_context_;
-  List<ContextChainElement> context_chain_;
-  Isolate* isolate_;
-  JavaScriptFrame* frame_;
-  int inlined_jsframe_index_;
-};
-}
-
-
-// Evaluate a piece of JavaScript in the context of a stack frame for
-// debugging.  Things that need special attention are:
-// - Parameters and stack-allocated locals need to be materialized.  Altered
-//   values need to be written back to the stack afterwards.
-// - The arguments object needs to materialized.
 RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
   HandleScope scope(isolate);
 
@@ -2610,50 +1291,17 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
   CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
   CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
 
-  // Handle the processing of break.
-  DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
-  // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
-  JavaScriptFrameIterator it(isolate, id);
-  JavaScriptFrame* frame = it.frame();
-
-  // Traverse the saved contexts chain to find the active context for the
-  // selected frame.
-  SaveContext* save = FindSavedContextForFrame(isolate, frame);
-
-  SaveContext savex(isolate);
-  isolate->set_context(*(save->context()));
-
-  // Materialize stack locals and the arguments object.
-
-  EvaluationContextBuilder context_builder(isolate, frame,
-                                           inlined_jsframe_index);
-  if (isolate->has_pending_exception()) {
-    return isolate->heap()->exception();
-  }
-
-
-  Handle<Object> receiver(frame->receiver(), isolate);
-  MaybeHandle<Object> maybe_result = DebugEvaluate(
-      isolate, context_builder.outer_info(),
-      context_builder.innermost_context(), context_extension, receiver, source);
+  StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
 
   Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
-  context_builder.UpdateVariables();
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source,
+                           disable_break, context_extension));
   return *result;
 }
 
 
-static inline bool IsDebugContext(Isolate* isolate, Context* context) {
-  // Try to unwrap script context if it exist.
-  if (context->IsScriptContext()) context = context->previous();
-  DCHECK_NOT_NULL(context);
-  return context == *isolate->debug()->debug_context();
-}
-
-
 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
   HandleScope scope(isolate);
 
@@ -2667,28 +1315,10 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
   CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
   CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
 
-  // Handle the processing of break.
-  DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
-  // Enter the top context from before the debugger was invoked.
-  SaveContext save(isolate);
-  SaveContext* top = &save;
-  while (top != NULL && IsDebugContext(isolate, *top->context())) {
-    top = top->prev();
-  }
-  if (top != NULL) {
-    isolate->set_context(*top->context());
-  }
-
-  // Get the native context now set to the top context from before the
-  // debugger was invoked.
-  Handle<Context> context = isolate->native_context();
-  Handle<JSObject> receiver(context->global_proxy());
-  Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, DebugEvaluate(isolate, outer_info, context,
-                                     context_extension, receiver, source));
+      isolate, result,
+      DebugEvaluate::Global(isolate, source, disable_break, context_extension));
   return *result;
 }
 
index e2b895f9a5259fc57e3d8552ca715d40594443c2..c53f30a8f897e31c2242dd17f8330fe3aef574bc 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/arguments.h"
 #include "src/debug/debug.h"
+#include "src/debug/debug-frames.h"
 #include "src/debug/liveedit.h"
 #include "src/runtime/runtime.h"
 #include "src/runtime/runtime-utils.h"
@@ -280,7 +281,8 @@ RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
   }
 
   JavaScriptFrameIterator it(isolate, id);
-  int inlined_jsframe_index = Runtime::FindIndexedNonNativeFrame(&it, index);
+  int inlined_jsframe_index =
+      DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
   if (inlined_jsframe_index == -1) return heap->undefined_value();
   // We don't really care what the inlined frame index is, since we are
   // throwing away the entire frame anyways.
index 23ea71cdebbf25e64e158b1e43fa5e33e0ccea60..6977cb6945065174d0e63761ed9f9edb966a972a 100644 (file)
@@ -929,8 +929,6 @@ class Runtime : public AllStatic {
 
   static void NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer);
 
-  static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index);
-
   enum TypedArrayId {
     // arrayIds below should be synchromized with typedarray.js natives.
     ARRAY_ID_UINT8 = 1,
index fda3b1bd38978c68a3618981ed4728393958e2a1..e490fd9ce48f11eff84aa20f143f852dfea3d7ac 100644 (file)
@@ -626,30 +626,6 @@ FunctionKind ScopeInfo::function_kind() {
 }
 
 
-void ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
-                                               Handle<Context> context,
-                                               Handle<JSObject> scope_object) {
-  Isolate* isolate = scope_info->GetIsolate();
-  int local_count = scope_info->ContextLocalCount();
-  if (local_count == 0) return;
-  // Fill all context locals to the context extension.
-  int first_context_var = scope_info->StackLocalCount();
-  int start = scope_info->ContextLocalNameEntriesIndex();
-  for (int i = 0; i < local_count; ++i) {
-    if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
-    int context_index = Context::MIN_CONTEXT_SLOTS + i;
-    Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
-    // Reflect variables under TDZ as undefined in scope object.
-    if (value->IsTheHole()) continue;
-    // This should always succeed.
-    // TODO(verwaest): Use AddDataProperty instead.
-    JSObject::SetOwnPropertyIgnoreAttributes(
-        scope_object, handle(String::cast(scope_info->get(i + start))), value,
-        ::NONE).Check();
-  }
-}
-
-
 int ScopeInfo::ParameterEntriesIndex() {
   DCHECK(length() > 0);
   return kVariablePartIndex;
index 5461f300fbf0aec04aa63193d5c1304d6d6064b4..4db53f85ff8a914a549343229a81c91b8164a242 100644 (file)
@@ -52,7 +52,6 @@ using ::v8::internal::Heap;
 using ::v8::internal::JSGlobalProxy;
 using ::v8::internal::Code;
 using ::v8::internal::Debug;
-using ::v8::internal::Debugger;
 using ::v8::internal::CommandMessage;
 using ::v8::internal::CommandMessageQueue;
 using ::v8::internal::StackFrame;
index acae8077f533e03b0ea46334bdefd7058033249b..913f95aa7e01a0435de56a3d4468ab1ad9efc364 100644 (file)
         '../../src/dateparser-inl.h',
         '../../src/dateparser.cc',
         '../../src/dateparser.h',
+        '../../src/debug/debug-evaluate.cc',
+        '../../src/debug/debug-evaluate.h',
+        '../../src/debug/debug-frames.cc',
+        '../../src/debug/debug-frames.h',
+        '../../src/debug/debug-scopes.cc',
+        '../../src/debug/debug-scopes.h',
         '../../src/debug/debug.cc',
         '../../src/debug/debug.h',
         '../../src/debug/liveedit.cc',