Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/debug/OWNERS b/src/debug/OWNERS
new file mode 100644
index 0000000..cf18bd8
--- /dev/null
+++ b/src/debug/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+bmeurer@chromium.org
+mvstanton@chromium.org
+ulan@chromium.org
+verwaest@chromium.org
+yangguo@chromium.org
diff --git a/src/debug/arm/OWNERS b/src/debug/arm/OWNERS
new file mode 100644
index 0000000..906a5ce
--- /dev/null
+++ b/src/debug/arm/OWNERS
@@ -0,0 +1 @@
+rmcilroy@chromium.org
diff --git a/src/debug/arm/debug-arm.cc b/src/debug/arm/debug-arm.cc
new file mode 100644
index 0000000..2d4cbf1
--- /dev/null
+++ b/src/debug/arm/debug-arm.cc
@@ -0,0 +1,153 @@
+// Copyright 2012 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.
+
+#if V8_TARGET_ARCH_ARM
+
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_size;
+  __ bind(&check_size);
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
+  }
+  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+            masm->InstructionsGeneratedSince(&check_size));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the constant pool in the debug break slot code.
+  Assembler::BlockConstPoolScope block_const_pool(masm);
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  // Patch the code changing the debug break slot code from
+  //   mov r2, r2
+  //   mov r2, r2
+  //   mov r2, r2
+  //   mov r2, r2
+  // to a call to the debug break slot code.
+  //   ldr ip, [pc, #0]
+  //   b skip
+  //   <debug break slot code entry point address>
+  //   skip:
+  //   blx ip
+  Label skip_constant;
+  patcher.masm()->ldr(ip, MemOperand(v8::internal::pc, 0));
+  patcher.masm()->b(&skip_constant);
+  patcher.Emit(code->entry());
+  patcher.masm()->bind(&skip_constant);
+  patcher.masm()->blx(ip);
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
+    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
+      __ push(ip);
+    }
+    __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
+    __ push(ip);
+
+    if (mode == SAVE_RESULT_REGISTER) __ push(r0);
+
+    __ mov(r0, Operand::Zero());  // no arguments
+    __ mov(r1,
+           Operand(ExternalReference(
+               Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ mov(reg, Operand(kDebugZapValue));
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ pop(r0);
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ mov(ip, Operand(after_break_target));
+  __ ldr(ip, MemOperand(ip));
+  __ Jump(ip);
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // Load the function pointer off of our current stack frame.
+  __ ldr(r1, MemOperand(fp,
+         StandardFrameConstants::kConstantPoolOffset - kPointerSize));
+
+  // Pop return address, frame and constant pool pointer (if
+  // FLAG_enable_embedded_constant_pool).
+  __ LeaveFrame(StackFrame::INTERNAL);
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(r1, no_reg, dummy, dummy);
+
+  { ConstantPoolUnavailableScope constant_pool_unavailable(masm);
+    // Load context from the function.
+    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+
+    // Clear new.target as a safety measure.
+    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+
+    // Get function code.
+    __ ldr(ip, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+    __ ldr(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
+    __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+    // Re-run JSFunction, r1 is function, cp is context.
+    __ Jump(ip);
+  }
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_ARM
diff --git a/src/debug/arm64/OWNERS b/src/debug/arm64/OWNERS
new file mode 100644
index 0000000..906a5ce
--- /dev/null
+++ b/src/debug/arm64/OWNERS
@@ -0,0 +1 @@
+rmcilroy@chromium.org
diff --git a/src/debug/arm64/debug-arm64.cc b/src/debug/arm64/debug-arm64.cc
new file mode 100644
index 0000000..c2b60a9
--- /dev/null
+++ b/src/debug/arm64/debug-arm64.cc
@@ -0,0 +1,161 @@
+// Copyright 2013 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.
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/frames-arm64.h"
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(Assembler* masm) {
+  Label check_size;
+  __ bind(&check_size);
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(Assembler::DEBUG_BREAK_NOP);
+  }
+  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+            static_cast<int>(masm->InstructionsGeneratedSince(&check_size)));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the constant pool in the debug break slot code.
+  InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions);
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  PatchingAssembler patcher(isolate, reinterpret_cast<Instruction*>(pc),
+                            Assembler::kDebugBreakSlotInstructions);
+  EmitDebugBreakSlot(&patcher);
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  PatchingAssembler patcher(isolate, reinterpret_cast<Instruction*>(pc),
+                            Assembler::kDebugBreakSlotInstructions);
+  // Patch the code emitted by DebugCodegen::GenerateSlots, changing the debug
+  // break slot code from
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  // to a call to the debug slot code.
+  //   ldr ip0, [pc, #(2 * kInstructionSize)]
+  //   blr ip0
+  //   b skip
+  //   <debug break slot code entry point address (64 bits)>
+  //   skip:
+
+  Label skip_constant;
+  // The first instruction of a patched debug break slot must be a load literal
+  // loading the address of the debug break slot code.
+  patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2);
+  patcher.b(&skip_constant);
+  patcher.dc64(reinterpret_cast<int64_t>(code->entry()));
+  patcher.bind(&skip_constant);
+  // TODO(all): check the following is correct.
+  // The debug break slot code will push a frame and call statically compiled
+  // code. By using blr,  this call site will be registered in the frame.
+  // The debugger can now iterate on the frames to find this call.
+  patcher.blr(ip0);
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+  Register scratch = x10;
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingValue));
+    __ PushMultipleTimes(scratch, LiveEdit::kFramePaddingInitialSize);
+    __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
+    __ Push(scratch);
+
+    if (mode == SAVE_RESULT_REGISTER) __ Push(x0);
+
+    __ Mov(x0, 0);  // No arguments.
+    __ Mov(x1, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
+                                 masm->isolate()));
+
+    CEntryStub stub(masm->isolate(), 1);
+    __ CallStub(&stub);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        Register reg = Register::XRegFromCode(JSCallerSavedCode(i));
+        __ Mov(reg, Operand(kDebugZapValue));
+      }
+    }
+
+    // Restore the register values from the expression stack.
+    if (mode == SAVE_RESULT_REGISTER) __ Pop(x0);
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ Mov(scratch, after_break_target);
+  __ Ldr(scratch, MemOperand(scratch));
+  __ Br(scratch);
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // We do not know our frame height, but set sp based on fp.
+  __ Sub(masm->StackPointer(), fp, kPointerSize);
+  __ AssertStackConsistency();
+
+  __ Pop(x1, fp, lr);  // Function, Frame, Return address.
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(x1, no_reg, dummy, dummy);
+
+  UseScratchRegisterScope temps(masm);
+  Register scratch = temps.AcquireX();
+
+  // Load context from the function.
+  __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
+
+  // Clear new.target as a safety measure.
+  __ LoadRoot(x3, Heap::kUndefinedValueRootIndex);
+
+  // Get function code.
+  __ Ldr(scratch, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(scratch, FieldMemOperand(scratch, SharedFunctionInfo::kCodeOffset));
+  __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
+
+  // Re-run JSFunction, x1 is function, cp is context.
+  __ Br(scratch);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/debug/debug-evaluate.cc b/src/debug/debug-evaluate.cc
new file mode 100644
index 0000000..e19b93e
--- /dev/null
+++ b/src/debug/debug-evaluate.cc
@@ -0,0 +1,407 @@
+// 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/frames-inl.h"
+#include "src/isolate-inl.h"
+
+namespace v8 {
+namespace internal {
+
+static inline bool IsDebugContext(Isolate* isolate, Context* context) {
+  return context->native_context() == *isolate->debug()->debug_context();
+}
+
+
+MaybeHandle<Object> DebugEvaluate::Global(
+    Isolate* isolate, Handle<String> source, bool disable_break,
+    Handle<HeapObject> 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<HeapObject> 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()));
+
+  // This is not a lot different than DebugEvaluate::Global, except that
+  // variables accessible by the function we are evaluating from are
+  // materialized and included on top of the native context. Changes to
+  // the materialized object are written back afterwards.
+  // Note that the native context is taken from the original context chain,
+  // which may not be the current native context of the isolate.
+  ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
+  if (isolate->has_pending_exception()) return MaybeHandle<Object>();
+
+  Handle<Context> context = context_builder.native_context();
+  Handle<JSObject> receiver(context->global_proxy());
+  MaybeHandle<Object> maybe_result = Evaluate(
+      isolate, context_builder.outer_info(),
+      context_builder.innermost_context(), context_extension, receiver, source);
+  if (!maybe_result.is_null() && !FLAG_debug_eval_readonly_locals) {
+    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<HeapObject> 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 = PrototypeIterator::GetCurrent<JSObject>(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> local_function =
+      handle(JSFunction::cast(frame_inspector.GetFunction()));
+  Handle<Context> outer_context(local_function->context());
+  native_context_ = Handle<Context>(outer_context->native_context());
+  Handle<JSFunction> global_function(native_context_->closure());
+  outer_info_ = handle(global_function->shared());
+  Handle<Context> inner_context;
+
+  bool stop = false;
+
+  // Iterate the original context chain to create a context chain that reflects
+  // our needs. The original context chain may look like this:
+  // <native context> <outer contexts> <function context> <inner contexts>
+  // In the resulting context chain, we want to materialize the receiver,
+  // the parameters of the current function, the stack locals. We only
+  // materialize context variables that the function already references,
+  // because only for those variables we can be sure that they will be resolved
+  // correctly. Variables that are not referenced by the function may be
+  // context-allocated and thus accessible, but may be shadowed by stack-
+  // allocated variables and the resolution would be incorrect.
+  // The result will look like this:
+  // <native context> <receiver context>
+  //     <materialized stack and accessible context vars> <inner contexts>
+  // All contexts use the closure of the native context, since there is no
+  // function context in the chain. Variables that cannot be resolved are
+  // bound to toplevel (script contexts or global object).
+  // Once debug-evaluate has been executed, the changes to the materialized
+  // objects are written back to the original context chain. Any changes to
+  // the original context chain will therefore be overwritten.
+  const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS;
+  for (ScopeIterator it(isolate, &frame_inspector, option);
+       !it.Failed() && !it.Done() && !stop; it.Next()) {
+    ScopeIterator::ScopeType scope_type = it.Type();
+    if (scope_type == ScopeIterator::ScopeTypeLocal) {
+      DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
+      it.GetNonLocals(&non_locals_);
+      Handle<Context> local_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".
+      Handle<Context> receiver_context =
+          MaterializeReceiver(native_context_, local_context, local_function,
+                              global_function, it.ThisIsNonLocal());
+
+      Handle<JSObject> materialized_function = NewJSObjectWithNullProto();
+      frame_inspector.MaterializeStackLocals(materialized_function,
+                                             local_function);
+      MaterializeArgumentsObject(materialized_function, local_function);
+      MaterializeContextChain(materialized_function, local_context);
+
+      Handle<Context> with_context = isolate->factory()->NewWithContext(
+          global_function, receiver_context, materialized_function);
+
+      ContextChainElement context_chain_element;
+      context_chain_element.original_context = local_context;
+      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, receiver_context, with_context);
+    } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
+               scope_type == ScopeIterator::ScopeTypeWith) {
+      Handle<Context> cloned_context = Handle<Context>::cast(
+          isolate->factory()->CopyFixedArray(it.CurrentContext()));
+
+      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(
+            isolate->factory()->CopyFixedArray(it.CurrentContext()));
+        Handle<Context> with_context = isolate->factory()->NewWithContext(
+            global_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(
+            global_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() {
+  // TODO(yangguo): remove updating values.
+  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);
+      if (element.scope_info->scope_type() == FUNCTION_SCOPE) {
+        DCHECK_EQ(context_chain_.length() - 1, i);
+        UpdateContextChainFromMaterializedObject(element.materialized_object,
+                                                 element.original_context);
+      }
+    }
+  }
+}
+
+
+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();
+}
+
+
+MaybeHandle<Object> DebugEvaluate::ContextBuilder::LoadFromContext(
+    Handle<Context> context, Handle<String> name, bool* global) {
+  static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN;
+  int index;
+  PropertyAttributes attributes;
+  BindingFlags binding;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding);
+  if (holder.is_null()) return MaybeHandle<Object>();
+  Handle<Object> value;
+  if (index != Context::kNotFound) {  // Found on context.
+    Handle<Context> context = Handle<Context>::cast(holder);
+    // Do not shadow variables on the script context.
+    *global = context->IsScriptContext();
+    return Handle<Object>(context->get(index), isolate_);
+  } else {  // Found on object.
+    Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
+    // Do not shadow properties on the global object.
+    *global = object->IsJSGlobalObject();
+    return JSReceiver::GetDataProperty(object, name);
+  }
+}
+
+
+void DebugEvaluate::ContextBuilder::MaterializeContextChain(
+    Handle<JSObject> target, Handle<Context> context) {
+  for (const Handle<String>& name : non_locals_) {
+    HandleScope scope(isolate_);
+    Handle<Object> value;
+    bool global;
+    if (!LoadFromContext(context, name, &global).ToHandle(&value) || global) {
+      // If resolving the variable fails, skip it. If it resolves to a global
+      // variable, skip it as well since it's not read-only and can be resolved
+      // within debug-evaluate.
+      continue;
+    }
+    JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
+  }
+}
+
+
+void DebugEvaluate::ContextBuilder::StoreToContext(Handle<Context> context,
+                                                   Handle<String> name,
+                                                   Handle<Object> value) {
+  static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN;
+  int index;
+  PropertyAttributes attributes;
+  BindingFlags binding;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding);
+  if (holder.is_null()) return;
+  if (attributes & READ_ONLY) return;
+  if (index != Context::kNotFound) {  // Found on context.
+    Handle<Context> context = Handle<Context>::cast(holder);
+    context->set(index, *value);
+  } else {  // Found on object.
+    Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
+    LookupIterator lookup(object, name);
+    if (lookup.state() != LookupIterator::DATA) return;
+    CHECK(JSReceiver::SetDataProperty(&lookup, value).FromJust());
+  }
+}
+
+
+void DebugEvaluate::ContextBuilder::UpdateContextChainFromMaterializedObject(
+    Handle<JSObject> source, Handle<Context> context) {
+  // TODO(yangguo): check whether overwriting context fields is actually safe
+  //                wrt fields we consider constant.
+  for (const Handle<String>& name : non_locals_) {
+    HandleScope scope(isolate_);
+    Handle<Object> value = JSReceiver::GetDataProperty(source, name);
+    StoreToContext(context, name, value);
+  }
+}
+
+
+Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver(
+    Handle<Context> parent_context, Handle<Context> lookup_context,
+    Handle<JSFunction> local_function, Handle<JSFunction> global_function,
+    bool this_is_non_local) {
+  Handle<Object> receiver = isolate_->factory()->undefined_value();
+  Handle<String> this_string = isolate_->factory()->this_string();
+  if (this_is_non_local) {
+    bool global;
+    LoadFromContext(lookup_context, this_string, &global).ToHandle(&receiver);
+  } else if (local_function->shared()->scope_info()->HasReceiver()) {
+    receiver = handle(frame_->receiver(), isolate_);
+  }
+  return isolate_->factory()->NewCatchContext(global_function, parent_context,
+                                              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
index 0000000..c0b1f02
--- /dev/null
+++ b/src/debug/debug-evaluate.h
@@ -0,0 +1,118 @@
+// 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<HeapObject> 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<HeapObject> 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<Context> native_context() const { return native_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);
+
+    void MaterializeContextChain(Handle<JSObject> target,
+                                 Handle<Context> context);
+
+    void UpdateContextChainFromMaterializedObject(Handle<JSObject> source,
+                                                  Handle<Context> context);
+
+    Handle<Context> MaterializeReceiver(Handle<Context> parent_context,
+                                        Handle<Context> lookup_context,
+                                        Handle<JSFunction> local_function,
+                                        Handle<JSFunction> global_function,
+                                        bool this_is_non_local);
+
+    MaybeHandle<Object> LoadFromContext(Handle<Context> context,
+                                        Handle<String> name, bool* global);
+
+    void StoreToContext(Handle<Context> context, Handle<String> name,
+                        Handle<Object> value);
+
+    Handle<SharedFunctionInfo> outer_info_;
+    Handle<Context> innermost_context_;
+    Handle<Context> native_context_;
+    List<ContextChainElement> context_chain_;
+    List<Handle<String> > non_locals_;
+    Isolate* isolate_;
+    JavaScriptFrame* frame_;
+    int inlined_jsframe_index_;
+  };
+
+  static MaybeHandle<Object> Evaluate(Isolate* isolate,
+                                      Handle<SharedFunctionInfo> outer_info,
+                                      Handle<Context> context,
+                                      Handle<HeapObject> 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
index 0000000..012d291
--- /dev/null
+++ b/src/debug/debug-frames.cc
@@ -0,0 +1,215 @@
+// 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"
+
+#include "src/frames-inl.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();
+}
+
+
+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.
+    // TODO(yangguo): check whether this is necessary, now that we materialize
+    //                context locals as well.
+    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;
+  InitializationFlag init_flag;
+  MaybeAssignedFlag maybe_assigned_flag;
+  return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &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()->shared()->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
index 0000000..c0d20bb
--- /dev/null
+++ b/src/debug/debug-frames.h
@@ -0,0 +1,80 @@
+// 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();
+  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
index 0000000..15a0594
--- /dev/null
+++ b/src/debug/debug-scopes.cc
@@ -0,0 +1,825 @@
+// 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/ast/scopes.h"
+#include "src/debug/debug.h"
+#include "src/frames-inl.h"
+#include "src/globals.h"
+#include "src/isolate-inl.h"
+#include "src/parsing/parser.h"
+
+namespace v8 {
+namespace internal {
+
+ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
+                             ScopeIterator::Option option)
+    : isolate_(isolate),
+      frame_inspector_(frame_inspector),
+      nested_scope_chain_(4),
+      non_locals_(nullptr),
+      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.
+  bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES);
+  bool collect_non_locals = (option == COLLECT_NON_LOCALS);
+  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, 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) {
+      nested_scope_chain_.Add(scope_info);
+    }
+    if (!collect_non_locals) return;
+  }
+
+  // Reparse the code and analyze the scopes.
+  Scope* scope = NULL;
+  // Check whether we are in global, eval or function code.
+  Zone zone;
+  if (scope_info->scope_type() != FUNCTION_SCOPE) {
+    // Global or eval code.
+    Handle<Script> script(Script::cast(shared_info->script()));
+    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.literal()->scope();
+    }
+    if (!ignore_nested_scopes) RetrieveScopeChain(scope);
+    if (collect_non_locals) CollectNonLocals(scope);
+  } else {
+    // Function code
+    ParseInfo info(&zone, function);
+    if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
+      scope = info.literal()->scope();
+    }
+    if (!ignore_nested_scopes) RetrieveScopeChain(scope);
+    if (collect_non_locals) CollectNonLocals(scope);
+  }
+}
+
+
+ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
+    : isolate_(isolate),
+      frame_inspector_(NULL),
+      context_(function->context()),
+      non_locals_(nullptr),
+      seen_script_scope_(false),
+      failed_(false) {
+  if (!function->shared()->IsSubjectToDebugging()) 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);
+  if (HasContext() && CurrentContext()->closure() != NULL) {
+    Handle<String> closure_name = JSFunction::GetDebugName(
+        Handle<JSFunction>(CurrentContext()->closure()));
+    if (!closure_name.is_null() && (closure_name->length() != 0))
+      details->set(kScopeDetailsNameIndex, *closure_name);
+  }
+  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:
+        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()->IsJSGlobalObject());
+    // 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_proxy());
+    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.
+      // TODO(neis): This breaks for proxies.
+      return handle(JSObject::cast(CurrentContext()->extension_receiver()));
+    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>(context_->scope_info());
+  } 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>();
+  }
+}
+
+
+void ScopeIterator::GetNonLocals(List<Handle<String> >* list_out) {
+  Handle<String> this_string = isolate_->factory()->this_string();
+  for (HashMap::Entry* entry = non_locals_->Start(); entry != nullptr;
+       entry = non_locals_->Next(entry)) {
+    Handle<String> name(reinterpret_cast<String**>(entry->key));
+    // We need to treat "this" differently.
+    if (name.is_identical_to(this_string)) continue;
+    list_out->Add(Handle<String>(reinterpret_cast<String**>(entry->key)));
+  }
+}
+
+
+bool ScopeIterator::ThisIsNonLocal() {
+  Handle<String> this_string = isolate_->factory()->this_string();
+  void* key = reinterpret_cast<void*>(this_string.location());
+  HashMap::Entry* entry = non_locals_->Lookup(key, this_string->Hash());
+  return entry != nullptr;
+}
+
+
+#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<HeapObject> 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<HeapObject> 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) {
+  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;
+  }
+}
+
+
+void ScopeIterator::CollectNonLocals(Scope* scope) {
+  if (scope != NULL) {
+    DCHECK_NULL(non_locals_);
+    non_locals_ = new HashMap(InternalizedStringMatch);
+    scope->CollectNonLocals(non_locals_);
+  }
+}
+
+
+MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() {
+  Handle<JSGlobalObject> 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(context->scope_info());
+    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 &&
+      function_context->has_extension() &&
+      !function_context->IsNativeContext()) {
+    bool success = CopyContextExtensionToScopeObject(
+        handle(function_context->extension_object(), isolate_),
+        local_scope, JSReceiver::INCLUDE_PROTOS);
+    if (!success) return MaybeHandle<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()) {
+    bool success = CopyContextExtensionToScopeObject(
+        handle(context->extension_object(), isolate_), closure_scope,
+        JSReceiver::OWN_ONLY);
+    DCHECK(success);
+    USE(success);
+  }
+
+  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(context->catch_name());
+  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()) {
+    // Fill all context locals.
+    CopyContextLocalsToScopeObject(handle(context->scope_info()),
+                                   context, block_scope);
+    // Fill all extension variables.
+    if (context->extension_object() != nullptr) {
+      bool success = CopyContextExtensionToScopeObject(
+          handle(context->extension_object()), block_scope,
+          JSReceiver::OWN_ONLY);
+      DCHECK(success);
+      USE(success);
+    }
+  }
+  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(context->scope_info());
+
+  // 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;
+      InitializationFlag init_flag;
+      MaybeAssignedFlag maybe_assigned_flag;
+      int context_index = ScopeInfo::ContextSlotIndex(
+          scope_info, next_name, &mode, &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(function_context->extension_object());
+
+        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()) {
+    Handle<Context> context = CurrentContext();
+    if (SetContextLocalValue(scope_info, context, variable_name, new_value)) {
+      return true;
+    }
+
+    Handle<JSObject> ext(context->extension_object(), isolate_);
+    if (!ext.is_null()) {
+      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;
+}
+
+
+// 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_object()));
+    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(context->catch_name());
+  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();
+  }
+}
+
+
+bool ScopeIterator::CopyContextExtensionToScopeObject(
+    Handle<JSObject> extension, Handle<JSObject> scope_object,
+    JSReceiver::KeyCollectionType type) {
+  Handle<FixedArray> keys;
+  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+      isolate_, keys, JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS),
+      false);
+
+  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_VALUE(
+        isolate_, value, Object::GetPropertyOrElement(extension, key), false);
+    RETURN_ON_EXCEPTION_VALUE(
+        isolate_, JSObject::SetOwnPropertyIgnoreAttributes(
+            scope_object, key, value, NONE), false);
+  }
+  return true;
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/debug/debug-scopes.h b/src/debug/debug-scopes.h
new file mode 100644
index 0000000..d4e335a
--- /dev/null
+++ b/src/debug/debug-scopes.h
@@ -0,0 +1,150 @@
+// 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 kScopeDetailsNameIndex = 2;
+  static const int kScopeDetailsSize = 3;
+
+  enum Option { DEFAULT, IGNORE_NESTED_SCOPES, COLLECT_NON_LOCALS };
+
+  ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
+                Option options = DEFAULT);
+
+  ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
+
+  ~ScopeIterator() { delete non_locals_; }
+
+  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();
+
+  // Populate the list with collected non-local variable names.
+  void GetNonLocals(List<Handle<String> >* list_out);
+
+  bool ThisIsNonLocal();
+
+#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_;
+  HashMap* non_locals_;
+  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()));
+  }
+
+  static bool InternalizedStringMatch(void* key1, void* key2) {
+    Handle<String> s1(reinterpret_cast<String**>(key1));
+    Handle<String> s2(reinterpret_cast<String**>(key2));
+    DCHECK(s1->IsInternalizedString());
+    DCHECK(s2->IsInternalizedString());
+    return s1.is_identical_to(s2);
+  }
+
+  void RetrieveScopeChain(Scope* scope);
+
+  void CollectNonLocals(Scope* scope);
+
+  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);
+  bool CopyContextExtensionToScopeObject(Handle<JSObject> extension,
+                                         Handle<JSObject> scope_object,
+                                         JSReceiver::KeyCollectionType type);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_DEBUG_DEBUG_SCOPES_H_
diff --git a/src/debug/debug.cc b/src/debug/debug.cc
new file mode 100644
index 0000000..bd45b71
--- /dev/null
+++ b/src/debug/debug.cc
@@ -0,0 +1,2414 @@
+// Copyright 2012 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.h"
+
+#include "src/api.h"
+#include "src/arguments.h"
+#include "src/bootstrapper.h"
+#include "src/code-stubs.h"
+#include "src/codegen.h"
+#include "src/compilation-cache.h"
+#include "src/compiler.h"
+#include "src/deoptimizer.h"
+#include "src/execution.h"
+#include "src/frames-inl.h"
+#include "src/full-codegen/full-codegen.h"
+#include "src/global-handles.h"
+#include "src/isolate-inl.h"
+#include "src/list.h"
+#include "src/log.h"
+#include "src/messages.h"
+#include "src/snapshot/natives.h"
+
+#include "include/v8-debug.h"
+
+namespace v8 {
+namespace internal {
+
+Debug::Debug(Isolate* isolate)
+    : debug_context_(Handle<Context>()),
+      event_listener_(Handle<Object>()),
+      event_listener_data_(Handle<Object>()),
+      message_handler_(NULL),
+      command_received_(0),
+      command_queue_(isolate->logger(), kQueueInitialSize),
+      is_active_(false),
+      is_suppressed_(false),
+      live_edit_enabled_(true),  // TODO(yangguo): set to false by default.
+      break_disabled_(false),
+      break_points_active_(true),
+      in_debug_event_listener_(false),
+      break_on_exception_(false),
+      break_on_uncaught_exception_(false),
+      debug_info_list_(NULL),
+      feature_tracker_(isolate),
+      isolate_(isolate) {
+  ThreadInit();
+}
+
+
+static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
+  Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
+  // Isolate::context() may have been NULL when "script collected" event
+  // occured.
+  if (context.is_null()) return v8::Local<v8::Context>();
+  Handle<Context> native_context(context->native_context());
+  return v8::Utils::ToLocal(native_context);
+}
+
+
+BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo,
+                             int position, int statement_position)
+    : debug_info_(debug_info),
+      pc_offset_(static_cast<int>(rinfo->pc() - debug_info->code()->entry())),
+      rmode_(rinfo->rmode()),
+      data_(rinfo->data()),
+      position_(position),
+      statement_position_(statement_position) {}
+
+
+BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info,
+                                  BreakLocatorType type)
+    : debug_info_(debug_info),
+      reloc_iterator_(debug_info->code(), GetModeMask(type)),
+      break_index_(-1),
+      position_(1),
+      statement_position_(1) {
+  if (!Done()) Next();
+}
+
+
+int BreakLocation::Iterator::GetModeMask(BreakLocatorType type) {
+  int mask = 0;
+  mask |= RelocInfo::ModeMask(RelocInfo::POSITION);
+  mask |= RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION);
+  mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
+  mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
+  if (type == ALL_BREAK_LOCATIONS) {
+    mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
+    mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT);
+  }
+  return mask;
+}
+
+
+void BreakLocation::Iterator::Next() {
+  DisallowHeapAllocation no_gc;
+  DCHECK(!Done());
+
+  // Iterate through reloc info for code and original code stopping at each
+  // breakable code target.
+  bool first = break_index_ == -1;
+  while (!Done()) {
+    if (!first) reloc_iterator_.next();
+    first = false;
+    if (Done()) return;
+
+    // Whenever a statement position or (plain) position is passed update the
+    // current value of these.
+    if (RelocInfo::IsPosition(rmode())) {
+      if (RelocInfo::IsStatementPosition(rmode())) {
+        statement_position_ = static_cast<int>(
+            rinfo()->data() - debug_info_->shared()->start_position());
+      }
+      // Always update the position as we don't want that to be before the
+      // statement position.
+      position_ = static_cast<int>(rinfo()->data() -
+                                   debug_info_->shared()->start_position());
+      DCHECK(position_ >= 0);
+      DCHECK(statement_position_ >= 0);
+      continue;
+    }
+
+    DCHECK(RelocInfo::IsDebugBreakSlot(rmode()) ||
+           RelocInfo::IsDebuggerStatement(rmode()));
+
+    if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) {
+      // Set the positions to the end of the function.
+      if (debug_info_->shared()->HasSourceCode()) {
+        position_ = debug_info_->shared()->end_position() -
+                    debug_info_->shared()->start_position() - 1;
+      } else {
+        position_ = 0;
+      }
+      statement_position_ = position_;
+    }
+
+    break;
+  }
+  break_index_++;
+}
+
+
+// Find the break point at the supplied address, or the closest one before
+// the address.
+BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info,
+                                         Address pc) {
+  Iterator it(debug_info, ALL_BREAK_LOCATIONS);
+  it.SkipTo(BreakIndexFromAddress(debug_info, pc));
+  return it.GetBreakLocation();
+}
+
+
+// Find the break point at the supplied address, or the closest one before
+// the address.
+void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info,
+                                             Address pc,
+                                             List<BreakLocation>* result_out) {
+  int break_index = BreakIndexFromAddress(debug_info, pc);
+  Iterator it(debug_info, ALL_BREAK_LOCATIONS);
+  it.SkipTo(break_index);
+  int statement_position = it.statement_position();
+  while (!it.Done() && it.statement_position() == statement_position) {
+    result_out->Add(it.GetBreakLocation());
+    it.Next();
+  }
+}
+
+
+int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info,
+                                         Address pc) {
+  // Run through all break points to locate the one closest to the address.
+  int closest_break = 0;
+  int distance = kMaxInt;
+  for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) {
+    // Check if this break point is closer that what was previously found.
+    if (it.pc() <= pc && pc - it.pc() < distance) {
+      closest_break = it.break_index();
+      distance = static_cast<int>(pc - it.pc());
+      // Check whether we can't get any closer.
+      if (distance == 0) break;
+    }
+  }
+  return closest_break;
+}
+
+
+BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
+                                          int position,
+                                          BreakPositionAlignment alignment) {
+  // Run through all break points to locate the one closest to the source
+  // position.
+  int closest_break = 0;
+  int distance = kMaxInt;
+
+  for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) {
+    int next_position;
+    if (alignment == STATEMENT_ALIGNED) {
+      next_position = it.statement_position();
+    } else {
+      DCHECK(alignment == BREAK_POSITION_ALIGNED);
+      next_position = it.position();
+    }
+    if (position <= next_position && next_position - position < distance) {
+      closest_break = it.break_index();
+      distance = next_position - position;
+      // Check whether we can't get any closer.
+      if (distance == 0) break;
+    }
+  }
+
+  Iterator it(debug_info, ALL_BREAK_LOCATIONS);
+  it.SkipTo(closest_break);
+  return it.GetBreakLocation();
+}
+
+
+void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) {
+  // If there is not already a real break point here patch code with debug
+  // break.
+  if (!HasBreakPoint()) SetDebugBreak();
+  DCHECK(IsDebugBreak() || IsDebuggerStatement());
+  // Set the break point information.
+  DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_,
+                           statement_position_, break_point_object);
+}
+
+
+void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) {
+  // Clear the break point information.
+  DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object);
+  // If there are no more break points here remove the debug break.
+  if (!HasBreakPoint()) {
+    ClearDebugBreak();
+    DCHECK(!IsDebugBreak());
+  }
+}
+
+
+void BreakLocation::SetOneShot() {
+  // Debugger statement always calls debugger. No need to modify it.
+  if (IsDebuggerStatement()) return;
+
+  // If there is a real break point here no more to do.
+  if (HasBreakPoint()) {
+    DCHECK(IsDebugBreak());
+    return;
+  }
+
+  // Patch code with debug break.
+  SetDebugBreak();
+}
+
+
+void BreakLocation::ClearOneShot() {
+  // Debugger statement always calls debugger. No need to modify it.
+  if (IsDebuggerStatement()) return;
+
+  // If there is a real break point here no more to do.
+  if (HasBreakPoint()) {
+    DCHECK(IsDebugBreak());
+    return;
+  }
+
+  // Patch code removing debug break.
+  ClearDebugBreak();
+  DCHECK(!IsDebugBreak());
+}
+
+
+void BreakLocation::SetDebugBreak() {
+  // Debugger statement always calls debugger. No need to modify it.
+  if (IsDebuggerStatement()) return;
+
+  // If there is already a break point here just return. This might happen if
+  // the same code is flooded with break points twice. Flooding the same
+  // function twice might happen when stepping in a function with an exception
+  // handler as the handler and the function is the same.
+  if (IsDebugBreak()) return;
+
+  DCHECK(IsDebugBreakSlot());
+  Isolate* isolate = debug_info_->GetIsolate();
+  Builtins* builtins = isolate->builtins();
+  Handle<Code> target =
+      IsReturn() ? builtins->Return_DebugBreak() : builtins->Slot_DebugBreak();
+  DebugCodegen::PatchDebugBreakSlot(isolate, pc(), target);
+  DCHECK(IsDebugBreak());
+}
+
+
+void BreakLocation::ClearDebugBreak() {
+  // Debugger statement always calls debugger. No need to modify it.
+  if (IsDebuggerStatement()) return;
+
+  DCHECK(IsDebugBreakSlot());
+  DebugCodegen::ClearDebugBreakSlot(debug_info_->GetIsolate(), pc());
+  DCHECK(!IsDebugBreak());
+}
+
+
+bool BreakLocation::IsDebugBreak() const {
+  if (IsDebuggerStatement()) return false;
+  DCHECK(IsDebugBreakSlot());
+  return rinfo().IsPatchedDebugBreakSlotSequence();
+}
+
+
+Handle<Object> BreakLocation::BreakPointObjects() const {
+  return debug_info_->GetBreakPointObjects(pc_offset_);
+}
+
+
+void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) {
+  uint32_t mask = 1 << feature;
+  // Only count one sample per feature and isolate.
+  if (bitfield_ & mask) return;
+  isolate_->counters()->debug_feature_usage()->AddSample(feature);
+  bitfield_ |= mask;
+}
+
+
+// Threading support.
+void Debug::ThreadInit() {
+  thread_local_.break_count_ = 0;
+  thread_local_.break_id_ = 0;
+  thread_local_.break_frame_id_ = StackFrame::NO_ID;
+  thread_local_.last_step_action_ = StepNone;
+  thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
+  thread_local_.last_fp_ = 0;
+  thread_local_.target_fp_ = 0;
+  thread_local_.step_in_enabled_ = false;
+  // TODO(isolates): frames_are_dropped_?
+  base::NoBarrier_Store(&thread_local_.current_debug_scope_,
+                        static_cast<base::AtomicWord>(0));
+}
+
+
+char* Debug::ArchiveDebug(char* storage) {
+  char* to = storage;
+  MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+  ThreadInit();
+  return storage + ArchiveSpacePerThread();
+}
+
+
+char* Debug::RestoreDebug(char* storage) {
+  char* from = storage;
+  MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+  return storage + ArchiveSpacePerThread();
+}
+
+
+int Debug::ArchiveSpacePerThread() {
+  return sizeof(ThreadLocal);
+}
+
+
+DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
+  // Globalize the request debug info object and make it weak.
+  GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
+  debug_info_ =
+      Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location();
+}
+
+
+DebugInfoListNode::~DebugInfoListNode() {
+  if (debug_info_ == nullptr) return;
+  GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_));
+  debug_info_ = nullptr;
+}
+
+
+bool Debug::Load() {
+  // Return if debugger is already loaded.
+  if (is_loaded()) return true;
+
+  // Bail out if we're already in the process of compiling the native
+  // JavaScript source code for the debugger.
+  if (is_suppressed_) return false;
+  SuppressDebug while_loading(this);
+
+  // Disable breakpoints and interrupts while compiling and running the
+  // debugger scripts including the context creation code.
+  DisableBreak disable(this, true);
+  PostponeInterruptsScope postpone(isolate_);
+
+  // Create the debugger context.
+  HandleScope scope(isolate_);
+  ExtensionConfiguration no_extensions;
+  Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment(
+      MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(), &no_extensions,
+      DEBUG_CONTEXT);
+
+  // Fail if no context could be created.
+  if (context.is_null()) return false;
+
+  debug_context_ = Handle<Context>::cast(
+      isolate_->global_handles()->Create(*context));
+
+  feature_tracker()->Track(DebugFeatureTracker::kActive);
+
+  return true;
+}
+
+
+void Debug::Unload() {
+  ClearAllBreakPoints();
+  ClearStepping();
+
+  // Return debugger is not loaded.
+  if (!is_loaded()) return;
+
+  // Clear debugger context global handle.
+  GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location());
+  debug_context_ = Handle<Context>();
+}
+
+
+void Debug::Break(Arguments args, JavaScriptFrame* frame) {
+  HandleScope scope(isolate_);
+  DCHECK(args.length() == 0);
+
+  // Initialize LiveEdit.
+  LiveEdit::InitializeThreadLocal(this);
+
+  // Just continue if breaks are disabled or debugger cannot be loaded.
+  if (break_disabled()) return;
+
+  // Enter the debugger.
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  // Postpone interrupt during breakpoint processing.
+  PostponeInterruptsScope postpone(isolate_);
+
+  // Get the debug info (create it if it does not exist).
+  Handle<JSFunction> function(frame->function());
+  Handle<SharedFunctionInfo> shared(function->shared());
+  if (!EnsureDebugInfo(shared, function)) {
+    // Return if we failed to retrieve the debug info.
+    return;
+  }
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+
+  // Find the break location where execution has stopped.
+  // 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;
+  BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc);
+
+  // Find actual break points, if any, and trigger debug break event.
+  if (break_points_active_ && location.HasBreakPoint()) {
+    Handle<Object> break_point_objects = location.BreakPointObjects();
+    Handle<Object> break_points_hit = CheckBreakPoints(break_point_objects);
+    if (!break_points_hit->IsUndefined()) {
+      // Clear all current stepping setup.
+      ClearStepping();
+      // Notify the debug event listeners.
+      OnDebugBreak(break_points_hit, false);
+      return;
+    }
+  }
+
+  // No break point. Check for stepping.
+  StepAction step_action = last_step_action();
+  Address current_fp = frame->UnpaddedFP();
+  Address target_fp = thread_local_.target_fp_;
+  Address last_fp = thread_local_.last_fp_;
+
+  bool step_break = true;
+  switch (step_action) {
+    case StepNone:
+      return;
+    case StepOut:
+      // Step out has not reached the target frame yet.
+      if (current_fp < target_fp) return;
+      break;
+    case StepNext:
+      // Step next should not break in a deeper frame.
+      if (current_fp < target_fp) return;
+    // Fall through.
+    case StepIn:
+      step_break = location.IsReturn() || (current_fp != last_fp) ||
+                   (thread_local_.last_statement_position_ !=
+                    location.code()->SourceStatementPosition(frame->pc()));
+      break;
+    case StepFrame:
+      step_break = current_fp != last_fp;
+      break;
+  }
+
+  // Clear all current stepping setup.
+  ClearStepping();
+
+  if (step_break) {
+    // Notify the debug event listeners.
+    OnDebugBreak(isolate_->factory()->undefined_value(), false);
+  } else {
+    // Re-prepare to continue.
+    PrepareStep(step_action);
+  }
+}
+
+
+// Check the break point objects for whether one or more are actually
+// triggered. This function returns a JSArray with the break point objects
+// which is triggered.
+Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
+  Factory* factory = isolate_->factory();
+
+  // Count the number of break points hit. If there are multiple break points
+  // they are in a FixedArray.
+  Handle<FixedArray> break_points_hit;
+  int break_points_hit_count = 0;
+  DCHECK(!break_point_objects->IsUndefined());
+  if (break_point_objects->IsFixedArray()) {
+    Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
+    break_points_hit = factory->NewFixedArray(array->length());
+    for (int i = 0; i < array->length(); i++) {
+      Handle<Object> o(array->get(i), isolate_);
+      if (CheckBreakPoint(o)) {
+        break_points_hit->set(break_points_hit_count++, *o);
+      }
+    }
+  } else {
+    break_points_hit = factory->NewFixedArray(1);
+    if (CheckBreakPoint(break_point_objects)) {
+      break_points_hit->set(break_points_hit_count++, *break_point_objects);
+    }
+  }
+
+  // Return undefined if no break points were triggered.
+  if (break_points_hit_count == 0) {
+    return factory->undefined_value();
+  }
+  // Return break points hit as a JSArray.
+  Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
+  result->set_length(Smi::FromInt(break_points_hit_count));
+  return result;
+}
+
+
+MaybeHandle<Object> Debug::CallFunction(const char* name, int argc,
+                                        Handle<Object> args[]) {
+  PostponeInterruptsScope no_interrupts(isolate_);
+  AssertDebugContext();
+  Handle<Object> holder = isolate_->natives_utils_object();
+  Handle<JSFunction> fun = Handle<JSFunction>::cast(
+      Object::GetProperty(isolate_, holder, name, STRICT).ToHandleChecked());
+  Handle<Object> undefined = isolate_->factory()->undefined_value();
+  return Execution::TryCall(isolate_, fun, undefined, argc, args);
+}
+
+
+// Check whether a single break point object is triggered.
+bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
+  Factory* factory = isolate_->factory();
+  HandleScope scope(isolate_);
+
+  // Ignore check if break point object is not a JSObject.
+  if (!break_point_object->IsJSObject()) return true;
+
+  // Get the break id as an object.
+  Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
+
+  // Call IsBreakPointTriggered.
+  Handle<Object> argv[] = { break_id, break_point_object };
+  Handle<Object> result;
+  if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv)
+           .ToHandle(&result)) {
+    return false;
+  }
+
+  // Return whether the break point is triggered.
+  return result->IsTrue();
+}
+
+
+bool Debug::SetBreakPoint(Handle<JSFunction> function,
+                          Handle<Object> break_point_object,
+                          int* source_position) {
+  HandleScope scope(isolate_);
+
+  // Make sure the function is compiled and has set up the debug info.
+  Handle<SharedFunctionInfo> shared(function->shared());
+  if (!EnsureDebugInfo(shared, function)) {
+    // Return if retrieving debug info failed.
+    return true;
+  }
+
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  // Source positions starts with zero.
+  DCHECK(*source_position >= 0);
+
+  // Find the break point and change it.
+  BreakLocation location = BreakLocation::FromPosition(
+      debug_info, *source_position, STATEMENT_ALIGNED);
+  *source_position = location.statement_position();
+  location.SetBreakPoint(break_point_object);
+
+  feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
+
+  // At least one active break point now.
+  return debug_info->GetBreakPointCount() > 0;
+}
+
+
+bool Debug::SetBreakPointForScript(Handle<Script> script,
+                                   Handle<Object> break_point_object,
+                                   int* source_position,
+                                   BreakPositionAlignment alignment) {
+  HandleScope scope(isolate_);
+
+  // Obtain shared function info for the function.
+  Handle<Object> result =
+      FindSharedFunctionInfoInScript(script, *source_position);
+  if (result->IsUndefined()) return false;
+
+  // Make sure the function has set up the debug info.
+  Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
+  if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
+    // Return if retrieving debug info failed.
+    return false;
+  }
+
+  // Find position within function. The script position might be before the
+  // source position of the first function.
+  int position;
+  if (shared->start_position() > *source_position) {
+    position = 0;
+  } else {
+    position = *source_position - shared->start_position();
+  }
+
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  // Source positions starts with zero.
+  DCHECK(position >= 0);
+
+  // Find the break point and change it.
+  BreakLocation location =
+      BreakLocation::FromPosition(debug_info, position, alignment);
+  location.SetBreakPoint(break_point_object);
+
+  feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
+
+  position = (alignment == STATEMENT_ALIGNED) ? location.statement_position()
+                                              : location.position();
+
+  *source_position = position + shared->start_position();
+
+  // At least one active break point now.
+  DCHECK(debug_info->GetBreakPointCount() > 0);
+  return true;
+}
+
+
+void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
+  HandleScope scope(isolate_);
+
+  DebugInfoListNode* node = debug_info_list_;
+  while (node != NULL) {
+    Handle<Object> result =
+        DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
+    if (!result->IsUndefined()) {
+      // Get information in the break point.
+      Handle<BreakPointInfo> break_point_info =
+          Handle<BreakPointInfo>::cast(result);
+      Handle<DebugInfo> debug_info = node->debug_info();
+
+      // Find the break point and clear it.
+      Address pc =
+          debug_info->code()->entry() + break_point_info->code_position();
+
+      BreakLocation location = BreakLocation::FromAddress(debug_info, pc);
+      location.ClearBreakPoint(break_point_object);
+
+      // If there are no more break points left remove the debug info for this
+      // function.
+      if (debug_info->GetBreakPointCount() == 0) {
+        RemoveDebugInfoAndClearFromShared(debug_info);
+      }
+
+      return;
+    }
+    node = node->next();
+  }
+}
+
+
+// Clear out all the debug break code. This is ONLY supposed to be used when
+// shutting down the debugger as it will leave the break point information in
+// DebugInfo even though the code is patched back to the non break point state.
+void Debug::ClearAllBreakPoints() {
+  for (DebugInfoListNode* node = debug_info_list_; node != NULL;
+       node = node->next()) {
+    for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+         !it.Done(); it.Next()) {
+      it.GetBreakLocation().ClearDebugBreak();
+    }
+  }
+  // Remove all debug info.
+  while (debug_info_list_ != NULL) {
+    RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
+  }
+}
+
+
+void Debug::FloodWithOneShot(Handle<JSFunction> function,
+                             BreakLocatorType type) {
+  // Debug utility functions are not subject to debugging.
+  if (function->native_context() == *debug_context()) return;
+
+  if (!function->shared()->IsSubjectToDebugging()) {
+    // Builtin functions are not subject to stepping, but need to be
+    // deoptimized, because optimized code does not check for debug
+    // step in at call sites.
+    Deoptimizer::DeoptimizeFunction(*function);
+    return;
+  }
+  // Make sure the function is compiled and has set up the debug info.
+  Handle<SharedFunctionInfo> shared(function->shared());
+  if (!EnsureDebugInfo(shared, function)) {
+    // Return if we failed to retrieve the debug info.
+    return;
+  }
+
+  // Flood the function with break points.
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  for (BreakLocation::Iterator it(debug_info, type); !it.Done(); it.Next()) {
+    it.GetBreakLocation().SetOneShot();
+  }
+}
+
+
+void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
+  if (type == BreakUncaughtException) {
+    break_on_uncaught_exception_ = enable;
+  } else {
+    break_on_exception_ = enable;
+  }
+}
+
+
+bool Debug::IsBreakOnException(ExceptionBreakType type) {
+  if (type == BreakUncaughtException) {
+    return break_on_uncaught_exception_;
+  } else {
+    return break_on_exception_;
+  }
+}
+
+
+FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) {
+  List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+  frame->Summarize(&frames);
+  return frames.first();
+}
+
+
+void Debug::PrepareStepIn(Handle<JSFunction> function) {
+  if (!is_active()) return;
+  if (last_step_action() < StepIn) return;
+  if (in_debug_scope()) return;
+  if (thread_local_.step_in_enabled_) {
+    FloodWithOneShot(function);
+  }
+}
+
+
+void Debug::PrepareStepOnThrow() {
+  if (!is_active()) return;
+  if (last_step_action() == StepNone) return;
+  if (in_debug_scope()) return;
+
+  ClearOneShot();
+
+  // Iterate through the JavaScript stack looking for handlers.
+  JavaScriptFrameIterator it(isolate_);
+  while (!it.done()) {
+    JavaScriptFrame* frame = it.frame();
+    int stack_slots = 0;  // The computed stack slot count is not used.
+    if (frame->LookupExceptionHandlerInTable(&stack_slots, NULL) > 0) break;
+    it.Advance();
+  }
+
+  // Find the closest Javascript frame we can flood with one-shots.
+  while (!it.done() &&
+         !it.frame()->function()->shared()->IsSubjectToDebugging()) {
+    it.Advance();
+  }
+
+  if (it.done()) return;  // No suitable Javascript catch handler.
+
+  FloodWithOneShot(Handle<JSFunction>(it.frame()->function()));
+}
+
+
+void Debug::PrepareStep(StepAction step_action) {
+  HandleScope scope(isolate_);
+
+  DCHECK(in_debug_scope());
+
+  // Get the frame where the execution has stopped and skip the debug frame if
+  // any. The debug frame will only be present if execution was stopped due to
+  // hitting a break point. In other situations (e.g. unhandled exception) the
+  // debug frame is not present.
+  StackFrame::Id frame_id = break_frame_id();
+  // If there is no JavaScript stack don't do anything.
+  if (frame_id == StackFrame::NO_ID) return;
+
+  JavaScriptFrameIterator frames_it(isolate_, frame_id);
+  JavaScriptFrame* frame = frames_it.frame();
+
+  feature_tracker()->Track(DebugFeatureTracker::kStepping);
+
+  // Remember this step action and count.
+  thread_local_.last_step_action_ = step_action;
+  STATIC_ASSERT(StepFrame > StepIn);
+  thread_local_.step_in_enabled_ = (step_action >= StepIn);
+
+  // If the function on the top frame is unresolved perform step out. This will
+  // be the case when calling unknown function and having the debugger stopped
+  // in an unhandled exception.
+  if (!frame->function()->IsJSFunction()) {
+    // Step out: Find the calling JavaScript frame and flood it with
+    // breakpoints.
+    frames_it.Advance();
+    // Fill the function to return to with one-shot break points.
+    JSFunction* function = frames_it.frame()->function();
+    FloodWithOneShot(Handle<JSFunction>(function));
+    return;
+  }
+
+  // Get the debug info (create it if it does not exist).
+  FrameSummary summary = GetFirstFrameSummary(frame);
+  Handle<JSFunction> function(summary.function());
+  Handle<SharedFunctionInfo> shared(function->shared());
+  if (!EnsureDebugInfo(shared, function)) {
+    // Return if ensuring debug info failed.
+    return;
+  }
+
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  // Refresh frame summary if the code has been recompiled for debugging.
+  if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame);
+
+  // 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 = summary.pc() - 1;
+  BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc);
+
+  // At a return statement we will step out either way.
+  if (location.IsReturn()) step_action = StepOut;
+
+  thread_local_.last_statement_position_ =
+      debug_info->code()->SourceStatementPosition(summary.pc());
+  thread_local_.last_fp_ = frame->UnpaddedFP();
+
+  switch (step_action) {
+    case StepNone:
+      UNREACHABLE();
+      break;
+    case StepOut:
+      // Advance to caller frame.
+      frames_it.Advance();
+      // Skip native and extension functions on the stack.
+      while (!frames_it.done() &&
+             !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) {
+        // Builtin functions are not subject to stepping, but need to be
+        // deoptimized to include checks for step-in at call sites.
+        Deoptimizer::DeoptimizeFunction(frames_it.frame()->function());
+        frames_it.Advance();
+      }
+      if (frames_it.done()) {
+        // Stepping out to the embedder. Disable step-in to avoid stepping into
+        // the next (unrelated) call that the embedder makes.
+        thread_local_.step_in_enabled_ = false;
+      } else {
+        // Fill the caller function to return to with one-shot break points.
+        Handle<JSFunction> caller_function(frames_it.frame()->function());
+        FloodWithOneShot(caller_function);
+        thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP();
+      }
+      // Clear last position info. For stepping out it does not matter.
+      thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
+      thread_local_.last_fp_ = 0;
+      break;
+    case StepNext:
+      thread_local_.target_fp_ = frame->UnpaddedFP();
+      FloodWithOneShot(function);
+      break;
+    case StepIn:
+      FloodWithOneShot(function);
+      break;
+    case StepFrame:
+      // No point in setting one-shot breaks at places where we are not about
+      // to leave the current frame.
+      FloodWithOneShot(function, CALLS_AND_RETURNS);
+      break;
+  }
+}
+
+
+// Simple function for returning the source positions for active break points.
+Handle<Object> Debug::GetSourceBreakLocations(
+    Handle<SharedFunctionInfo> shared,
+    BreakPositionAlignment position_alignment) {
+  Isolate* isolate = shared->GetIsolate();
+  Heap* heap = isolate->heap();
+  if (!shared->HasDebugInfo()) {
+    return Handle<Object>(heap->undefined_value(), isolate);
+  }
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  if (debug_info->GetBreakPointCount() == 0) {
+    return Handle<Object>(heap->undefined_value(), isolate);
+  }
+  Handle<FixedArray> locations =
+      isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
+  int count = 0;
+  for (int i = 0; i < debug_info->break_points()->length(); ++i) {
+    if (!debug_info->break_points()->get(i)->IsUndefined()) {
+      BreakPointInfo* break_point_info =
+          BreakPointInfo::cast(debug_info->break_points()->get(i));
+      int break_points = break_point_info->GetBreakPointCount();
+      if (break_points == 0) continue;
+      Smi* position = NULL;
+      switch (position_alignment) {
+        case STATEMENT_ALIGNED:
+          position = Smi::FromInt(break_point_info->statement_position());
+          break;
+        case BREAK_POSITION_ALIGNED:
+          position = Smi::FromInt(break_point_info->source_position());
+          break;
+      }
+      for (int j = 0; j < break_points; ++j) locations->set(count++, position);
+    }
+  }
+  return locations;
+}
+
+
+void Debug::ClearStepping() {
+  // Clear the various stepping setup.
+  ClearOneShot();
+
+  thread_local_.last_step_action_ = StepNone;
+  thread_local_.step_in_enabled_ = false;
+  thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
+  thread_local_.last_fp_ = 0;
+  thread_local_.target_fp_ = 0;
+}
+
+
+// Clears all the one-shot break points that are currently set. Normally this
+// function is called each time a break point is hit as one shot break points
+// are used to support stepping.
+void Debug::ClearOneShot() {
+  // The current implementation just runs through all the breakpoints. When the
+  // last break point for a function is removed that function is automatically
+  // removed from the list.
+  for (DebugInfoListNode* node = debug_info_list_; node != NULL;
+       node = node->next()) {
+    for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+         !it.Done(); it.Next()) {
+      it.GetBreakLocation().ClearOneShot();
+    }
+  }
+}
+
+
+void Debug::EnableStepIn() {
+  STATIC_ASSERT(StepFrame > StepIn);
+  thread_local_.step_in_enabled_ = (last_step_action() >= StepIn);
+}
+
+
+bool MatchingCodeTargets(Code* target1, Code* target2) {
+  if (target1 == target2) return true;
+  if (target1->kind() != target2->kind()) return false;
+  return target1->is_handler() || target1->is_inline_cache_stub();
+}
+
+
+// Count the number of calls before the current frame PC to find the
+// corresponding PC in the newly recompiled code.
+static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code,
+                                       Address old_pc) {
+  DCHECK_EQ(old_code->kind(), Code::FUNCTION);
+  DCHECK_EQ(new_code->kind(), Code::FUNCTION);
+  DCHECK(new_code->has_debug_break_slots());
+  static const int mask = RelocInfo::kCodeTargetMask;
+
+  // Find the target of the current call.
+  Code* target = NULL;
+  intptr_t delta = 0;
+  for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
+    RelocInfo* rinfo = it.rinfo();
+    Address current_pc = rinfo->pc();
+    // The frame PC is behind the call instruction by the call instruction size.
+    if (current_pc > old_pc) break;
+    delta = old_pc - current_pc;
+    target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+  }
+
+  // Count the number of calls to the same target before the current call.
+  int index = 0;
+  for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
+    RelocInfo* rinfo = it.rinfo();
+    Address current_pc = rinfo->pc();
+    if (current_pc > old_pc) break;
+    Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
+    if (MatchingCodeTargets(target, current)) index++;
+  }
+
+  DCHECK(index > 0);
+
+  // Repeat the count on the new code to find corresponding call.
+  for (RelocIterator it(new_code, mask); !it.done(); it.next()) {
+    RelocInfo* rinfo = it.rinfo();
+    Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
+    if (MatchingCodeTargets(target, current)) index--;
+    if (index == 0) return rinfo->pc() + delta;
+  }
+
+  UNREACHABLE();
+  return NULL;
+}
+
+
+// Count the number of continuations at which the current pc offset is at.
+static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) {
+  DCHECK_EQ(code->kind(), Code::FUNCTION);
+  Address pc = code->instruction_start() + pc_offset;
+  int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
+  int index = 0;
+  for (RelocIterator it(code, mask); !it.done(); it.next()) {
+    index++;
+    RelocInfo* rinfo = it.rinfo();
+    Address current_pc = rinfo->pc();
+    if (current_pc == pc) break;
+    DCHECK(current_pc < pc);
+  }
+  return index;
+}
+
+
+// Find the pc offset for the given continuation index.
+static int ComputePcOffsetFromContinuationIndex(Code* code, int index) {
+  DCHECK_EQ(code->kind(), Code::FUNCTION);
+  DCHECK(code->has_debug_break_slots());
+  int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
+  RelocIterator it(code, mask);
+  for (int i = 1; i < index; i++) it.next();
+  return static_cast<int>(it.rinfo()->pc() - code->instruction_start());
+}
+
+
+class RedirectActiveFunctions : public ThreadVisitor {
+ public:
+  explicit RedirectActiveFunctions(SharedFunctionInfo* shared)
+      : shared_(shared) {
+    DCHECK(shared->HasDebugCode());
+  }
+
+  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
+    for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
+      JavaScriptFrame* frame = it.frame();
+      JSFunction* function = frame->function();
+      if (frame->is_optimized()) continue;
+      if (!function->Inlines(shared_)) continue;
+
+      Code* frame_code = frame->LookupCode();
+      DCHECK(frame_code->kind() == Code::FUNCTION);
+      if (frame_code->has_debug_break_slots()) continue;
+
+      Code* new_code = function->shared()->code();
+      Address old_pc = frame->pc();
+      Address new_pc = ComputeNewPcForRedirect(new_code, frame_code, old_pc);
+
+      if (FLAG_trace_deopt) {
+        PrintF("Replacing pc for debugging: %08" V8PRIxPTR " => %08" V8PRIxPTR
+               "\n",
+               reinterpret_cast<intptr_t>(old_pc),
+               reinterpret_cast<intptr_t>(new_pc));
+      }
+
+      if (FLAG_enable_embedded_constant_pool) {
+        // Update constant pool pointer for new code.
+        frame->set_constant_pool(new_code->constant_pool());
+      }
+
+      // Patch the return address to return into the code with
+      // debug break slots.
+      frame->set_pc(new_pc);
+    }
+  }
+
+ private:
+  SharedFunctionInfo* shared_;
+  DisallowHeapAllocation no_gc_;
+};
+
+
+bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
+  DCHECK(shared->is_compiled());
+
+  if (isolate_->concurrent_recompilation_enabled()) {
+    isolate_->optimizing_compile_dispatcher()->Flush();
+  }
+
+  List<Handle<JSFunction> > functions;
+  List<Handle<JSGeneratorObject> > suspended_generators;
+
+  // Flush all optimized code maps. Note that the below heap iteration does not
+  // cover this, because the given function might have been inlined into code
+  // for which no JSFunction exists.
+  {
+    SharedFunctionInfo::Iterator iterator(isolate_);
+    while (SharedFunctionInfo* shared = iterator.Next()) {
+      if (!shared->OptimizedCodeMapIsCleared()) {
+        shared->ClearOptimizedCodeMap();
+      }
+    }
+  }
+
+  // Make sure we abort incremental marking.
+  isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
+                                      "prepare for break points");
+
+  {
+    HeapIterator iterator(isolate_->heap());
+    HeapObject* obj;
+    bool include_generators = shared->is_generator();
+
+    while ((obj = iterator.next())) {
+      if (obj->IsJSFunction()) {
+        JSFunction* function = JSFunction::cast(obj);
+        if (!function->Inlines(*shared)) continue;
+        if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) {
+          Deoptimizer::DeoptimizeFunction(function);
+        }
+        if (function->shared() == *shared) functions.Add(handle(function));
+      } else if (include_generators && obj->IsJSGeneratorObject()) {
+        JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj);
+        if (!generator_obj->is_suspended()) continue;
+        JSFunction* function = generator_obj->function();
+        if (!function->Inlines(*shared)) continue;
+        int pc_offset = generator_obj->continuation();
+        int index =
+            ComputeContinuationIndexFromPcOffset(function->code(), pc_offset);
+        generator_obj->set_continuation(index);
+        suspended_generators.Add(handle(generator_obj));
+      }
+    }
+  }
+
+  if (!shared->HasDebugCode()) {
+    DCHECK(functions.length() > 0);
+    if (!Compiler::CompileDebugCode(functions.first())) return false;
+  }
+
+  for (Handle<JSFunction> const function : functions) {
+    function->ReplaceCode(shared->code());
+  }
+
+  for (Handle<JSGeneratorObject> const generator_obj : suspended_generators) {
+    int index = generator_obj->continuation();
+    int pc_offset = ComputePcOffsetFromContinuationIndex(shared->code(), index);
+    generator_obj->set_continuation(pc_offset);
+  }
+
+  // Update PCs on the stack to point to recompiled code.
+  RedirectActiveFunctions redirect_visitor(*shared);
+  redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
+  isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
+
+  return true;
+}
+
+
+class SharedFunctionInfoFinder {
+ public:
+  explicit SharedFunctionInfoFinder(int target_position)
+      : current_candidate_(NULL),
+        current_candidate_closure_(NULL),
+        current_start_position_(RelocInfo::kNoPosition),
+        target_position_(target_position) {}
+
+  void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) {
+    if (!shared->IsSubjectToDebugging()) return;
+    int start_position = shared->function_token_position();
+    if (start_position == RelocInfo::kNoPosition) {
+      start_position = shared->start_position();
+    }
+
+    if (start_position > target_position_) return;
+    if (target_position_ > shared->end_position()) return;
+
+    if (current_candidate_ != NULL) {
+      if (current_start_position_ == start_position &&
+          shared->end_position() == current_candidate_->end_position()) {
+        // If we already have a matching closure, do not throw it away.
+        if (current_candidate_closure_ != NULL && closure == NULL) return;
+        // If a top-level function contains only one function
+        // declaration the source for the top-level and the function
+        // is the same. In that case prefer the non top-level function.
+        if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return;
+      } else if (start_position < current_start_position_ ||
+                 current_candidate_->end_position() < shared->end_position()) {
+        return;
+      }
+    }
+
+    current_start_position_ = start_position;
+    current_candidate_ = shared;
+    current_candidate_closure_ = closure;
+  }
+
+  SharedFunctionInfo* Result() { return current_candidate_; }
+
+  JSFunction* ResultClosure() { return current_candidate_closure_; }
+
+ private:
+  SharedFunctionInfo* current_candidate_;
+  JSFunction* current_candidate_closure_;
+  int current_start_position_;
+  int target_position_;
+  DisallowHeapAllocation no_gc_;
+};
+
+
+// We need to find a SFI for a literal that may not yet have been compiled yet,
+// and there may not be a JSFunction referencing it. Find the SFI closest to
+// the given position, compile it to reveal possible inner SFIs and repeat.
+// While we are at this, also ensure code with debug break slots so that we do
+// not have to compile a SFI without JSFunction, which is paifu for those that
+// cannot be compiled without context (need to find outer compilable SFI etc.)
+Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
+                                                     int position) {
+  for (int iteration = 0;; iteration++) {
+    // Go through all shared function infos associated with this script to
+    // find the inner most function containing this position.
+    // If there is no shared function info for this script at all, there is
+    // no point in looking for it by walking the heap.
+    if (!script->shared_function_infos()->IsWeakFixedArray()) break;
+
+    SharedFunctionInfo* shared;
+    {
+      SharedFunctionInfoFinder finder(position);
+      WeakFixedArray::Iterator iterator(script->shared_function_infos());
+      SharedFunctionInfo* candidate;
+      while ((candidate = iterator.Next<SharedFunctionInfo>())) {
+        finder.NewCandidate(candidate);
+      }
+      shared = finder.Result();
+      if (shared == NULL) break;
+      // We found it if it's already compiled and has debug code.
+      if (shared->HasDebugCode()) {
+        Handle<SharedFunctionInfo> shared_handle(shared);
+        // If the iteration count is larger than 1, we had to compile the outer
+        // function in order to create this shared function info. So there can
+        // be no JSFunction referencing it. We can anticipate creating a debug
+        // info while bypassing PrepareFunctionForBreakpoints.
+        if (iteration > 1) {
+          AllowHeapAllocation allow_before_return;
+          CreateDebugInfo(shared_handle);
+        }
+        return shared_handle;
+      }
+    }
+    // If not, compile to reveal inner functions, if possible.
+    if (shared->allows_lazy_compilation_without_context()) {
+      HandleScope scope(isolate_);
+      if (!Compiler::CompileDebugCode(handle(shared))) break;
+      continue;
+    }
+
+    // If not possible, comb the heap for the best suitable compile target.
+    JSFunction* closure;
+    {
+      HeapIterator it(isolate_->heap());
+      SharedFunctionInfoFinder finder(position);
+      while (HeapObject* object = it.next()) {
+        JSFunction* candidate_closure = NULL;
+        SharedFunctionInfo* candidate = NULL;
+        if (object->IsJSFunction()) {
+          candidate_closure = JSFunction::cast(object);
+          candidate = candidate_closure->shared();
+        } else if (object->IsSharedFunctionInfo()) {
+          candidate = SharedFunctionInfo::cast(object);
+          if (!candidate->allows_lazy_compilation_without_context()) continue;
+        } else {
+          continue;
+        }
+        if (candidate->script() == *script) {
+          finder.NewCandidate(candidate, candidate_closure);
+        }
+      }
+      closure = finder.ResultClosure();
+      shared = finder.Result();
+    }
+    if (shared == NULL) break;
+    HandleScope scope(isolate_);
+    if (closure == NULL) {
+      if (!Compiler::CompileDebugCode(handle(shared))) break;
+    } else {
+      if (!Compiler::CompileDebugCode(handle(closure))) break;
+    }
+  }
+  return isolate_->factory()->undefined_value();
+}
+
+
+// Ensures the debug information is present for shared.
+bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
+                            Handle<JSFunction> function) {
+  if (!shared->IsSubjectToDebugging()) return false;
+
+  // Return if we already have the debug info for shared.
+  if (shared->HasDebugInfo()) return true;
+
+  if (function.is_null()) {
+    DCHECK(shared->HasDebugCode());
+  } else if (!Compiler::Compile(function, CLEAR_EXCEPTION)) {
+    return false;
+  }
+
+  if (!PrepareFunctionForBreakPoints(shared)) return false;
+
+  CreateDebugInfo(shared);
+
+  return true;
+}
+
+
+void Debug::CreateDebugInfo(Handle<SharedFunctionInfo> shared) {
+  // Create the debug info object.
+  DCHECK(shared->HasDebugCode());
+  Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared);
+
+  // Add debug info to the list.
+  DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
+  node->set_next(debug_info_list_);
+  debug_info_list_ = node;
+}
+
+
+void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
+  HandleScope scope(isolate_);
+  Handle<SharedFunctionInfo> shared(debug_info->shared());
+
+  DCHECK_NOT_NULL(debug_info_list_);
+  // Run through the debug info objects to find this one and remove it.
+  DebugInfoListNode* prev = NULL;
+  DebugInfoListNode* current = debug_info_list_;
+  while (current != NULL) {
+    if (current->debug_info().is_identical_to(debug_info)) {
+      // Unlink from list. If prev is NULL we are looking at the first element.
+      if (prev == NULL) {
+        debug_info_list_ = current->next();
+      } else {
+        prev->set_next(current->next());
+      }
+      delete current;
+      shared->set_debug_info(isolate_->heap()->undefined_value());
+      return;
+    }
+    // Move to next in list.
+    prev = current;
+    current = current->next();
+  }
+
+  UNREACHABLE();
+}
+
+
+void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
+  after_break_target_ = NULL;
+
+  if (LiveEdit::SetAfterBreakTarget(this)) return;  // LiveEdit did the job.
+
+  // Continue just after the slot.
+  after_break_target_ = frame->pc();
+}
+
+
+bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
+  HandleScope scope(isolate_);
+
+  // Get the executing function in which the debug break occurred.
+  Handle<JSFunction> function(JSFunction::cast(frame->function()));
+  Handle<SharedFunctionInfo> shared(function->shared());
+
+  // With no debug info there are no break points, so we can't be at a return.
+  if (!shared->HasDebugInfo()) return false;
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  Handle<Code> code(debug_info->code());
+#ifdef DEBUG
+  // Get the code which is actually executing.
+  Handle<Code> frame_code(frame->LookupCode());
+  DCHECK(frame_code.is_identical_to(code));
+#endif
+
+  // Find the reloc info matching the start of the debug break slot.
+  Address slot_pc = frame->pc() - Assembler::kDebugBreakSlotLength;
+  int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
+  for (RelocIterator it(*code, mask); !it.done(); it.next()) {
+    if (it.rinfo()->pc() == slot_pc) return true;
+  }
+  return false;
+}
+
+
+void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
+                                  LiveEdit::FrameDropMode mode) {
+  if (mode != LiveEdit::CURRENTLY_SET_MODE) {
+    thread_local_.frame_drop_mode_ = mode;
+  }
+  thread_local_.break_frame_id_ = new_break_frame_id;
+}
+
+
+bool Debug::IsDebugGlobal(JSGlobalObject* global) {
+  return is_loaded() && global == debug_context()->global_object();
+}
+
+
+void Debug::ClearMirrorCache() {
+  PostponeInterruptsScope postpone(isolate_);
+  HandleScope scope(isolate_);
+  CallFunction("ClearMirrorCache", 0, NULL);
+}
+
+
+Handle<FixedArray> Debug::GetLoadedScripts() {
+  isolate_->heap()->CollectAllGarbage();
+  Factory* factory = isolate_->factory();
+  if (!factory->script_list()->IsWeakFixedArray()) {
+    return factory->empty_fixed_array();
+  }
+  Handle<WeakFixedArray> array =
+      Handle<WeakFixedArray>::cast(factory->script_list());
+  Handle<FixedArray> results = factory->NewFixedArray(array->Length());
+  int length = 0;
+  {
+    Script::Iterator iterator(isolate_);
+    Script* script;
+    while ((script = iterator.Next())) {
+      if (script->HasValidSource()) results->set(length++, script);
+    }
+  }
+  results->Shrink(length);
+  return results;
+}
+
+
+void Debug::GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id,
+                               List<int>* results_out) {
+  FrameSummary summary = GetFirstFrameSummary(frame);
+
+  Handle<JSFunction> fun = Handle<JSFunction>(summary.function());
+  Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
+
+  if (!EnsureDebugInfo(shared, fun)) return;
+
+  Handle<DebugInfo> debug_info(shared->GetDebugInfo());
+  // Refresh frame summary if the code has been recompiled for debugging.
+  if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame);
+
+  // Find range of break points starting from the break point where execution
+  // has stopped.
+  Address call_pc = summary.pc() - 1;
+  List<BreakLocation> locations;
+  BreakLocation::FromAddressSameStatement(debug_info, call_pc, &locations);
+
+  for (BreakLocation location : locations) {
+    if (location.pc() <= summary.pc()) {
+      // The break point is near our pc. Could be a step-in possibility,
+      // that is currently taken by active debugger call.
+      if (break_frame_id() == StackFrame::NO_ID) {
+        continue;  // We are not stepping.
+      } else {
+        JavaScriptFrameIterator frame_it(isolate_, break_frame_id());
+        // If our frame is a top frame and we are stepping, we can do step-in
+        // at this place.
+        if (frame_it.frame()->id() != frame_id) continue;
+      }
+    }
+    if (location.IsCall()) results_out->Add(location.position());
+  }
+}
+
+
+void Debug::RecordEvalCaller(Handle<Script> script) {
+  script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
+  // For eval scripts add information on the function from which eval was
+  // called.
+  StackTraceFrameIterator it(script->GetIsolate());
+  if (!it.done()) {
+    script->set_eval_from_shared(it.frame()->function()->shared());
+    Code* code = it.frame()->LookupCode();
+    int offset = static_cast<int>(
+        it.frame()->pc() - code->instruction_start());
+    script->set_eval_from_instructions_offset(offset);
+  }
+}
+
+
+MaybeHandle<Object> Debug::MakeExecutionState() {
+  // Create the execution state object.
+  Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) };
+  return CallFunction("MakeExecutionState", arraysize(argv), argv);
+}
+
+
+MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
+  // Create the new break event object.
+  Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
+                            break_points_hit };
+  return CallFunction("MakeBreakEvent", arraysize(argv), argv);
+}
+
+
+MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
+                                              bool uncaught,
+                                              Handle<Object> promise) {
+  // Create the new exception event object.
+  Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
+                            exception,
+                            isolate_->factory()->ToBoolean(uncaught),
+                            promise };
+  return CallFunction("MakeExceptionEvent", arraysize(argv), argv);
+}
+
+
+MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
+                                            v8::DebugEvent type) {
+  // Create the compile event object.
+  Handle<Object> script_wrapper = Script::GetWrapper(script);
+  Handle<Object> argv[] = { script_wrapper,
+                            isolate_->factory()->NewNumberFromInt(type) };
+  return CallFunction("MakeCompileEvent", arraysize(argv), argv);
+}
+
+
+MaybeHandle<Object> Debug::MakePromiseEvent(Handle<JSObject> event_data) {
+  // Create the promise event object.
+  Handle<Object> argv[] = { event_data };
+  return CallFunction("MakePromiseEvent", arraysize(argv), argv);
+}
+
+
+MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) {
+  // Create the async task event object.
+  Handle<Object> argv[] = { task_event };
+  return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv);
+}
+
+
+void Debug::OnThrow(Handle<Object> exception) {
+  if (in_debug_scope() || ignore_events()) return;
+  PrepareStepOnThrow();
+  // Temporarily clear any scheduled_exception to allow evaluating
+  // JavaScript from the debug event handler.
+  HandleScope scope(isolate_);
+  Handle<Object> scheduled_exception;
+  if (isolate_->has_scheduled_exception()) {
+    scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
+    isolate_->clear_scheduled_exception();
+  }
+  OnException(exception, isolate_->GetPromiseOnStackOnThrow());
+  if (!scheduled_exception.is_null()) {
+    isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
+  }
+}
+
+
+void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
+  if (in_debug_scope() || ignore_events()) return;
+  HandleScope scope(isolate_);
+  // Check whether the promise has been marked as having triggered a message.
+  Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
+  if (JSReceiver::GetDataProperty(promise, key)->IsUndefined()) {
+    OnException(value, promise);
+  }
+}
+
+
+MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
+    Handle<JSObject> promise) {
+  Handle<JSFunction> fun = isolate_->promise_has_user_defined_reject_handler();
+  return Execution::Call(isolate_, fun, promise, 0, NULL);
+}
+
+
+void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
+  // In our prediction, try-finally is not considered to catch.
+  Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
+  bool uncaught = (catch_type == Isolate::NOT_CAUGHT);
+  if (promise->IsJSObject()) {
+    Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
+    // Mark the promise as already having triggered a message.
+    Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
+    JSObject::SetProperty(jspromise, key, key, STRICT).Assert();
+    // Check whether the promise reject is considered an uncaught exception.
+    Handle<Object> has_reject_handler;
+    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+        isolate_, has_reject_handler,
+        PromiseHasUserDefinedRejectHandler(jspromise), /* void */);
+    uncaught = has_reject_handler->IsFalse();
+  }
+  // Bail out if exception breaks are not active
+  if (uncaught) {
+    // Uncaught exceptions are reported by either flags.
+    if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
+  } else {
+    // Caught exceptions are reported is activated.
+    if (!break_on_exception_) return;
+  }
+
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  // Create the event data object.
+  Handle<Object> event_data;
+  // Bail out and don't call debugger if exception.
+  if (!MakeExceptionEvent(
+          exception, uncaught, promise).ToHandle(&event_data)) {
+    return;
+  }
+
+  // Process debug event.
+  ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
+  // Return to continue execution from where the exception was thrown.
+}
+
+
+void Debug::OnDebugBreak(Handle<Object> break_points_hit,
+                            bool auto_continue) {
+  // The caller provided for DebugScope.
+  AssertDebugContext();
+  // Bail out if there is no listener for this event
+  if (ignore_events()) return;
+
+  HandleScope scope(isolate_);
+  // Create the event data object.
+  Handle<Object> event_data;
+  // Bail out and don't call debugger if exception.
+  if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
+
+  // Process debug event.
+  ProcessDebugEvent(v8::Break,
+                    Handle<JSObject>::cast(event_data),
+                    auto_continue);
+}
+
+
+void Debug::OnCompileError(Handle<Script> script) {
+  ProcessCompileEvent(v8::CompileError, script);
+}
+
+
+void Debug::OnBeforeCompile(Handle<Script> script) {
+  ProcessCompileEvent(v8::BeforeCompile, script);
+}
+
+
+// Handle debugger actions when a new script is compiled.
+void Debug::OnAfterCompile(Handle<Script> script) {
+  ProcessCompileEvent(v8::AfterCompile, script);
+}
+
+
+void Debug::OnPromiseEvent(Handle<JSObject> data) {
+  if (in_debug_scope() || ignore_events()) return;
+
+  HandleScope scope(isolate_);
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  // Create the script collected state object.
+  Handle<Object> event_data;
+  // Bail out and don't call debugger if exception.
+  if (!MakePromiseEvent(data).ToHandle(&event_data)) return;
+
+  // Process debug event.
+  ProcessDebugEvent(v8::PromiseEvent,
+                    Handle<JSObject>::cast(event_data),
+                    true);
+}
+
+
+void Debug::OnAsyncTaskEvent(Handle<JSObject> data) {
+  if (in_debug_scope() || ignore_events()) return;
+
+  HandleScope scope(isolate_);
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  // Create the script collected state object.
+  Handle<Object> event_data;
+  // Bail out and don't call debugger if exception.
+  if (!MakeAsyncTaskEvent(data).ToHandle(&event_data)) return;
+
+  // Process debug event.
+  ProcessDebugEvent(v8::AsyncTaskEvent,
+                    Handle<JSObject>::cast(event_data),
+                    true);
+}
+
+
+void Debug::ProcessDebugEvent(v8::DebugEvent event,
+                              Handle<JSObject> event_data,
+                              bool auto_continue) {
+  HandleScope scope(isolate_);
+
+  // Create the execution state.
+  Handle<Object> exec_state;
+  // Bail out and don't call debugger if exception.
+  if (!MakeExecutionState().ToHandle(&exec_state)) return;
+
+  // First notify the message handler if any.
+  if (message_handler_ != NULL) {
+    NotifyMessageHandler(event,
+                         Handle<JSObject>::cast(exec_state),
+                         event_data,
+                         auto_continue);
+  }
+  // Notify registered debug event listener. This can be either a C or
+  // a JavaScript function. Don't call event listener for v8::Break
+  // here, if it's only a debug command -- they will be processed later.
+  if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
+    CallEventCallback(event, exec_state, event_data, NULL);
+  }
+}
+
+
+void Debug::CallEventCallback(v8::DebugEvent event,
+                              Handle<Object> exec_state,
+                              Handle<Object> event_data,
+                              v8::Debug::ClientData* client_data) {
+  // Prevent other interrupts from triggering, for example API callbacks,
+  // while dispatching event listners.
+  PostponeInterruptsScope postpone(isolate_);
+  bool previous = in_debug_event_listener_;
+  in_debug_event_listener_ = true;
+  if (event_listener_->IsForeign()) {
+    // Invoke the C debug event listener.
+    v8::Debug::EventCallback callback =
+        FUNCTION_CAST<v8::Debug::EventCallback>(
+            Handle<Foreign>::cast(event_listener_)->foreign_address());
+    EventDetailsImpl event_details(event,
+                                   Handle<JSObject>::cast(exec_state),
+                                   Handle<JSObject>::cast(event_data),
+                                   event_listener_data_,
+                                   client_data);
+    callback(event_details);
+    DCHECK(!isolate_->has_scheduled_exception());
+  } else {
+    // Invoke the JavaScript debug event listener.
+    DCHECK(event_listener_->IsJSFunction());
+    Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_),
+                              exec_state,
+                              event_data,
+                              event_listener_data_ };
+    Handle<JSReceiver> global(isolate_->global_proxy());
+    Execution::TryCall(isolate_, Handle<JSFunction>::cast(event_listener_),
+                       global, arraysize(argv), argv);
+  }
+  in_debug_event_listener_ = previous;
+}
+
+
+void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
+  if (ignore_events()) return;
+  SuppressDebug while_processing(this);
+
+  bool in_nested_debug_scope = in_debug_scope();
+  HandleScope scope(isolate_);
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  if (event == v8::AfterCompile) {
+    // If debugging there might be script break points registered for this
+    // script. Make sure that these break points are set.
+    Handle<Object> argv[] = {Script::GetWrapper(script)};
+    if (CallFunction("UpdateScriptBreakPoints", arraysize(argv), argv)
+            .is_null()) {
+      return;
+    }
+  }
+
+  // Create the compile state object.
+  Handle<Object> event_data;
+  // Bail out and don't call debugger if exception.
+  if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
+
+  // Don't call NotifyMessageHandler if already in debug scope to avoid running
+  // nested command loop.
+  if (in_nested_debug_scope) {
+    if (event_listener_.is_null()) return;
+    // Create the execution state.
+    Handle<Object> exec_state;
+    // Bail out and don't call debugger if exception.
+    if (!MakeExecutionState().ToHandle(&exec_state)) return;
+
+    CallEventCallback(event, exec_state, event_data, NULL);
+  } else {
+    // Process debug event.
+    ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true);
+  }
+}
+
+
+Handle<Context> Debug::GetDebugContext() {
+  if (!is_loaded()) return Handle<Context>();
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return Handle<Context>();
+  // The global handle may be destroyed soon after.  Return it reboxed.
+  return handle(*debug_context(), isolate_);
+}
+
+
+void Debug::NotifyMessageHandler(v8::DebugEvent event,
+                                 Handle<JSObject> exec_state,
+                                 Handle<JSObject> event_data,
+                                 bool auto_continue) {
+  // Prevent other interrupts from triggering, for example API callbacks,
+  // while dispatching message handler callbacks.
+  PostponeInterruptsScope no_interrupts(isolate_);
+  DCHECK(is_active_);
+  HandleScope scope(isolate_);
+  // Process the individual events.
+  bool sendEventMessage = false;
+  switch (event) {
+    case v8::Break:
+      sendEventMessage = !auto_continue;
+      break;
+    case v8::NewFunction:
+    case v8::BeforeCompile:
+    case v8::CompileError:
+    case v8::PromiseEvent:
+    case v8::AsyncTaskEvent:
+      break;
+    case v8::Exception:
+    case v8::AfterCompile:
+      sendEventMessage = true;
+      break;
+  }
+
+  // The debug command interrupt flag might have been set when the command was
+  // added. It should be enough to clear the flag only once while we are in the
+  // debugger.
+  DCHECK(in_debug_scope());
+  isolate_->stack_guard()->ClearDebugCommand();
+
+  // Notify the debugger that a debug event has occurred unless auto continue is
+  // active in which case no event is send.
+  if (sendEventMessage) {
+    MessageImpl message = MessageImpl::NewEvent(
+        event,
+        auto_continue,
+        Handle<JSObject>::cast(exec_state),
+        Handle<JSObject>::cast(event_data));
+    InvokeMessageHandler(message);
+  }
+
+  // If auto continue don't make the event cause a break, but process messages
+  // in the queue if any. For script collected events don't even process
+  // messages in the queue as the execution state might not be what is expected
+  // by the client.
+  if (auto_continue && !has_commands()) return;
+
+  // DebugCommandProcessor goes here.
+  bool running = auto_continue;
+
+  Handle<Object> cmd_processor_ctor = Object::GetProperty(
+      isolate_, exec_state, "debugCommandProcessor").ToHandleChecked();
+  Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) };
+  Handle<Object> cmd_processor = Execution::Call(
+      isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked();
+  Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
+      Object::GetProperty(
+          isolate_, cmd_processor, "processDebugRequest").ToHandleChecked());
+  Handle<Object> is_running = Object::GetProperty(
+      isolate_, cmd_processor, "isRunning").ToHandleChecked();
+
+  // Process requests from the debugger.
+  do {
+    // Wait for new command in the queue.
+    command_received_.Wait();
+
+    // Get the command from the queue.
+    CommandMessage command = command_queue_.Get();
+    isolate_->logger()->DebugTag(
+        "Got request from command queue, in interactive loop.");
+    if (!is_active()) {
+      // Delete command text and user data.
+      command.Dispose();
+      return;
+    }
+
+    Vector<const uc16> command_text(
+        const_cast<const uc16*>(command.text().start()),
+        command.text().length());
+    Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte(
+        command_text).ToHandleChecked();
+    Handle<Object> request_args[] = { request_text };
+    Handle<Object> answer_value;
+    Handle<String> answer;
+    MaybeHandle<Object> maybe_exception;
+    MaybeHandle<Object> maybe_result =
+        Execution::TryCall(isolate_, process_debug_request, cmd_processor, 1,
+                           request_args, &maybe_exception);
+
+    if (maybe_result.ToHandle(&answer_value)) {
+      if (answer_value->IsUndefined()) {
+        answer = isolate_->factory()->empty_string();
+      } else {
+        answer = Handle<String>::cast(answer_value);
+      }
+
+      // Log the JSON request/response.
+      if (FLAG_trace_debug_json) {
+        PrintF("%s\n", request_text->ToCString().get());
+        PrintF("%s\n", answer->ToCString().get());
+      }
+
+      Handle<Object> is_running_args[] = { answer };
+      maybe_result = Execution::Call(
+          isolate_, is_running, cmd_processor, 1, is_running_args);
+      Handle<Object> result;
+      if (!maybe_result.ToHandle(&result)) break;
+      running = result->IsTrue();
+    } else {
+      Handle<Object> exception;
+      if (!maybe_exception.ToHandle(&exception)) break;
+      Handle<Object> result;
+      if (!Object::ToString(isolate_, exception).ToHandle(&result)) break;
+      answer = Handle<String>::cast(result);
+    }
+
+    // Return the result.
+    MessageImpl message = MessageImpl::NewResponse(
+        event, running, exec_state, event_data, answer, command.client_data());
+    InvokeMessageHandler(message);
+    command.Dispose();
+
+    // Return from debug event processing if either the VM is put into the
+    // running state (through a continue command) or auto continue is active
+    // and there are no more commands queued.
+  } while (!running || has_commands());
+  command_queue_.Clear();
+}
+
+
+void Debug::SetEventListener(Handle<Object> callback,
+                             Handle<Object> data) {
+  GlobalHandles* global_handles = isolate_->global_handles();
+
+  // Remove existing entry.
+  GlobalHandles::Destroy(event_listener_.location());
+  event_listener_ = Handle<Object>();
+  GlobalHandles::Destroy(event_listener_data_.location());
+  event_listener_data_ = Handle<Object>();
+
+  // Set new entry.
+  if (!callback->IsUndefined() && !callback->IsNull()) {
+    event_listener_ = global_handles->Create(*callback);
+    if (data.is_null()) data = isolate_->factory()->undefined_value();
+    event_listener_data_ = global_handles->Create(*data);
+  }
+
+  UpdateState();
+}
+
+
+void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
+  message_handler_ = handler;
+  UpdateState();
+  if (handler == NULL && in_debug_scope()) {
+    // Send an empty command to the debugger if in a break to make JavaScript
+    // run again if the debugger is closed.
+    EnqueueCommandMessage(Vector<const uint16_t>::empty());
+  }
+}
+
+
+
+void Debug::UpdateState() {
+  bool is_active = message_handler_ != NULL || !event_listener_.is_null();
+  if (is_active || in_debug_scope()) {
+    // Note that the debug context could have already been loaded to
+    // bootstrap test cases.
+    isolate_->compilation_cache()->Disable();
+    is_active = Load();
+  } else if (is_loaded()) {
+    isolate_->compilation_cache()->Enable();
+    Unload();
+  }
+  is_active_ = is_active;
+}
+
+
+// Calls the registered debug message handler. This callback is part of the
+// public API.
+void Debug::InvokeMessageHandler(MessageImpl message) {
+  if (message_handler_ != NULL) message_handler_(message);
+}
+
+
+// Puts a command coming from the public API on the queue.  Creates
+// a copy of the command string managed by the debugger.  Up to this
+// point, the command data was managed by the API client.  Called
+// by the API client thread.
+void Debug::EnqueueCommandMessage(Vector<const uint16_t> command,
+                                  v8::Debug::ClientData* client_data) {
+  // Need to cast away const.
+  CommandMessage message = CommandMessage::New(
+      Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
+                       command.length()),
+      client_data);
+  isolate_->logger()->DebugTag("Put command on command_queue.");
+  command_queue_.Put(message);
+  command_received_.Signal();
+
+  // Set the debug command break flag to have the command processed.
+  if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
+}
+
+
+MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return isolate_->factory()->undefined_value();
+
+  // Create the execution state.
+  Handle<Object> exec_state;
+  if (!MakeExecutionState().ToHandle(&exec_state)) {
+    return isolate_->factory()->undefined_value();
+  }
+
+  Handle<Object> argv[] = { exec_state, data };
+  return Execution::Call(
+      isolate_,
+      fun,
+      Handle<Object>(debug_context()->global_proxy(), isolate_),
+      arraysize(argv),
+      argv);
+}
+
+
+void Debug::HandleDebugBreak() {
+  // Ignore debug break during bootstrapping.
+  if (isolate_->bootstrapper()->IsActive()) return;
+  // Just continue if breaks are disabled.
+  if (break_disabled()) return;
+  // Ignore debug break if debugger is not active.
+  if (!is_active()) return;
+
+  StackLimitCheck check(isolate_);
+  if (check.HasOverflowed()) return;
+
+  { JavaScriptFrameIterator it(isolate_);
+    DCHECK(!it.done());
+    Object* fun = it.frame()->function();
+    if (fun && fun->IsJSFunction()) {
+      // Don't stop in builtin functions.
+      if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return;
+      JSGlobalObject* global =
+          JSFunction::cast(fun)->context()->global_object();
+      // Don't stop in debugger functions.
+      if (IsDebugGlobal(global)) return;
+    }
+  }
+
+  // Collect the break state before clearing the flags.
+  bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
+                            !isolate_->stack_guard()->CheckDebugBreak();
+
+  isolate_->stack_guard()->ClearDebugBreak();
+
+  // Clear stepping to avoid duplicate breaks.
+  ClearStepping();
+
+  ProcessDebugMessages(debug_command_only);
+}
+
+
+void Debug::ProcessDebugMessages(bool debug_command_only) {
+  isolate_->stack_guard()->ClearDebugCommand();
+
+  StackLimitCheck check(isolate_);
+  if (check.HasOverflowed()) return;
+
+  HandleScope scope(isolate_);
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  // Notify the debug event listeners. Indicate auto continue if the break was
+  // a debug command break.
+  OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only);
+}
+
+
+DebugScope::DebugScope(Debug* debug)
+    : debug_(debug),
+      prev_(debug->debugger_entry()),
+      save_(debug_->isolate_),
+      no_termination_exceptons_(debug_->isolate_,
+                                StackGuard::TERMINATE_EXECUTION) {
+  // Link recursive debugger entry.
+  base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
+                        reinterpret_cast<base::AtomicWord>(this));
+
+  // Store the previous break id and frame id.
+  break_id_ = debug_->break_id();
+  break_frame_id_ = debug_->break_frame_id();
+
+  // Create the new break info. If there is no JavaScript frames there is no
+  // break frame id.
+  JavaScriptFrameIterator it(isolate());
+  bool has_js_frames = !it.done();
+  debug_->thread_local_.break_frame_id_ = has_js_frames ? it.frame()->id()
+                                                        : StackFrame::NO_ID;
+  debug_->SetNextBreakId();
+
+  debug_->UpdateState();
+  // Make sure that debugger is loaded and enter the debugger context.
+  // The previous context is kept in save_.
+  failed_ = !debug_->is_loaded();
+  if (!failed_) isolate()->set_context(*debug->debug_context());
+}
+
+
+DebugScope::~DebugScope() {
+  if (!failed_ && prev_ == NULL) {
+    // Clear mirror cache when leaving the debugger. Skip this if there is a
+    // pending exception as clearing the mirror cache calls back into
+    // JavaScript. This can happen if the v8::Debug::Call is used in which
+    // case the exception should end up in the calling code.
+    if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache();
+
+    // If there are commands in the queue when leaving the debugger request
+    // that these commands are processed.
+    if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand();
+  }
+
+  // Leaving this debugger entry.
+  base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
+                        reinterpret_cast<base::AtomicWord>(prev_));
+
+  // Restore to the previous break state.
+  debug_->thread_local_.break_frame_id_ = break_frame_id_;
+  debug_->thread_local_.break_id_ = break_id_;
+
+  debug_->UpdateState();
+}
+
+
+MessageImpl MessageImpl::NewEvent(DebugEvent event,
+                                  bool running,
+                                  Handle<JSObject> exec_state,
+                                  Handle<JSObject> event_data) {
+  MessageImpl message(true, event, running,
+                      exec_state, event_data, Handle<String>(), NULL);
+  return message;
+}
+
+
+MessageImpl MessageImpl::NewResponse(DebugEvent event,
+                                     bool running,
+                                     Handle<JSObject> exec_state,
+                                     Handle<JSObject> event_data,
+                                     Handle<String> response_json,
+                                     v8::Debug::ClientData* client_data) {
+  MessageImpl message(false, event, running,
+                      exec_state, event_data, response_json, client_data);
+  return message;
+}
+
+
+MessageImpl::MessageImpl(bool is_event,
+                         DebugEvent event,
+                         bool running,
+                         Handle<JSObject> exec_state,
+                         Handle<JSObject> event_data,
+                         Handle<String> response_json,
+                         v8::Debug::ClientData* client_data)
+    : is_event_(is_event),
+      event_(event),
+      running_(running),
+      exec_state_(exec_state),
+      event_data_(event_data),
+      response_json_(response_json),
+      client_data_(client_data) {}
+
+
+bool MessageImpl::IsEvent() const {
+  return is_event_;
+}
+
+
+bool MessageImpl::IsResponse() const {
+  return !is_event_;
+}
+
+
+DebugEvent MessageImpl::GetEvent() const {
+  return event_;
+}
+
+
+bool MessageImpl::WillStartRunning() const {
+  return running_;
+}
+
+
+v8::Local<v8::Object> MessageImpl::GetExecutionState() const {
+  return v8::Utils::ToLocal(exec_state_);
+}
+
+
+v8::Isolate* MessageImpl::GetIsolate() const {
+  return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
+}
+
+
+v8::Local<v8::Object> MessageImpl::GetEventData() const {
+  return v8::Utils::ToLocal(event_data_);
+}
+
+
+v8::Local<v8::String> MessageImpl::GetJSON() const {
+  Isolate* isolate = event_data_->GetIsolate();
+  v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
+
+  if (IsEvent()) {
+    // Call toJSONProtocol on the debug event object.
+    Handle<Object> fun = Object::GetProperty(
+        isolate, event_data_, "toJSONProtocol").ToHandleChecked();
+    if (!fun->IsJSFunction()) {
+      return v8::Local<v8::String>();
+    }
+
+    MaybeHandle<Object> maybe_json =
+        Execution::TryCall(isolate, fun, event_data_, 0, NULL);
+    Handle<Object> json;
+    if (!maybe_json.ToHandle(&json) || !json->IsString()) {
+      return v8::Local<v8::String>();
+    }
+    return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
+  } else {
+    return v8::Utils::ToLocal(response_json_);
+  }
+}
+
+
+v8::Local<v8::Context> MessageImpl::GetEventContext() const {
+  Isolate* isolate = event_data_->GetIsolate();
+  v8::Local<v8::Context> context = GetDebugEventContext(isolate);
+  // Isolate::context() may be NULL when "script collected" event occurs.
+  DCHECK(!context.IsEmpty());
+  return context;
+}
+
+
+v8::Debug::ClientData* MessageImpl::GetClientData() const {
+  return client_data_;
+}
+
+
+EventDetailsImpl::EventDetailsImpl(DebugEvent event,
+                                   Handle<JSObject> exec_state,
+                                   Handle<JSObject> event_data,
+                                   Handle<Object> callback_data,
+                                   v8::Debug::ClientData* client_data)
+    : event_(event),
+      exec_state_(exec_state),
+      event_data_(event_data),
+      callback_data_(callback_data),
+      client_data_(client_data) {}
+
+
+DebugEvent EventDetailsImpl::GetEvent() const {
+  return event_;
+}
+
+
+v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const {
+  return v8::Utils::ToLocal(exec_state_);
+}
+
+
+v8::Local<v8::Object> EventDetailsImpl::GetEventData() const {
+  return v8::Utils::ToLocal(event_data_);
+}
+
+
+v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const {
+  return GetDebugEventContext(exec_state_->GetIsolate());
+}
+
+
+v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const {
+  return v8::Utils::ToLocal(callback_data_);
+}
+
+
+v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
+  return client_data_;
+}
+
+
+CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
+                                   client_data_(NULL) {
+}
+
+
+CommandMessage::CommandMessage(const Vector<uint16_t>& text,
+                               v8::Debug::ClientData* data)
+    : text_(text),
+      client_data_(data) {
+}
+
+
+void CommandMessage::Dispose() {
+  text_.Dispose();
+  delete client_data_;
+  client_data_ = NULL;
+}
+
+
+CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
+                                   v8::Debug::ClientData* data) {
+  return CommandMessage(command.Clone(), data);
+}
+
+
+CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
+                                                     size_(size) {
+  messages_ = NewArray<CommandMessage>(size);
+}
+
+
+CommandMessageQueue::~CommandMessageQueue() {
+  while (!IsEmpty()) Get().Dispose();
+  DeleteArray(messages_);
+}
+
+
+CommandMessage CommandMessageQueue::Get() {
+  DCHECK(!IsEmpty());
+  int result = start_;
+  start_ = (start_ + 1) % size_;
+  return messages_[result];
+}
+
+
+void CommandMessageQueue::Put(const CommandMessage& message) {
+  if ((end_ + 1) % size_ == start_) {
+    Expand();
+  }
+  messages_[end_] = message;
+  end_ = (end_ + 1) % size_;
+}
+
+
+void CommandMessageQueue::Expand() {
+  CommandMessageQueue new_queue(size_ * 2);
+  while (!IsEmpty()) {
+    new_queue.Put(Get());
+  }
+  CommandMessage* array_to_free = messages_;
+  *this = new_queue;
+  new_queue.messages_ = array_to_free;
+  // Make the new_queue empty so that it doesn't call Dispose on any messages.
+  new_queue.start_ = new_queue.end_;
+  // Automatic destructor called on new_queue, freeing array_to_free.
+}
+
+
+LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
+    : logger_(logger), queue_(size) {}
+
+
+bool LockingCommandMessageQueue::IsEmpty() const {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  return queue_.IsEmpty();
+}
+
+
+CommandMessage LockingCommandMessageQueue::Get() {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  CommandMessage result = queue_.Get();
+  logger_->DebugEvent("Get", result.text());
+  return result;
+}
+
+
+void LockingCommandMessageQueue::Put(const CommandMessage& message) {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  queue_.Put(message);
+  logger_->DebugEvent("Put", message.text());
+}
+
+
+void LockingCommandMessageQueue::Clear() {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  queue_.Clear();
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/debug/debug.h b/src/debug/debug.h
new file mode 100644
index 0000000..7dcc2b5
--- /dev/null
+++ b/src/debug/debug.h
@@ -0,0 +1,749 @@
+// Copyright 2012 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_H_
+#define V8_DEBUG_DEBUG_H_
+
+#include "src/allocation.h"
+#include "src/arguments.h"
+#include "src/assembler.h"
+#include "src/base/atomicops.h"
+#include "src/base/platform/platform.h"
+#include "src/debug/liveedit.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/flags.h"
+#include "src/frames.h"
+#include "src/hashmap.h"
+#include "src/runtime/runtime.h"
+#include "src/string-stream.h"
+#include "src/v8threads.h"
+
+#include "include/v8-debug.h"
+
+namespace v8 {
+namespace internal {
+
+
+// Forward declarations.
+class DebugScope;
+
+
+// Step actions. NOTE: These values are in macros.py as well.
+enum StepAction : int8_t {
+  StepNone = -1,  // Stepping not prepared.
+  StepOut = 0,    // Step out of the current function.
+  StepNext = 1,   // Step to the next statement in the current function.
+  StepIn = 2,     // Step into new functions invoked or the next statement
+                  // in the current function.
+  StepFrame = 3   // Step into a new frame or return to previous frame.
+};
+
+
+// Type of exception break. NOTE: These values are in macros.py as well.
+enum ExceptionBreakType {
+  BreakException = 0,
+  BreakUncaughtException = 1
+};
+
+
+// Type of exception break.
+enum BreakLocatorType { ALL_BREAK_LOCATIONS, CALLS_AND_RETURNS };
+
+
+// The different types of breakpoint position alignments.
+// Must match Debug.BreakPositionAlignment in debug.js
+enum BreakPositionAlignment {
+  STATEMENT_ALIGNED = 0,
+  BREAK_POSITION_ALIGNED = 1
+};
+
+
+class BreakLocation {
+ public:
+  // Find the break point at the supplied address, or the closest one before
+  // the address.
+  static BreakLocation FromAddress(Handle<DebugInfo> debug_info, Address pc);
+
+  static void FromAddressSameStatement(Handle<DebugInfo> debug_info, Address pc,
+                                       List<BreakLocation>* result_out);
+
+  static BreakLocation FromPosition(Handle<DebugInfo> debug_info, int position,
+                                    BreakPositionAlignment alignment);
+
+  bool IsDebugBreak() const;
+
+  inline bool IsReturn() const {
+    return RelocInfo::IsDebugBreakSlotAtReturn(rmode_);
+  }
+  inline bool IsCall() const {
+    return RelocInfo::IsDebugBreakSlotAtCall(rmode_);
+  }
+  inline bool HasBreakPoint() const {
+    return debug_info_->HasBreakPoint(pc_offset_);
+  }
+
+  Handle<Object> BreakPointObjects() const;
+
+  void SetBreakPoint(Handle<Object> break_point_object);
+  void ClearBreakPoint(Handle<Object> break_point_object);
+
+  void SetOneShot();
+  void ClearOneShot();
+
+
+  inline RelocInfo rinfo() const {
+    return RelocInfo(debug_info_->GetIsolate(), pc(), rmode(), data_, code());
+  }
+
+  inline int position() const { return position_; }
+  inline int statement_position() const { return statement_position_; }
+
+  inline Address pc() const { return code()->entry() + pc_offset_; }
+
+  inline RelocInfo::Mode rmode() const { return rmode_; }
+
+  inline Code* code() const { return debug_info_->code(); }
+
+ private:
+  BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo, int position,
+                int statement_position);
+
+  class Iterator {
+   public:
+    Iterator(Handle<DebugInfo> debug_info, BreakLocatorType type);
+
+    BreakLocation GetBreakLocation() {
+      return BreakLocation(debug_info_, rinfo(), position(),
+                           statement_position());
+    }
+
+    inline bool Done() const { return reloc_iterator_.done(); }
+    void Next();
+
+    void SkipTo(int count) {
+      while (count-- > 0) Next();
+    }
+
+    inline RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); }
+    inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); }
+    inline Address pc() { return rinfo()->pc(); }
+    int break_index() const { return break_index_; }
+    inline int position() const { return position_; }
+    inline int statement_position() const { return statement_position_; }
+
+   private:
+    static int GetModeMask(BreakLocatorType type);
+
+    Handle<DebugInfo> debug_info_;
+    RelocIterator reloc_iterator_;
+    int break_index_;
+    int position_;
+    int statement_position_;
+
+    DisallowHeapAllocation no_gc_;
+
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
+  friend class Debug;
+
+  static int BreakIndexFromAddress(Handle<DebugInfo> debug_info, Address pc);
+
+  void SetDebugBreak();
+  void ClearDebugBreak();
+
+  inline bool IsDebuggerStatement() const {
+    return RelocInfo::IsDebuggerStatement(rmode_);
+  }
+  inline bool IsDebugBreakSlot() const {
+    return RelocInfo::IsDebugBreakSlot(rmode_);
+  }
+
+  Handle<DebugInfo> debug_info_;
+  int pc_offset_;
+  RelocInfo::Mode rmode_;
+  intptr_t data_;
+  int position_;
+  int statement_position_;
+};
+
+
+// Linked list holding debug info objects. The debug info objects are kept as
+// weak handles to avoid a debug info object to keep a function alive.
+class DebugInfoListNode {
+ public:
+  explicit DebugInfoListNode(DebugInfo* debug_info);
+  ~DebugInfoListNode();
+
+  DebugInfoListNode* next() { return next_; }
+  void set_next(DebugInfoListNode* next) { next_ = next; }
+  Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); }
+
+ private:
+  // Global (weak) handle to the debug info object.
+  DebugInfo** debug_info_;
+
+  // Next pointer for linked list.
+  DebugInfoListNode* next_;
+};
+
+
+
+// Message delivered to the message handler callback. This is either a debugger
+// event or the response to a command.
+class MessageImpl: public v8::Debug::Message {
+ public:
+  // Create a message object for a debug event.
+  static MessageImpl NewEvent(DebugEvent event,
+                              bool running,
+                              Handle<JSObject> exec_state,
+                              Handle<JSObject> event_data);
+
+  // Create a message object for the response to a debug command.
+  static MessageImpl NewResponse(DebugEvent event,
+                                 bool running,
+                                 Handle<JSObject> exec_state,
+                                 Handle<JSObject> event_data,
+                                 Handle<String> response_json,
+                                 v8::Debug::ClientData* client_data);
+
+  // Implementation of interface v8::Debug::Message.
+  virtual bool IsEvent() const;
+  virtual bool IsResponse() const;
+  virtual DebugEvent GetEvent() const;
+  virtual bool WillStartRunning() const;
+  virtual v8::Local<v8::Object> GetExecutionState() const;
+  virtual v8::Local<v8::Object> GetEventData() const;
+  virtual v8::Local<v8::String> GetJSON() const;
+  virtual v8::Local<v8::Context> GetEventContext() const;
+  virtual v8::Debug::ClientData* GetClientData() const;
+  virtual v8::Isolate* GetIsolate() const;
+
+ private:
+  MessageImpl(bool is_event,
+              DebugEvent event,
+              bool running,
+              Handle<JSObject> exec_state,
+              Handle<JSObject> event_data,
+              Handle<String> response_json,
+              v8::Debug::ClientData* client_data);
+
+  bool is_event_;  // Does this message represent a debug event?
+  DebugEvent event_;  // Debug event causing the break.
+  bool running_;  // Will the VM start running after this event?
+  Handle<JSObject> exec_state_;  // Current execution state.
+  Handle<JSObject> event_data_;  // Data associated with the event.
+  Handle<String> response_json_;  // Response JSON if message holds a response.
+  v8::Debug::ClientData* client_data_;  // Client data passed with the request.
+};
+
+
+// Details of the debug event delivered to the debug event listener.
+class EventDetailsImpl : public v8::Debug::EventDetails {
+ public:
+  EventDetailsImpl(DebugEvent event,
+                   Handle<JSObject> exec_state,
+                   Handle<JSObject> event_data,
+                   Handle<Object> callback_data,
+                   v8::Debug::ClientData* client_data);
+  virtual DebugEvent GetEvent() const;
+  virtual v8::Local<v8::Object> GetExecutionState() const;
+  virtual v8::Local<v8::Object> GetEventData() const;
+  virtual v8::Local<v8::Context> GetEventContext() const;
+  virtual v8::Local<v8::Value> GetCallbackData() const;
+  virtual v8::Debug::ClientData* GetClientData() const;
+ private:
+  DebugEvent event_;  // Debug event causing the break.
+  Handle<JSObject> exec_state_;         // Current execution state.
+  Handle<JSObject> event_data_;         // Data associated with the event.
+  Handle<Object> callback_data_;        // User data passed with the callback
+                                        // when it was registered.
+  v8::Debug::ClientData* client_data_;  // Data passed to DebugBreakForCommand.
+};
+
+
+// Message send by user to v8 debugger or debugger output message.
+// In addition to command text it may contain a pointer to some user data
+// which are expected to be passed along with the command reponse to message
+// handler.
+class CommandMessage {
+ public:
+  static CommandMessage New(const Vector<uint16_t>& command,
+                            v8::Debug::ClientData* data);
+  CommandMessage();
+
+  // Deletes user data and disposes of the text.
+  void Dispose();
+  Vector<uint16_t> text() const { return text_; }
+  v8::Debug::ClientData* client_data() const { return client_data_; }
+ private:
+  CommandMessage(const Vector<uint16_t>& text,
+                 v8::Debug::ClientData* data);
+
+  Vector<uint16_t> text_;
+  v8::Debug::ClientData* client_data_;
+};
+
+
+// A Queue of CommandMessage objects.  A thread-safe version is
+// LockingCommandMessageQueue, based on this class.
+class CommandMessageQueue BASE_EMBEDDED {
+ public:
+  explicit CommandMessageQueue(int size);
+  ~CommandMessageQueue();
+  bool IsEmpty() const { return start_ == end_; }
+  CommandMessage Get();
+  void Put(const CommandMessage& message);
+  void Clear() { start_ = end_ = 0; }  // Queue is empty after Clear().
+ private:
+  // Doubles the size of the message queue, and copies the messages.
+  void Expand();
+
+  CommandMessage* messages_;
+  int start_;
+  int end_;
+  int size_;  // The size of the queue buffer.  Queue can hold size-1 messages.
+};
+
+
+// LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage
+// messages.  The message data is not managed by LockingCommandMessageQueue.
+// Pointers to the data are passed in and out. Implemented by adding a
+// Mutex to CommandMessageQueue.  Includes logging of all puts and gets.
+class LockingCommandMessageQueue BASE_EMBEDDED {
+ public:
+  LockingCommandMessageQueue(Logger* logger, int size);
+  bool IsEmpty() const;
+  CommandMessage Get();
+  void Put(const CommandMessage& message);
+  void Clear();
+ private:
+  Logger* logger_;
+  CommandMessageQueue queue_;
+  mutable base::Mutex mutex_;
+  DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue);
+};
+
+
+class DebugFeatureTracker {
+ public:
+  enum Feature {
+    kActive = 1,
+    kBreakPoint = 2,
+    kStepping = 3,
+    kHeapSnapshot = 4,
+    kAllocationTracking = 5,
+    kProfiler = 6,
+    kLiveEdit = 7,
+  };
+
+  explicit DebugFeatureTracker(Isolate* isolate)
+      : isolate_(isolate), bitfield_(0) {}
+  void Track(Feature feature);
+
+ private:
+  Isolate* isolate_;
+  uint32_t bitfield_;
+};
+
+
+// This class contains the debugger support. The main purpose is to handle
+// setting break points in the code.
+//
+// This class controls the debug info for all functions which currently have
+// active breakpoints in them. This debug info is held in the heap root object
+// debug_info which is a FixedArray. Each entry in this list is of class
+// DebugInfo.
+class Debug {
+ public:
+  // Debug event triggers.
+  void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
+
+  void OnThrow(Handle<Object> exception);
+  void OnPromiseReject(Handle<JSObject> promise, Handle<Object> value);
+  void OnCompileError(Handle<Script> script);
+  void OnBeforeCompile(Handle<Script> script);
+  void OnAfterCompile(Handle<Script> script);
+  void OnPromiseEvent(Handle<JSObject> data);
+  void OnAsyncTaskEvent(Handle<JSObject> data);
+
+  // API facing.
+  void SetEventListener(Handle<Object> callback, Handle<Object> data);
+  void SetMessageHandler(v8::Debug::MessageHandler handler);
+  void EnqueueCommandMessage(Vector<const uint16_t> command,
+                             v8::Debug::ClientData* client_data = NULL);
+  MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun,
+                                           Handle<Object> data);
+  Handle<Context> GetDebugContext();
+  void HandleDebugBreak();
+  void ProcessDebugMessages(bool debug_command_only);
+
+  // Internal logic
+  bool Load();
+  void Break(Arguments args, JavaScriptFrame*);
+  void SetAfterBreakTarget(JavaScriptFrame* frame);
+
+  // Scripts handling.
+  Handle<FixedArray> GetLoadedScripts();
+
+  // Break point handling.
+  bool SetBreakPoint(Handle<JSFunction> function,
+                     Handle<Object> break_point_object,
+                     int* source_position);
+  bool SetBreakPointForScript(Handle<Script> script,
+                              Handle<Object> break_point_object,
+                              int* source_position,
+                              BreakPositionAlignment alignment);
+  void ClearBreakPoint(Handle<Object> break_point_object);
+  void ClearAllBreakPoints();
+  void FloodWithOneShot(Handle<JSFunction> function,
+                        BreakLocatorType type = ALL_BREAK_LOCATIONS);
+  void ChangeBreakOnException(ExceptionBreakType type, bool enable);
+  bool IsBreakOnException(ExceptionBreakType type);
+
+  // Stepping handling.
+  void PrepareStep(StepAction step_action);
+  void PrepareStepIn(Handle<JSFunction> function);
+  void PrepareStepOnThrow();
+  void ClearStepping();
+  void ClearStepOut();
+  void EnableStepIn();
+
+  void GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id,
+                          List<int>* results_out);
+
+  bool PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared);
+
+  // Returns whether the operation succeeded. Compilation can only be triggered
+  // if a valid closure is passed as the second argument, otherwise the shared
+  // function needs to be compiled already.
+  bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
+                       Handle<JSFunction> function);
+  void CreateDebugInfo(Handle<SharedFunctionInfo> shared);
+  static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
+
+  template <typename C>
+  bool CompileToRevealInnerFunctions(C* compilable);
+
+  // This function is used in FunctionNameUsing* tests.
+  Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script,
+                                                int position);
+
+  static Handle<Object> GetSourceBreakLocations(
+      Handle<SharedFunctionInfo> shared,
+      BreakPositionAlignment position_aligment);
+
+  // Check whether a global object is the debug global object.
+  bool IsDebugGlobal(JSGlobalObject* global);
+
+  // Check whether this frame is just about to return.
+  bool IsBreakAtReturn(JavaScriptFrame* frame);
+
+  // Support for LiveEdit
+  void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
+                             LiveEdit::FrameDropMode mode);
+
+  // Threading support.
+  char* ArchiveDebug(char* to);
+  char* RestoreDebug(char* from);
+  static int ArchiveSpacePerThread();
+  void FreeThreadResources() { }
+
+  // Record function from which eval was called.
+  static void RecordEvalCaller(Handle<Script> script);
+
+  bool CheckExecutionState(int id) {
+    return is_active() && !debug_context().is_null() && break_id() != 0 &&
+           break_id() == id;
+  }
+
+  // Flags and states.
+  DebugScope* debugger_entry() {
+    return reinterpret_cast<DebugScope*>(
+        base::NoBarrier_Load(&thread_local_.current_debug_scope_));
+  }
+  inline Handle<Context> debug_context() { return debug_context_; }
+
+  void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
+  bool live_edit_enabled() const {
+    return FLAG_enable_liveedit && live_edit_enabled_;
+  }
+
+  inline bool is_active() const { return is_active_; }
+  inline bool is_loaded() const { return !debug_context_.is_null(); }
+  inline bool in_debug_scope() const {
+    return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_);
+  }
+  void set_break_points_active(bool v) { break_points_active_ = v; }
+  bool break_points_active() const { return break_points_active_; }
+
+  StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; }
+  int break_id() { return thread_local_.break_id_; }
+
+  // Support for embedding into generated code.
+  Address is_active_address() {
+    return reinterpret_cast<Address>(&is_active_);
+  }
+
+  Address after_break_target_address() {
+    return reinterpret_cast<Address>(&after_break_target_);
+  }
+
+  Address step_in_enabled_address() {
+    return reinterpret_cast<Address>(&thread_local_.step_in_enabled_);
+  }
+
+  StepAction last_step_action() { return thread_local_.last_step_action_; }
+
+  DebugFeatureTracker* feature_tracker() { return &feature_tracker_; }
+
+ private:
+  explicit Debug(Isolate* isolate);
+
+  void UpdateState();
+  void Unload();
+  void SetNextBreakId() {
+    thread_local_.break_id_ = ++thread_local_.break_count_;
+  }
+
+  // Check whether there are commands in the command queue.
+  inline bool has_commands() const { return !command_queue_.IsEmpty(); }
+  inline bool ignore_events() const { return is_suppressed_ || !is_active_; }
+  inline bool break_disabled() const {
+    return break_disabled_ || in_debug_event_listener_;
+  }
+
+  void OnException(Handle<Object> exception, Handle<Object> promise);
+
+  // Constructors for debug event objects.
+  MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState();
+  MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent(
+      Handle<Object> break_points_hit);
+  MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent(
+      Handle<Object> exception,
+      bool uncaught,
+      Handle<Object> promise);
+  MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent(
+      Handle<Script> script, v8::DebugEvent type);
+  MUST_USE_RESULT MaybeHandle<Object> MakePromiseEvent(
+      Handle<JSObject> promise_event);
+  MUST_USE_RESULT MaybeHandle<Object> MakeAsyncTaskEvent(
+      Handle<JSObject> task_event);
+
+  // Mirror cache handling.
+  void ClearMirrorCache();
+
+  MaybeHandle<Object> PromiseHasUserDefinedRejectHandler(
+      Handle<JSObject> promise);
+
+  void CallEventCallback(v8::DebugEvent event,
+                         Handle<Object> exec_state,
+                         Handle<Object> event_data,
+                         v8::Debug::ClientData* client_data);
+  void ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script);
+  void ProcessDebugEvent(v8::DebugEvent event,
+                         Handle<JSObject> event_data,
+                         bool auto_continue);
+  void NotifyMessageHandler(v8::DebugEvent event,
+                            Handle<JSObject> exec_state,
+                            Handle<JSObject> event_data,
+                            bool auto_continue);
+  void InvokeMessageHandler(MessageImpl message);
+
+  void ClearOneShot();
+  void ActivateStepOut(StackFrame* frame);
+  void RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info);
+  Handle<Object> CheckBreakPoints(Handle<Object> break_point);
+  bool CheckBreakPoint(Handle<Object> break_point_object);
+  MaybeHandle<Object> CallFunction(const char* name, int argc,
+                                   Handle<Object> args[]);
+
+  inline void AssertDebugContext() {
+    DCHECK(isolate_->context() == *debug_context());
+    DCHECK(in_debug_scope());
+  }
+
+  void ThreadInit();
+
+  // Global handles.
+  Handle<Context> debug_context_;
+  Handle<Object> event_listener_;
+  Handle<Object> event_listener_data_;
+
+  v8::Debug::MessageHandler message_handler_;
+
+  static const int kQueueInitialSize = 4;
+  base::Semaphore command_received_;  // Signaled for each command received.
+  LockingCommandMessageQueue command_queue_;
+
+  bool is_active_;
+  bool is_suppressed_;
+  bool live_edit_enabled_;
+  bool break_disabled_;
+  bool break_points_active_;
+  bool in_debug_event_listener_;
+  bool break_on_exception_;
+  bool break_on_uncaught_exception_;
+
+  DebugInfoListNode* debug_info_list_;  // List of active debug info objects.
+
+  // Storage location for jump when exiting debug break calls.
+  // Note that this address is not GC safe.  It should be computed immediately
+  // before returning to the DebugBreakCallHelper.
+  Address after_break_target_;
+
+  // Used to collect histogram data on debugger feature usage.
+  DebugFeatureTracker feature_tracker_;
+
+  // Per-thread data.
+  class ThreadLocal {
+   public:
+    // Top debugger entry.
+    base::AtomicWord current_debug_scope_;
+
+    // Counter for generating next break id.
+    int break_count_;
+
+    // Current break id.
+    int break_id_;
+
+    // Frame id for the frame of the current break.
+    StackFrame::Id break_frame_id_;
+
+    // Step action for last step performed.
+    StepAction last_step_action_;
+
+    // Source statement position from last step next action.
+    int last_statement_position_;
+
+    // Frame pointer from last step next or step frame action.
+    Address last_fp_;
+
+    // Frame pointer of the target frame we want to arrive at.
+    Address target_fp_;
+
+    // Whether functions are flooded on entry for step-in and step-frame.
+    // If we stepped out to the embedder, disable flooding to spill stepping
+    // to the next call that the embedder makes.
+    bool step_in_enabled_;
+
+    // Stores the way how LiveEdit has patched the stack. It is used when
+    // debugger returns control back to user script.
+    LiveEdit::FrameDropMode frame_drop_mode_;
+  };
+
+  // Storage location for registers when handling debug break calls
+  ThreadLocal thread_local_;
+
+  Isolate* isolate_;
+
+  friend class Isolate;
+  friend class DebugScope;
+  friend class DisableBreak;
+  friend class LiveEdit;
+  friend class SuppressDebug;
+
+  friend Handle<FixedArray> GetDebuggedFunctions();  // In test-debug.cc
+  friend void CheckDebuggerUnloaded(bool check_functions);  // In test-debug.cc
+
+  DISALLOW_COPY_AND_ASSIGN(Debug);
+};
+
+
+// This scope is used to load and enter the debug context and create a new
+// break state.  Leaving the scope will restore the previous state.
+// On failure to load, FailedToEnter returns true.
+class DebugScope BASE_EMBEDDED {
+ public:
+  explicit DebugScope(Debug* debug);
+  ~DebugScope();
+
+  // Check whether loading was successful.
+  inline bool failed() { return failed_; }
+
+  // Get the active context from before entering the debugger.
+  inline Handle<Context> GetContext() { return save_.context(); }
+
+ private:
+  Isolate* isolate() { return debug_->isolate_; }
+
+  Debug* debug_;
+  DebugScope* prev_;               // Previous scope if entered recursively.
+  StackFrame::Id break_frame_id_;  // Previous break frame id.
+  int break_id_;                   // Previous break id.
+  bool failed_;                    // Did the debug context fail to load?
+  SaveContext save_;               // Saves previous context.
+  PostponeInterruptsScope no_termination_exceptons_;
+};
+
+
+// Stack allocated class for disabling break.
+class DisableBreak BASE_EMBEDDED {
+ public:
+  explicit DisableBreak(Debug* debug, bool disable_break)
+      : debug_(debug),
+        previous_break_disabled_(debug->break_disabled_),
+        previous_in_debug_event_listener_(debug->in_debug_event_listener_) {
+    debug_->break_disabled_ = disable_break;
+    debug_->in_debug_event_listener_ = disable_break;
+  }
+  ~DisableBreak() {
+    debug_->break_disabled_ = previous_break_disabled_;
+    debug_->in_debug_event_listener_ = previous_in_debug_event_listener_;
+  }
+
+ private:
+  Debug* debug_;
+  bool previous_break_disabled_;
+  bool previous_in_debug_event_listener_;
+  DISALLOW_COPY_AND_ASSIGN(DisableBreak);
+};
+
+
+class SuppressDebug BASE_EMBEDDED {
+ public:
+  explicit SuppressDebug(Debug* debug)
+      : debug_(debug), old_state_(debug->is_suppressed_) {
+    debug_->is_suppressed_ = true;
+  }
+  ~SuppressDebug() { debug_->is_suppressed_ = old_state_; }
+
+ private:
+  Debug* debug_;
+  bool old_state_;
+  DISALLOW_COPY_AND_ASSIGN(SuppressDebug);
+};
+
+
+// Code generator routines.
+class DebugCodegen : public AllStatic {
+ public:
+  enum DebugBreakCallHelperMode {
+    SAVE_RESULT_REGISTER,
+    IGNORE_RESULT_REGISTER
+  };
+
+  static void GenerateDebugBreakStub(MacroAssembler* masm,
+                                     DebugBreakCallHelperMode mode);
+
+  // FrameDropper is a code replacement for a JavaScript frame with possibly
+  // several frames above.
+  // There is no calling conventions here, because it never actually gets
+  // called, it only gets returned to.
+  static void GenerateFrameDropperLiveEdit(MacroAssembler* masm);
+
+
+  static void GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode);
+
+  static void PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                  Handle<Code> code);
+  static void ClearDebugBreakSlot(Isolate* isolate, Address pc);
+};
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_DEBUG_DEBUG_H_
diff --git a/src/debug/debug.js b/src/debug/debug.js
new file mode 100644
index 0000000..bc2c696
--- /dev/null
+++ b/src/debug/debug.js
@@ -0,0 +1,2612 @@
+// Copyright 2012 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.
+
+(function (global, utils) {
+"use strict";
+
+// ----------------------------------------------------------------------------
+// Imports
+
+var FrameMirror = global.FrameMirror;
+var GlobalArray = global.Array;
+var GlobalRegExp = global.RegExp;
+var IsNaN = global.isNaN;
+var JSONParse = global.JSON.parse;
+var JSONStringify = global.JSON.stringify;
+var LookupMirror = global.LookupMirror;
+var MakeError;
+var MakeTypeError;
+var MakeMirror = global.MakeMirror;
+var MakeMirrorSerializer = global.MakeMirrorSerializer;
+var MathMin = global.Math.min;
+var Mirror = global.Mirror;
+var MirrorType;
+var ParseInt = global.parseInt;
+var ValueMirror = global.ValueMirror;
+
+utils.Import(function(from) {
+  MakeError = from.MakeError;
+  MakeTypeError = from.MakeTypeError;
+  MirrorType = from.MirrorType;
+});
+
+//----------------------------------------------------------------------------
+
+// Default number of frames to include in the response to backtrace request.
+var kDefaultBacktraceLength = 10;
+
+var Debug = {};
+
+// Regular expression to skip "crud" at the beginning of a source line which is
+// not really code. Currently the regular expression matches whitespace and
+// comments.
+var sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
+
+// Debug events which can occour in the V8 JavaScript engine. These originate
+// from the API include file debug.h.
+Debug.DebugEvent = { Break: 1,
+                     Exception: 2,
+                     NewFunction: 3,
+                     BeforeCompile: 4,
+                     AfterCompile: 5,
+                     CompileError: 6,
+                     PromiseEvent: 7,
+                     AsyncTaskEvent: 8 };
+
+// Types of exceptions that can be broken upon.
+Debug.ExceptionBreak = { Caught : 0,
+                         Uncaught: 1 };
+
+// The different types of steps.
+Debug.StepAction = { StepOut: 0,
+                     StepNext: 1,
+                     StepIn: 2,
+                     StepFrame: 3 };
+
+// The different types of scripts matching enum ScriptType in objects.h.
+Debug.ScriptType = { Native: 0,
+                     Extension: 1,
+                     Normal: 2 };
+
+// The different types of script compilations matching enum
+// Script::CompilationType in objects.h.
+Debug.ScriptCompilationType = { Host: 0,
+                                Eval: 1,
+                                JSON: 2 };
+
+// The different script break point types.
+Debug.ScriptBreakPointType = { ScriptId: 0,
+                               ScriptName: 1,
+                               ScriptRegExp: 2 };
+
+// The different types of breakpoint position alignments.
+// Must match BreakPositionAlignment in debug.h.
+Debug.BreakPositionAlignment = {
+  Statement: 0,
+  BreakPosition: 1
+};
+
+function ScriptTypeFlag(type) {
+  return (1 << type);
+}
+
+// Globals.
+var next_response_seq = 0;
+var next_break_point_number = 1;
+var break_points = [];
+var script_break_points = [];
+var debugger_flags = {
+  breakPointsActive: {
+    value: true,
+    getValue: function() { return this.value; },
+    setValue: function(value) {
+      this.value = !!value;
+      %SetBreakPointsActive(this.value);
+    }
+  },
+  breakOnCaughtException: {
+    getValue: function() { return Debug.isBreakOnException(); },
+    setValue: function(value) {
+      if (value) {
+        Debug.setBreakOnException();
+      } else {
+        Debug.clearBreakOnException();
+      }
+    }
+  },
+  breakOnUncaughtException: {
+    getValue: function() { return Debug.isBreakOnUncaughtException(); },
+    setValue: function(value) {
+      if (value) {
+        Debug.setBreakOnUncaughtException();
+      } else {
+        Debug.clearBreakOnUncaughtException();
+      }
+    }
+  },
+};
+
+
+// Create a new break point object and add it to the list of break points.
+function MakeBreakPoint(source_position, opt_script_break_point) {
+  var break_point = new BreakPoint(source_position, opt_script_break_point);
+  break_points.push(break_point);
+  return break_point;
+}
+
+
+// Object representing a break point.
+// NOTE: This object does not have a reference to the function having break
+// point as this would cause function not to be garbage collected when it is
+// not used any more. We do not want break points to keep functions alive.
+function BreakPoint(source_position, opt_script_break_point) {
+  this.source_position_ = source_position;
+  if (opt_script_break_point) {
+    this.script_break_point_ = opt_script_break_point;
+  } else {
+    this.number_ = next_break_point_number++;
+  }
+  this.hit_count_ = 0;
+  this.active_ = true;
+  this.condition_ = null;
+  this.ignoreCount_ = 0;
+}
+
+
+BreakPoint.prototype.number = function() {
+  return this.number_;
+};
+
+
+BreakPoint.prototype.func = function() {
+  return this.func_;
+};
+
+
+BreakPoint.prototype.source_position = function() {
+  return this.source_position_;
+};
+
+
+BreakPoint.prototype.hit_count = function() {
+  return this.hit_count_;
+};
+
+
+BreakPoint.prototype.active = function() {
+  if (this.script_break_point()) {
+    return this.script_break_point().active();
+  }
+  return this.active_;
+};
+
+
+BreakPoint.prototype.condition = function() {
+  if (this.script_break_point() && this.script_break_point().condition()) {
+    return this.script_break_point().condition();
+  }
+  return this.condition_;
+};
+
+
+BreakPoint.prototype.ignoreCount = function() {
+  return this.ignoreCount_;
+};
+
+
+BreakPoint.prototype.script_break_point = function() {
+  return this.script_break_point_;
+};
+
+
+BreakPoint.prototype.enable = function() {
+  this.active_ = true;
+};
+
+
+BreakPoint.prototype.disable = function() {
+  this.active_ = false;
+};
+
+
+BreakPoint.prototype.setCondition = function(condition) {
+  this.condition_ = condition;
+};
+
+
+BreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
+  this.ignoreCount_ = ignoreCount;
+};
+
+
+BreakPoint.prototype.isTriggered = function(exec_state) {
+  // Break point not active - not triggered.
+  if (!this.active()) return false;
+
+  // Check for conditional break point.
+  if (this.condition()) {
+    // If break point has condition try to evaluate it in the top frame.
+    try {
+      var mirror = exec_state.frame(0).evaluate(this.condition());
+      // If no sensible mirror or non true value break point not triggered.
+      if (!(mirror instanceof ValueMirror) || !mirror.value_) {
+        return false;
+      }
+    } catch (e) {
+      // Exception evaluating condition counts as not triggered.
+      return false;
+    }
+  }
+
+  // Update the hit count.
+  this.hit_count_++;
+  if (this.script_break_point_) {
+    this.script_break_point_.hit_count_++;
+  }
+
+  // If the break point has an ignore count it is not triggered.
+  if (this.ignoreCount_ > 0) {
+    this.ignoreCount_--;
+    return false;
+  }
+
+  // Break point triggered.
+  return true;
+};
+
+
+// Function called from the runtime when a break point is hit. Returns true if
+// the break point is triggered and supposed to break execution.
+function IsBreakPointTriggered(break_id, break_point) {
+  return break_point.isTriggered(MakeExecutionState(break_id));
+}
+
+
+// Object representing a script break point. The script is referenced by its
+// script name or script id and the break point is represented as line and
+// column.
+function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
+                          opt_groupId, opt_position_alignment) {
+  this.type_ = type;
+  if (type == Debug.ScriptBreakPointType.ScriptId) {
+    this.script_id_ = script_id_or_name;
+  } else if (type == Debug.ScriptBreakPointType.ScriptName) {
+    this.script_name_ = script_id_or_name;
+  } else if (type == Debug.ScriptBreakPointType.ScriptRegExp) {
+    this.script_regexp_object_ = new GlobalRegExp(script_id_or_name);
+  } else {
+    throw MakeError(kDebugger, "Unexpected breakpoint type " + type);
+  }
+  this.line_ = opt_line || 0;
+  this.column_ = opt_column;
+  this.groupId_ = opt_groupId;
+  this.position_alignment_ = IS_UNDEFINED(opt_position_alignment)
+      ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
+  this.hit_count_ = 0;
+  this.active_ = true;
+  this.condition_ = null;
+  this.ignoreCount_ = 0;
+  this.break_points_ = [];
+}
+
+
+// Creates a clone of script breakpoint that is linked to another script.
+ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
+  var copy = new ScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
+      other_script.id, this.line_, this.column_, this.groupId_,
+      this.position_alignment_);
+  copy.number_ = next_break_point_number++;
+  script_break_points.push(copy);
+
+  copy.hit_count_ = this.hit_count_;
+  copy.active_ = this.active_;
+  copy.condition_ = this.condition_;
+  copy.ignoreCount_ = this.ignoreCount_;
+  return copy;
+};
+
+
+ScriptBreakPoint.prototype.number = function() {
+  return this.number_;
+};
+
+
+ScriptBreakPoint.prototype.groupId = function() {
+  return this.groupId_;
+};
+
+
+ScriptBreakPoint.prototype.type = function() {
+  return this.type_;
+};
+
+
+ScriptBreakPoint.prototype.script_id = function() {
+  return this.script_id_;
+};
+
+
+ScriptBreakPoint.prototype.script_name = function() {
+  return this.script_name_;
+};
+
+
+ScriptBreakPoint.prototype.script_regexp_object = function() {
+  return this.script_regexp_object_;
+};
+
+
+ScriptBreakPoint.prototype.line = function() {
+  return this.line_;
+};
+
+
+ScriptBreakPoint.prototype.column = function() {
+  return this.column_;
+};
+
+
+ScriptBreakPoint.prototype.actual_locations = function() {
+  var locations = [];
+  for (var i = 0; i < this.break_points_.length; i++) {
+    locations.push(this.break_points_[i].actual_location);
+  }
+  return locations;
+};
+
+
+ScriptBreakPoint.prototype.update_positions = function(line, column) {
+  this.line_ = line;
+  this.column_ = column;
+};
+
+
+ScriptBreakPoint.prototype.hit_count = function() {
+  return this.hit_count_;
+};
+
+
+ScriptBreakPoint.prototype.active = function() {
+  return this.active_;
+};
+
+
+ScriptBreakPoint.prototype.condition = function() {
+  return this.condition_;
+};
+
+
+ScriptBreakPoint.prototype.ignoreCount = function() {
+  return this.ignoreCount_;
+};
+
+
+ScriptBreakPoint.prototype.enable = function() {
+  this.active_ = true;
+};
+
+
+ScriptBreakPoint.prototype.disable = function() {
+  this.active_ = false;
+};
+
+
+ScriptBreakPoint.prototype.setCondition = function(condition) {
+  this.condition_ = condition;
+};
+
+
+ScriptBreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
+  this.ignoreCount_ = ignoreCount;
+
+  // Set ignore count on all break points created from this script break point.
+  for (var i = 0; i < this.break_points_.length; i++) {
+    this.break_points_[i].setIgnoreCount(ignoreCount);
+  }
+};
+
+
+// Check whether a script matches this script break point. Currently this is
+// only based on script name.
+ScriptBreakPoint.prototype.matchesScript = function(script) {
+  if (this.type_ == Debug.ScriptBreakPointType.ScriptId) {
+    return this.script_id_ == script.id;
+  } else {
+    // We might want to account columns here as well.
+    if (!(script.line_offset <= this.line_  &&
+          this.line_ < script.line_offset + script.lineCount())) {
+      return false;
+    }
+    if (this.type_ == Debug.ScriptBreakPointType.ScriptName) {
+      return this.script_name_ == script.nameOrSourceURL();
+    } else if (this.type_ == Debug.ScriptBreakPointType.ScriptRegExp) {
+      return this.script_regexp_object_.test(script.nameOrSourceURL());
+    } else {
+      throw MakeError(kDebugger, "Unexpected breakpoint type " + this.type_);
+    }
+  }
+};
+
+
+// Set the script break point in a script.
+ScriptBreakPoint.prototype.set = function (script) {
+  var column = this.column();
+  var line = this.line();
+  // If the column is undefined the break is on the line. To help locate the
+  // first piece of breakable code on the line try to find the column on the
+  // line which contains some source.
+  if (IS_UNDEFINED(column)) {
+    var source_line = script.sourceLine(this.line());
+
+    // Allocate array for caching the columns where the actual source starts.
+    if (!script.sourceColumnStart_) {
+      script.sourceColumnStart_ = new GlobalArray(script.lineCount());
+    }
+
+    // Fill cache if needed and get column where the actual source starts.
+    if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
+      script.sourceColumnStart_[line] =
+          source_line.match(sourceLineBeginningSkip)[0].length;
+    }
+    column = script.sourceColumnStart_[line];
+  }
+
+  // Convert the line and column into an absolute position within the script.
+  var position = Debug.findScriptSourcePosition(script, this.line(), column);
+
+  // If the position is not found in the script (the script might be shorter
+  // than it used to be) just ignore it.
+  if (IS_NULL(position)) return;
+
+  // Create a break point object and set the break point.
+  var break_point = MakeBreakPoint(position, this);
+  break_point.setIgnoreCount(this.ignoreCount());
+  var actual_position = %SetScriptBreakPoint(script, position,
+                                             this.position_alignment_,
+                                             break_point);
+  if (IS_UNDEFINED(actual_position)) {
+    actual_position = position;
+  }
+  var actual_location = script.locationFromPosition(actual_position, true);
+  break_point.actual_location = { line: actual_location.line,
+                                  column: actual_location.column,
+                                  script_id: script.id };
+  this.break_points_.push(break_point);
+  return break_point;
+};
+
+
+// Clear all the break points created from this script break point
+ScriptBreakPoint.prototype.clear = function () {
+  var remaining_break_points = [];
+  for (var i = 0; i < break_points.length; i++) {
+    if (break_points[i].script_break_point() &&
+        break_points[i].script_break_point() === this) {
+      %ClearBreakPoint(break_points[i]);
+    } else {
+      remaining_break_points.push(break_points[i]);
+    }
+  }
+  break_points = remaining_break_points;
+  this.break_points_ = [];
+};
+
+
+// Function called from runtime when a new script is compiled to set any script
+// break points set in this script.
+function UpdateScriptBreakPoints(script) {
+  for (var i = 0; i < script_break_points.length; i++) {
+    var break_point = script_break_points[i];
+    if ((break_point.type() == Debug.ScriptBreakPointType.ScriptName ||
+         break_point.type() == Debug.ScriptBreakPointType.ScriptRegExp) &&
+        break_point.matchesScript(script)) {
+      break_point.set(script);
+    }
+  }
+}
+
+
+function GetScriptBreakPoints(script) {
+  var result = [];
+  for (var i = 0; i < script_break_points.length; i++) {
+    if (script_break_points[i].matchesScript(script)) {
+      result.push(script_break_points[i]);
+    }
+  }
+  return result;
+}
+
+
+Debug.setListener = function(listener, opt_data) {
+  if (!IS_FUNCTION(listener) && !IS_UNDEFINED(listener) && !IS_NULL(listener)) {
+    throw MakeTypeError(kDebuggerType);
+  }
+  %SetDebugEventListener(listener, opt_data);
+};
+
+
+Debug.breakLocations = function(f, opt_position_aligment) {
+  if (!IS_FUNCTION(f)) throw MakeTypeError(kDebuggerType);
+  var position_aligment = IS_UNDEFINED(opt_position_aligment)
+      ? Debug.BreakPositionAlignment.Statement : opt_position_aligment;
+  return %GetBreakLocations(f, position_aligment);
+};
+
+// Returns a Script object. If the parameter is a function the return value
+// is the script in which the function is defined. If the parameter is a string
+// the return value is the script for which the script name has that string
+// value.  If it is a regexp and there is a unique script whose name matches
+// we return that, otherwise undefined.
+Debug.findScript = function(func_or_script_name) {
+  if (IS_FUNCTION(func_or_script_name)) {
+    return %FunctionGetScript(func_or_script_name);
+  } else if (IS_REGEXP(func_or_script_name)) {
+    var scripts = Debug.scripts();
+    var last_result = null;
+    var result_count = 0;
+    for (var i in scripts) {
+      var script = scripts[i];
+      if (func_or_script_name.test(script.name)) {
+        last_result = script;
+        result_count++;
+      }
+    }
+    // Return the unique script matching the regexp.  If there are more
+    // than one we don't return a value since there is no good way to
+    // decide which one to return.  Returning a "random" one, say the
+    // first, would introduce nondeterminism (or something close to it)
+    // because the order is the heap iteration order.
+    if (result_count == 1) {
+      return last_result;
+    } else {
+      return UNDEFINED;
+    }
+  } else {
+    return %GetScript(func_or_script_name);
+  }
+};
+
+// Returns the script source. If the parameter is a function the return value
+// is the script source for the script in which the function is defined. If the
+// parameter is a string the return value is the script for which the script
+// name has that string value.
+Debug.scriptSource = function(func_or_script_name) {
+  return this.findScript(func_or_script_name).source;
+};
+
+
+Debug.source = function(f) {
+  if (!IS_FUNCTION(f)) throw MakeTypeError(kDebuggerType);
+  return %FunctionGetSourceCode(f);
+};
+
+
+Debug.sourcePosition = function(f) {
+  if (!IS_FUNCTION(f)) throw MakeTypeError(kDebuggerType);
+  return %FunctionGetScriptSourcePosition(f);
+};
+
+
+Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
+  var script = %FunctionGetScript(func);
+  var script_offset = %FunctionGetScriptSourcePosition(func);
+  return script.locationFromLine(opt_line, opt_column, script_offset);
+};
+
+
+// Returns the character position in a script based on a line number and an
+// optional position within that line.
+Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
+  var location = script.locationFromLine(opt_line, opt_column);
+  return location ? location.position : null;
+};
+
+
+Debug.findBreakPoint = function(break_point_number, remove) {
+  var break_point;
+  for (var i = 0; i < break_points.length; i++) {
+    if (break_points[i].number() == break_point_number) {
+      break_point = break_points[i];
+      // Remove the break point from the list if requested.
+      if (remove) {
+        break_points.splice(i, 1);
+      }
+      break;
+    }
+  }
+  if (break_point) {
+    return break_point;
+  } else {
+    return this.findScriptBreakPoint(break_point_number, remove);
+  }
+};
+
+Debug.findBreakPointActualLocations = function(break_point_number) {
+  for (var i = 0; i < script_break_points.length; i++) {
+    if (script_break_points[i].number() == break_point_number) {
+      return script_break_points[i].actual_locations();
+    }
+  }
+  for (var i = 0; i < break_points.length; i++) {
+    if (break_points[i].number() == break_point_number) {
+      return [break_points[i].actual_location];
+    }
+  }
+  return [];
+};
+
+Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
+  if (!IS_FUNCTION(func)) throw MakeTypeError(kDebuggerType);
+  // Break points in API functions are not supported.
+  if (%FunctionIsAPIFunction(func)) {
+    throw MakeError(kDebugger, 'Cannot set break point in native code.');
+  }
+  // Find source position relative to start of the function
+  var break_position =
+      this.findFunctionSourceLocation(func, opt_line, opt_column).position;
+  var source_position = break_position - this.sourcePosition(func);
+  // Find the script for the function.
+  var script = %FunctionGetScript(func);
+  // Break in builtin JavaScript code is not supported.
+  if (script.type == Debug.ScriptType.Native) {
+    throw MakeError(kDebugger, 'Cannot set break point in native code.');
+  }
+  // If the script for the function has a name convert this to a script break
+  // point.
+  if (script && script.id) {
+    // Adjust the source position to be script relative.
+    source_position += %FunctionGetScriptSourcePosition(func);
+    // Find line and column for the position in the script and set a script
+    // break point from that.
+    var location = script.locationFromPosition(source_position, false);
+    return this.setScriptBreakPointById(script.id,
+                                        location.line, location.column,
+                                        opt_condition);
+  } else {
+    // Set a break point directly on the function.
+    var break_point = MakeBreakPoint(source_position);
+    var actual_position =
+        %SetFunctionBreakPoint(func, source_position, break_point);
+    actual_position += this.sourcePosition(func);
+    var actual_location = script.locationFromPosition(actual_position, true);
+    break_point.actual_location = { line: actual_location.line,
+                                    column: actual_location.column,
+                                    script_id: script.id };
+    break_point.setCondition(opt_condition);
+    return break_point.number();
+  }
+};
+
+
+Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
+                                                    condition, enabled,
+                                                    opt_position_alignment)
+{
+  var break_point = MakeBreakPoint(position);
+  break_point.setCondition(condition);
+  if (!enabled) {
+    break_point.disable();
+  }
+  var scripts = this.scripts();
+  var position_alignment = IS_UNDEFINED(opt_position_alignment)
+      ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
+  for (var i = 0; i < scripts.length; i++) {
+    if (script_id == scripts[i].id) {
+      break_point.actual_position = %SetScriptBreakPoint(scripts[i], position,
+          position_alignment, break_point);
+      break;
+    }
+  }
+  return break_point;
+};
+
+
+Debug.enableBreakPoint = function(break_point_number) {
+  var break_point = this.findBreakPoint(break_point_number, false);
+  // Only enable if the breakpoint hasn't been deleted:
+  if (break_point) {
+    break_point.enable();
+  }
+};
+
+
+Debug.disableBreakPoint = function(break_point_number) {
+  var break_point = this.findBreakPoint(break_point_number, false);
+  // Only enable if the breakpoint hasn't been deleted:
+  if (break_point) {
+    break_point.disable();
+  }
+};
+
+
+Debug.changeBreakPointCondition = function(break_point_number, condition) {
+  var break_point = this.findBreakPoint(break_point_number, false);
+  break_point.setCondition(condition);
+};
+
+
+Debug.changeBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
+  if (ignoreCount < 0) throw MakeError(kDebugger, 'Invalid argument');
+  var break_point = this.findBreakPoint(break_point_number, false);
+  break_point.setIgnoreCount(ignoreCount);
+};
+
+
+Debug.clearBreakPoint = function(break_point_number) {
+  var break_point = this.findBreakPoint(break_point_number, true);
+  if (break_point) {
+    return %ClearBreakPoint(break_point);
+  } else {
+    break_point = this.findScriptBreakPoint(break_point_number, true);
+    if (!break_point) throw MakeError(kDebugger, 'Invalid breakpoint');
+  }
+};
+
+
+Debug.clearAllBreakPoints = function() {
+  for (var i = 0; i < break_points.length; i++) {
+    var break_point = break_points[i];
+    %ClearBreakPoint(break_point);
+  }
+  break_points = [];
+};
+
+
+Debug.disableAllBreakPoints = function() {
+  // Disable all user defined breakpoints:
+  for (var i = 1; i < next_break_point_number; i++) {
+    Debug.disableBreakPoint(i);
+  }
+  // Disable all exception breakpoints:
+  %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
+  %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
+};
+
+
+Debug.findScriptBreakPoint = function(break_point_number, remove) {
+  var script_break_point;
+  for (var i = 0; i < script_break_points.length; i++) {
+    if (script_break_points[i].number() == break_point_number) {
+      script_break_point = script_break_points[i];
+      // Remove the break point from the list if requested.
+      if (remove) {
+        script_break_point.clear();
+        script_break_points.splice(i,1);
+      }
+      break;
+    }
+  }
+  return script_break_point;
+};
+
+
+// Sets a breakpoint in a script identified through id or name at the
+// specified source line and column within that line.
+Debug.setScriptBreakPoint = function(type, script_id_or_name,
+                                     opt_line, opt_column, opt_condition,
+                                     opt_groupId, opt_position_alignment) {
+  // Create script break point object.
+  var script_break_point =
+      new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
+                           opt_groupId, opt_position_alignment);
+
+  // Assign number to the new script break point and add it.
+  script_break_point.number_ = next_break_point_number++;
+  script_break_point.setCondition(opt_condition);
+  script_break_points.push(script_break_point);
+
+  // Run through all scripts to see if this script break point matches any
+  // loaded scripts.
+  var scripts = this.scripts();
+  for (var i = 0; i < scripts.length; i++) {
+    if (script_break_point.matchesScript(scripts[i])) {
+      script_break_point.set(scripts[i]);
+    }
+  }
+
+  return script_break_point.number();
+};
+
+
+Debug.setScriptBreakPointById = function(script_id,
+                                         opt_line, opt_column,
+                                         opt_condition, opt_groupId,
+                                         opt_position_alignment) {
+  return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
+                                  script_id, opt_line, opt_column,
+                                  opt_condition, opt_groupId,
+                                  opt_position_alignment);
+};
+
+
+Debug.setScriptBreakPointByName = function(script_name,
+                                           opt_line, opt_column,
+                                           opt_condition, opt_groupId) {
+  return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
+                                  script_name, opt_line, opt_column,
+                                  opt_condition, opt_groupId);
+};
+
+
+Debug.setScriptBreakPointByRegExp = function(script_regexp,
+                                             opt_line, opt_column,
+                                             opt_condition, opt_groupId) {
+  return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptRegExp,
+                                  script_regexp, opt_line, opt_column,
+                                  opt_condition, opt_groupId);
+};
+
+
+Debug.enableScriptBreakPoint = function(break_point_number) {
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.enable();
+};
+
+
+Debug.disableScriptBreakPoint = function(break_point_number) {
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.disable();
+};
+
+
+Debug.changeScriptBreakPointCondition = function(
+    break_point_number, condition) {
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.setCondition(condition);
+};
+
+
+Debug.changeScriptBreakPointIgnoreCount = function(
+    break_point_number, ignoreCount) {
+  if (ignoreCount < 0) throw MakeError(kDebugger, 'Invalid argument');
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.setIgnoreCount(ignoreCount);
+};
+
+
+Debug.scriptBreakPoints = function() {
+  return script_break_points;
+};
+
+
+Debug.clearStepping = function() {
+  %ClearStepping();
+};
+
+Debug.setBreakOnException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true);
+};
+
+Debug.clearBreakOnException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
+};
+
+Debug.isBreakOnException = function() {
+  return !!%IsBreakOnException(Debug.ExceptionBreak.Caught);
+};
+
+Debug.setBreakOnUncaughtException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, true);
+};
+
+Debug.clearBreakOnUncaughtException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
+};
+
+Debug.isBreakOnUncaughtException = function() {
+  return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
+};
+
+Debug.showBreakPoints = function(f, full, opt_position_alignment) {
+  if (!IS_FUNCTION(f)) throw MakeError(kDebuggerType);
+  var source = full ? this.scriptSource(f) : this.source(f);
+  var offset = full ? this.sourcePosition(f) : 0;
+  var locations = this.breakLocations(f, opt_position_alignment);
+  if (!locations) return source;
+  locations.sort(function(x, y) { return x - y; });
+  var result = "";
+  var prev_pos = 0;
+  var pos;
+  for (var i = 0; i < locations.length; i++) {
+    pos = locations[i] - offset;
+    result += source.slice(prev_pos, pos);
+    result += "[B" + i + "]";
+    prev_pos = pos;
+  }
+  pos = source.length;
+  result += source.substring(prev_pos, pos);
+  return result;
+};
+
+
+// Get all the scripts currently loaded. Locating all the scripts is based on
+// scanning the heap.
+Debug.scripts = function() {
+  // Collect all scripts in the heap.
+  return %DebugGetLoadedScripts();
+};
+
+
+Debug.debuggerFlags = function() {
+  return debugger_flags;
+};
+
+Debug.MakeMirror = MakeMirror;
+
+function MakeExecutionState(break_id) {
+  return new ExecutionState(break_id);
+}
+
+function ExecutionState(break_id) {
+  this.break_id = break_id;
+  this.selected_frame = 0;
+}
+
+ExecutionState.prototype.prepareStep = function(action) {
+  if (action === Debug.StepAction.StepIn ||
+      action === Debug.StepAction.StepOut ||
+      action === Debug.StepAction.StepNext ||
+      action === Debug.StepAction.StepFrame) {
+    return %PrepareStep(this.break_id, action);
+  }
+  throw MakeTypeError(kDebuggerType);
+};
+
+ExecutionState.prototype.evaluateGlobal = function(source, disable_break,
+    opt_additional_context) {
+  return MakeMirror(%DebugEvaluateGlobal(this.break_id, source,
+                                         TO_BOOLEAN(disable_break),
+                                         opt_additional_context));
+};
+
+ExecutionState.prototype.frameCount = function() {
+  return %GetFrameCount(this.break_id);
+};
+
+ExecutionState.prototype.threadCount = function() {
+  return %GetThreadCount(this.break_id);
+};
+
+ExecutionState.prototype.frame = function(opt_index) {
+  // If no index supplied return the selected frame.
+  if (opt_index == null) opt_index = this.selected_frame;
+  if (opt_index < 0 || opt_index >= this.frameCount()) {
+    throw MakeTypeError(kDebuggerFrame);
+  }
+  return new FrameMirror(this.break_id, opt_index);
+};
+
+ExecutionState.prototype.setSelectedFrame = function(index) {
+  var i = TO_NUMBER(index);
+  if (i < 0 || i >= this.frameCount()) {
+    throw MakeTypeError(kDebuggerFrame);
+  }
+  this.selected_frame = i;
+};
+
+ExecutionState.prototype.selectedFrame = function() {
+  return this.selected_frame;
+};
+
+ExecutionState.prototype.debugCommandProcessor = function(opt_is_running) {
+  return new DebugCommandProcessor(this, opt_is_running);
+};
+
+
+function MakeBreakEvent(break_id, break_points_hit) {
+  return new BreakEvent(break_id, break_points_hit);
+}
+
+
+function BreakEvent(break_id, break_points_hit) {
+  this.frame_ = new FrameMirror(break_id, 0);
+  this.break_points_hit_ = break_points_hit;
+}
+
+
+BreakEvent.prototype.eventType = function() {
+  return Debug.DebugEvent.Break;
+};
+
+
+BreakEvent.prototype.func = function() {
+  return this.frame_.func();
+};
+
+
+BreakEvent.prototype.sourceLine = function() {
+  return this.frame_.sourceLine();
+};
+
+
+BreakEvent.prototype.sourceColumn = function() {
+  return this.frame_.sourceColumn();
+};
+
+
+BreakEvent.prototype.sourceLineText = function() {
+  return this.frame_.sourceLineText();
+};
+
+
+BreakEvent.prototype.breakPointsHit = function() {
+  return this.break_points_hit_;
+};
+
+
+BreakEvent.prototype.toJSONProtocol = function() {
+  var o = { seq: next_response_seq++,
+            type: "event",
+            event: "break",
+            body: { invocationText: this.frame_.invocationText() }
+          };
+
+  // Add script related information to the event if available.
+  var script = this.func().script();
+  if (script) {
+    o.body.sourceLine = this.sourceLine(),
+    o.body.sourceColumn = this.sourceColumn(),
+    o.body.sourceLineText = this.sourceLineText(),
+    o.body.script = MakeScriptObject_(script, false);
+  }
+
+  // Add an Array of break points hit if any.
+  if (this.breakPointsHit()) {
+    o.body.breakpoints = [];
+    for (var i = 0; i < this.breakPointsHit().length; i++) {
+      // Find the break point number. For break points originating from a
+      // script break point supply the script break point number.
+      var breakpoint = this.breakPointsHit()[i];
+      var script_break_point = breakpoint.script_break_point();
+      var number;
+      if (script_break_point) {
+        number = script_break_point.number();
+      } else {
+        number = breakpoint.number();
+      }
+      o.body.breakpoints.push(number);
+    }
+  }
+  return JSONStringify(ObjectToProtocolObject_(o));
+};
+
+
+function MakeExceptionEvent(break_id, exception, uncaught, promise) {
+  return new ExceptionEvent(break_id, exception, uncaught, promise);
+}
+
+
+function ExceptionEvent(break_id, exception, uncaught, promise) {
+  this.exec_state_ = new ExecutionState(break_id);
+  this.exception_ = exception;
+  this.uncaught_ = uncaught;
+  this.promise_ = promise;
+}
+
+
+ExceptionEvent.prototype.eventType = function() {
+  return Debug.DebugEvent.Exception;
+};
+
+
+ExceptionEvent.prototype.exception = function() {
+  return this.exception_;
+};
+
+
+ExceptionEvent.prototype.uncaught = function() {
+  return this.uncaught_;
+};
+
+
+ExceptionEvent.prototype.promise = function() {
+  return this.promise_;
+};
+
+
+ExceptionEvent.prototype.func = function() {
+  return this.exec_state_.frame(0).func();
+};
+
+
+ExceptionEvent.prototype.sourceLine = function() {
+  return this.exec_state_.frame(0).sourceLine();
+};
+
+
+ExceptionEvent.prototype.sourceColumn = function() {
+  return this.exec_state_.frame(0).sourceColumn();
+};
+
+
+ExceptionEvent.prototype.sourceLineText = function() {
+  return this.exec_state_.frame(0).sourceLineText();
+};
+
+
+ExceptionEvent.prototype.toJSONProtocol = function() {
+  var o = new ProtocolMessage();
+  o.event = "exception";
+  o.body = { uncaught: this.uncaught_,
+             exception: MakeMirror(this.exception_)
+           };
+
+  // Exceptions might happen whithout any JavaScript frames.
+  if (this.exec_state_.frameCount() > 0) {
+    o.body.sourceLine = this.sourceLine();
+    o.body.sourceColumn = this.sourceColumn();
+    o.body.sourceLineText = this.sourceLineText();
+
+    // Add script information to the event if available.
+    var script = this.func().script();
+    if (script) {
+      o.body.script = MakeScriptObject_(script, false);
+    }
+  } else {
+    o.body.sourceLine = -1;
+  }
+
+  return o.toJSONProtocol();
+};
+
+
+function MakeCompileEvent(script, type) {
+  return new CompileEvent(script, type);
+}
+
+
+function CompileEvent(script, type) {
+  this.script_ = MakeMirror(script);
+  this.type_ = type;
+}
+
+
+CompileEvent.prototype.eventType = function() {
+  return this.type_;
+};
+
+
+CompileEvent.prototype.script = function() {
+  return this.script_;
+};
+
+
+CompileEvent.prototype.toJSONProtocol = function() {
+  var o = new ProtocolMessage();
+  o.running = true;
+  switch (this.type_) {
+    case Debug.DebugEvent.BeforeCompile:
+      o.event = "beforeCompile";
+      break;
+    case Debug.DebugEvent.AfterCompile:
+      o.event = "afterCompile";
+      break;
+    case Debug.DebugEvent.CompileError:
+      o.event = "compileError";
+      break;
+  }
+  o.body = {};
+  o.body.script = this.script_;
+
+  return o.toJSONProtocol();
+};
+
+
+function MakeScriptObject_(script, include_source) {
+  var o = { id: script.id(),
+            name: script.name(),
+            lineOffset: script.lineOffset(),
+            columnOffset: script.columnOffset(),
+            lineCount: script.lineCount(),
+          };
+  if (!IS_UNDEFINED(script.data())) {
+    o.data = script.data();
+  }
+  if (include_source) {
+    o.source = script.source();
+  }
+  return o;
+}
+
+
+function MakePromiseEvent(event_data) {
+  return new PromiseEvent(event_data);
+}
+
+
+function PromiseEvent(event_data) {
+  this.promise_ = event_data.promise;
+  this.parentPromise_ = event_data.parentPromise;
+  this.status_ = event_data.status;
+  this.value_ = event_data.value;
+}
+
+
+PromiseEvent.prototype.promise = function() {
+  return MakeMirror(this.promise_);
+}
+
+
+PromiseEvent.prototype.parentPromise = function() {
+  return MakeMirror(this.parentPromise_);
+}
+
+
+PromiseEvent.prototype.status = function() {
+  return this.status_;
+}
+
+
+PromiseEvent.prototype.value = function() {
+  return MakeMirror(this.value_);
+}
+
+
+function MakeAsyncTaskEvent(event_data) {
+  return new AsyncTaskEvent(event_data);
+}
+
+
+function AsyncTaskEvent(event_data) {
+  this.type_ = event_data.type;
+  this.name_ = event_data.name;
+  this.id_ = event_data.id;
+}
+
+
+AsyncTaskEvent.prototype.type = function() {
+  return this.type_;
+}
+
+
+AsyncTaskEvent.prototype.name = function() {
+  return this.name_;
+}
+
+
+AsyncTaskEvent.prototype.id = function() {
+  return this.id_;
+}
+
+
+function DebugCommandProcessor(exec_state, opt_is_running) {
+  this.exec_state_ = exec_state;
+  this.running_ = opt_is_running || false;
+}
+
+
+DebugCommandProcessor.prototype.processDebugRequest = function (request) {
+  return this.processDebugJSONRequest(request);
+};
+
+
+function ProtocolMessage(request) {
+  // Update sequence number.
+  this.seq = next_response_seq++;
+
+  if (request) {
+    // If message is based on a request this is a response. Fill the initial
+    // response from the request.
+    this.type = 'response';
+    this.request_seq = request.seq;
+    this.command = request.command;
+  } else {
+    // If message is not based on a request it is a dabugger generated event.
+    this.type = 'event';
+  }
+  this.success = true;
+  // Handler may set this field to control debugger state.
+  this.running = UNDEFINED;
+}
+
+
+ProtocolMessage.prototype.setOption = function(name, value) {
+  if (!this.options_) {
+    this.options_ = {};
+  }
+  this.options_[name] = value;
+};
+
+
+ProtocolMessage.prototype.failed = function(message, opt_details) {
+  this.success = false;
+  this.message = message;
+  if (IS_OBJECT(opt_details)) {
+    this.error_details = opt_details;
+  }
+};
+
+
+ProtocolMessage.prototype.toJSONProtocol = function() {
+  // Encode the protocol header.
+  var json = {};
+  json.seq= this.seq;
+  if (this.request_seq) {
+    json.request_seq = this.request_seq;
+  }
+  json.type = this.type;
+  if (this.event) {
+    json.event = this.event;
+  }
+  if (this.command) {
+    json.command = this.command;
+  }
+  if (this.success) {
+    json.success = this.success;
+  } else {
+    json.success = false;
+  }
+  if (this.body) {
+    // Encode the body part.
+    var bodyJson;
+    var serializer = MakeMirrorSerializer(true, this.options_);
+    if (this.body instanceof Mirror) {
+      bodyJson = serializer.serializeValue(this.body);
+    } else if (this.body instanceof GlobalArray) {
+      bodyJson = [];
+      for (var i = 0; i < this.body.length; i++) {
+        if (this.body[i] instanceof Mirror) {
+          bodyJson.push(serializer.serializeValue(this.body[i]));
+        } else {
+          bodyJson.push(ObjectToProtocolObject_(this.body[i], serializer));
+        }
+      }
+    } else {
+      bodyJson = ObjectToProtocolObject_(this.body, serializer);
+    }
+    json.body = bodyJson;
+    json.refs = serializer.serializeReferencedObjects();
+  }
+  if (this.message) {
+    json.message = this.message;
+  }
+  if (this.error_details) {
+    json.error_details = this.error_details;
+  }
+  json.running = this.running;
+  return JSONStringify(json);
+};
+
+
+DebugCommandProcessor.prototype.createResponse = function(request) {
+  return new ProtocolMessage(request);
+};
+
+
+DebugCommandProcessor.prototype.processDebugJSONRequest = function(
+    json_request) {
+  var request;  // Current request.
+  var response;  // Generated response.
+  try {
+    try {
+      // Convert the JSON string to an object.
+      request = JSONParse(json_request);
+
+      // Create an initial response.
+      response = this.createResponse(request);
+
+      if (!request.type) {
+        throw MakeError(kDebugger, 'Type not specified');
+      }
+
+      if (request.type != 'request') {
+        throw MakeError(kDebugger,
+                        "Illegal type '" + request.type + "' in request");
+      }
+
+      if (!request.command) {
+        throw MakeError(kDebugger, 'Command not specified');
+      }
+
+      if (request.arguments) {
+        var args = request.arguments;
+        // TODO(yurys): remove request.arguments.compactFormat check once
+        // ChromeDevTools are switched to 'inlineRefs'
+        if (args.inlineRefs || args.compactFormat) {
+          response.setOption('inlineRefs', true);
+        }
+        if (!IS_UNDEFINED(args.maxStringLength)) {
+          response.setOption('maxStringLength', args.maxStringLength);
+        }
+      }
+
+      var key = request.command.toLowerCase();
+      var handler = DebugCommandProcessor.prototype.dispatch_[key];
+      if (IS_FUNCTION(handler)) {
+        %_Call(handler, this, request, response);
+      } else {
+        throw MakeError(kDebugger,
+                        'Unknown command "' + request.command + '" in request');
+      }
+    } catch (e) {
+      // If there is no response object created one (without command).
+      if (!response) {
+        response = this.createResponse();
+      }
+      response.success = false;
+      response.message = TO_STRING(e);
+    }
+
+    // Return the response as a JSON encoded string.
+    try {
+      if (!IS_UNDEFINED(response.running)) {
+        // Response controls running state.
+        this.running_ = response.running;
+      }
+      response.running = this.running_;
+      return response.toJSONProtocol();
+    } catch (e) {
+      // Failed to generate response - return generic error.
+      return '{"seq":' + response.seq + ',' +
+              '"request_seq":' + request.seq + ',' +
+              '"type":"response",' +
+              '"success":false,' +
+              '"message":"Internal error: ' + TO_STRING(e) + '"}';
+    }
+  } catch (e) {
+    // Failed in one of the catch blocks above - most generic error.
+    return '{"seq":0,"type":"response","success":false,"message":"Internal error"}';
+  }
+};
+
+
+DebugCommandProcessor.prototype.continueRequest_ = function(request, response) {
+  // Check for arguments for continue.
+  if (request.arguments) {
+    var action = Debug.StepAction.StepIn;
+
+    // Pull out arguments.
+    var stepaction = request.arguments.stepaction;
+
+    // Get the stepaction argument.
+    if (stepaction) {
+      if (stepaction == 'in') {
+        action = Debug.StepAction.StepIn;
+      } else if (stepaction == 'next') {
+        action = Debug.StepAction.StepNext;
+      } else if (stepaction == 'out') {
+        action = Debug.StepAction.StepOut;
+      } else {
+        throw MakeError(kDebugger,
+                        'Invalid stepaction argument "' + stepaction + '".');
+      }
+    }
+
+    // Set up the VM for stepping.
+    this.exec_state_.prepareStep(action);
+  }
+
+  // VM should be running after executing this request.
+  response.running = true;
+};
+
+
+DebugCommandProcessor.prototype.breakRequest_ = function(request, response) {
+  // Ignore as break command does not do anything when broken.
+};
+
+
+DebugCommandProcessor.prototype.setBreakPointRequest_ =
+    function(request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var type = request.arguments.type;
+  var target = request.arguments.target;
+  var line = request.arguments.line;
+  var column = request.arguments.column;
+  var enabled = IS_UNDEFINED(request.arguments.enabled) ?
+      true : request.arguments.enabled;
+  var condition = request.arguments.condition;
+  var ignoreCount = request.arguments.ignoreCount;
+  var groupId = request.arguments.groupId;
+
+  // Check for legal arguments.
+  if (!type || IS_UNDEFINED(target)) {
+    response.failed('Missing argument "type" or "target"');
+    return;
+  }
+
+  // Either function or script break point.
+  var break_point_number;
+  if (type == 'function') {
+    // Handle function break point.
+    if (!IS_STRING(target)) {
+      response.failed('Argument "target" is not a string value');
+      return;
+    }
+    var f;
+    try {
+      // Find the function through a global evaluate.
+      f = this.exec_state_.evaluateGlobal(target).value();
+    } catch (e) {
+      response.failed('Error: "' + TO_STRING(e) +
+                      '" evaluating "' + target + '"');
+      return;
+    }
+    if (!IS_FUNCTION(f)) {
+      response.failed('"' + target + '" does not evaluate to a function');
+      return;
+    }
+
+    // Set function break point.
+    break_point_number = Debug.setBreakPoint(f, line, column, condition);
+  } else if (type == 'handle') {
+    // Find the object pointed by the specified handle.
+    var handle = ParseInt(target, 10);
+    var mirror = LookupMirror(handle);
+    if (!mirror) {
+      return response.failed('Object #' + handle + '# not found');
+    }
+    if (!mirror.isFunction()) {
+      return response.failed('Object #' + handle + '# is not a function');
+    }
+
+    // Set function break point.
+    break_point_number = Debug.setBreakPoint(mirror.value(),
+                                             line, column, condition);
+  } else if (type == 'script') {
+    // set script break point.
+    break_point_number =
+        Debug.setScriptBreakPointByName(target, line, column, condition,
+                                        groupId);
+  } else if (type == 'scriptId') {
+    break_point_number =
+        Debug.setScriptBreakPointById(target, line, column, condition, groupId);
+  } else if (type == 'scriptRegExp') {
+    break_point_number =
+        Debug.setScriptBreakPointByRegExp(target, line, column, condition,
+                                          groupId);
+  } else {
+    response.failed('Illegal type "' + type + '"');
+    return;
+  }
+
+  // Set additional break point properties.
+  var break_point = Debug.findBreakPoint(break_point_number);
+  if (ignoreCount) {
+    Debug.changeBreakPointIgnoreCount(break_point_number, ignoreCount);
+  }
+  if (!enabled) {
+    Debug.disableBreakPoint(break_point_number);
+  }
+
+  // Add the break point number to the response.
+  response.body = { type: type,
+                    breakpoint: break_point_number };
+
+  // Add break point information to the response.
+  if (break_point instanceof ScriptBreakPoint) {
+    if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
+      response.body.type = 'scriptId';
+      response.body.script_id = break_point.script_id();
+    } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptName) {
+      response.body.type = 'scriptName';
+      response.body.script_name = break_point.script_name();
+    } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptRegExp) {
+      response.body.type = 'scriptRegExp';
+      response.body.script_regexp = break_point.script_regexp_object().source;
+    } else {
+      throw MakeError(kDebugger,
+                      "Unexpected breakpoint type: " + break_point.type());
+    }
+    response.body.line = break_point.line();
+    response.body.column = break_point.column();
+    response.body.actual_locations = break_point.actual_locations();
+  } else {
+    response.body.type = 'function';
+    response.body.actual_locations = [break_point.actual_location];
+  }
+};
+
+
+DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(
+    request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var break_point = TO_NUMBER(request.arguments.breakpoint);
+  var enabled = request.arguments.enabled;
+  var condition = request.arguments.condition;
+  var ignoreCount = request.arguments.ignoreCount;
+
+  // Check for legal arguments.
+  if (!break_point) {
+    response.failed('Missing argument "breakpoint"');
+    return;
+  }
+
+  // Change enabled state if supplied.
+  if (!IS_UNDEFINED(enabled)) {
+    if (enabled) {
+      Debug.enableBreakPoint(break_point);
+    } else {
+      Debug.disableBreakPoint(break_point);
+    }
+  }
+
+  // Change condition if supplied
+  if (!IS_UNDEFINED(condition)) {
+    Debug.changeBreakPointCondition(break_point, condition);
+  }
+
+  // Change ignore count if supplied
+  if (!IS_UNDEFINED(ignoreCount)) {
+    Debug.changeBreakPointIgnoreCount(break_point, ignoreCount);
+  }
+};
+
+
+DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(
+    request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var group_id = request.arguments.groupId;
+
+  // Check for legal arguments.
+  if (!group_id) {
+    response.failed('Missing argument "groupId"');
+    return;
+  }
+
+  var cleared_break_points = [];
+  var new_script_break_points = [];
+  for (var i = 0; i < script_break_points.length; i++) {
+    var next_break_point = script_break_points[i];
+    if (next_break_point.groupId() == group_id) {
+      cleared_break_points.push(next_break_point.number());
+      next_break_point.clear();
+    } else {
+      new_script_break_points.push(next_break_point);
+    }
+  }
+  script_break_points = new_script_break_points;
+
+  // Add the cleared break point numbers to the response.
+  response.body = { breakpoints: cleared_break_points };
+};
+
+
+DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(
+    request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var break_point = TO_NUMBER(request.arguments.breakpoint);
+
+  // Check for legal arguments.
+  if (!break_point) {
+    response.failed('Missing argument "breakpoint"');
+    return;
+  }
+
+  // Clear break point.
+  Debug.clearBreakPoint(break_point);
+
+  // Add the cleared break point number to the response.
+  response.body = { breakpoint: break_point };
+};
+
+
+DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(
+    request, response) {
+  var array = [];
+  for (var i = 0; i < script_break_points.length; i++) {
+    var break_point = script_break_points[i];
+
+    var description = {
+      number: break_point.number(),
+      line: break_point.line(),
+      column: break_point.column(),
+      groupId: break_point.groupId(),
+      hit_count: break_point.hit_count(),
+      active: break_point.active(),
+      condition: break_point.condition(),
+      ignoreCount: break_point.ignoreCount(),
+      actual_locations: break_point.actual_locations()
+    };
+
+    if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
+      description.type = 'scriptId';
+      description.script_id = break_point.script_id();
+    } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptName) {
+      description.type = 'scriptName';
+      description.script_name = break_point.script_name();
+    } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptRegExp) {
+      description.type = 'scriptRegExp';
+      description.script_regexp = break_point.script_regexp_object().source;
+    } else {
+      throw MakeError(kDebugger,
+                      "Unexpected breakpoint type: " + break_point.type());
+    }
+    array.push(description);
+  }
+
+  response.body = {
+    breakpoints: array,
+    breakOnExceptions: Debug.isBreakOnException(),
+    breakOnUncaughtExceptions: Debug.isBreakOnUncaughtException()
+  };
+};
+
+
+DebugCommandProcessor.prototype.disconnectRequest_ =
+    function(request, response) {
+  Debug.disableAllBreakPoints();
+  this.continueRequest_(request, response);
+};
+
+
+DebugCommandProcessor.prototype.setExceptionBreakRequest_ =
+    function(request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out and check the 'type' argument:
+  var type = request.arguments.type;
+  if (!type) {
+    response.failed('Missing argument "type"');
+    return;
+  }
+
+  // Initialize the default value of enable:
+  var enabled;
+  if (type == 'all') {
+    enabled = !Debug.isBreakOnException();
+  } else if (type == 'uncaught') {
+    enabled = !Debug.isBreakOnUncaughtException();
+  }
+
+  // Pull out and check the 'enabled' argument if present:
+  if (!IS_UNDEFINED(request.arguments.enabled)) {
+    enabled = request.arguments.enabled;
+    if ((enabled != true) && (enabled != false)) {
+      response.failed('Illegal value for "enabled":"' + enabled + '"');
+    }
+  }
+
+  // Now set the exception break state:
+  if (type == 'all') {
+    %ChangeBreakOnException(Debug.ExceptionBreak.Caught, enabled);
+  } else if (type == 'uncaught') {
+    %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, enabled);
+  } else {
+    response.failed('Unknown "type":"' + type + '"');
+  }
+
+  // Add the cleared break point number to the response.
+  response.body = { 'type': type, 'enabled': enabled };
+};
+
+
+DebugCommandProcessor.prototype.backtraceRequest_ = function(
+    request, response) {
+  // Get the number of frames.
+  var total_frames = this.exec_state_.frameCount();
+
+  // Create simple response if there are no frames.
+  if (total_frames == 0) {
+    response.body = {
+      totalFrames: total_frames
+    };
+    return;
+  }
+
+  // Default frame range to include in backtrace.
+  var from_index = 0;
+  var to_index = kDefaultBacktraceLength;
+
+  // Get the range from the arguments.
+  if (request.arguments) {
+    if (request.arguments.fromFrame) {
+      from_index = request.arguments.fromFrame;
+    }
+    if (request.arguments.toFrame) {
+      to_index = request.arguments.toFrame;
+    }
+    if (request.arguments.bottom) {
+      var tmp_index = total_frames - from_index;
+      from_index = total_frames - to_index;
+      to_index = tmp_index;
+    }
+    if (from_index < 0 || to_index < 0) {
+      return response.failed('Invalid frame number');
+    }
+  }
+
+  // Adjust the index.
+  to_index = MathMin(total_frames, to_index);
+
+  if (to_index <= from_index) {
+    var error = 'Invalid frame range';
+    return response.failed(error);
+  }
+
+  // Create the response body.
+  var frames = [];
+  for (var i = from_index; i < to_index; i++) {
+    frames.push(this.exec_state_.frame(i));
+  }
+  response.body = {
+    fromFrame: from_index,
+    toFrame: to_index,
+    totalFrames: total_frames,
+    frames: frames
+  };
+};
+
+
+DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
+  // No frames no source.
+  if (this.exec_state_.frameCount() == 0) {
+    return response.failed('No frames');
+  }
+
+  // With no arguments just keep the selected frame.
+  if (request.arguments) {
+    var index = request.arguments.number;
+    if (index < 0 || this.exec_state_.frameCount() <= index) {
+      return response.failed('Invalid frame number');
+    }
+
+    this.exec_state_.setSelectedFrame(request.arguments.number);
+  }
+  response.body = this.exec_state_.frame();
+};
+
+
+DebugCommandProcessor.prototype.resolveFrameFromScopeDescription_ =
+    function(scope_description) {
+  // Get the frame for which the scope or scopes are requested.
+  // With no frameNumber argument use the currently selected frame.
+  if (scope_description && !IS_UNDEFINED(scope_description.frameNumber)) {
+    var frame_index = scope_description.frameNumber;
+    if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
+      throw MakeTypeError(kDebuggerFrame);
+    }
+    return this.exec_state_.frame(frame_index);
+  } else {
+    return this.exec_state_.frame();
+  }
+};
+
+
+// Gets scope host object from request. It is either a function
+// ('functionHandle' argument must be specified) or a stack frame
+// ('frameNumber' may be specified and the current frame is taken by default).
+DebugCommandProcessor.prototype.resolveScopeHolder_ =
+    function(scope_description) {
+  if (scope_description && "functionHandle" in scope_description) {
+    if (!IS_NUMBER(scope_description.functionHandle)) {
+      throw MakeError(kDebugger, 'Function handle must be a number');
+    }
+    var function_mirror = LookupMirror(scope_description.functionHandle);
+    if (!function_mirror) {
+      throw MakeError(kDebugger, 'Failed to find function object by handle');
+    }
+    if (!function_mirror.isFunction()) {
+      throw MakeError(kDebugger,
+                      'Value of non-function type is found by handle');
+    }
+    return function_mirror;
+  } else {
+    // No frames no scopes.
+    if (this.exec_state_.frameCount() == 0) {
+      throw MakeError(kDebugger, 'No scopes');
+    }
+
+    // Get the frame for which the scopes are requested.
+    var frame = this.resolveFrameFromScopeDescription_(scope_description);
+    return frame;
+  }
+}
+
+
+DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
+  var scope_holder = this.resolveScopeHolder_(request.arguments);
+
+  // Fill all scopes for this frame or function.
+  var total_scopes = scope_holder.scopeCount();
+  var scopes = [];
+  for (var i = 0; i < total_scopes; i++) {
+    scopes.push(scope_holder.scope(i));
+  }
+  response.body = {
+    fromScope: 0,
+    toScope: total_scopes,
+    totalScopes: total_scopes,
+    scopes: scopes
+  };
+};
+
+
+DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
+  // Get the frame or function for which the scope is requested.
+  var scope_holder = this.resolveScopeHolder_(request.arguments);
+
+  // With no scope argument just return top scope.
+  var scope_index = 0;
+  if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
+    scope_index = TO_NUMBER(request.arguments.number);
+    if (scope_index < 0 || scope_holder.scopeCount() <= scope_index) {
+      return response.failed('Invalid scope number');
+    }
+  }
+
+  response.body = scope_holder.scope(scope_index);
+};
+
+
+// Reads value from protocol description. Description may be in form of type
+// (for singletons), raw value (primitive types supported in JSON),
+// string value description plus type (for primitive values) or handle id.
+// Returns raw value or throws exception.
+DebugCommandProcessor.resolveValue_ = function(value_description) {
+  if ("handle" in value_description) {
+    var value_mirror = LookupMirror(value_description.handle);
+    if (!value_mirror) {
+      throw MakeError(kDebugger, "Failed to resolve value by handle, ' #" +
+                                 value_description.handle + "# not found");
+    }
+    return value_mirror.value();
+  } else if ("stringDescription" in value_description) {
+    if (value_description.type == MirrorType.BOOLEAN_TYPE) {
+      return TO_BOOLEAN(value_description.stringDescription);
+    } else if (value_description.type == MirrorType.NUMBER_TYPE) {
+      return TO_NUMBER(value_description.stringDescription);
+    } if (value_description.type == MirrorType.STRING_TYPE) {
+      return TO_STRING(value_description.stringDescription);
+    } else {
+      throw MakeError(kDebugger, "Unknown type");
+    }
+  } else if ("value" in value_description) {
+    return value_description.value;
+  } else if (value_description.type == MirrorType.UNDEFINED_TYPE) {
+    return UNDEFINED;
+  } else if (value_description.type == MirrorType.NULL_TYPE) {
+    return null;
+  } else {
+    throw MakeError(kDebugger, "Failed to parse value description");
+  }
+};
+
+
+DebugCommandProcessor.prototype.setVariableValueRequest_ =
+    function(request, response) {
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  if (IS_UNDEFINED(request.arguments.name)) {
+    response.failed('Missing variable name');
+  }
+  var variable_name = request.arguments.name;
+
+  var scope_description = request.arguments.scope;
+
+  // Get the frame or function for which the scope is requested.
+  var scope_holder = this.resolveScopeHolder_(scope_description);
+
+  if (IS_UNDEFINED(scope_description.number)) {
+    response.failed('Missing scope number');
+  }
+  var scope_index = TO_NUMBER(scope_description.number);
+
+  var scope = scope_holder.scope(scope_index);
+
+  var new_value =
+      DebugCommandProcessor.resolveValue_(request.arguments.newValue);
+
+  scope.setVariableValue(variable_name, new_value);
+
+  var new_value_mirror = MakeMirror(new_value);
+
+  response.body = {
+    newValue: new_value_mirror
+  };
+};
+
+
+DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+
+  // Pull out arguments.
+  var expression = request.arguments.expression;
+  var frame = request.arguments.frame;
+  var global = request.arguments.global;
+  var disable_break = request.arguments.disable_break;
+  var additional_context = request.arguments.additional_context;
+
+  // The expression argument could be an integer so we convert it to a
+  // string.
+  try {
+    expression = TO_STRING(expression);
+  } catch(e) {
+    return response.failed('Failed to convert expression argument to string');
+  }
+
+  // Check for legal arguments.
+  if (!IS_UNDEFINED(frame) && global) {
+    return response.failed('Arguments "frame" and "global" are exclusive');
+  }
+
+  var additional_context_object;
+  if (additional_context) {
+    additional_context_object = {};
+    for (var i = 0; i < additional_context.length; i++) {
+      var mapping = additional_context[i];
+
+      if (!IS_STRING(mapping.name)) {
+        return response.failed("Context element #" + i +
+            " doesn't contain name:string property");
+      }
+
+      var raw_value = DebugCommandProcessor.resolveValue_(mapping);
+      additional_context_object[mapping.name] = raw_value;
+    }
+  }
+
+  // Global evaluate.
+  if (global) {
+    // Evaluate in the native context.
+    response.body = this.exec_state_.evaluateGlobal(
+        expression, TO_BOOLEAN(disable_break), additional_context_object);
+    return;
+  }
+
+  // Default value for disable_break is true.
+  if (IS_UNDEFINED(disable_break)) {
+    disable_break = true;
+  }
+
+  // No frames no evaluate in frame.
+  if (this.exec_state_.frameCount() == 0) {
+    return response.failed('No frames');
+  }
+
+  // Check whether a frame was specified.
+  if (!IS_UNDEFINED(frame)) {
+    var frame_number = TO_NUMBER(frame);
+    if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
+      return response.failed('Invalid frame "' + frame + '"');
+    }
+    // Evaluate in the specified frame.
+    response.body = this.exec_state_.frame(frame_number).evaluate(
+        expression, TO_BOOLEAN(disable_break), additional_context_object);
+    return;
+  } else {
+    // Evaluate in the selected frame.
+    response.body = this.exec_state_.frame().evaluate(
+        expression, TO_BOOLEAN(disable_break), additional_context_object);
+    return;
+  }
+};
+
+
+DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+
+  // Pull out arguments.
+  var handles = request.arguments.handles;
+
+  // Check for legal arguments.
+  if (IS_UNDEFINED(handles)) {
+    return response.failed('Argument "handles" missing');
+  }
+
+  // Set 'includeSource' option for script lookup.
+  if (!IS_UNDEFINED(request.arguments.includeSource)) {
+    var includeSource = TO_BOOLEAN(request.arguments.includeSource);
+    response.setOption('includeSource', includeSource);
+  }
+
+  // Lookup handles.
+  var mirrors = {};
+  for (var i = 0; i < handles.length; i++) {
+    var handle = handles[i];
+    var mirror = LookupMirror(handle);
+    if (!mirror) {
+      return response.failed('Object #' + handle + '# not found');
+    }
+    mirrors[handle] = mirror;
+  }
+  response.body = mirrors;
+};
+
+
+DebugCommandProcessor.prototype.referencesRequest_ =
+    function(request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+
+  // Pull out arguments.
+  var type = request.arguments.type;
+  var handle = request.arguments.handle;
+
+  // Check for legal arguments.
+  if (IS_UNDEFINED(type)) {
+    return response.failed('Argument "type" missing');
+  }
+  if (IS_UNDEFINED(handle)) {
+    return response.failed('Argument "handle" missing');
+  }
+  if (type != 'referencedBy' && type != 'constructedBy') {
+    return response.failed('Invalid type "' + type + '"');
+  }
+
+  // Lookup handle and return objects with references the object.
+  var mirror = LookupMirror(handle);
+  if (mirror) {
+    if (type == 'referencedBy') {
+      response.body = mirror.referencedBy();
+    } else {
+      response.body = mirror.constructedBy();
+    }
+  } else {
+    return response.failed('Object #' + handle + '# not found');
+  }
+};
+
+
+DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
+  // No frames no source.
+  if (this.exec_state_.frameCount() == 0) {
+    return response.failed('No source');
+  }
+
+  var from_line;
+  var to_line;
+  var frame = this.exec_state_.frame();
+  if (request.arguments) {
+    // Pull out arguments.
+    from_line = request.arguments.fromLine;
+    to_line = request.arguments.toLine;
+
+    if (!IS_UNDEFINED(request.arguments.frame)) {
+      var frame_number = TO_NUMBER(request.arguments.frame);
+      if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
+        return response.failed('Invalid frame "' + frame + '"');
+      }
+      frame = this.exec_state_.frame(frame_number);
+    }
+  }
+
+  // Get the script selected.
+  var script = frame.func().script();
+  if (!script) {
+    return response.failed('No source');
+  }
+
+  // Get the source slice and fill it into the response.
+  var slice = script.sourceSlice(from_line, to_line);
+  if (!slice) {
+    return response.failed('Invalid line interval');
+  }
+  response.body = {};
+  response.body.source = slice.sourceText();
+  response.body.fromLine = slice.from_line;
+  response.body.toLine = slice.to_line;
+  response.body.fromPosition = slice.from_position;
+  response.body.toPosition = slice.to_position;
+  response.body.totalLines = script.lineCount();
+};
+
+
+DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
+  var types = ScriptTypeFlag(Debug.ScriptType.Normal);
+  var includeSource = false;
+  var idsToInclude = null;
+  if (request.arguments) {
+    // Pull out arguments.
+    if (!IS_UNDEFINED(request.arguments.types)) {
+      types = TO_NUMBER(request.arguments.types);
+      if (IsNaN(types) || types < 0) {
+        return response.failed('Invalid types "' +
+                               request.arguments.types + '"');
+      }
+    }
+
+    if (!IS_UNDEFINED(request.arguments.includeSource)) {
+      includeSource = TO_BOOLEAN(request.arguments.includeSource);
+      response.setOption('includeSource', includeSource);
+    }
+
+    if (IS_ARRAY(request.arguments.ids)) {
+      idsToInclude = {};
+      var ids = request.arguments.ids;
+      for (var i = 0; i < ids.length; i++) {
+        idsToInclude[ids[i]] = true;
+      }
+    }
+
+    var filterStr = null;
+    var filterNum = null;
+    if (!IS_UNDEFINED(request.arguments.filter)) {
+      var num = TO_NUMBER(request.arguments.filter);
+      if (!IsNaN(num)) {
+        filterNum = num;
+      }
+      filterStr = request.arguments.filter;
+    }
+  }
+
+  // Collect all scripts in the heap.
+  var scripts = %DebugGetLoadedScripts();
+
+  response.body = [];
+
+  for (var i = 0; i < scripts.length; i++) {
+    if (idsToInclude && !idsToInclude[scripts[i].id]) {
+      continue;
+    }
+    if (filterStr || filterNum) {
+      var script = scripts[i];
+      var found = false;
+      if (filterNum && !found) {
+        if (script.id && script.id === filterNum) {
+          found = true;
+        }
+      }
+      if (filterStr && !found) {
+        if (script.name && script.name.indexOf(filterStr) >= 0) {
+          found = true;
+        }
+      }
+      if (!found) continue;
+    }
+    if (types & ScriptTypeFlag(scripts[i].type)) {
+      response.body.push(MakeMirror(scripts[i]));
+    }
+  }
+};
+
+
+DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
+  // Get the number of threads.
+  var total_threads = this.exec_state_.threadCount();
+
+  // Get information for all threads.
+  var threads = [];
+  for (var i = 0; i < total_threads; i++) {
+    var details = %GetThreadDetails(this.exec_state_.break_id, i);
+    var thread_info = { current: details[0],
+                        id: details[1]
+                      };
+    threads.push(thread_info);
+  }
+
+  // Create the response body.
+  response.body = {
+    totalThreads: total_threads,
+    threads: threads
+  };
+};
+
+
+DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
+  response.running = false;
+};
+
+
+DebugCommandProcessor.prototype.versionRequest_ = function(request, response) {
+  response.body = {
+    V8Version: %GetV8Version()
+  };
+};
+
+
+DebugCommandProcessor.prototype.changeLiveRequest_ = function(
+    request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+  var script_id = request.arguments.script_id;
+  var preview_only = !!request.arguments.preview_only;
+
+  var scripts = %DebugGetLoadedScripts();
+
+  var the_script = null;
+  for (var i = 0; i < scripts.length; i++) {
+    if (scripts[i].id == script_id) {
+      the_script = scripts[i];
+    }
+  }
+  if (!the_script) {
+    response.failed('Script not found');
+    return;
+  }
+
+  var change_log = new GlobalArray();
+
+  if (!IS_STRING(request.arguments.new_source)) {
+    throw "new_source argument expected";
+  }
+
+  var new_source = request.arguments.new_source;
+
+  var result_description;
+  try {
+    result_description = Debug.LiveEdit.SetScriptSource(the_script,
+        new_source, preview_only, change_log);
+  } catch (e) {
+    if (e instanceof Debug.LiveEdit.Failure && "details" in e) {
+      response.failed(e.message, e.details);
+      return;
+    }
+    throw e;
+  }
+  response.body = {change_log: change_log, result: result_description};
+
+  if (!preview_only && !this.running_ && result_description.stack_modified) {
+    response.body.stepin_recommended = true;
+  }
+};
+
+
+DebugCommandProcessor.prototype.restartFrameRequest_ = function(
+    request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+  var frame = request.arguments.frame;
+
+  // No frames to evaluate in frame.
+  if (this.exec_state_.frameCount() == 0) {
+    return response.failed('No frames');
+  }
+
+  var frame_mirror;
+  // Check whether a frame was specified.
+  if (!IS_UNDEFINED(frame)) {
+    var frame_number = TO_NUMBER(frame);
+    if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
+      return response.failed('Invalid frame "' + frame + '"');
+    }
+    // Restart specified frame.
+    frame_mirror = this.exec_state_.frame(frame_number);
+  } else {
+    // Restart selected frame.
+    frame_mirror = this.exec_state_.frame();
+  }
+
+  var result_description = Debug.LiveEdit.RestartFrame(frame_mirror);
+  response.body = {result: result_description};
+};
+
+
+DebugCommandProcessor.prototype.debuggerFlagsRequest_ = function(request,
+                                                                 response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var flags = request.arguments.flags;
+
+  response.body = { flags: [] };
+  if (!IS_UNDEFINED(flags)) {
+    for (var i = 0; i < flags.length; i++) {
+      var name = flags[i].name;
+      var debugger_flag = debugger_flags[name];
+      if (!debugger_flag) {
+        continue;
+      }
+      if ('value' in flags[i]) {
+        debugger_flag.setValue(flags[i].value);
+      }
+      response.body.flags.push({ name: name, value: debugger_flag.getValue() });
+    }
+  } else {
+    for (var name in debugger_flags) {
+      var value = debugger_flags[name].getValue();
+      response.body.flags.push({ name: name, value: value });
+    }
+  }
+};
+
+
+DebugCommandProcessor.prototype.v8FlagsRequest_ = function(request, response) {
+  var flags = request.arguments.flags;
+  if (!flags) flags = '';
+  %SetFlags(flags);
+};
+
+
+DebugCommandProcessor.prototype.gcRequest_ = function(request, response) {
+  var type = request.arguments.type;
+  if (!type) type = 'all';
+
+  var before = %GetHeapUsage();
+  %CollectGarbage(type);
+  var after = %GetHeapUsage();
+
+  response.body = { "before": before, "after": after };
+};
+
+
+DebugCommandProcessor.prototype.dispatch_ = (function() {
+  var proto = DebugCommandProcessor.prototype;
+  return {
+    "continue":             proto.continueRequest_,
+    "break"   :             proto.breakRequest_,
+    "setbreakpoint" :       proto.setBreakPointRequest_,
+    "changebreakpoint":     proto.changeBreakPointRequest_,
+    "clearbreakpoint":      proto.clearBreakPointRequest_,
+    "clearbreakpointgroup": proto.clearBreakPointGroupRequest_,
+    "disconnect":           proto.disconnectRequest_,
+    "setexceptionbreak":    proto.setExceptionBreakRequest_,
+    "listbreakpoints":      proto.listBreakpointsRequest_,
+    "backtrace":            proto.backtraceRequest_,
+    "frame":                proto.frameRequest_,
+    "scopes":               proto.scopesRequest_,
+    "scope":                proto.scopeRequest_,
+    "setvariablevalue":     proto.setVariableValueRequest_,
+    "evaluate":             proto.evaluateRequest_,
+    "lookup":               proto.lookupRequest_,
+    "references":           proto.referencesRequest_,
+    "source":               proto.sourceRequest_,
+    "scripts":              proto.scriptsRequest_,
+    "threads":              proto.threadsRequest_,
+    "suspend":              proto.suspendRequest_,
+    "version":              proto.versionRequest_,
+    "changelive":           proto.changeLiveRequest_,
+    "restartframe":         proto.restartFrameRequest_,
+    "flags":                proto.debuggerFlagsRequest_,
+    "v8flag":               proto.v8FlagsRequest_,
+    "gc":                   proto.gcRequest_,
+  };
+})();
+
+
+// Check whether the previously processed command caused the VM to become
+// running.
+DebugCommandProcessor.prototype.isRunning = function() {
+  return this.running_;
+};
+
+
+DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
+  return %SystemBreak();
+};
+
+
+/**
+ * Convert an Object to its debugger protocol representation. The representation
+ * may be serilized to a JSON object using JSON.stringify().
+ * This implementation simply runs through all string property names, converts
+ * each property value to a protocol value and adds the property to the result
+ * object. For type "object" the function will be called recursively. Note that
+ * circular structures will cause infinite recursion.
+ * @param {Object} object The object to format as protocol object.
+ * @param {MirrorSerializer} mirror_serializer The serializer to use if any
+ *     mirror objects are encountered.
+ * @return {Object} Protocol object value.
+ */
+function ObjectToProtocolObject_(object, mirror_serializer) {
+  var content = {};
+  for (var key in object) {
+    // Only consider string keys.
+    if (typeof key == 'string') {
+      // Format the value based on its type.
+      var property_value_json = ValueToProtocolValue_(object[key],
+                                                      mirror_serializer);
+      // Add the property if relevant.
+      if (!IS_UNDEFINED(property_value_json)) {
+        content[key] = property_value_json;
+      }
+    }
+  }
+
+  return content;
+}
+
+
+/**
+ * Convert an array to its debugger protocol representation. It will convert
+ * each array element to a protocol value.
+ * @param {Array} array The array to format as protocol array.
+ * @param {MirrorSerializer} mirror_serializer The serializer to use if any
+ *     mirror objects are encountered.
+ * @return {Array} Protocol array value.
+ */
+function ArrayToProtocolArray_(array, mirror_serializer) {
+  var json = [];
+  for (var i = 0; i < array.length; i++) {
+    json.push(ValueToProtocolValue_(array[i], mirror_serializer));
+  }
+  return json;
+}
+
+
+/**
+ * Convert a value to its debugger protocol representation.
+ * @param {*} value The value to format as protocol value.
+ * @param {MirrorSerializer} mirror_serializer The serializer to use if any
+ *     mirror objects are encountered.
+ * @return {*} Protocol value.
+ */
+function ValueToProtocolValue_(value, mirror_serializer) {
+  // Format the value based on its type.
+  var json;
+  switch (typeof value) {
+    case 'object':
+      if (value instanceof Mirror) {
+        json = mirror_serializer.serializeValue(value);
+      } else if (IS_ARRAY(value)){
+        json = ArrayToProtocolArray_(value, mirror_serializer);
+      } else {
+        json = ObjectToProtocolObject_(value, mirror_serializer);
+      }
+      break;
+
+    case 'boolean':
+    case 'string':
+    case 'number':
+      json = value;
+      break;
+
+    default:
+      json = null;
+  }
+  return json;
+}
+
+
+// -------------------------------------------------------------------
+// Exports
+
+utils.InstallConstants(global, [
+  "Debug", Debug,
+  "DebugCommandProcessor", DebugCommandProcessor,
+  "BreakEvent", BreakEvent,
+  "CompileEvent", CompileEvent,
+  "BreakPoint", BreakPoint,
+]);
+
+// Functions needed by the debugger runtime.
+utils.InstallFunctions(utils, DONT_ENUM, [
+  "MakeExecutionState", MakeExecutionState,
+  "MakeExceptionEvent", MakeExceptionEvent,
+  "MakeBreakEvent", MakeBreakEvent,
+  "MakeCompileEvent", MakeCompileEvent,
+  "MakePromiseEvent", MakePromiseEvent,
+  "MakeAsyncTaskEvent", MakeAsyncTaskEvent,
+  "IsBreakPointTriggered", IsBreakPointTriggered,
+  "UpdateScriptBreakPoints", UpdateScriptBreakPoints,
+]);
+
+// Export to liveedit.js
+utils.Export(function(to) {
+  to.GetScriptBreakPoints = GetScriptBreakPoints;
+});
+
+})
diff --git a/src/debug/ia32/debug-ia32.cc b/src/debug/ia32/debug-ia32.cc
new file mode 100644
index 0000000..d489a01
--- /dev/null
+++ b/src/debug/ia32/debug-ia32.cc
@@ -0,0 +1,141 @@
+// Copyright 2012 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.
+
+#if V8_TARGET_ARCH_IA32
+
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+#include "src/ia32/frames-ia32.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_codesize;
+  __ bind(&check_codesize);
+  __ Nop(Assembler::kDebugBreakSlotLength);
+  DCHECK_EQ(Assembler::kDebugBreakSlotLength,
+            masm->SizeOfCodeGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction.
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  static const int kSize = Assembler::kDebugBreakSlotLength;
+  CodePatcher patcher(isolate, pc, kSize);
+
+  // Add a label for checking the size of the code used for returning.
+  Label check_codesize;
+  patcher.masm()->bind(&check_codesize);
+  patcher.masm()->call(code->entry(), RelocInfo::NONE32);
+  // Check that the size of the code generated is as expected.
+  DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+
+  // Enter an internal frame.
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
+      __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue)));
+    }
+    __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
+
+    if (mode == SAVE_RESULT_REGISTER) __ push(eax);
+
+    __ Move(eax, Immediate(0));  // No arguments.
+    __ mov(ebx,
+           Immediate(ExternalReference(
+               Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; ++i) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ Move(reg, Immediate(kDebugZapValue));
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
+
+    __ pop(ebx);
+    // We divide stored value by 2 (untagging) and multiply it by word's size.
+    STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
+    __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0));
+
+    // Get rid of the internal frame.
+  }
+
+  // This call did not replace a call , so there will be an unwanted
+  // return address left on the stack. Here we get rid of that.
+  __ add(esp, Immediate(kPointerSize));
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ jmp(Operand::StaticVariable(after_break_target));
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // We do not know our frame height, but set esp based on ebp.
+  __ lea(esp, Operand(ebp, -1 * kPointerSize));
+
+  __ pop(edi);  // Function.
+  __ pop(ebp);
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(edi, no_reg, dummy, dummy);
+
+  // Load context from the function.
+  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+  // Clear new.target register as a safety measure.
+  __ mov(edx, masm->isolate()->factory()->undefined_value());
+
+  // Get function code.
+  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
+  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
+
+  // Re-run JSFunction, edi is function, esi is context.
+  __ jmp(ebx);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_IA32
diff --git a/src/debug/liveedit.cc b/src/debug/liveedit.cc
new file mode 100644
index 0000000..f1f3f23
--- /dev/null
+++ b/src/debug/liveedit.cc
@@ -0,0 +1,2046 @@
+// Copyright 2012 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/liveedit.h"
+
+#include "src/ast/scopeinfo.h"
+#include "src/ast/scopes.h"
+#include "src/code-stubs.h"
+#include "src/compilation-cache.h"
+#include "src/compiler.h"
+#include "src/debug/debug.h"
+#include "src/deoptimizer.h"
+#include "src/frames-inl.h"
+#include "src/global-handles.h"
+#include "src/isolate-inl.h"
+#include "src/messages.h"
+#include "src/parsing/parser.h"
+#include "src/v8.h"
+#include "src/v8memory.h"
+
+namespace v8 {
+namespace internal {
+
+void SetElementSloppy(Handle<JSObject> object,
+                      uint32_t index,
+                      Handle<Object> value) {
+  // Ignore return value from SetElement. It can only be a failure if there
+  // are element setters causing exceptions and the debugger context has none
+  // of these.
+  Object::SetElement(object->GetIsolate(), object, index, value, SLOPPY)
+      .Assert();
+}
+
+
+// A simple implementation of dynamic programming algorithm. It solves
+// the problem of finding the difference of 2 arrays. It uses a table of results
+// of subproblems. Each cell contains a number together with 2-bit flag
+// that helps building the chunk list.
+class Differencer {
+ public:
+  explicit Differencer(Comparator::Input* input)
+      : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
+    buffer_ = NewArray<int>(len1_ * len2_);
+  }
+  ~Differencer() {
+    DeleteArray(buffer_);
+  }
+
+  void Initialize() {
+    int array_size = len1_ * len2_;
+    for (int i = 0; i < array_size; i++) {
+      buffer_[i] = kEmptyCellValue;
+    }
+  }
+
+  // Makes sure that result for the full problem is calculated and stored
+  // in the table together with flags showing a path through subproblems.
+  void FillTable() {
+    CompareUpToTail(0, 0);
+  }
+
+  void SaveResult(Comparator::Output* chunk_writer) {
+    ResultWriter writer(chunk_writer);
+
+    int pos1 = 0;
+    int pos2 = 0;
+    while (true) {
+      if (pos1 < len1_) {
+        if (pos2 < len2_) {
+          Direction dir = get_direction(pos1, pos2);
+          switch (dir) {
+            case EQ:
+              writer.eq();
+              pos1++;
+              pos2++;
+              break;
+            case SKIP1:
+              writer.skip1(1);
+              pos1++;
+              break;
+            case SKIP2:
+            case SKIP_ANY:
+              writer.skip2(1);
+              pos2++;
+              break;
+            default:
+              UNREACHABLE();
+          }
+        } else {
+          writer.skip1(len1_ - pos1);
+          break;
+        }
+      } else {
+        if (len2_ != pos2) {
+          writer.skip2(len2_ - pos2);
+        }
+        break;
+      }
+    }
+    writer.close();
+  }
+
+ private:
+  Comparator::Input* input_;
+  int* buffer_;
+  int len1_;
+  int len2_;
+
+  enum Direction {
+    EQ = 0,
+    SKIP1,
+    SKIP2,
+    SKIP_ANY,
+
+    MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
+  };
+
+  // Computes result for a subtask and optionally caches it in the buffer table.
+  // All results values are shifted to make space for flags in the lower bits.
+  int CompareUpToTail(int pos1, int pos2) {
+    if (pos1 < len1_) {
+      if (pos2 < len2_) {
+        int cached_res = get_value4(pos1, pos2);
+        if (cached_res == kEmptyCellValue) {
+          Direction dir;
+          int res;
+          if (input_->Equals(pos1, pos2)) {
+            res = CompareUpToTail(pos1 + 1, pos2 + 1);
+            dir = EQ;
+          } else {
+            int res1 = CompareUpToTail(pos1 + 1, pos2) +
+                (1 << kDirectionSizeBits);
+            int res2 = CompareUpToTail(pos1, pos2 + 1) +
+                (1 << kDirectionSizeBits);
+            if (res1 == res2) {
+              res = res1;
+              dir = SKIP_ANY;
+            } else if (res1 < res2) {
+              res = res1;
+              dir = SKIP1;
+            } else {
+              res = res2;
+              dir = SKIP2;
+            }
+          }
+          set_value4_and_dir(pos1, pos2, res, dir);
+          cached_res = res;
+        }
+        return cached_res;
+      } else {
+        return (len1_ - pos1) << kDirectionSizeBits;
+      }
+    } else {
+      return (len2_ - pos2) << kDirectionSizeBits;
+    }
+  }
+
+  inline int& get_cell(int i1, int i2) {
+    return buffer_[i1 + i2 * len1_];
+  }
+
+  // Each cell keeps a value plus direction. Value is multiplied by 4.
+  void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
+    DCHECK((value4 & kDirectionMask) == 0);
+    get_cell(i1, i2) = value4 | dir;
+  }
+
+  int get_value4(int i1, int i2) {
+    return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
+  }
+  Direction get_direction(int i1, int i2) {
+    return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
+  }
+
+  static const int kDirectionSizeBits = 2;
+  static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
+  static const int kEmptyCellValue = ~0u << kDirectionSizeBits;
+
+  // This method only holds static assert statement (unfortunately you cannot
+  // place one in class scope).
+  void StaticAssertHolder() {
+    STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
+  }
+
+  class ResultWriter {
+   public:
+    explicit ResultWriter(Comparator::Output* chunk_writer)
+        : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
+          pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
+    }
+    void eq() {
+      FlushChunk();
+      pos1_++;
+      pos2_++;
+    }
+    void skip1(int len1) {
+      StartChunk();
+      pos1_ += len1;
+    }
+    void skip2(int len2) {
+      StartChunk();
+      pos2_ += len2;
+    }
+    void close() {
+      FlushChunk();
+    }
+
+   private:
+    Comparator::Output* chunk_writer_;
+    int pos1_;
+    int pos2_;
+    int pos1_begin_;
+    int pos2_begin_;
+    bool has_open_chunk_;
+
+    void StartChunk() {
+      if (!has_open_chunk_) {
+        pos1_begin_ = pos1_;
+        pos2_begin_ = pos2_;
+        has_open_chunk_ = true;
+      }
+    }
+
+    void FlushChunk() {
+      if (has_open_chunk_) {
+        chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
+                                pos1_ - pos1_begin_, pos2_ - pos2_begin_);
+        has_open_chunk_ = false;
+      }
+    }
+  };
+};
+
+
+void Comparator::CalculateDifference(Comparator::Input* input,
+                                     Comparator::Output* result_writer) {
+  Differencer differencer(input);
+  differencer.Initialize();
+  differencer.FillTable();
+  differencer.SaveResult(result_writer);
+}
+
+
+static bool CompareSubstrings(Handle<String> s1, int pos1,
+                              Handle<String> s2, int pos2, int len) {
+  for (int i = 0; i < len; i++) {
+    if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+// Additional to Input interface. Lets switch Input range to subrange.
+// More elegant way would be to wrap one Input as another Input object
+// and translate positions there, but that would cost us additional virtual
+// call per comparison.
+class SubrangableInput : public Comparator::Input {
+ public:
+  virtual void SetSubrange1(int offset, int len) = 0;
+  virtual void SetSubrange2(int offset, int len) = 0;
+};
+
+
+class SubrangableOutput : public Comparator::Output {
+ public:
+  virtual void SetSubrange1(int offset, int len) = 0;
+  virtual void SetSubrange2(int offset, int len) = 0;
+};
+
+
+static int min(int a, int b) {
+  return a < b ? a : b;
+}
+
+
+// Finds common prefix and suffix in input. This parts shouldn't take space in
+// linear programming table. Enable subranging in input and output.
+static void NarrowDownInput(SubrangableInput* input,
+    SubrangableOutput* output) {
+  const int len1 = input->GetLength1();
+  const int len2 = input->GetLength2();
+
+  int common_prefix_len;
+  int common_suffix_len;
+
+  {
+    common_prefix_len = 0;
+    int prefix_limit = min(len1, len2);
+    while (common_prefix_len < prefix_limit &&
+        input->Equals(common_prefix_len, common_prefix_len)) {
+      common_prefix_len++;
+    }
+
+    common_suffix_len = 0;
+    int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
+
+    while (common_suffix_len < suffix_limit &&
+        input->Equals(len1 - common_suffix_len - 1,
+        len2 - common_suffix_len - 1)) {
+      common_suffix_len++;
+    }
+  }
+
+  if (common_prefix_len > 0 || common_suffix_len > 0) {
+    int new_len1 = len1 - common_suffix_len - common_prefix_len;
+    int new_len2 = len2 - common_suffix_len - common_prefix_len;
+
+    input->SetSubrange1(common_prefix_len, new_len1);
+    input->SetSubrange2(common_prefix_len, new_len2);
+
+    output->SetSubrange1(common_prefix_len, new_len1);
+    output->SetSubrange2(common_prefix_len, new_len2);
+  }
+}
+
+
+// A helper class that writes chunk numbers into JSArray.
+// Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
+class CompareOutputArrayWriter {
+ public:
+  explicit CompareOutputArrayWriter(Isolate* isolate)
+      : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
+
+  Handle<JSArray> GetResult() {
+    return array_;
+  }
+
+  void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
+    Isolate* isolate = array_->GetIsolate();
+    SetElementSloppy(array_,
+                     current_size_,
+                     Handle<Object>(Smi::FromInt(char_pos1), isolate));
+    SetElementSloppy(array_,
+                     current_size_ + 1,
+                     Handle<Object>(Smi::FromInt(char_pos1 + char_len1),
+                                    isolate));
+    SetElementSloppy(array_,
+                     current_size_ + 2,
+                     Handle<Object>(Smi::FromInt(char_pos2 + char_len2),
+                                    isolate));
+    current_size_ += 3;
+  }
+
+ private:
+  Handle<JSArray> array_;
+  int current_size_;
+};
+
+
+// Represents 2 strings as 2 arrays of tokens.
+// TODO(LiveEdit): Currently it's actually an array of charactres.
+//     Make array of tokens instead.
+class TokensCompareInput : public Comparator::Input {
+ public:
+  TokensCompareInput(Handle<String> s1, int offset1, int len1,
+                       Handle<String> s2, int offset2, int len2)
+      : s1_(s1), offset1_(offset1), len1_(len1),
+        s2_(s2), offset2_(offset2), len2_(len2) {
+  }
+  virtual int GetLength1() {
+    return len1_;
+  }
+  virtual int GetLength2() {
+    return len2_;
+  }
+  bool Equals(int index1, int index2) {
+    return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
+  }
+
+ private:
+  Handle<String> s1_;
+  int offset1_;
+  int len1_;
+  Handle<String> s2_;
+  int offset2_;
+  int len2_;
+};
+
+
+// Stores compare result in JSArray. Converts substring positions
+// to absolute positions.
+class TokensCompareOutput : public Comparator::Output {
+ public:
+  TokensCompareOutput(CompareOutputArrayWriter* array_writer,
+                      int offset1, int offset2)
+        : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
+  }
+
+  void AddChunk(int pos1, int pos2, int len1, int len2) {
+    array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
+  }
+
+ private:
+  CompareOutputArrayWriter* array_writer_;
+  int offset1_;
+  int offset2_;
+};
+
+
+// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
+// never has terminating new line character.
+class LineEndsWrapper {
+ public:
+  explicit LineEndsWrapper(Handle<String> string)
+      : ends_array_(String::CalculateLineEnds(string, false)),
+        string_len_(string->length()) {
+  }
+  int length() {
+    return ends_array_->length() + 1;
+  }
+  // Returns start for any line including start of the imaginary line after
+  // the last line.
+  int GetLineStart(int index) {
+    if (index == 0) {
+      return 0;
+    } else {
+      return GetLineEnd(index - 1);
+    }
+  }
+  int GetLineEnd(int index) {
+    if (index == ends_array_->length()) {
+      // End of the last line is always an end of the whole string.
+      // If the string ends with a new line character, the last line is an
+      // empty string after this character.
+      return string_len_;
+    } else {
+      return GetPosAfterNewLine(index);
+    }
+  }
+
+ private:
+  Handle<FixedArray> ends_array_;
+  int string_len_;
+
+  int GetPosAfterNewLine(int index) {
+    return Smi::cast(ends_array_->get(index))->value() + 1;
+  }
+};
+
+
+// Represents 2 strings as 2 arrays of lines.
+class LineArrayCompareInput : public SubrangableInput {
+ public:
+  LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
+                        LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
+      : s1_(s1), s2_(s2), line_ends1_(line_ends1),
+        line_ends2_(line_ends2),
+        subrange_offset1_(0), subrange_offset2_(0),
+        subrange_len1_(line_ends1_.length()),
+        subrange_len2_(line_ends2_.length()) {
+  }
+  int GetLength1() {
+    return subrange_len1_;
+  }
+  int GetLength2() {
+    return subrange_len2_;
+  }
+  bool Equals(int index1, int index2) {
+    index1 += subrange_offset1_;
+    index2 += subrange_offset2_;
+
+    int line_start1 = line_ends1_.GetLineStart(index1);
+    int line_start2 = line_ends2_.GetLineStart(index2);
+    int line_end1 = line_ends1_.GetLineEnd(index1);
+    int line_end2 = line_ends2_.GetLineEnd(index2);
+    int len1 = line_end1 - line_start1;
+    int len2 = line_end2 - line_start2;
+    if (len1 != len2) {
+      return false;
+    }
+    return CompareSubstrings(s1_, line_start1, s2_, line_start2,
+                             len1);
+  }
+  void SetSubrange1(int offset, int len) {
+    subrange_offset1_ = offset;
+    subrange_len1_ = len;
+  }
+  void SetSubrange2(int offset, int len) {
+    subrange_offset2_ = offset;
+    subrange_len2_ = len;
+  }
+
+ private:
+  Handle<String> s1_;
+  Handle<String> s2_;
+  LineEndsWrapper line_ends1_;
+  LineEndsWrapper line_ends2_;
+  int subrange_offset1_;
+  int subrange_offset2_;
+  int subrange_len1_;
+  int subrange_len2_;
+};
+
+
+// Stores compare result in JSArray. For each chunk tries to conduct
+// a fine-grained nested diff token-wise.
+class TokenizingLineArrayCompareOutput : public SubrangableOutput {
+ public:
+  TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
+                                   LineEndsWrapper line_ends2,
+                                   Handle<String> s1, Handle<String> s2)
+      : array_writer_(s1->GetIsolate()),
+        line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
+        subrange_offset1_(0), subrange_offset2_(0) {
+  }
+
+  void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
+    line_pos1 += subrange_offset1_;
+    line_pos2 += subrange_offset2_;
+
+    int char_pos1 = line_ends1_.GetLineStart(line_pos1);
+    int char_pos2 = line_ends2_.GetLineStart(line_pos2);
+    int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
+    int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
+
+    if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
+      // Chunk is small enough to conduct a nested token-level diff.
+      HandleScope subTaskScope(s1_->GetIsolate());
+
+      TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
+                                      s2_, char_pos2, char_len2);
+      TokensCompareOutput tokens_output(&array_writer_, char_pos1,
+                                          char_pos2);
+
+      Comparator::CalculateDifference(&tokens_input, &tokens_output);
+    } else {
+      array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
+    }
+  }
+  void SetSubrange1(int offset, int len) {
+    subrange_offset1_ = offset;
+  }
+  void SetSubrange2(int offset, int len) {
+    subrange_offset2_ = offset;
+  }
+
+  Handle<JSArray> GetResult() {
+    return array_writer_.GetResult();
+  }
+
+ private:
+  static const int CHUNK_LEN_LIMIT = 800;
+
+  CompareOutputArrayWriter array_writer_;
+  LineEndsWrapper line_ends1_;
+  LineEndsWrapper line_ends2_;
+  Handle<String> s1_;
+  Handle<String> s2_;
+  int subrange_offset1_;
+  int subrange_offset2_;
+};
+
+
+Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
+                                         Handle<String> s2) {
+  s1 = String::Flatten(s1);
+  s2 = String::Flatten(s2);
+
+  LineEndsWrapper line_ends1(s1);
+  LineEndsWrapper line_ends2(s2);
+
+  LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
+  TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
+
+  NarrowDownInput(&input, &output);
+
+  Comparator::CalculateDifference(&input, &output);
+
+  return output.GetResult();
+}
+
+
+// Unwraps JSValue object, returning its field "value"
+static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
+  return Handle<Object>(jsValue->value(), jsValue->GetIsolate());
+}
+
+
+// Wraps any object into a OpaqueReference, that will hide the object
+// from JavaScript.
+static Handle<JSValue> WrapInJSValue(Handle<HeapObject> object) {
+  Isolate* isolate = object->GetIsolate();
+  Handle<JSFunction> constructor = isolate->opaque_reference_function();
+  Handle<JSValue> result =
+      Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
+  result->set_value(*object);
+  return result;
+}
+
+
+static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
+    Handle<JSValue> jsValue) {
+  Object* shared = jsValue->value();
+  CHECK(shared->IsSharedFunctionInfo());
+  return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
+}
+
+
+static int GetArrayLength(Handle<JSArray> array) {
+  Object* length = array->length();
+  CHECK(length->IsSmi());
+  return Smi::cast(length)->value();
+}
+
+
+void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
+                                               int start_position,
+                                               int end_position, int param_num,
+                                               int literal_count,
+                                               int parent_index) {
+  HandleScope scope(isolate());
+  this->SetField(kFunctionNameOffset_, name);
+  this->SetSmiValueField(kStartPositionOffset_, start_position);
+  this->SetSmiValueField(kEndPositionOffset_, end_position);
+  this->SetSmiValueField(kParamNumOffset_, param_num);
+  this->SetSmiValueField(kLiteralNumOffset_, literal_count);
+  this->SetSmiValueField(kParentIndexOffset_, parent_index);
+}
+
+
+void FunctionInfoWrapper::SetFunctionCode(Handle<Code> function_code,
+                                          Handle<HeapObject> code_scope_info) {
+  Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
+  this->SetField(kCodeOffset_, code_wrapper);
+
+  Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
+  this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
+}
+
+
+void FunctionInfoWrapper::SetSharedFunctionInfo(
+    Handle<SharedFunctionInfo> info) {
+  Handle<JSValue> info_holder = WrapInJSValue(info);
+  this->SetField(kSharedFunctionInfoOffset_, info_holder);
+}
+
+
+Handle<Code> FunctionInfoWrapper::GetFunctionCode() {
+  Handle<Object> element = this->GetField(kCodeOffset_);
+  Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
+  Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
+  CHECK(raw_result->IsCode());
+  return Handle<Code>::cast(raw_result);
+}
+
+
+MaybeHandle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
+  Handle<Object> element = this->GetField(kSharedFunctionInfoOffset_);
+  if (element->IsJSValue()) {
+    Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
+    Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
+    Handle<SharedFunctionInfo> shared =
+        Handle<SharedFunctionInfo>::cast(raw_result);
+    return Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
+  } else {
+    // Scripts may never have a SharedFunctionInfo created.
+    return MaybeHandle<TypeFeedbackVector>();
+  }
+}
+
+
+Handle<Object> FunctionInfoWrapper::GetCodeScopeInfo() {
+  Handle<Object> element = this->GetField(kCodeScopeInfoOffset_);
+  return UnwrapJSValue(Handle<JSValue>::cast(element));
+}
+
+
+void SharedInfoWrapper::SetProperties(Handle<String> name,
+                                      int start_position,
+                                      int end_position,
+                                      Handle<SharedFunctionInfo> info) {
+  HandleScope scope(isolate());
+  this->SetField(kFunctionNameOffset_, name);
+  Handle<JSValue> info_holder = WrapInJSValue(info);
+  this->SetField(kSharedInfoOffset_, info_holder);
+  this->SetSmiValueField(kStartPositionOffset_, start_position);
+  this->SetSmiValueField(kEndPositionOffset_, end_position);
+}
+
+
+Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() {
+  Handle<Object> element = this->GetField(kSharedInfoOffset_);
+  Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
+  return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
+}
+
+
+class FunctionInfoListener {
+ public:
+  explicit FunctionInfoListener(Isolate* isolate) {
+    current_parent_index_ = -1;
+    len_ = 0;
+    result_ = isolate->factory()->NewJSArray(10);
+  }
+
+  void FunctionStarted(FunctionLiteral* fun) {
+    HandleScope scope(isolate());
+    FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
+    info.SetInitialProperties(fun->name(), fun->start_position(),
+                              fun->end_position(), fun->parameter_count(),
+                              fun->materialized_literal_count(),
+                              current_parent_index_);
+    current_parent_index_ = len_;
+    SetElementSloppy(result_, len_, info.GetJSArray());
+    len_++;
+  }
+
+  void FunctionDone() {
+    HandleScope scope(isolate());
+    FunctionInfoWrapper info =
+        FunctionInfoWrapper::cast(
+            *Object::GetElement(
+                isolate(), result_, current_parent_index_).ToHandleChecked());
+    current_parent_index_ = info.GetParentIndex();
+  }
+
+  // Saves only function code, because for a script function we
+  // may never create a SharedFunctionInfo object.
+  void FunctionCode(Handle<Code> function_code) {
+    FunctionInfoWrapper info =
+        FunctionInfoWrapper::cast(
+            *Object::GetElement(
+                isolate(), result_, current_parent_index_).ToHandleChecked());
+    info.SetFunctionCode(function_code,
+                         Handle<HeapObject>(isolate()->heap()->null_value()));
+  }
+
+  // Saves full information about a function: its code, its scope info
+  // and a SharedFunctionInfo object.
+  void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
+                    Zone* zone) {
+    if (!shared->IsSharedFunctionInfo()) {
+      return;
+    }
+    FunctionInfoWrapper info =
+        FunctionInfoWrapper::cast(
+            *Object::GetElement(
+                isolate(), result_, current_parent_index_).ToHandleChecked());
+    info.SetFunctionCode(Handle<Code>(shared->code()),
+                         Handle<HeapObject>(shared->scope_info()));
+    info.SetSharedFunctionInfo(shared);
+
+    Handle<Object> scope_info_list = SerializeFunctionScope(scope, zone);
+    info.SetFunctionScopeInfo(scope_info_list);
+  }
+
+  Handle<JSArray> GetResult() { return result_; }
+
+ private:
+  Isolate* isolate() const { return result_->GetIsolate(); }
+
+  Handle<Object> SerializeFunctionScope(Scope* scope, Zone* zone) {
+    Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10);
+    int scope_info_length = 0;
+
+    // Saves some description of scope. It stores name and indexes of
+    // variables in the whole scope chain. Null-named slots delimit
+    // scopes of this chain.
+    Scope* current_scope = scope;
+    while (current_scope != NULL) {
+      HandleScope handle_scope(isolate());
+      ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone);
+      ZoneList<Variable*> context_list(
+          current_scope->ContextLocalCount(), zone);
+      ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(),
+                                       zone);
+      current_scope->CollectStackAndContextLocals(&stack_list, &context_list,
+                                                  &globals_list);
+      context_list.Sort(&Variable::CompareIndex);
+
+      for (int i = 0; i < context_list.length(); i++) {
+        SetElementSloppy(scope_info_list,
+                         scope_info_length,
+                         context_list[i]->name());
+        scope_info_length++;
+        SetElementSloppy(
+            scope_info_list,
+            scope_info_length,
+            Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate()));
+        scope_info_length++;
+      }
+      SetElementSloppy(scope_info_list,
+                       scope_info_length,
+                       Handle<Object>(isolate()->heap()->null_value(),
+                                      isolate()));
+      scope_info_length++;
+
+      current_scope = current_scope->outer_scope();
+    }
+
+    return scope_info_list;
+  }
+
+  Handle<JSArray> result_;
+  int len_;
+  int current_parent_index_;
+};
+
+
+void LiveEdit::InitializeThreadLocal(Debug* debug) {
+  debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED;
+}
+
+
+bool LiveEdit::SetAfterBreakTarget(Debug* debug) {
+  Code* code = NULL;
+  Isolate* isolate = debug->isolate_;
+  switch (debug->thread_local_.frame_drop_mode_) {
+    case FRAMES_UNTOUCHED:
+      return false;
+    case FRAME_DROPPED_IN_DEBUG_SLOT_CALL:
+      // Debug break slot stub does not return normally, instead it manually
+      // cleans the stack and jumps. We should patch the jump address.
+      code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit);
+      break;
+    case FRAME_DROPPED_IN_DIRECT_CALL:
+      // Nothing to do, after_break_target is not used here.
+      return true;
+    case FRAME_DROPPED_IN_RETURN_CALL:
+      code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit);
+      break;
+    case CURRENTLY_SET_MODE:
+      UNREACHABLE();
+      break;
+  }
+  debug->after_break_target_ = code->entry();
+  return true;
+}
+
+
+MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
+                                                 Handle<String> source) {
+  Isolate* isolate = script->GetIsolate();
+
+  FunctionInfoListener listener(isolate);
+  Handle<Object> original_source =
+      Handle<Object>(script->source(), isolate);
+  script->set_source(*source);
+  isolate->set_active_function_info_listener(&listener);
+
+  {
+    // Creating verbose TryCatch from public API is currently the only way to
+    // force code save location. We do not use this the object directly.
+    v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
+    try_catch.SetVerbose(true);
+
+    // A logical 'try' section.
+    Compiler::CompileForLiveEdit(script);
+  }
+
+  // A logical 'catch' section.
+  Handle<JSObject> rethrow_exception;
+  if (isolate->has_pending_exception()) {
+    Handle<Object> exception(isolate->pending_exception(), isolate);
+    MessageLocation message_location = isolate->GetMessageLocation();
+
+    isolate->clear_pending_message();
+    isolate->clear_pending_exception();
+
+    // If possible, copy positions from message object to exception object.
+    if (exception->IsJSObject() && !message_location.script().is_null()) {
+      rethrow_exception = Handle<JSObject>::cast(exception);
+
+      Factory* factory = isolate->factory();
+      Handle<String> start_pos_key = factory->InternalizeOneByteString(
+          STATIC_CHAR_VECTOR("startPosition"));
+      Handle<String> end_pos_key =
+          factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("endPosition"));
+      Handle<String> script_obj_key =
+          factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptObject"));
+      Handle<Smi> start_pos(
+          Smi::FromInt(message_location.start_pos()), isolate);
+      Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
+      Handle<JSObject> script_obj =
+          Script::GetWrapper(message_location.script());
+      Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY)
+          .Assert();
+      Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
+          .Assert();
+      Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY)
+          .Assert();
+    }
+  }
+
+  // A logical 'finally' section.
+  isolate->set_active_function_info_listener(NULL);
+  script->set_source(*original_source);
+
+  if (rethrow_exception.is_null()) {
+    return listener.GetResult();
+  } else {
+    return isolate->Throw<JSArray>(rethrow_exception);
+  }
+}
+
+
+// Visitor that finds all references to a particular code object,
+// including "CODE_TARGET" references in other code objects and replaces
+// them on the fly.
+class ReplacingVisitor : public ObjectVisitor {
+ public:
+  explicit ReplacingVisitor(Code* original, Code* substitution)
+    : original_(original), substitution_(substitution) {
+  }
+
+  void VisitPointers(Object** start, Object** end) override {
+    for (Object** p = start; p < end; p++) {
+      if (*p == original_) {
+        *p = substitution_;
+      }
+    }
+  }
+
+  void VisitCodeEntry(Address entry) override {
+    if (Code::GetObjectFromEntryAddress(entry) == original_) {
+      Address substitution_entry = substitution_->instruction_start();
+      Memory::Address_at(entry) = substitution_entry;
+    }
+  }
+
+  void VisitCodeTarget(RelocInfo* rinfo) override {
+    if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
+        Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
+      Address substitution_entry = substitution_->instruction_start();
+      rinfo->set_target_address(substitution_entry);
+    }
+  }
+
+  void VisitDebugTarget(RelocInfo* rinfo) override { VisitCodeTarget(rinfo); }
+
+ private:
+  Code* original_;
+  Code* substitution_;
+};
+
+
+// Finds all references to original and replaces them with substitution.
+static void ReplaceCodeObject(Handle<Code> original,
+                              Handle<Code> substitution) {
+  // Perform a full GC in order to ensure that we are not in the middle of an
+  // incremental marking phase when we are replacing the code object.
+  // Since we are not in an incremental marking phase we can write pointers
+  // to code objects (that are never in new space) without worrying about
+  // write barriers.
+  Heap* heap = original->GetHeap();
+  HeapIterator iterator(heap);
+
+  DCHECK(!heap->InNewSpace(*substitution));
+
+  ReplacingVisitor visitor(*original, *substitution);
+
+  // Iterate over all roots. Stack frames may have pointer into original code,
+  // so temporary replace the pointers with offset numbers
+  // in prologue/epilogue.
+  heap->IterateRoots(&visitor, VISIT_ALL);
+
+  // Now iterate over all pointers of all objects, including code_target
+  // implicit pointers.
+  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+    obj->Iterate(&visitor);
+  }
+}
+
+
+// Patch function literals.
+// Name 'literals' is a misnomer. Rather it's a cache for complex object
+// boilerplates and for a native context. We must clean cached values.
+// Additionally we may need to allocate a new array if number of literals
+// changed.
+class LiteralFixer {
+ public:
+  static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper,
+                            Handle<SharedFunctionInfo> shared_info,
+                            Isolate* isolate) {
+    int new_literal_count = compile_info_wrapper->GetLiteralCount();
+    int old_literal_count = shared_info->num_literals();
+
+    if (old_literal_count == new_literal_count) {
+      // If literal count didn't change, simply go over all functions
+      // and clear literal arrays.
+      ClearValuesVisitor visitor;
+      IterateJSFunctions(shared_info, &visitor);
+    } else {
+      // When literal count changes, we have to create new array instances.
+      // Since we cannot create instances when iterating heap, we should first
+      // collect all functions and fix their literal arrays.
+      Handle<FixedArray> function_instances =
+          CollectJSFunctions(shared_info, isolate);
+      Handle<TypeFeedbackVector> vector(shared_info->feedback_vector());
+
+      for (int i = 0; i < function_instances->length(); i++) {
+        Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
+        Handle<LiteralsArray> new_literals =
+            LiteralsArray::New(isolate, vector, new_literal_count, TENURED);
+        fun->set_literals(*new_literals);
+      }
+
+      shared_info->set_num_literals(new_literal_count);
+    }
+  }
+
+ private:
+  // Iterates all function instances in the HEAP that refers to the
+  // provided shared_info.
+  template<typename Visitor>
+  static void IterateJSFunctions(Handle<SharedFunctionInfo> shared_info,
+                                 Visitor* visitor) {
+    HeapIterator iterator(shared_info->GetHeap());
+    for (HeapObject* obj = iterator.next(); obj != NULL;
+        obj = iterator.next()) {
+      if (obj->IsJSFunction()) {
+        JSFunction* function = JSFunction::cast(obj);
+        if (function->shared() == *shared_info) {
+          visitor->visit(function);
+        }
+      }
+    }
+  }
+
+  // Finds all instances of JSFunction that refers to the provided shared_info
+  // and returns array with them.
+  static Handle<FixedArray> CollectJSFunctions(
+      Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
+    CountVisitor count_visitor;
+    count_visitor.count = 0;
+    IterateJSFunctions(shared_info, &count_visitor);
+    int size = count_visitor.count;
+
+    Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
+    if (size > 0) {
+      CollectVisitor collect_visitor(result);
+      IterateJSFunctions(shared_info, &collect_visitor);
+    }
+    return result;
+  }
+
+  class ClearValuesVisitor {
+   public:
+    void visit(JSFunction* fun) {
+      FixedArray* literals = fun->literals();
+      int len = literals->length();
+      for (int j = 0; j < len; j++) {
+        literals->set_undefined(j);
+      }
+    }
+  };
+
+  class CountVisitor {
+   public:
+    void visit(JSFunction* fun) {
+      count++;
+    }
+    int count;
+  };
+
+  class CollectVisitor {
+   public:
+    explicit CollectVisitor(Handle<FixedArray> output)
+        : m_output(output), m_pos(0) {}
+
+    void visit(JSFunction* fun) {
+      m_output->set(m_pos, fun);
+      m_pos++;
+    }
+   private:
+    Handle<FixedArray> m_output;
+    int m_pos;
+  };
+};
+
+
+// Marks code that shares the same shared function info or has inlined
+// code that shares the same function info.
+class DependentFunctionMarker: public OptimizedFunctionVisitor {
+ public:
+  SharedFunctionInfo* shared_info_;
+  bool found_;
+
+  explicit DependentFunctionMarker(SharedFunctionInfo* shared_info)
+    : shared_info_(shared_info), found_(false) { }
+
+  virtual void EnterContext(Context* context) { }  // Don't care.
+  virtual void LeaveContext(Context* context)  { }  // Don't care.
+  virtual void VisitFunction(JSFunction* function) {
+    // It should be guaranteed by the iterator that everything is optimized.
+    DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
+    if (function->Inlines(shared_info_)) {
+      // Mark the code for deoptimization.
+      function->code()->set_marked_for_deoptimization(true);
+      found_ = true;
+    }
+  }
+};
+
+
+static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
+  DisallowHeapAllocation no_allocation;
+  DependentFunctionMarker marker(function_info);
+  // TODO(titzer): need to traverse all optimized code to find OSR code here.
+  Deoptimizer::VisitAllOptimizedFunctions(function_info->GetIsolate(), &marker);
+
+  if (marker.found_) {
+    // Only go through with the deoptimization if something was found.
+    Deoptimizer::DeoptimizeMarkedCode(function_info->GetIsolate());
+  }
+}
+
+
+void LiveEdit::ReplaceFunctionCode(
+    Handle<JSArray> new_compile_info_array,
+    Handle<JSArray> shared_info_array) {
+  Isolate* isolate = new_compile_info_array->GetIsolate();
+
+  FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
+  SharedInfoWrapper shared_info_wrapper(shared_info_array);
+
+  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
+
+  if (shared_info->code()->kind() == Code::FUNCTION) {
+    Handle<Code> code = compile_info_wrapper.GetFunctionCode();
+    ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
+    Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
+    if (code_scope_info->IsFixedArray()) {
+      shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
+    }
+    shared_info->DisableOptimization(kLiveEdit);
+    // Update the type feedback vector, if needed.
+    MaybeHandle<TypeFeedbackVector> feedback_vector =
+        compile_info_wrapper.GetFeedbackVector();
+    if (!feedback_vector.is_null()) {
+      shared_info->set_feedback_vector(*feedback_vector.ToHandleChecked());
+    }
+  }
+
+  int start_position = compile_info_wrapper.GetStartPosition();
+  int end_position = compile_info_wrapper.GetEndPosition();
+  shared_info->set_start_position(start_position);
+  shared_info->set_end_position(end_position);
+
+  LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate);
+
+  DeoptimizeDependentFunctions(*shared_info);
+  isolate->compilation_cache()->Remove(shared_info);
+}
+
+
+void LiveEdit::FunctionSourceUpdated(Handle<JSArray> shared_info_array) {
+  SharedInfoWrapper shared_info_wrapper(shared_info_array);
+  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
+
+  DeoptimizeDependentFunctions(*shared_info);
+  shared_info_array->GetIsolate()->compilation_cache()->Remove(shared_info);
+}
+
+
+void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
+                                 Handle<Object> script_handle) {
+  Handle<SharedFunctionInfo> shared_info =
+      UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
+  CHECK(script_handle->IsScript() || script_handle->IsUndefined());
+  SharedFunctionInfo::SetScript(shared_info, script_handle);
+  shared_info->DisableOptimization(kLiveEdit);
+
+  function_wrapper->GetIsolate()->compilation_cache()->Remove(shared_info);
+}
+
+
+// For a script text change (defined as position_change_array), translates
+// position in unchanged text to position in changed text.
+// Text change is a set of non-overlapping regions in text, that have changed
+// their contents and length. It is specified as array of groups of 3 numbers:
+// (change_begin, change_end, change_end_new_position).
+// Each group describes a change in text; groups are sorted by change_begin.
+// Only position in text beyond any changes may be successfully translated.
+// If a positions is inside some region that changed, result is currently
+// undefined.
+static int TranslatePosition(int original_position,
+                             Handle<JSArray> position_change_array) {
+  int position_diff = 0;
+  int array_len = GetArrayLength(position_change_array);
+  Isolate* isolate = position_change_array->GetIsolate();
+  // TODO(635): binary search may be used here
+  for (int i = 0; i < array_len; i += 3) {
+    HandleScope scope(isolate);
+    Handle<Object> element = Object::GetElement(
+        isolate, position_change_array, i).ToHandleChecked();
+    CHECK(element->IsSmi());
+    int chunk_start = Handle<Smi>::cast(element)->value();
+    if (original_position < chunk_start) {
+      break;
+    }
+    element = Object::GetElement(
+        isolate, position_change_array, i + 1).ToHandleChecked();
+    CHECK(element->IsSmi());
+    int chunk_end = Handle<Smi>::cast(element)->value();
+    // Position mustn't be inside a chunk.
+    DCHECK(original_position >= chunk_end);
+    element = Object::GetElement(
+        isolate, position_change_array, i + 2).ToHandleChecked();
+    CHECK(element->IsSmi());
+    int chunk_changed_end = Handle<Smi>::cast(element)->value();
+    position_diff = chunk_changed_end - chunk_end;
+  }
+
+  return original_position + position_diff;
+}
+
+
+// Auto-growing buffer for writing relocation info code section. This buffer
+// is a simplified version of buffer from Assembler. Unlike Assembler, this
+// class is platform-independent and it works without dealing with instructions.
+// As specified by RelocInfo format, the buffer is filled in reversed order:
+// from upper to lower addresses.
+// It uses NewArray/DeleteArray for memory management.
+class RelocInfoBuffer {
+ public:
+  RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
+    buffer_size_ = buffer_initial_capicity + kBufferGap;
+    buffer_ = NewArray<byte>(buffer_size_);
+
+    reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
+  }
+  ~RelocInfoBuffer() {
+    DeleteArray(buffer_);
+  }
+
+  // As specified by RelocInfo format, the buffer is filled in reversed order:
+  // from upper to lower addresses.
+  void Write(const RelocInfo* rinfo) {
+    if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
+      Grow();
+    }
+    reloc_info_writer_.Write(rinfo);
+  }
+
+  Vector<byte> GetResult() {
+    // Return the bytes from pos up to end of buffer.
+    int result_size =
+        static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
+    return Vector<byte>(reloc_info_writer_.pos(), result_size);
+  }
+
+ private:
+  void Grow() {
+    // Compute new buffer size.
+    int new_buffer_size;
+    if (buffer_size_ < 2 * KB) {
+      new_buffer_size = 4 * KB;
+    } else {
+      new_buffer_size = 2 * buffer_size_;
+    }
+    // Some internal data structures overflow for very large buffers,
+    // they must ensure that kMaximalBufferSize is not too large.
+    if (new_buffer_size > kMaximalBufferSize) {
+      V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
+    }
+
+    // Set up new buffer.
+    byte* new_buffer = NewArray<byte>(new_buffer_size);
+
+    // Copy the data.
+    int curently_used_size =
+        static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
+    MemMove(new_buffer + new_buffer_size - curently_used_size,
+            reloc_info_writer_.pos(), curently_used_size);
+
+    reloc_info_writer_.Reposition(
+        new_buffer + new_buffer_size - curently_used_size,
+        reloc_info_writer_.last_pc());
+
+    DeleteArray(buffer_);
+    buffer_ = new_buffer;
+    buffer_size_ = new_buffer_size;
+  }
+
+  RelocInfoWriter reloc_info_writer_;
+  byte* buffer_;
+  int buffer_size_;
+
+  static const int kBufferGap = RelocInfoWriter::kMaxSize;
+  static const int kMaximalBufferSize = 512*MB;
+};
+
+
+// Patch positions in code (changes relocation info section) and possibly
+// returns new instance of code.
+static Handle<Code> PatchPositionsInCode(
+    Handle<Code> code,
+    Handle<JSArray> position_change_array) {
+  Isolate* isolate = code->GetIsolate();
+
+  RelocInfoBuffer buffer_writer(code->relocation_size(),
+                                code->instruction_start());
+
+  {
+    for (RelocIterator it(*code); !it.done(); it.next()) {
+      RelocInfo* rinfo = it.rinfo();
+      if (RelocInfo::IsPosition(rinfo->rmode())) {
+        int position = static_cast<int>(rinfo->data());
+        int new_position = TranslatePosition(position,
+                                             position_change_array);
+        if (position != new_position) {
+          RelocInfo info_copy(rinfo->isolate(), rinfo->pc(), rinfo->rmode(),
+                              new_position, NULL);
+          buffer_writer.Write(&info_copy);
+          continue;
+        }
+      }
+      if (RelocInfo::IsRealRelocMode(rinfo->rmode())) {
+        buffer_writer.Write(it.rinfo());
+      }
+    }
+  }
+
+  Vector<byte> buffer = buffer_writer.GetResult();
+
+  if (buffer.length() == code->relocation_size()) {
+    // Simply patch relocation area of code.
+    MemCopy(code->relocation_start(), buffer.start(), buffer.length());
+    return code;
+  } else {
+    // Relocation info section now has different size. We cannot simply
+    // rewrite it inside code object. Instead we have to create a new
+    // code object.
+    Handle<Code> result(isolate->factory()->CopyCode(code, buffer));
+    return result;
+  }
+}
+
+
+void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
+                                      Handle<JSArray> position_change_array) {
+  SharedInfoWrapper shared_info_wrapper(shared_info_array);
+  Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
+
+  int old_function_start = info->start_position();
+  int new_function_start = TranslatePosition(old_function_start,
+                                             position_change_array);
+  int new_function_end = TranslatePosition(info->end_position(),
+                                           position_change_array);
+  int new_function_token_pos =
+      TranslatePosition(info->function_token_position(), position_change_array);
+
+  info->set_start_position(new_function_start);
+  info->set_end_position(new_function_end);
+  info->set_function_token_position(new_function_token_pos);
+
+  if (info->code()->kind() == Code::FUNCTION) {
+    // Patch relocation info section of the code.
+    Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
+                                                     position_change_array);
+    if (*patched_code != info->code()) {
+      // Replace all references to the code across the heap. In particular,
+      // some stubs may refer to this code and this code may be being executed
+      // on stack (it is safe to substitute the code object on stack, because
+      // we only change the structure of rinfo and leave instructions
+      // untouched).
+      ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
+    }
+  }
+}
+
+
+static Handle<Script> CreateScriptCopy(Handle<Script> original) {
+  Isolate* isolate = original->GetIsolate();
+
+  Handle<String> original_source(String::cast(original->source()));
+  Handle<Script> copy = isolate->factory()->NewScript(original_source);
+
+  copy->set_name(original->name());
+  copy->set_line_offset(original->line_offset());
+  copy->set_column_offset(original->column_offset());
+  copy->set_type(original->type());
+  copy->set_context_data(original->context_data());
+  copy->set_eval_from_shared(original->eval_from_shared());
+  copy->set_eval_from_instructions_offset(
+      original->eval_from_instructions_offset());
+
+  // Copy all the flags, but clear compilation state.
+  copy->set_flags(original->flags());
+  copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
+
+  return copy;
+}
+
+
+Handle<Object> LiveEdit::ChangeScriptSource(Handle<Script> original_script,
+                                            Handle<String> new_source,
+                                            Handle<Object> old_script_name) {
+  Isolate* isolate = original_script->GetIsolate();
+  Handle<Object> old_script_object;
+  if (old_script_name->IsString()) {
+    Handle<Script> old_script = CreateScriptCopy(original_script);
+    old_script->set_name(String::cast(*old_script_name));
+    old_script_object = old_script;
+    isolate->debug()->OnAfterCompile(old_script);
+  } else {
+    old_script_object = isolate->factory()->null_value();
+  }
+
+  original_script->set_source(*new_source);
+
+  // Drop line ends so that they will be recalculated.
+  original_script->set_line_ends(isolate->heap()->undefined_value());
+
+  return old_script_object;
+}
+
+
+
+void LiveEdit::ReplaceRefToNestedFunction(
+    Handle<JSValue> parent_function_wrapper,
+    Handle<JSValue> orig_function_wrapper,
+    Handle<JSValue> subst_function_wrapper) {
+
+  Handle<SharedFunctionInfo> parent_shared =
+      UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
+  Handle<SharedFunctionInfo> orig_shared =
+      UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
+  Handle<SharedFunctionInfo> subst_shared =
+      UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
+
+  for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
+    if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
+      if (it.rinfo()->target_object() == *orig_shared) {
+        it.rinfo()->set_target_object(*subst_shared);
+      }
+    }
+  }
+}
+
+
+// Check an activation against list of functions. If there is a function
+// that matches, its status in result array is changed to status argument value.
+static bool CheckActivation(Handle<JSArray> shared_info_array,
+                            Handle<JSArray> result,
+                            StackFrame* frame,
+                            LiveEdit::FunctionPatchabilityStatus status) {
+  if (!frame->is_java_script()) return false;
+
+  Handle<JSFunction> function(JavaScriptFrame::cast(frame)->function());
+
+  Isolate* isolate = shared_info_array->GetIsolate();
+  int len = GetArrayLength(shared_info_array);
+  for (int i = 0; i < len; i++) {
+    HandleScope scope(isolate);
+    Handle<Object> element =
+        Object::GetElement(isolate, shared_info_array, i).ToHandleChecked();
+    Handle<JSValue> jsvalue = Handle<JSValue>::cast(element);
+    Handle<SharedFunctionInfo> shared =
+        UnwrapSharedFunctionInfoFromJSValue(jsvalue);
+
+    if (function->Inlines(*shared)) {
+      SetElementSloppy(result, i, Handle<Smi>(Smi::FromInt(status), isolate));
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// Iterates over handler chain and removes all elements that are inside
+// frames being dropped.
+static bool FixTryCatchHandler(StackFrame* top_frame,
+                               StackFrame* bottom_frame) {
+  Address* pointer_address =
+      &Memory::Address_at(top_frame->isolate()->get_address_from_id(
+          Isolate::kHandlerAddress));
+
+  while (*pointer_address < top_frame->sp()) {
+    pointer_address = &Memory::Address_at(*pointer_address);
+  }
+  Address* above_frame_address = pointer_address;
+  while (*pointer_address < bottom_frame->fp()) {
+    pointer_address = &Memory::Address_at(*pointer_address);
+  }
+  bool change = *above_frame_address != *pointer_address;
+  *above_frame_address = *pointer_address;
+  return change;
+}
+
+
+// Initializes an artificial stack frame. The data it contains is used for:
+//  a. successful work of frame dropper code which eventually gets control,
+//  b. being compatible with regular stack structure for various stack
+//     iterators.
+// Frame structure (conforms InternalFrame structure):
+//   -- code
+//   -- SMI maker
+//   -- function (slot is called "context")
+//   -- frame base
+static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
+                                   Handle<Code> code) {
+  DCHECK(bottom_js_frame->is_java_script());
+
+  Address fp = bottom_js_frame->fp();
+
+  // Move function pointer into "context" slot.
+  Memory::Object_at(fp + StandardFrameConstants::kContextOffset) =
+      Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset);
+
+  Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code;
+  Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) =
+      Smi::FromInt(StackFrame::INTERNAL);
+}
+
+
+// Removes specified range of frames from stack. There may be 1 or more
+// frames in range. Anyway the bottom frame is restarted rather than dropped,
+// and therefore has to be a JavaScript frame.
+// Returns error message or NULL.
+static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index,
+                              int bottom_js_frame_index,
+                              LiveEdit::FrameDropMode* mode) {
+  if (!LiveEdit::kFrameDropperSupported) {
+    return "Stack manipulations are not supported in this architecture.";
+  }
+
+  StackFrame* pre_top_frame = frames[top_frame_index - 1];
+  StackFrame* top_frame = frames[top_frame_index];
+  StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
+
+  DCHECK(bottom_js_frame->is_java_script());
+
+  // Check the nature of the top frame.
+  Isolate* isolate = bottom_js_frame->isolate();
+  Code* pre_top_frame_code = pre_top_frame->LookupCode();
+  bool frame_has_padding = true;
+  if (pre_top_frame_code ==
+      isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) {
+    // OK, we can drop debug break slot.
+    *mode = LiveEdit::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
+  } else if (pre_top_frame_code ==
+             isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) {
+    // OK, we can drop our own code.
+    pre_top_frame = frames[top_frame_index - 2];
+    top_frame = frames[top_frame_index - 1];
+    *mode = LiveEdit::CURRENTLY_SET_MODE;
+    frame_has_padding = false;
+  } else if (pre_top_frame_code ==
+             isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
+    *mode = LiveEdit::FRAME_DROPPED_IN_RETURN_CALL;
+  } else if (pre_top_frame_code->kind() == Code::STUB &&
+             CodeStub::GetMajorKey(pre_top_frame_code) == CodeStub::CEntry) {
+    // Entry from our unit tests on 'debugger' statement.
+    // It's fine, we support this case.
+    *mode = LiveEdit::FRAME_DROPPED_IN_DIRECT_CALL;
+    // We don't have a padding from 'debugger' statement call.
+    // Here the stub is CEntry, it's not debug-only and can't be padded.
+    // If anyone would complain, a proxy padded stub could be added.
+    frame_has_padding = false;
+  } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
+    // This must be adaptor that remain from the frame dropping that
+    // is still on stack. A frame dropper frame must be above it.
+    DCHECK(frames[top_frame_index - 2]->LookupCode() ==
+           isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
+    pre_top_frame = frames[top_frame_index - 3];
+    top_frame = frames[top_frame_index - 2];
+    *mode = LiveEdit::CURRENTLY_SET_MODE;
+    frame_has_padding = false;
+  } else {
+    return "Unknown structure of stack above changing function";
+  }
+
+  Address unused_stack_top = top_frame->sp();
+  int new_frame_size = LiveEdit::kFrameDropperFrameSize * kPointerSize;
+  Address unused_stack_bottom = bottom_js_frame->fp()
+      - new_frame_size + kPointerSize;  // Bigger address end is exclusive.
+
+  Address* top_frame_pc_address = top_frame->pc_address();
+
+  // top_frame may be damaged below this point. Do not used it.
+  DCHECK(!(top_frame = NULL));
+
+  if (unused_stack_top > unused_stack_bottom) {
+    if (frame_has_padding) {
+      int shortage_bytes =
+          static_cast<int>(unused_stack_top - unused_stack_bottom);
+
+      Address padding_start = pre_top_frame->fp() -
+          LiveEdit::kFrameDropperFrameSize * kPointerSize;
+
+      Address padding_pointer = padding_start;
+      Smi* padding_object = Smi::FromInt(LiveEdit::kFramePaddingValue);
+      while (Memory::Object_at(padding_pointer) == padding_object) {
+        padding_pointer -= kPointerSize;
+      }
+      int padding_counter =
+          Smi::cast(Memory::Object_at(padding_pointer))->value();
+      if (padding_counter * kPointerSize < shortage_bytes) {
+        return "Not enough space for frame dropper frame "
+            "(even with padding frame)";
+      }
+      Memory::Object_at(padding_pointer) =
+          Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
+
+      StackFrame* pre_pre_frame = frames[top_frame_index - 2];
+
+      MemMove(padding_start + kPointerSize - shortage_bytes,
+              padding_start + kPointerSize,
+              LiveEdit::kFrameDropperFrameSize * kPointerSize);
+
+      pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
+      pre_pre_frame->SetCallerFp(pre_top_frame->fp());
+      unused_stack_top -= shortage_bytes;
+
+      STATIC_ASSERT(sizeof(Address) == kPointerSize);
+      top_frame_pc_address -= shortage_bytes / kPointerSize;
+    } else {
+      return "Not enough space for frame dropper frame";
+    }
+  }
+
+  // Committing now. After this point we should return only NULL value.
+
+  FixTryCatchHandler(pre_top_frame, bottom_js_frame);
+  // Make sure FixTryCatchHandler is idempotent.
+  DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
+
+  Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit();
+  *top_frame_pc_address = code->entry();
+  pre_top_frame->SetCallerFp(bottom_js_frame->fp());
+
+  SetUpFrameDropperFrame(bottom_js_frame, code);
+
+  for (Address a = unused_stack_top;
+      a < unused_stack_bottom;
+      a += kPointerSize) {
+    Memory::Object_at(a) = Smi::FromInt(0);
+  }
+
+  return NULL;
+}
+
+
+// Describes a set of call frames that execute any of listed functions.
+// Finding no such frames does not mean error.
+class MultipleFunctionTarget {
+ public:
+  MultipleFunctionTarget(Handle<JSArray> old_shared_array,
+                         Handle<JSArray> new_shared_array,
+                         Handle<JSArray> result)
+      : old_shared_array_(old_shared_array),
+        new_shared_array_(new_shared_array),
+        result_(result) {}
+  bool MatchActivation(StackFrame* frame,
+      LiveEdit::FunctionPatchabilityStatus status) {
+    return CheckActivation(old_shared_array_, result_, frame, status);
+  }
+  const char* GetNotFoundMessage() const {
+    return NULL;
+  }
+  bool FrameUsesNewTarget(StackFrame* frame) {
+    if (!frame->is_java_script()) return false;
+    JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
+    Handle<SharedFunctionInfo> old_shared(jsframe->function()->shared());
+    Isolate* isolate = old_shared->GetIsolate();
+    int len = GetArrayLength(old_shared_array_);
+    // Find corresponding new shared function info and return whether it
+    // references new.target.
+    for (int i = 0; i < len; i++) {
+      HandleScope scope(isolate);
+      Handle<Object> old_element =
+          Object::GetElement(isolate, old_shared_array_, i).ToHandleChecked();
+      if (!old_shared.is_identical_to(UnwrapSharedFunctionInfoFromJSValue(
+              Handle<JSValue>::cast(old_element)))) {
+        continue;
+      }
+
+      Handle<Object> new_element =
+          Object::GetElement(isolate, new_shared_array_, i).ToHandleChecked();
+      if (new_element->IsUndefined()) return false;
+      Handle<SharedFunctionInfo> new_shared =
+          UnwrapSharedFunctionInfoFromJSValue(
+              Handle<JSValue>::cast(new_element));
+      if (new_shared->scope_info()->HasNewTarget()) {
+        SetElementSloppy(
+            result_, i,
+            Handle<Smi>(
+                Smi::FromInt(
+                    LiveEdit::FUNCTION_BLOCKED_NO_NEW_TARGET_ON_RESTART),
+                isolate));
+        return true;
+      }
+      return false;
+    }
+    return false;
+  }
+
+ private:
+  Handle<JSArray> old_shared_array_;
+  Handle<JSArray> new_shared_array_;
+  Handle<JSArray> result_;
+};
+
+
+// Drops all call frame matched by target and all frames above them.
+template <typename TARGET>
+static const char* DropActivationsInActiveThreadImpl(Isolate* isolate,
+                                                     TARGET& target,  // NOLINT
+                                                     bool do_drop) {
+  Debug* debug = isolate->debug();
+  Zone zone;
+  Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
+
+
+  int top_frame_index = -1;
+  int frame_index = 0;
+  for (; frame_index < frames.length(); frame_index++) {
+    StackFrame* frame = frames[frame_index];
+    if (frame->id() == debug->break_frame_id()) {
+      top_frame_index = frame_index;
+      break;
+    }
+    if (target.MatchActivation(
+            frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
+      // We are still above break_frame. It is not a target frame,
+      // it is a problem.
+      return "Debugger mark-up on stack is not found";
+    }
+  }
+
+  if (top_frame_index == -1) {
+    // We haven't found break frame, but no function is blocking us anyway.
+    return target.GetNotFoundMessage();
+  }
+
+  bool target_frame_found = false;
+  int bottom_js_frame_index = top_frame_index;
+  bool non_droppable_frame_found = false;
+  LiveEdit::FunctionPatchabilityStatus non_droppable_reason;
+
+  for (; frame_index < frames.length(); frame_index++) {
+    StackFrame* frame = frames[frame_index];
+    if (frame->is_exit()) {
+      non_droppable_frame_found = true;
+      non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE;
+      break;
+    }
+    if (frame->is_java_script()) {
+      SharedFunctionInfo* shared =
+          JavaScriptFrame::cast(frame)->function()->shared();
+      if (shared->is_generator()) {
+        non_droppable_frame_found = true;
+        non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR;
+        break;
+      }
+    }
+    if (target.MatchActivation(
+            frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
+      target_frame_found = true;
+      bottom_js_frame_index = frame_index;
+    }
+  }
+
+  if (non_droppable_frame_found) {
+    // There is a C or generator frame on stack.  We can't drop C frames, and we
+    // can't restart generators.  Check that there are no target frames below
+    // them.
+    for (; frame_index < frames.length(); frame_index++) {
+      StackFrame* frame = frames[frame_index];
+      if (frame->is_java_script()) {
+        if (target.MatchActivation(frame, non_droppable_reason)) {
+          // Fail.
+          return NULL;
+        }
+      }
+    }
+  }
+
+  // We cannot restart a frame that uses new.target.
+  if (target.FrameUsesNewTarget(frames[bottom_js_frame_index])) return NULL;
+
+  if (!do_drop) {
+    // We are in check-only mode.
+    return NULL;
+  }
+
+  if (!target_frame_found) {
+    // Nothing to drop.
+    return target.GetNotFoundMessage();
+  }
+
+  LiveEdit::FrameDropMode drop_mode = LiveEdit::FRAMES_UNTOUCHED;
+  const char* error_message =
+      DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode);
+
+  if (error_message != NULL) {
+    return error_message;
+  }
+
+  // Adjust break_frame after some frames has been dropped.
+  StackFrame::Id new_id = StackFrame::NO_ID;
+  for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
+    if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
+      new_id = frames[i]->id();
+      break;
+    }
+  }
+  debug->FramesHaveBeenDropped(new_id, drop_mode);
+  return NULL;
+}
+
+
+// Fills result array with statuses of functions. Modifies the stack
+// removing all listed function if possible and if do_drop is true.
+static const char* DropActivationsInActiveThread(
+    Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
+    Handle<JSArray> result, bool do_drop) {
+  MultipleFunctionTarget target(old_shared_array, new_shared_array, result);
+  Isolate* isolate = old_shared_array->GetIsolate();
+
+  const char* message =
+      DropActivationsInActiveThreadImpl(isolate, target, do_drop);
+  if (message) {
+    return message;
+  }
+
+  int array_len = GetArrayLength(old_shared_array);
+
+  // Replace "blocked on active" with "replaced on active" status.
+  for (int i = 0; i < array_len; i++) {
+    Handle<Object> obj =
+        Object::GetElement(isolate, result, i).ToHandleChecked();
+    if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
+      Handle<Object> replaced(
+          Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
+      SetElementSloppy(result, i, replaced);
+    }
+  }
+  return NULL;
+}
+
+
+bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array,
+                                    Handle<FixedArray> result,
+                                    int len) {
+  Isolate* isolate = shared_info_array->GetIsolate();
+  bool found_suspended_activations = false;
+
+  DCHECK_LE(len, result->length());
+
+  FunctionPatchabilityStatus active = FUNCTION_BLOCKED_ACTIVE_GENERATOR;
+
+  Heap* heap = isolate->heap();
+  HeapIterator iterator(heap);
+  HeapObject* obj = NULL;
+  while ((obj = iterator.next()) != NULL) {
+    if (!obj->IsJSGeneratorObject()) continue;
+
+    JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
+    if (gen->is_closed()) continue;
+
+    HandleScope scope(isolate);
+
+    for (int i = 0; i < len; i++) {
+      Handle<JSValue> jsvalue =
+          Handle<JSValue>::cast(FixedArray::get(shared_info_array, i));
+      Handle<SharedFunctionInfo> shared =
+          UnwrapSharedFunctionInfoFromJSValue(jsvalue);
+
+      if (gen->function()->shared() == *shared) {
+        result->set(i, Smi::FromInt(active));
+        found_suspended_activations = true;
+      }
+    }
+  }
+
+  return found_suspended_activations;
+}
+
+
+class InactiveThreadActivationsChecker : public ThreadVisitor {
+ public:
+  InactiveThreadActivationsChecker(Handle<JSArray> old_shared_array,
+                                   Handle<JSArray> result)
+      : old_shared_array_(old_shared_array),
+        result_(result),
+        has_blocked_functions_(false) {}
+  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
+    for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
+      has_blocked_functions_ |=
+          CheckActivation(old_shared_array_, result_, it.frame(),
+                          LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
+    }
+  }
+  bool HasBlockedFunctions() {
+    return has_blocked_functions_;
+  }
+
+ private:
+  Handle<JSArray> old_shared_array_;
+  Handle<JSArray> result_;
+  bool has_blocked_functions_;
+};
+
+
+Handle<JSArray> LiveEdit::CheckAndDropActivations(
+    Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
+    bool do_drop) {
+  Isolate* isolate = old_shared_array->GetIsolate();
+  int len = GetArrayLength(old_shared_array);
+
+  DCHECK(old_shared_array->HasFastElements());
+  Handle<FixedArray> old_shared_array_elements(
+      FixedArray::cast(old_shared_array->elements()));
+
+  Handle<JSArray> result = isolate->factory()->NewJSArray(len);
+  Handle<FixedArray> result_elements =
+      JSObject::EnsureWritableFastElements(result);
+
+  // Fill the default values.
+  for (int i = 0; i < len; i++) {
+    FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH;
+    result_elements->set(i, Smi::FromInt(status));
+  }
+
+  // Scan the heap for active generators -- those that are either currently
+  // running (as we wouldn't want to restart them, because we don't know where
+  // to restart them from) or suspended.  Fail if any one corresponds to the set
+  // of functions being edited.
+  if (FindActiveGenerators(old_shared_array_elements, result_elements, len)) {
+    return result;
+  }
+
+  // Check inactive threads. Fail if some functions are blocked there.
+  InactiveThreadActivationsChecker inactive_threads_checker(old_shared_array,
+                                                            result);
+  isolate->thread_manager()->IterateArchivedThreads(
+      &inactive_threads_checker);
+  if (inactive_threads_checker.HasBlockedFunctions()) {
+    return result;
+  }
+
+  // Try to drop activations from the current stack.
+  const char* error_message = DropActivationsInActiveThread(
+      old_shared_array, new_shared_array, result, do_drop);
+  if (error_message != NULL) {
+    // Add error message as an array extra element.
+    Handle<String> str =
+        isolate->factory()->NewStringFromAsciiChecked(error_message);
+    SetElementSloppy(result, len, str);
+  }
+  return result;
+}
+
+
+// Describes a single callframe a target. Not finding this frame
+// means an error.
+class SingleFrameTarget {
+ public:
+  explicit SingleFrameTarget(JavaScriptFrame* frame)
+      : m_frame(frame),
+        m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
+
+  bool MatchActivation(StackFrame* frame,
+      LiveEdit::FunctionPatchabilityStatus status) {
+    if (frame->fp() == m_frame->fp()) {
+      m_saved_status = status;
+      return true;
+    }
+    return false;
+  }
+  const char* GetNotFoundMessage() const {
+    return "Failed to found requested frame";
+  }
+  LiveEdit::FunctionPatchabilityStatus saved_status() {
+    return m_saved_status;
+  }
+  void set_status(LiveEdit::FunctionPatchabilityStatus status) {
+    m_saved_status = status;
+  }
+
+  bool FrameUsesNewTarget(StackFrame* frame) {
+    if (!frame->is_java_script()) return false;
+    JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
+    Handle<SharedFunctionInfo> shared(jsframe->function()->shared());
+    return shared->scope_info()->HasNewTarget();
+  }
+
+ private:
+  JavaScriptFrame* m_frame;
+  LiveEdit::FunctionPatchabilityStatus m_saved_status;
+};
+
+
+// Finds a drops required frame and all frames above.
+// Returns error message or NULL.
+const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
+  SingleFrameTarget target(frame);
+
+  const char* result =
+      DropActivationsInActiveThreadImpl(frame->isolate(), target, true);
+  if (result != NULL) {
+    return result;
+  }
+  if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
+    return "Function is blocked under native code";
+  }
+  if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) {
+    return "Function is blocked under a generator activation";
+  }
+  return NULL;
+}
+
+
+LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
+                                                 FunctionLiteral* fun)
+    : isolate_(isolate) {
+  if (isolate_->active_function_info_listener() != NULL) {
+    isolate_->active_function_info_listener()->FunctionStarted(fun);
+  }
+}
+
+
+LiveEditFunctionTracker::~LiveEditFunctionTracker() {
+  if (isolate_->active_function_info_listener() != NULL) {
+    isolate_->active_function_info_listener()->FunctionDone();
+  }
+}
+
+
+void LiveEditFunctionTracker::RecordFunctionInfo(
+    Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
+    Zone* zone) {
+  if (isolate_->active_function_info_listener() != NULL) {
+    isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
+                                                            zone);
+  }
+}
+
+
+void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
+  isolate_->active_function_info_listener()->FunctionCode(code);
+}
+
+
+bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
+  return isolate->active_function_info_listener() != NULL;
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/debug/liveedit.h b/src/debug/liveedit.h
new file mode 100644
index 0000000..f3d6c54
--- /dev/null
+++ b/src/debug/liveedit.h
@@ -0,0 +1,371 @@
+// Copyright 2012 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_LIVEEDIT_H_
+#define V8_DEBUG_LIVEEDIT_H_
+
+
+// Live Edit feature implementation.
+// User should be able to change script on already running VM. This feature
+// matches hot swap features in other frameworks.
+//
+// The basic use-case is when user spots some mistake in function body
+// from debugger and wishes to change the algorithm without restart.
+//
+// A single change always has a form of a simple replacement (in pseudo-code):
+//   script.source[positions, positions+length] = new_string;
+// Implementation first determines, which function's body includes this
+// change area. Then both old and new versions of script are fully compiled
+// in order to analyze, whether the function changed its outer scope
+// expectations (or number of parameters). If it didn't, function's code is
+// patched with a newly compiled code. If it did change, enclosing function
+// gets patched. All inner functions are left untouched, whatever happened
+// to them in a new script version. However, new version of code will
+// instantiate newly compiled functions.
+
+
+#include "src/allocation.h"
+#include "src/compiler.h"
+
+namespace v8 {
+namespace internal {
+
+// This class collects some specific information on structure of functions
+// in a particular script. It gets called from compiler all the time, but
+// actually records any data only when liveedit operation is in process;
+// in any other time this class is very cheap.
+//
+// The primary interest of the Tracker is to record function scope structures
+// in order to analyze whether function code maybe safely patched (with new
+// code successfully reading existing data from function scopes). The Tracker
+// also collects compiled function codes.
+class LiveEditFunctionTracker {
+ public:
+  explicit LiveEditFunctionTracker(Isolate* isolate, FunctionLiteral* fun);
+  ~LiveEditFunctionTracker();
+  void RecordFunctionInfo(Handle<SharedFunctionInfo> info,
+                          FunctionLiteral* lit, Zone* zone);
+  void RecordRootFunctionInfo(Handle<Code> code);
+
+  static bool IsActive(Isolate* isolate);
+
+ private:
+  Isolate* isolate_;
+};
+
+
+class LiveEdit : AllStatic {
+ public:
+  // Describes how exactly a frame has been dropped from stack.
+  enum FrameDropMode {
+    // No frame has been dropped.
+    FRAMES_UNTOUCHED,
+    // The top JS frame had been calling debug break slot stub. Patch the
+    // address this stub jumps to in the end.
+    FRAME_DROPPED_IN_DEBUG_SLOT_CALL,
+    // The top JS frame had been calling some C++ function. The return address
+    // gets patched automatically.
+    FRAME_DROPPED_IN_DIRECT_CALL,
+    FRAME_DROPPED_IN_RETURN_CALL,
+    CURRENTLY_SET_MODE
+  };
+
+  static void InitializeThreadLocal(Debug* debug);
+
+  static bool SetAfterBreakTarget(Debug* debug);
+
+  MUST_USE_RESULT static MaybeHandle<JSArray> GatherCompileInfo(
+      Handle<Script> script,
+      Handle<String> source);
+
+  static void ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
+                                  Handle<JSArray> shared_info_array);
+
+  static void FunctionSourceUpdated(Handle<JSArray> shared_info_array);
+
+  // Updates script field in FunctionSharedInfo.
+  static void SetFunctionScript(Handle<JSValue> function_wrapper,
+                                Handle<Object> script_handle);
+
+  static void PatchFunctionPositions(Handle<JSArray> shared_info_array,
+                                     Handle<JSArray> position_change_array);
+
+  // For a script updates its source field. If old_script_name is provided
+  // (i.e. is a String), also creates a copy of the script with its original
+  // source and sends notification to debugger.
+  static Handle<Object> ChangeScriptSource(Handle<Script> original_script,
+                                           Handle<String> new_source,
+                                           Handle<Object> old_script_name);
+
+  // In a code of a parent function replaces original function as embedded
+  // object with a substitution one.
+  static void ReplaceRefToNestedFunction(Handle<JSValue> parent_function_shared,
+                                         Handle<JSValue> orig_function_shared,
+                                         Handle<JSValue> subst_function_shared);
+
+  // Find open generator activations, and set corresponding "result" elements to
+  // FUNCTION_BLOCKED_ACTIVE_GENERATOR.
+  static bool FindActiveGenerators(Handle<FixedArray> shared_info_array,
+                                   Handle<FixedArray> result, int len);
+
+  // Checks listed functions on stack and return array with corresponding
+  // FunctionPatchabilityStatus statuses; extra array element may
+  // contain general error message. Modifies the current stack and
+  // has restart the lowest found frames and drops all other frames above
+  // if possible and if do_drop is true.
+  static Handle<JSArray> CheckAndDropActivations(
+      Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
+      bool do_drop);
+
+  // Restarts the call frame and completely drops all frames above it.
+  // Return error message or NULL.
+  static const char* RestartFrame(JavaScriptFrame* frame);
+
+  // A copy of this is in liveedit.js.
+  enum FunctionPatchabilityStatus {
+    FUNCTION_AVAILABLE_FOR_PATCH = 1,
+    FUNCTION_BLOCKED_ON_ACTIVE_STACK = 2,
+    FUNCTION_BLOCKED_ON_OTHER_STACK = 3,
+    FUNCTION_BLOCKED_UNDER_NATIVE_CODE = 4,
+    FUNCTION_REPLACED_ON_ACTIVE_STACK = 5,
+    FUNCTION_BLOCKED_UNDER_GENERATOR = 6,
+    FUNCTION_BLOCKED_ACTIVE_GENERATOR = 7,
+    FUNCTION_BLOCKED_NO_NEW_TARGET_ON_RESTART = 8
+  };
+
+  // Compares 2 strings line-by-line, then token-wise and returns diff in form
+  // of array of triplets (pos1, pos1_end, pos2_end) describing list
+  // of diff chunks.
+  static Handle<JSArray> CompareStrings(Handle<String> s1,
+                                        Handle<String> s2);
+
+  // Architecture-specific constant.
+  static const bool kFrameDropperSupported;
+
+  /**
+   * Defines layout of a stack frame that supports padding. This is a regular
+   * internal frame that has a flexible stack structure. LiveEdit can shift
+   * its lower part up the stack, taking up the 'padding' space when additional
+   * stack memory is required.
+   * Such frame is expected immediately above the topmost JavaScript frame.
+   *
+   * Stack Layout:
+   *   --- Top
+   *   LiveEdit routine frames
+   *   ---
+   *   C frames of debug handler
+   *   ---
+   *   ...
+   *   ---
+   *      An internal frame that has n padding words:
+   *      - any number of words as needed by code -- upper part of frame
+   *      - padding size: a Smi storing n -- current size of padding
+   *      - padding: n words filled with kPaddingValue in form of Smi
+   *      - 3 context/type words of a regular InternalFrame
+   *      - fp
+   *   ---
+   *      Topmost JavaScript frame
+   *   ---
+   *   ...
+   *   --- Bottom
+   */
+  // A size of frame base including fp. Padding words starts right above
+  // the base.
+  static const int kFrameDropperFrameSize =
+      4 + StandardFrameConstants::kCPSlotCount;
+  // A number of words that should be reserved on stack for the LiveEdit use.
+  // Stored on stack in form of Smi.
+  static const int kFramePaddingInitialSize = 1;
+  // A value that padding words are filled with (in form of Smi). Going
+  // bottom-top, the first word not having this value is a counter word.
+  static const int kFramePaddingValue = kFramePaddingInitialSize + 1;
+};
+
+
+// A general-purpose comparator between 2 arrays.
+class Comparator {
+ public:
+  // Holds 2 arrays of some elements allowing to compare any pair of
+  // element from the first array and element from the second array.
+  class Input {
+   public:
+    virtual int GetLength1() = 0;
+    virtual int GetLength2() = 0;
+    virtual bool Equals(int index1, int index2) = 0;
+
+   protected:
+    virtual ~Input() {}
+  };
+
+  // Receives compare result as a series of chunks.
+  class Output {
+   public:
+    // Puts another chunk in result list. Note that technically speaking
+    // only 3 arguments actually needed with 4th being derivable.
+    virtual void AddChunk(int pos1, int pos2, int len1, int len2) = 0;
+
+   protected:
+    virtual ~Output() {}
+  };
+
+  // Finds the difference between 2 arrays of elements.
+  static void CalculateDifference(Input* input,
+                                  Output* result_writer);
+};
+
+
+
+// Simple helper class that creates more or less typed structures over
+// JSArray object. This is an adhoc method of passing structures from C++
+// to JavaScript.
+template<typename S>
+class JSArrayBasedStruct {
+ public:
+  static S Create(Isolate* isolate) {
+    Factory* factory = isolate->factory();
+    Handle<JSArray> array = factory->NewJSArray(S::kSize_);
+    return S(array);
+  }
+
+  static S cast(Object* object) {
+    JSArray* array = JSArray::cast(object);
+    Handle<JSArray> array_handle(array);
+    return S(array_handle);
+  }
+
+  explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
+  }
+
+  Handle<JSArray> GetJSArray() {
+    return array_;
+  }
+
+  Isolate* isolate() const {
+    return array_->GetIsolate();
+  }
+
+ protected:
+  void SetField(int field_position, Handle<Object> value) {
+    Object::SetElement(isolate(), array_, field_position, value, SLOPPY)
+        .Assert();
+  }
+
+  void SetSmiValueField(int field_position, int value) {
+    SetField(field_position, Handle<Smi>(Smi::FromInt(value), isolate()));
+  }
+
+  Handle<Object> GetField(int field_position) {
+    return Object::GetElement(
+        isolate(), array_, field_position).ToHandleChecked();
+  }
+
+  int GetSmiValueField(int field_position) {
+    Handle<Object> res = GetField(field_position);
+    return Handle<Smi>::cast(res)->value();
+  }
+
+ private:
+  Handle<JSArray> array_;
+};
+
+
+// Represents some function compilation details. This structure will be used
+// from JavaScript. It contains Code object, which is kept wrapped
+// into a BlindReference for sanitizing reasons.
+class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
+ public:
+  explicit FunctionInfoWrapper(Handle<JSArray> array)
+      : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
+  }
+
+  void SetInitialProperties(Handle<String> name, int start_position,
+                            int end_position, int param_num, int literal_count,
+                            int parent_index);
+
+  void SetFunctionCode(Handle<Code> function_code,
+                       Handle<HeapObject> code_scope_info);
+
+  void SetFunctionScopeInfo(Handle<Object> scope_info_array) {
+    this->SetField(kFunctionScopeInfoOffset_, scope_info_array);
+  }
+
+  void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info);
+
+  int GetLiteralCount() {
+    return this->GetSmiValueField(kLiteralNumOffset_);
+  }
+
+  int GetParentIndex() {
+    return this->GetSmiValueField(kParentIndexOffset_);
+  }
+
+  Handle<Code> GetFunctionCode();
+
+  MaybeHandle<TypeFeedbackVector> GetFeedbackVector();
+
+  Handle<Object> GetCodeScopeInfo();
+
+  int GetStartPosition() {
+    return this->GetSmiValueField(kStartPositionOffset_);
+  }
+
+  int GetEndPosition() { return this->GetSmiValueField(kEndPositionOffset_); }
+
+ private:
+  static const int kFunctionNameOffset_ = 0;
+  static const int kStartPositionOffset_ = 1;
+  static const int kEndPositionOffset_ = 2;
+  static const int kParamNumOffset_ = 3;
+  static const int kCodeOffset_ = 4;
+  static const int kCodeScopeInfoOffset_ = 5;
+  static const int kFunctionScopeInfoOffset_ = 6;
+  static const int kParentIndexOffset_ = 7;
+  static const int kSharedFunctionInfoOffset_ = 8;
+  static const int kLiteralNumOffset_ = 9;
+  static const int kSize_ = 10;
+
+  friend class JSArrayBasedStruct<FunctionInfoWrapper>;
+};
+
+
+// Wraps SharedFunctionInfo along with some of its fields for passing it
+// back to JavaScript. SharedFunctionInfo object itself is additionally
+// wrapped into BlindReference for sanitizing reasons.
+class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
+ public:
+  static bool IsInstance(Handle<JSArray> array) {
+    if (array->length() != Smi::FromInt(kSize_)) return false;
+    Handle<Object> element(
+        Object::GetElement(array->GetIsolate(),
+                           array,
+                           kSharedInfoOffset_).ToHandleChecked());
+    if (!element->IsJSValue()) return false;
+    return Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo();
+  }
+
+  explicit SharedInfoWrapper(Handle<JSArray> array)
+      : JSArrayBasedStruct<SharedInfoWrapper>(array) {
+  }
+
+  void SetProperties(Handle<String> name,
+                     int start_position,
+                     int end_position,
+                     Handle<SharedFunctionInfo> info);
+
+  Handle<SharedFunctionInfo> GetInfo();
+
+ private:
+  static const int kFunctionNameOffset_ = 0;
+  static const int kStartPositionOffset_ = 1;
+  static const int kEndPositionOffset_ = 2;
+  static const int kSharedInfoOffset_ = 3;
+  static const int kSize_ = 4;
+
+  friend class JSArrayBasedStruct<SharedInfoWrapper>;
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif /* V8_DEBUG_LIVEEDIT_H_ */
diff --git a/src/debug/liveedit.js b/src/debug/liveedit.js
new file mode 100644
index 0000000..85e55c4
--- /dev/null
+++ b/src/debug/liveedit.js
@@ -0,0 +1,1132 @@
+// Copyright 2012 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.
+
+// LiveEdit feature implementation. The script should be executed after
+// debug.js.
+
+// A LiveEdit namespace. It contains functions that modifies JavaScript code
+// according to changes of script source (if possible).
+//
+// When new script source is put in, the difference is calculated textually,
+// in form of list of delete/add/change chunks. The functions that include
+// change chunk(s) get recompiled, or their enclosing functions are
+// recompiled instead.
+// If the function may not be recompiled (e.g. it was completely erased in new
+// version of the script) it remains unchanged, but the code that could
+// create a new instance of this function goes away. An old version of script
+// is created to back up this obsolete function.
+// All unchanged functions have their positions updated accordingly.
+//
+// LiveEdit namespace is declared inside a single function constructor.
+
+(function(global, utils) {
+  "use strict";
+
+  // -------------------------------------------------------------------
+  // Imports
+
+  var FindScriptSourcePosition = global.Debug.findScriptSourcePosition;
+  var GetScriptBreakPoints;
+  var GlobalArray = global.Array;
+  var MathFloor = global.Math.floor;
+  var SyntaxError = global.SyntaxError;
+
+  utils.Import(function(from) {
+    GetScriptBreakPoints = from.GetScriptBreakPoints;
+  });
+
+  // -------------------------------------------------------------------
+
+  // Forward declaration for minifier.
+  var FunctionStatus;
+
+  // Applies the change to the script.
+  // The change is in form of list of chunks encoded in a single array as
+  // a series of triplets (pos1_start, pos1_end, pos2_end)
+  function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only,
+      change_log) {
+
+    var old_source = script.source;
+
+    // Gather compile information about old version of script.
+    var old_compile_info = GatherCompileInfo(old_source, script);
+
+    // Build tree structures for old and new versions of the script.
+    var root_old_node = BuildCodeInfoTree(old_compile_info);
+
+    var pos_translator = new PosTranslator(diff_array);
+
+    // Analyze changes.
+    MarkChangedFunctions(root_old_node, pos_translator.GetChunks());
+
+    // Find all SharedFunctionInfo's that were compiled from this script.
+    FindLiveSharedInfos(root_old_node, script);
+
+    // Gather compile information about new version of script.
+    var new_compile_info;
+    try {
+      new_compile_info = GatherCompileInfo(new_source, script);
+    } catch (e) {
+      var failure =
+          new Failure("Failed to compile new version of script: " + e);
+      if (e instanceof SyntaxError) {
+        var details = {
+          type: "liveedit_compile_error",
+          syntaxErrorMessage: e.message
+        };
+        CopyErrorPositionToDetails(e, details);
+        failure.details = details;
+      }
+      throw failure;
+    }
+    var root_new_node = BuildCodeInfoTree(new_compile_info);
+
+    // Link recompiled script data with other data.
+    FindCorrespondingFunctions(root_old_node, root_new_node);
+
+    // Prepare to-do lists.
+    var replace_code_list = new GlobalArray();
+    var link_to_old_script_list = new GlobalArray();
+    var link_to_original_script_list = new GlobalArray();
+    var update_positions_list = new GlobalArray();
+
+    function HarvestTodo(old_node) {
+      function CollectDamaged(node) {
+        link_to_old_script_list.push(node);
+        for (var i = 0; i < node.children.length; i++) {
+          CollectDamaged(node.children[i]);
+        }
+      }
+
+      // Recursively collects all newly compiled functions that are going into
+      // business and should have link to the actual script updated.
+      function CollectNew(node_list) {
+        for (var i = 0; i < node_list.length; i++) {
+          link_to_original_script_list.push(node_list[i]);
+          CollectNew(node_list[i].children);
+        }
+      }
+
+      if (old_node.status == FunctionStatus.DAMAGED) {
+        CollectDamaged(old_node);
+        return;
+      }
+      if (old_node.status == FunctionStatus.UNCHANGED) {
+        update_positions_list.push(old_node);
+      } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) {
+        update_positions_list.push(old_node);
+      } else if (old_node.status == FunctionStatus.CHANGED) {
+        replace_code_list.push(old_node);
+        CollectNew(old_node.unmatched_new_nodes);
+      }
+      for (var i = 0; i < old_node.children.length; i++) {
+        HarvestTodo(old_node.children[i]);
+      }
+    }
+
+    var preview_description = {
+        change_tree: DescribeChangeTree(root_old_node),
+        textual_diff: {
+          old_len: old_source.length,
+          new_len: new_source.length,
+          chunks: diff_array
+        },
+        updated: false
+    };
+
+    if (preview_only) {
+      return preview_description;
+    }
+
+    HarvestTodo(root_old_node);
+
+    // Collect shared infos for functions whose code need to be patched.
+    var replaced_function_old_infos = new GlobalArray();
+    var replaced_function_new_infos = new GlobalArray();
+    for (var i = 0; i < replace_code_list.length; i++) {
+      var old_infos = replace_code_list[i].live_shared_function_infos;
+      var new_info =
+          replace_code_list[i].corresponding_node.info.shared_function_info;
+
+      if (old_infos) {
+        for (var j = 0; j < old_infos.length; j++) {
+          replaced_function_old_infos.push(old_infos[j]);
+          replaced_function_new_infos.push(new_info);
+        }
+      }
+    }
+
+    // We haven't changed anything before this line yet.
+    // Committing all changes.
+
+    // Check that function being patched is not currently on stack or drop them.
+    var dropped_functions_number =
+        CheckStackActivations(replaced_function_old_infos,
+                              replaced_function_new_infos,
+                              change_log);
+
+    // Our current implementation requires client to manually issue "step in"
+    // command for correct stack state if the stack was modified.
+    preview_description.stack_modified = dropped_functions_number != 0;
+
+    // Start with breakpoints. Convert their line/column positions and
+    // temporary remove.
+    var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);
+
+    var old_script;
+
+    // Create an old script only if there are function that should be linked
+    // to old version.
+    if (link_to_old_script_list.length == 0) {
+      %LiveEditReplaceScript(script, new_source, null);
+      old_script = UNDEFINED;
+    } else {
+      var old_script_name = CreateNameForOldScript(script);
+
+      // Update the script text and create a new script representing an old
+      // version of the script.
+      old_script = %LiveEditReplaceScript(script, new_source,
+          old_script_name);
+
+      var link_to_old_script_report = new GlobalArray();
+      change_log.push( { linked_to_old_script: link_to_old_script_report } );
+
+      // We need to link to old script all former nested functions.
+      for (var i = 0; i < link_to_old_script_list.length; i++) {
+        LinkToOldScript(link_to_old_script_list[i], old_script,
+            link_to_old_script_report);
+      }
+
+      preview_description.created_script_name = old_script_name;
+    }
+
+    // Link to an actual script all the functions that we are going to use.
+    for (var i = 0; i < link_to_original_script_list.length; i++) {
+      %LiveEditFunctionSetScript(
+          link_to_original_script_list[i].info.shared_function_info, script);
+    }
+
+    for (var i = 0; i < replace_code_list.length; i++) {
+      PatchFunctionCode(replace_code_list[i], change_log);
+    }
+
+    var position_patch_report = new GlobalArray();
+    change_log.push( {position_patched: position_patch_report} );
+
+    for (var i = 0; i < update_positions_list.length; i++) {
+      // TODO(LiveEdit): take into account whether it's source_changed or
+      // unchanged and whether positions changed at all.
+      PatchPositions(update_positions_list[i], diff_array,
+          position_patch_report);
+
+      if (update_positions_list[i].live_shared_function_infos) {
+        update_positions_list[i].live_shared_function_infos.
+            forEach(function (info) {
+                %LiveEditFunctionSourceUpdated(info.raw_array);
+              });
+      }
+    }
+
+    break_points_restorer(pos_translator, old_script);
+
+    preview_description.updated = true;
+    return preview_description;
+  }
+
+  // Fully compiles source string as a script. Returns Array of
+  // FunctionCompileInfo -- a descriptions of all functions of the script.
+  // Elements of array are ordered by start positions of functions (from top
+  // to bottom) in the source. Fields outer_index and next_sibling_index help
+  // to navigate the nesting structure of functions.
+  //
+  // All functions get compiled linked to script provided as parameter script.
+  // TODO(LiveEdit): consider not using actual scripts as script, because
+  // we have to manually erase all links right after compile.
+  function GatherCompileInfo(source, script) {
+    // Get function info, elements are partially sorted (it is a tree of
+    // nested functions serialized as parent followed by serialized children.
+    var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
+
+    // Sort function infos by start position field.
+    var compile_info = new GlobalArray();
+    var old_index_map = new GlobalArray();
+    for (var i = 0; i < raw_compile_info.length; i++) {
+      var info = new FunctionCompileInfo(raw_compile_info[i]);
+      // Remove all links to the actual script. Breakpoints system and
+      // LiveEdit itself believe that any function in heap that points to a
+      // particular script is a regular function.
+      // For some functions we will restore this link later.
+      %LiveEditFunctionSetScript(info.shared_function_info, UNDEFINED);
+      compile_info.push(info);
+      old_index_map.push(i);
+    }
+
+    for (var i = 0; i < compile_info.length; i++) {
+      var k = i;
+      for (var j = i + 1; j < compile_info.length; j++) {
+        if (compile_info[k].start_position > compile_info[j].start_position) {
+          k = j;
+        }
+      }
+      if (k != i) {
+        var temp_info = compile_info[k];
+        var temp_index = old_index_map[k];
+        compile_info[k] = compile_info[i];
+        old_index_map[k] = old_index_map[i];
+        compile_info[i] = temp_info;
+        old_index_map[i] = temp_index;
+      }
+    }
+
+    // After sorting update outer_index field using old_index_map. Also
+    // set next_sibling_index field.
+    var current_index = 0;
+
+    // The recursive function, that goes over all children of a particular
+    // node (i.e. function info).
+    function ResetIndexes(new_parent_index, old_parent_index) {
+      var previous_sibling = -1;
+      while (current_index < compile_info.length &&
+          compile_info[current_index].outer_index == old_parent_index) {
+        var saved_index = current_index;
+        compile_info[saved_index].outer_index = new_parent_index;
+        if (previous_sibling != -1) {
+          compile_info[previous_sibling].next_sibling_index = saved_index;
+        }
+        previous_sibling = saved_index;
+        current_index++;
+        ResetIndexes(saved_index, old_index_map[saved_index]);
+      }
+      if (previous_sibling != -1) {
+        compile_info[previous_sibling].next_sibling_index = -1;
+      }
+    }
+
+    ResetIndexes(-1, -1);
+    Assert(current_index == compile_info.length);
+
+    return compile_info;
+  }
+
+
+  // Replaces function's Code.
+  function PatchFunctionCode(old_node, change_log) {
+    var new_info = old_node.corresponding_node.info;
+    if (old_node.live_shared_function_infos) {
+      old_node.live_shared_function_infos.forEach(function (old_info) {
+        %LiveEditReplaceFunctionCode(new_info.raw_array,
+                                     old_info.raw_array);
+
+        // The function got a new code. However, this new code brings all new
+        // instances of SharedFunctionInfo for nested functions. However,
+        // we want the original instances to be used wherever possible.
+        // (This is because old instances and new instances will be both
+        // linked to a script and breakpoints subsystem does not really
+        // expects this; neither does LiveEdit subsystem on next call).
+        for (var i = 0; i < old_node.children.length; i++) {
+          if (old_node.children[i].corresponding_node) {
+            var corresponding_child_info =
+                old_node.children[i].corresponding_node.info.
+                    shared_function_info;
+
+            if (old_node.children[i].live_shared_function_infos) {
+              old_node.children[i].live_shared_function_infos.
+                  forEach(function (old_child_info) {
+                    %LiveEditReplaceRefToNestedFunction(
+                        old_info.info,
+                        corresponding_child_info,
+                        old_child_info.info);
+                  });
+            }
+          }
+        }
+      });
+
+      change_log.push( {function_patched: new_info.function_name} );
+    } else {
+      change_log.push( {function_patched: new_info.function_name,
+          function_info_not_found: true} );
+    }
+  }
+
+
+  // Makes a function associated with another instance of a script (the
+  // one representing its old version). This way the function still
+  // may access its own text.
+  function LinkToOldScript(old_info_node, old_script, report_array) {
+    if (old_info_node.live_shared_function_infos) {
+      old_info_node.live_shared_function_infos.
+          forEach(function (info) {
+            %LiveEditFunctionSetScript(info.info, old_script);
+          });
+
+      report_array.push( { name: old_info_node.info.function_name } );
+    } else {
+      report_array.push(
+          { name: old_info_node.info.function_name, not_found: true } );
+    }
+  }
+
+
+  // Returns function that restores breakpoints.
+  function TemporaryRemoveBreakPoints(original_script, change_log) {
+    var script_break_points = GetScriptBreakPoints(original_script);
+
+    var break_points_update_report = [];
+    change_log.push( { break_points_update: break_points_update_report } );
+
+    var break_point_old_positions = [];
+    for (var i = 0; i < script_break_points.length; i++) {
+      var break_point = script_break_points[i];
+
+      break_point.clear();
+
+      // TODO(LiveEdit): be careful with resource offset here.
+      var break_point_position = FindScriptSourcePosition(original_script,
+          break_point.line(), break_point.column());
+
+      var old_position_description = {
+          position: break_point_position,
+          line: break_point.line(),
+          column: break_point.column()
+      };
+      break_point_old_positions.push(old_position_description);
+    }
+
+
+    // Restores breakpoints and creates their copies in the "old" copy of
+    // the script.
+    return function (pos_translator, old_script_copy_opt) {
+      // Update breakpoints (change positions and restore them in old version
+      // of script.
+      for (var i = 0; i < script_break_points.length; i++) {
+        var break_point = script_break_points[i];
+        if (old_script_copy_opt) {
+          var clone = break_point.cloneForOtherScript(old_script_copy_opt);
+          clone.set(old_script_copy_opt);
+
+          break_points_update_report.push( {
+            type: "copied_to_old",
+            id: break_point.number(),
+            new_id: clone.number(),
+            positions: break_point_old_positions[i]
+            } );
+        }
+
+        var updated_position = pos_translator.Translate(
+            break_point_old_positions[i].position,
+            PosTranslator.ShiftWithTopInsideChunkHandler);
+
+        var new_location =
+            original_script.locationFromPosition(updated_position, false);
+
+        break_point.update_positions(new_location.line, new_location.column);
+
+        var new_position_description = {
+            position: updated_position,
+            line: new_location.line,
+            column: new_location.column
+        };
+
+        break_point.set(original_script);
+
+        break_points_update_report.push( { type: "position_changed",
+          id: break_point.number(),
+          old_positions: break_point_old_positions[i],
+          new_positions: new_position_description
+          } );
+      }
+    };
+  }
+
+
+  function Assert(condition, message) {
+    if (!condition) {
+      if (message) {
+        throw "Assert " + message;
+      } else {
+        throw "Assert";
+      }
+    }
+  }
+
+  function DiffChunk(pos1, pos2, len1, len2) {
+    this.pos1 = pos1;
+    this.pos2 = pos2;
+    this.len1 = len1;
+    this.len2 = len2;
+  }
+
+  function PosTranslator(diff_array) {
+    var chunks = new GlobalArray();
+    var current_diff = 0;
+    for (var i = 0; i < diff_array.length; i += 3) {
+      var pos1_begin = diff_array[i];
+      var pos2_begin = pos1_begin + current_diff;
+      var pos1_end = diff_array[i + 1];
+      var pos2_end = diff_array[i + 2];
+      chunks.push(new DiffChunk(pos1_begin, pos2_begin, pos1_end - pos1_begin,
+          pos2_end - pos2_begin));
+      current_diff = pos2_end - pos1_end;
+    }
+    this.chunks = chunks;
+  }
+  PosTranslator.prototype.GetChunks = function() {
+    return this.chunks;
+  };
+
+  PosTranslator.prototype.Translate = function(pos, inside_chunk_handler) {
+    var array = this.chunks;
+    if (array.length == 0 || pos < array[0].pos1) {
+      return pos;
+    }
+    var chunk_index1 = 0;
+    var chunk_index2 = array.length - 1;
+
+    while (chunk_index1 < chunk_index2) {
+      var middle_index = MathFloor((chunk_index1 + chunk_index2) / 2);
+      if (pos < array[middle_index + 1].pos1) {
+        chunk_index2 = middle_index;
+      } else {
+        chunk_index1 = middle_index + 1;
+      }
+    }
+    var chunk = array[chunk_index1];
+    if (pos >= chunk.pos1 + chunk.len1) {
+      return pos + chunk.pos2 + chunk.len2 - chunk.pos1 - chunk.len1;
+    }
+
+    if (!inside_chunk_handler) {
+      inside_chunk_handler = PosTranslator.DefaultInsideChunkHandler;
+    }
+    return inside_chunk_handler(pos, chunk);
+  };
+
+  PosTranslator.DefaultInsideChunkHandler = function(pos, diff_chunk) {
+    Assert(false, "Cannot translate position in changed area");
+  };
+
+  PosTranslator.ShiftWithTopInsideChunkHandler =
+      function(pos, diff_chunk) {
+    // We carelessly do not check whether we stay inside the chunk after
+    // translation.
+    return pos - diff_chunk.pos1 + diff_chunk.pos2;
+  };
+
+  var FunctionStatus = {
+      // No change to function or its inner functions; however its positions
+      // in script may have been shifted.
+      UNCHANGED: "unchanged",
+      // The code of a function remains unchanged, but something happened inside
+      // some inner functions.
+      SOURCE_CHANGED: "source changed",
+      // The code of a function is changed or some nested function cannot be
+      // properly patched so this function must be recompiled.
+      CHANGED: "changed",
+      // Function is changed but cannot be patched.
+      DAMAGED: "damaged"
+  };
+
+  function CodeInfoTreeNode(code_info, children, array_index) {
+    this.info = code_info;
+    this.children = children;
+    // an index in array of compile_info
+    this.array_index = array_index;
+    this.parent = UNDEFINED;
+
+    this.status = FunctionStatus.UNCHANGED;
+    // Status explanation is used for debugging purposes and will be shown
+    // in user UI if some explanations are needed.
+    this.status_explanation = UNDEFINED;
+    this.new_start_pos = UNDEFINED;
+    this.new_end_pos = UNDEFINED;
+    this.corresponding_node = UNDEFINED;
+    this.unmatched_new_nodes = UNDEFINED;
+
+    // 'Textual' correspondence/matching is weaker than 'pure'
+    // correspondence/matching. We need 'textual' level for visual presentation
+    // in UI, we use 'pure' level for actual code manipulation.
+    // Sometimes only function body is changed (functions in old and new script
+    // textually correspond), but we cannot patch the code, so we see them
+    // as an old function deleted and new function created.
+    this.textual_corresponding_node = UNDEFINED;
+    this.textually_unmatched_new_nodes = UNDEFINED;
+
+    this.live_shared_function_infos = UNDEFINED;
+  }
+
+  // From array of function infos that is implicitly a tree creates
+  // an actual tree of functions in script.
+  function BuildCodeInfoTree(code_info_array) {
+    // Throughtout all function we iterate over input array.
+    var index = 0;
+
+    // Recursive function that builds a branch of tree.
+    function BuildNode() {
+      var my_index = index;
+      index++;
+      var child_array = new GlobalArray();
+      while (index < code_info_array.length &&
+          code_info_array[index].outer_index == my_index) {
+        child_array.push(BuildNode());
+      }
+      var node = new CodeInfoTreeNode(code_info_array[my_index], child_array,
+          my_index);
+      for (var i = 0; i < child_array.length; i++) {
+        child_array[i].parent = node;
+      }
+      return node;
+    }
+
+    var root = BuildNode();
+    Assert(index == code_info_array.length);
+    return root;
+  }
+
+  // Applies a list of the textual diff chunks onto the tree of functions.
+  // Determines status of each function (from unchanged to damaged). However
+  // children of unchanged functions are ignored.
+  function MarkChangedFunctions(code_info_tree, chunks) {
+
+    // A convenient iterator over diff chunks that also translates
+    // positions from old to new in a current non-changed part of script.
+    var chunk_it = new function() {
+      var chunk_index = 0;
+      var pos_diff = 0;
+      this.current = function() { return chunks[chunk_index]; };
+      this.next = function() {
+        var chunk = chunks[chunk_index];
+        pos_diff = chunk.pos2 + chunk.len2 - (chunk.pos1 + chunk.len1);
+        chunk_index++;
+      };
+      this.done = function() { return chunk_index >= chunks.length; };
+      this.TranslatePos = function(pos) { return pos + pos_diff; };
+    };
+
+    // A recursive function that processes internals of a function and all its
+    // inner functions. Iterator chunk_it initially points to a chunk that is
+    // below function start.
+    function ProcessInternals(info_node) {
+      info_node.new_start_pos = chunk_it.TranslatePos(
+          info_node.info.start_position);
+      var child_index = 0;
+      var code_changed = false;
+      var source_changed = false;
+      // Simultaneously iterates over child functions and over chunks.
+      while (!chunk_it.done() &&
+          chunk_it.current().pos1 < info_node.info.end_position) {
+        if (child_index < info_node.children.length) {
+          var child = info_node.children[child_index];
+
+          if (child.info.end_position <= chunk_it.current().pos1) {
+            ProcessUnchangedChild(child);
+            child_index++;
+            continue;
+          } else if (child.info.start_position >=
+              chunk_it.current().pos1 + chunk_it.current().len1) {
+            code_changed = true;
+            chunk_it.next();
+            continue;
+          } else if (child.info.start_position <= chunk_it.current().pos1 &&
+              child.info.end_position >= chunk_it.current().pos1 +
+              chunk_it.current().len1) {
+            ProcessInternals(child);
+            source_changed = source_changed ||
+                ( child.status != FunctionStatus.UNCHANGED );
+            code_changed = code_changed ||
+                ( child.status == FunctionStatus.DAMAGED );
+            child_index++;
+            continue;
+          } else {
+            code_changed = true;
+            child.status = FunctionStatus.DAMAGED;
+            child.status_explanation =
+                "Text diff overlaps with function boundary";
+            child_index++;
+            continue;
+          }
+        } else {
+          if (chunk_it.current().pos1 + chunk_it.current().len1 <=
+              info_node.info.end_position) {
+            info_node.status = FunctionStatus.CHANGED;
+            chunk_it.next();
+            continue;
+          } else {
+            info_node.status = FunctionStatus.DAMAGED;
+            info_node.status_explanation =
+                "Text diff overlaps with function boundary";
+            return;
+          }
+        }
+        Assert("Unreachable", false);
+      }
+      while (child_index < info_node.children.length) {
+        var child = info_node.children[child_index];
+        ProcessUnchangedChild(child);
+        child_index++;
+      }
+      if (code_changed) {
+        info_node.status = FunctionStatus.CHANGED;
+      } else if (source_changed) {
+        info_node.status = FunctionStatus.SOURCE_CHANGED;
+      }
+      info_node.new_end_pos =
+          chunk_it.TranslatePos(info_node.info.end_position);
+    }
+
+    function ProcessUnchangedChild(node) {
+      node.new_start_pos = chunk_it.TranslatePos(node.info.start_position);
+      node.new_end_pos = chunk_it.TranslatePos(node.info.end_position);
+    }
+
+    ProcessInternals(code_info_tree);
+  }
+
+  // For each old function (if it is not damaged) tries to find a corresponding
+  // function in new script. Typically it should succeed (non-damaged functions
+  // by definition may only have changes inside their bodies). However there are
+  // reasons for correspondence not to be found; function with unmodified text
+  // in new script may become enclosed into other function; the innocent change
+  // inside function body may in fact be something like "} function B() {" that
+  // splits a function into 2 functions.
+  function FindCorrespondingFunctions(old_code_tree, new_code_tree) {
+
+    // A recursive function that tries to find a correspondence for all
+    // child functions and for their inner functions.
+    function ProcessNode(old_node, new_node) {
+      var scope_change_description =
+          IsFunctionContextLocalsChanged(old_node.info, new_node.info);
+      if (scope_change_description) {
+        old_node.status = FunctionStatus.CHANGED;
+      }
+
+      var old_children = old_node.children;
+      var new_children = new_node.children;
+
+      var unmatched_new_nodes_list = [];
+      var textually_unmatched_new_nodes_list = [];
+
+      var old_index = 0;
+      var new_index = 0;
+      while (old_index < old_children.length) {
+        if (old_children[old_index].status == FunctionStatus.DAMAGED) {
+          old_index++;
+        } else if (new_index < new_children.length) {
+          if (new_children[new_index].info.start_position <
+              old_children[old_index].new_start_pos) {
+            unmatched_new_nodes_list.push(new_children[new_index]);
+            textually_unmatched_new_nodes_list.push(new_children[new_index]);
+            new_index++;
+          } else if (new_children[new_index].info.start_position ==
+              old_children[old_index].new_start_pos) {
+            if (new_children[new_index].info.end_position ==
+                old_children[old_index].new_end_pos) {
+              old_children[old_index].corresponding_node =
+                  new_children[new_index];
+              old_children[old_index].textual_corresponding_node =
+                  new_children[new_index];
+              if (scope_change_description) {
+                old_children[old_index].status = FunctionStatus.DAMAGED;
+                old_children[old_index].status_explanation =
+                    "Enclosing function is now incompatible. " +
+                    scope_change_description;
+                old_children[old_index].corresponding_node = UNDEFINED;
+              } else if (old_children[old_index].status !=
+                  FunctionStatus.UNCHANGED) {
+                ProcessNode(old_children[old_index],
+                    new_children[new_index]);
+                if (old_children[old_index].status == FunctionStatus.DAMAGED) {
+                  unmatched_new_nodes_list.push(
+                      old_children[old_index].corresponding_node);
+                  old_children[old_index].corresponding_node = UNDEFINED;
+                  old_node.status = FunctionStatus.CHANGED;
+                }
+              }
+            } else {
+              old_children[old_index].status = FunctionStatus.DAMAGED;
+              old_children[old_index].status_explanation =
+                  "No corresponding function in new script found";
+              old_node.status = FunctionStatus.CHANGED;
+              unmatched_new_nodes_list.push(new_children[new_index]);
+              textually_unmatched_new_nodes_list.push(new_children[new_index]);
+            }
+            new_index++;
+            old_index++;
+          } else {
+            old_children[old_index].status = FunctionStatus.DAMAGED;
+            old_children[old_index].status_explanation =
+                "No corresponding function in new script found";
+            old_node.status = FunctionStatus.CHANGED;
+            old_index++;
+          }
+        } else {
+          old_children[old_index].status = FunctionStatus.DAMAGED;
+          old_children[old_index].status_explanation =
+              "No corresponding function in new script found";
+          old_node.status = FunctionStatus.CHANGED;
+          old_index++;
+        }
+      }
+
+      while (new_index < new_children.length) {
+        unmatched_new_nodes_list.push(new_children[new_index]);
+        textually_unmatched_new_nodes_list.push(new_children[new_index]);
+        new_index++;
+      }
+
+      if (old_node.status == FunctionStatus.CHANGED) {
+        if (old_node.info.param_num != new_node.info.param_num) {
+          old_node.status = FunctionStatus.DAMAGED;
+          old_node.status_explanation = "Changed parameter number: " +
+              old_node.info.param_num + " and " + new_node.info.param_num;
+        }
+      }
+      old_node.unmatched_new_nodes = unmatched_new_nodes_list;
+      old_node.textually_unmatched_new_nodes =
+          textually_unmatched_new_nodes_list;
+    }
+
+    ProcessNode(old_code_tree, new_code_tree);
+
+    old_code_tree.corresponding_node = new_code_tree;
+    old_code_tree.textual_corresponding_node = new_code_tree;
+
+    Assert(old_code_tree.status != FunctionStatus.DAMAGED,
+        "Script became damaged");
+  }
+
+  function FindLiveSharedInfos(old_code_tree, script) {
+    var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
+
+    var shared_infos = new GlobalArray();
+
+    for (var i = 0; i < shared_raw_list.length; i++) {
+      shared_infos.push(new SharedInfoWrapper(shared_raw_list[i]));
+    }
+
+    // Finds all SharedFunctionInfos that corresponds to compile info
+    // in old version of the script.
+    function FindFunctionInfos(compile_info) {
+      var wrappers = [];
+
+      for (var i = 0; i < shared_infos.length; i++) {
+        var wrapper = shared_infos[i];
+        if (wrapper.start_position == compile_info.start_position &&
+            wrapper.end_position == compile_info.end_position) {
+          wrappers.push(wrapper);
+        }
+      }
+
+      if (wrappers.length > 0) {
+        return wrappers;
+      }
+    }
+
+    function TraverseTree(node) {
+      node.live_shared_function_infos = FindFunctionInfos(node.info);
+
+      for (var i = 0; i < node.children.length; i++) {
+        TraverseTree(node.children[i]);
+      }
+    }
+
+    TraverseTree(old_code_tree);
+  }
+
+
+  // An object describing function compilation details. Its index fields
+  // apply to indexes inside array that stores these objects.
+  function FunctionCompileInfo(raw_array) {
+    this.function_name = raw_array[0];
+    this.start_position = raw_array[1];
+    this.end_position = raw_array[2];
+    this.param_num = raw_array[3];
+    this.code = raw_array[4];
+    this.code_scope_info = raw_array[5];
+    this.scope_info = raw_array[6];
+    this.outer_index = raw_array[7];
+    this.shared_function_info = raw_array[8];
+    this.next_sibling_index = null;
+    this.raw_array = raw_array;
+  }
+
+  function SharedInfoWrapper(raw_array) {
+    this.function_name = raw_array[0];
+    this.start_position = raw_array[1];
+    this.end_position = raw_array[2];
+    this.info = raw_array[3];
+    this.raw_array = raw_array;
+  }
+
+  // Changes positions (including all statements) in function.
+  function PatchPositions(old_info_node, diff_array, report_array) {
+    if (old_info_node.live_shared_function_infos) {
+      old_info_node.live_shared_function_infos.forEach(function (info) {
+          %LiveEditPatchFunctionPositions(info.raw_array,
+                                          diff_array);
+      });
+
+      report_array.push( { name: old_info_node.info.function_name } );
+    } else {
+      // TODO(LiveEdit): function is not compiled yet or is already collected.
+      report_array.push(
+          { name: old_info_node.info.function_name, info_not_found: true } );
+    }
+  }
+
+  // Adds a suffix to script name to mark that it is old version.
+  function CreateNameForOldScript(script) {
+    // TODO(635): try better than this; support several changes.
+    return script.name + " (old)";
+  }
+
+  // Compares a function scope heap structure, old and new version, whether it
+  // changed or not. Returns explanation if they differ.
+  function IsFunctionContextLocalsChanged(function_info1, function_info2) {
+    var scope_info1 = function_info1.scope_info;
+    var scope_info2 = function_info2.scope_info;
+
+    var scope_info1_text;
+    var scope_info2_text;
+
+    if (scope_info1) {
+      scope_info1_text = scope_info1.toString();
+    } else {
+      scope_info1_text = "";
+    }
+    if (scope_info2) {
+      scope_info2_text = scope_info2.toString();
+    } else {
+      scope_info2_text = "";
+    }
+
+    if (scope_info1_text != scope_info2_text) {
+      return "Variable map changed: [" + scope_info1_text +
+          "] => [" + scope_info2_text + "]";
+    }
+    // No differences. Return undefined.
+    return;
+  }
+
+  // Minifier forward declaration.
+  var FunctionPatchabilityStatus;
+
+  // For array of wrapped shared function infos checks that none of them
+  // have activations on stack (of any thread). Throws a Failure exception
+  // if this proves to be false.
+  function CheckStackActivations(old_shared_wrapper_list,
+                                 new_shared_list,
+                                 change_log) {
+    var old_shared_list = new GlobalArray();
+    for (var i = 0; i < old_shared_wrapper_list.length; i++) {
+      old_shared_list[i] = old_shared_wrapper_list[i].info;
+    }
+    var result = %LiveEditCheckAndDropActivations(
+                     old_shared_list, new_shared_list, true);
+    if (result[old_shared_wrapper_list.length]) {
+      // Extra array element may contain error message.
+      throw new Failure(result[old_shared_wrapper_list.length]);
+    }
+
+    var problems = new GlobalArray();
+    var dropped = new GlobalArray();
+    for (var i = 0; i < old_shared_list.length; i++) {
+      var shared = old_shared_wrapper_list[i];
+      if (result[i] == FunctionPatchabilityStatus.REPLACED_ON_ACTIVE_STACK) {
+        dropped.push({ name: shared.function_name } );
+      } else if (result[i] != FunctionPatchabilityStatus.AVAILABLE_FOR_PATCH) {
+        var description = {
+            name: shared.function_name,
+            start_pos: shared.start_position,
+            end_pos: shared.end_position,
+            replace_problem:
+                FunctionPatchabilityStatus.SymbolName(result[i])
+        };
+        problems.push(description);
+      }
+    }
+    if (dropped.length > 0) {
+      change_log.push({ dropped_from_stack: dropped });
+    }
+    if (problems.length > 0) {
+      change_log.push( { functions_on_stack: problems } );
+      throw new Failure("Blocked by functions on stack");
+    }
+
+    return dropped.length;
+  }
+
+  // A copy of the FunctionPatchabilityStatus enum from liveedit.h
+  var FunctionPatchabilityStatus = {
+      AVAILABLE_FOR_PATCH: 1,
+      BLOCKED_ON_ACTIVE_STACK: 2,
+      BLOCKED_ON_OTHER_STACK: 3,
+      BLOCKED_UNDER_NATIVE_CODE: 4,
+      REPLACED_ON_ACTIVE_STACK: 5,
+      BLOCKED_UNDER_GENERATOR: 6,
+      BLOCKED_ACTIVE_GENERATOR: 7,
+      BLOCKED_NO_NEW_TARGET_ON_RESTART: 8
+  };
+
+  FunctionPatchabilityStatus.SymbolName = function(code) {
+    var enumeration = FunctionPatchabilityStatus;
+    for (var name in enumeration) {
+      if (enumeration[name] == code) {
+        return name;
+      }
+    }
+  };
+
+
+  // A logical failure in liveedit process. This means that change_log
+  // is valid and consistent description of what happened.
+  function Failure(message) {
+    this.message = message;
+  }
+
+  Failure.prototype.toString = function() {
+    return "LiveEdit Failure: " + this.message;
+  };
+
+  function CopyErrorPositionToDetails(e, details) {
+    function createPositionStruct(script, position) {
+      if (position == -1) return;
+      var location = script.locationFromPosition(position, true);
+      if (location == null) return;
+      return {
+        line: location.line + 1,
+        column: location.column + 1,
+        position: position
+      };
+    }
+
+    if (!("scriptObject" in e) || !("startPosition" in e)) {
+      return;
+    }
+
+    var script = e.scriptObject;
+
+    var position_struct = {
+      start: createPositionStruct(script, e.startPosition),
+      end: createPositionStruct(script, e.endPosition)
+    };
+    details.position = position_struct;
+  }
+
+  // A testing entry.
+  function GetPcFromSourcePos(func, source_pos) {
+    return %GetFunctionCodePositionFromSource(func, source_pos);
+  }
+
+  // LiveEdit main entry point: changes a script text to a new string.
+  function SetScriptSource(script, new_source, preview_only, change_log) {
+    var old_source = script.source;
+    var diff = CompareStrings(old_source, new_source);
+    return ApplyPatchMultiChunk(script, diff, new_source, preview_only,
+        change_log);
+  }
+
+  function CompareStrings(s1, s2) {
+    return %LiveEditCompareStrings(s1, s2);
+  }
+
+  // Applies the change to the script.
+  // The change is always a substring (change_pos, change_pos + change_len)
+  // being replaced with a completely different string new_str.
+  // This API is a legacy and is obsolete.
+  //
+  // @param {Script} script that is being changed
+  // @param {Array} change_log a list that collects engineer-readable
+  //     description of what happened.
+  function ApplySingleChunkPatch(script, change_pos, change_len, new_str,
+      change_log) {
+    var old_source = script.source;
+
+    // Prepare new source string.
+    var new_source = old_source.substring(0, change_pos) +
+        new_str + old_source.substring(change_pos + change_len);
+
+    return ApplyPatchMultiChunk(script,
+        [ change_pos, change_pos + change_len, change_pos + new_str.length],
+        new_source, false, change_log);
+  }
+
+  // Creates JSON description for a change tree.
+  function DescribeChangeTree(old_code_tree) {
+
+    function ProcessOldNode(node) {
+      var child_infos = [];
+      for (var i = 0; i < node.children.length; i++) {
+        var child = node.children[i];
+        if (child.status != FunctionStatus.UNCHANGED) {
+          child_infos.push(ProcessOldNode(child));
+        }
+      }
+      var new_child_infos = [];
+      if (node.textually_unmatched_new_nodes) {
+        for (var i = 0; i < node.textually_unmatched_new_nodes.length; i++) {
+          var child = node.textually_unmatched_new_nodes[i];
+          new_child_infos.push(ProcessNewNode(child));
+        }
+      }
+      var res = {
+        name: node.info.function_name,
+        positions: DescribePositions(node),
+        status: node.status,
+        children: child_infos,
+        new_children: new_child_infos
+      };
+      if (node.status_explanation) {
+        res.status_explanation = node.status_explanation;
+      }
+      if (node.textual_corresponding_node) {
+        res.new_positions = DescribePositions(node.textual_corresponding_node);
+      }
+      return res;
+    }
+
+    function ProcessNewNode(node) {
+      var child_infos = [];
+      // Do not list ancestors.
+      if (false) {
+        for (var i = 0; i < node.children.length; i++) {
+          child_infos.push(ProcessNewNode(node.children[i]));
+        }
+      }
+      var res = {
+        name: node.info.function_name,
+        positions: DescribePositions(node),
+        children: child_infos,
+      };
+      return res;
+    }
+
+    function DescribePositions(node) {
+      return {
+        start_position: node.info.start_position,
+        end_position: node.info.end_position
+      };
+    }
+
+    return ProcessOldNode(old_code_tree);
+  }
+
+  // -------------------------------------------------------------------
+  // Exports
+
+  var LiveEdit = {};
+  LiveEdit.SetScriptSource = SetScriptSource;
+  LiveEdit.ApplyPatchMultiChunk = ApplyPatchMultiChunk;
+  LiveEdit.Failure = Failure;
+  LiveEdit.GetPcFromSourcePos = GetPcFromSourcePos;
+
+  LiveEdit.TestApi = {
+    PosTranslator: PosTranslator,
+    CompareStrings: CompareStrings,
+    ApplySingleChunkPatch: ApplySingleChunkPatch
+  };
+
+  global.Debug.LiveEdit = LiveEdit;
+
+})
diff --git a/src/debug/mips/OWNERS b/src/debug/mips/OWNERS
new file mode 100644
index 0000000..89455a4
--- /dev/null
+++ b/src/debug/mips/OWNERS
@@ -0,0 +1,6 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
+ivica.bogosavljevic@imgtec.com
diff --git a/src/debug/mips/debug-mips.cc b/src/debug/mips/debug-mips.cc
new file mode 100644
index 0000000..c5c58d0
--- /dev/null
+++ b/src/debug/mips/debug-mips.cc
@@ -0,0 +1,143 @@
+// Copyright 2012 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.
+
+#if V8_TARGET_ARCH_MIPS
+
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_size;
+  __ bind(&check_size);
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
+  }
+  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+            masm->InstructionsGeneratedSince(&check_size));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the trampoline pool in the debug break slot code.
+  Assembler::BlockTrampolinePoolScope block_pool(masm);
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  // Patch the code changing the debug break slot code from:
+  //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
+  //   nop(DEBUG_BREAK_NOP)
+  //   nop(DEBUG_BREAK_NOP)
+  //   nop(DEBUG_BREAK_NOP)
+  // to a call to the debug break slot code.
+  //   li t9, address   (lui t9 / ori t9 instruction pair)
+  //   call t9          (jalr t9 / nop instruction pair)
+  patcher.masm()->li(v8::internal::t9,
+                     Operand(reinterpret_cast<int32_t>(code->entry())));
+  patcher.masm()->Call(v8::internal::t9);
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
+    __ Subu(sp, sp,
+            Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize));
+    for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) {
+      __ sw(at, MemOperand(sp, kPointerSize * i));
+    }
+    __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
+    __ push(at);
+
+    if (mode == SAVE_RESULT_REGISTER) __ push(v0);
+
+    __ PrepareCEntryArgs(0);  // No arguments.
+    __ PrepareCEntryFunction(ExternalReference(
+        Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ li(reg, kDebugZapValue);
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ pop(v0);
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ li(t9, Operand(after_break_target));
+  __ lw(t9, MemOperand(t9));
+  __ Jump(t9);
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // We do not know our frame height, but set sp based on fp.
+  __ Subu(sp, fp, Operand(kPointerSize));
+
+  __ Pop(ra, fp, a1);  // Return address, Frame, Function.
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(a1, no_reg, dummy, dummy);
+
+  // Load context from the function.
+  __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+
+  // Clear new.target as a safety measure.
+  __ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
+
+  // Get function code.
+  __ lw(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  __ lw(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset));
+  __ Addu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // Re-run JSFunction, a1 is function, cp is context.
+  __ Jump(t9);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_MIPS
diff --git a/src/debug/mips64/OWNERS b/src/debug/mips64/OWNERS
new file mode 100644
index 0000000..89455a4
--- /dev/null
+++ b/src/debug/mips64/OWNERS
@@ -0,0 +1,6 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
+ivica.bogosavljevic@imgtec.com
diff --git a/src/debug/mips64/debug-mips64.cc b/src/debug/mips64/debug-mips64.cc
new file mode 100644
index 0000000..1d65fd9
--- /dev/null
+++ b/src/debug/mips64/debug-mips64.cc
@@ -0,0 +1,145 @@
+// Copyright 2012 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.
+
+#if V8_TARGET_ARCH_MIPS64
+
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_size;
+  __ bind(&check_size);
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
+  }
+  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+            masm->InstructionsGeneratedSince(&check_size));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the trampoline pool in the debug break slot code.
+  Assembler::BlockTrampolinePoolScope block_pool(masm);
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  // Patch the code changing the debug break slot code from:
+  //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
+  //   nop(DEBUG_BREAK_NOP)
+  //   nop(DEBUG_BREAK_NOP)
+  //   nop(DEBUG_BREAK_NOP)
+  //   nop(DEBUG_BREAK_NOP)
+  //   nop(DEBUG_BREAK_NOP)
+  // to a call to the debug break slot code.
+  //   li t9, address   (4-instruction sequence on mips64)
+  //   call t9          (jalr t9 / nop instruction pair)
+  patcher.masm()->li(v8::internal::t9,
+                     Operand(reinterpret_cast<int64_t>(code->entry())),
+                     ADDRESS_LOAD);
+  patcher.masm()->Call(v8::internal::t9);
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
+    __ Dsubu(sp, sp,
+            Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize));
+    for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) {
+      __ sd(at, MemOperand(sp, kPointerSize * i));
+    }
+    __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
+    __ push(at);
+
+    if (mode == SAVE_RESULT_REGISTER) __ push(v0);
+
+    __ PrepareCEntryArgs(0);  // No arguments.
+    __ PrepareCEntryFunction(ExternalReference(
+        Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ li(reg, kDebugZapValue);
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ pop(v0);
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ li(t9, Operand(after_break_target));
+  __ ld(t9, MemOperand(t9));
+  __ Jump(t9);
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // We do not know our frame height, but set sp based on fp.
+  __ Dsubu(sp, fp, Operand(kPointerSize));
+
+  __ Pop(ra, fp, a1);  // Return address, Frame, Function.
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(a1, no_reg, dummy, dummy);
+
+  // Load context from the function.
+  __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+
+  // Clear new.target as a safety measure.
+  __ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
+
+  // Get function code.
+  __ ld(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  __ ld(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset));
+  __ Daddu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // Re-run JSFunction, a1 is function, cp is context.
+  __ Jump(t9);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_MIPS64
diff --git a/src/debug/mirrors.js b/src/debug/mirrors.js
new file mode 100644
index 0000000..1fd5fa9
--- /dev/null
+++ b/src/debug/mirrors.js
@@ -0,0 +1,3053 @@
+// Copyright 2006-2012 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.
+
+(function(global, utils) {
+"use strict";
+
+// ----------------------------------------------------------------------------
+// Imports
+
+var ErrorToString;
+var GlobalArray = global.Array;
+var IsNaN = global.isNaN;
+var JSONStringify = global.JSON.stringify;
+var MakeError;
+var MapEntries;
+var MapIteratorNext;
+var MathMin = global.Math.min;
+var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
+var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
+var SetIteratorNext;
+var SetValues;
+var SymbolToString;
+
+utils.Import(function(from) {
+  ErrorToString = from.ErrorToString;
+  MakeError = from.MakeError;
+  MapEntries = from.MapEntries;
+  MapIteratorNext = from.MapIteratorNext;
+  SetIteratorNext = from.SetIteratorNext;
+  SetValues = from.SetValues;
+  SymbolToString = from.SymbolToString;
+});
+
+// ----------------------------------------------------------------------------
+
+// Mirror hierarchy:
+// - Mirror
+//   - ValueMirror
+//     - UndefinedMirror
+//     - NullMirror
+//     - BooleanMirror
+//     - NumberMirror
+//     - StringMirror
+//     - SymbolMirror
+//     - ObjectMirror
+//       - FunctionMirror
+//         - UnresolvedFunctionMirror
+//       - ArrayMirror
+//       - DateMirror
+//       - RegExpMirror
+//       - ErrorMirror
+//       - PromiseMirror
+//       - MapMirror
+//       - SetMirror
+//       - IteratorMirror
+//       - GeneratorMirror
+//   - PropertyMirror
+//   - InternalPropertyMirror
+//   - FrameMirror
+//   - ScriptMirror
+//   - ScopeMirror
+
+// Type names of the different mirrors.
+var MirrorType = {
+  UNDEFINED_TYPE : 'undefined',
+  NULL_TYPE : 'null',
+  BOOLEAN_TYPE : 'boolean',
+  NUMBER_TYPE : 'number',
+  STRING_TYPE : 'string',
+  SYMBOL_TYPE : 'symbol',
+  OBJECT_TYPE : 'object',
+  FUNCTION_TYPE : 'function',
+  REGEXP_TYPE : 'regexp',
+  ERROR_TYPE : 'error',
+  PROPERTY_TYPE : 'property',
+  INTERNAL_PROPERTY_TYPE : 'internalProperty',
+  FRAME_TYPE : 'frame',
+  SCRIPT_TYPE : 'script',
+  CONTEXT_TYPE : 'context',
+  SCOPE_TYPE : 'scope',
+  PROMISE_TYPE : 'promise',
+  MAP_TYPE : 'map',
+  SET_TYPE : 'set',
+  ITERATOR_TYPE : 'iterator',
+  GENERATOR_TYPE : 'generator',
+}
+
+
+// Handle id counters.
+var next_handle_ = 0;
+var next_transient_handle_ = -1;
+
+// Mirror cache.
+var mirror_cache_ = [];
+var mirror_cache_enabled_ = true;
+
+
+function MirrorCacheIsEmpty() {
+  return next_handle_ == 0 && mirror_cache_.length == 0;
+}
+
+
+function ToggleMirrorCache(value) {
+  mirror_cache_enabled_ = value;
+  ClearMirrorCache();
+}
+
+
+function ClearMirrorCache(value) {
+  next_handle_ = 0;
+  mirror_cache_ = [];
+}
+
+
+function ObjectIsPromise(value) {
+  return IS_RECEIVER(value) &&
+         !IS_UNDEFINED(%DebugGetProperty(value, promiseStatusSymbol));
+}
+
+
+/**
+ * Returns the mirror for a specified value or object.
+ *
+ * @param {value or Object} value the value or object to retreive the mirror for
+ * @param {boolean} transient indicate whether this object is transient and
+ *    should not be added to the mirror cache. The default is not transient.
+ * @returns {Mirror} the mirror reflects the passed value or object
+ */
+function MakeMirror(value, opt_transient) {
+  var mirror;
+
+  // Look for non transient mirrors in the mirror cache.
+  if (!opt_transient && mirror_cache_enabled_) {
+    for (var id in mirror_cache_) {
+      mirror = mirror_cache_[id];
+      if (mirror.value() === value) {
+        return mirror;
+      }
+      // Special check for NaN as NaN == NaN is false.
+      if (mirror.isNumber() && IsNaN(mirror.value()) &&
+          typeof value == 'number' && IsNaN(value)) {
+        return mirror;
+      }
+    }
+  }
+
+  if (IS_UNDEFINED(value)) {
+    mirror = new UndefinedMirror();
+  } else if (IS_NULL(value)) {
+    mirror = new NullMirror();
+  } else if (IS_BOOLEAN(value)) {
+    mirror = new BooleanMirror(value);
+  } else if (IS_NUMBER(value)) {
+    mirror = new NumberMirror(value);
+  } else if (IS_STRING(value)) {
+    mirror = new StringMirror(value);
+  } else if (IS_SYMBOL(value)) {
+    mirror = new SymbolMirror(value);
+  } else if (IS_ARRAY(value)) {
+    mirror = new ArrayMirror(value);
+  } else if (IS_DATE(value)) {
+    mirror = new DateMirror(value);
+  } else if (IS_FUNCTION(value)) {
+    mirror = new FunctionMirror(value);
+  } else if (IS_REGEXP(value)) {
+    mirror = new RegExpMirror(value);
+  } else if (IS_ERROR(value)) {
+    mirror = new ErrorMirror(value);
+  } else if (IS_SCRIPT(value)) {
+    mirror = new ScriptMirror(value);
+  } else if (IS_MAP(value) || IS_WEAKMAP(value)) {
+    mirror = new MapMirror(value);
+  } else if (IS_SET(value) || IS_WEAKSET(value)) {
+    mirror = new SetMirror(value);
+  } else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) {
+    mirror = new IteratorMirror(value);
+  } else if (ObjectIsPromise(value)) {
+    mirror = new PromiseMirror(value);
+  } else if (IS_GENERATOR(value)) {
+    mirror = new GeneratorMirror(value);
+  } else {
+    mirror = new ObjectMirror(value, MirrorType.OBJECT_TYPE, opt_transient);
+  }
+
+  if (mirror_cache_enabled_) mirror_cache_[mirror.handle()] = mirror;
+  return mirror;
+}
+
+
+/**
+ * Returns the mirror for a specified mirror handle.
+ *
+ * @param {number} handle the handle to find the mirror for
+ * @returns {Mirror or undefiend} the mirror with the requested handle or
+ *     undefined if no mirror with the requested handle was found
+ */
+function LookupMirror(handle) {
+  if (!mirror_cache_enabled_) {
+    throw MakeError(kDebugger, "Mirror cache is disabled");
+  }
+  return mirror_cache_[handle];
+}
+
+
+/**
+ * Returns the mirror for the undefined value.
+ *
+ * @returns {Mirror} the mirror reflects the undefined value
+ */
+function GetUndefinedMirror() {
+  return MakeMirror(UNDEFINED);
+}
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
+ * during bootstrapping this function needs to be revritten using some native
+ * functions as prototype setup using normal JavaScript does not work as
+ * expected during bootstrapping (see mirror.js in r114903).
+ *
+ * @param {function} ctor Constructor function which needs to inherit the
+ *     prototype
+ * @param {function} superCtor Constructor function to inherit prototype from
+ */
+function inherits(ctor, superCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = superCtor.prototype;
+  ctor.super_ = superCtor.prototype;
+  ctor.prototype = new tempCtor();
+  ctor.prototype.constructor = ctor;
+}
+
+// Maximum length when sending strings through the JSON protocol.
+var kMaxProtocolStringLength = 80;
+
+
+// A copy of the PropertyType enum from property-details.h
+var PropertyType = {};
+PropertyType.Data                        = 0;
+PropertyType.DataConstant                = 2;
+PropertyType.AccessorConstant            = 3;
+
+
+// Different attributes for a property.
+var PropertyAttribute = {};
+PropertyAttribute.None       = NONE;
+PropertyAttribute.ReadOnly   = READ_ONLY;
+PropertyAttribute.DontEnum   = DONT_ENUM;
+PropertyAttribute.DontDelete = DONT_DELETE;
+
+
+// A copy of the scope types from runtime-debug.cc.
+// NOTE: these constants should be backward-compatible, so
+// add new ones to the end of this list.
+var ScopeType = { Global: 0,
+                  Local: 1,
+                  With: 2,
+                  Closure: 3,
+                  Catch: 4,
+                  Block: 5,
+                  Script: 6 };
+
+/**
+ * Base class for all mirror objects.
+ * @param {string} type The type of the mirror
+ * @constructor
+ */
+function Mirror(type) {
+  this.type_ = type;
+}
+
+
+Mirror.prototype.type = function() {
+  return this.type_;
+};
+
+
+/**
+ * Check whether the mirror reflects a value.
+ * @returns {boolean} True if the mirror reflects a value.
+ */
+Mirror.prototype.isValue = function() {
+  return this instanceof ValueMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects the undefined value.
+ * @returns {boolean} True if the mirror reflects the undefined value.
+ */
+Mirror.prototype.isUndefined = function() {
+  return this instanceof UndefinedMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects the null value.
+ * @returns {boolean} True if the mirror reflects the null value
+ */
+Mirror.prototype.isNull = function() {
+  return this instanceof NullMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a boolean value.
+ * @returns {boolean} True if the mirror reflects a boolean value
+ */
+Mirror.prototype.isBoolean = function() {
+  return this instanceof BooleanMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a number value.
+ * @returns {boolean} True if the mirror reflects a number value
+ */
+Mirror.prototype.isNumber = function() {
+  return this instanceof NumberMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a string value.
+ * @returns {boolean} True if the mirror reflects a string value
+ */
+Mirror.prototype.isString = function() {
+  return this instanceof StringMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a symbol.
+ * @returns {boolean} True if the mirror reflects a symbol
+ */
+Mirror.prototype.isSymbol = function() {
+  return this instanceof SymbolMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects an object.
+ * @returns {boolean} True if the mirror reflects an object
+ */
+Mirror.prototype.isObject = function() {
+  return this instanceof ObjectMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a function.
+ * @returns {boolean} True if the mirror reflects a function
+ */
+Mirror.prototype.isFunction = function() {
+  return this instanceof FunctionMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects an unresolved function.
+ * @returns {boolean} True if the mirror reflects an unresolved function
+ */
+Mirror.prototype.isUnresolvedFunction = function() {
+  return this instanceof UnresolvedFunctionMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects an array.
+ * @returns {boolean} True if the mirror reflects an array
+ */
+Mirror.prototype.isArray = function() {
+  return this instanceof ArrayMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a date.
+ * @returns {boolean} True if the mirror reflects a date
+ */
+Mirror.prototype.isDate = function() {
+  return this instanceof DateMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a regular expression.
+ * @returns {boolean} True if the mirror reflects a regular expression
+ */
+Mirror.prototype.isRegExp = function() {
+  return this instanceof RegExpMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects an error.
+ * @returns {boolean} True if the mirror reflects an error
+ */
+Mirror.prototype.isError = function() {
+  return this instanceof ErrorMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a promise.
+ * @returns {boolean} True if the mirror reflects a promise
+ */
+Mirror.prototype.isPromise = function() {
+  return this instanceof PromiseMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a generator object.
+ * @returns {boolean} True if the mirror reflects a generator object
+ */
+Mirror.prototype.isGenerator = function() {
+  return this instanceof GeneratorMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a property.
+ * @returns {boolean} True if the mirror reflects a property
+ */
+Mirror.prototype.isProperty = function() {
+  return this instanceof PropertyMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects an internal property.
+ * @returns {boolean} True if the mirror reflects an internal property
+ */
+Mirror.prototype.isInternalProperty = function() {
+  return this instanceof InternalPropertyMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a stack frame.
+ * @returns {boolean} True if the mirror reflects a stack frame
+ */
+Mirror.prototype.isFrame = function() {
+  return this instanceof FrameMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a script.
+ * @returns {boolean} True if the mirror reflects a script
+ */
+Mirror.prototype.isScript = function() {
+  return this instanceof ScriptMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a context.
+ * @returns {boolean} True if the mirror reflects a context
+ */
+Mirror.prototype.isContext = function() {
+  return this instanceof ContextMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a scope.
+ * @returns {boolean} True if the mirror reflects a scope
+ */
+Mirror.prototype.isScope = function() {
+  return this instanceof ScopeMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a map.
+ * @returns {boolean} True if the mirror reflects a map
+ */
+Mirror.prototype.isMap = function() {
+  return this instanceof MapMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects a set.
+ * @returns {boolean} True if the mirror reflects a set
+ */
+Mirror.prototype.isSet = function() {
+  return this instanceof SetMirror;
+};
+
+
+/**
+ * Check whether the mirror reflects an iterator.
+ * @returns {boolean} True if the mirror reflects an iterator
+ */
+Mirror.prototype.isIterator = function() {
+  return this instanceof IteratorMirror;
+};
+
+
+/**
+ * Allocate a handle id for this object.
+ */
+Mirror.prototype.allocateHandle_ = function() {
+  if (mirror_cache_enabled_) this.handle_ = next_handle_++;
+};
+
+
+/**
+ * Allocate a transient handle id for this object. Transient handles are
+ * negative.
+ */
+Mirror.prototype.allocateTransientHandle_ = function() {
+  this.handle_ = next_transient_handle_--;
+};
+
+
+Mirror.prototype.toText = function() {
+  // Simpel to text which is used when on specialization in subclass.
+  return "#<" + this.constructor.name + ">";
+};
+
+
+/**
+ * Base class for all value mirror objects.
+ * @param {string} type The type of the mirror
+ * @param {value} value The value reflected by this mirror
+ * @param {boolean} transient indicate whether this object is transient with a
+ *    transient handle
+ * @constructor
+ * @extends Mirror
+ */
+function ValueMirror(type, value, transient) {
+  %_Call(Mirror, this, type);
+  this.value_ = value;
+  if (!transient) {
+    this.allocateHandle_();
+  } else {
+    this.allocateTransientHandle_();
+  }
+}
+inherits(ValueMirror, Mirror);
+
+
+Mirror.prototype.handle = function() {
+  return this.handle_;
+};
+
+
+/**
+ * Check whether this is a primitive value.
+ * @return {boolean} True if the mirror reflects a primitive value
+ */
+ValueMirror.prototype.isPrimitive = function() {
+  var type = this.type();
+  return type === 'undefined' ||
+         type === 'null' ||
+         type === 'boolean' ||
+         type === 'number' ||
+         type === 'string' ||
+         type === 'symbol';
+};
+
+
+/**
+ * Get the actual value reflected by this mirror.
+ * @return {value} The value reflected by this mirror
+ */
+ValueMirror.prototype.value = function() {
+  return this.value_;
+};
+
+
+/**
+ * Mirror object for Undefined.
+ * @constructor
+ * @extends ValueMirror
+ */
+function UndefinedMirror() {
+  %_Call(ValueMirror, this, MirrorType.UNDEFINED_TYPE, UNDEFINED);
+}
+inherits(UndefinedMirror, ValueMirror);
+
+
+UndefinedMirror.prototype.toText = function() {
+  return 'undefined';
+};
+
+
+/**
+ * Mirror object for null.
+ * @constructor
+ * @extends ValueMirror
+ */
+function NullMirror() {
+  %_Call(ValueMirror, this, MirrorType.NULL_TYPE, null);
+}
+inherits(NullMirror, ValueMirror);
+
+
+NullMirror.prototype.toText = function() {
+  return 'null';
+};
+
+
+/**
+ * Mirror object for boolean values.
+ * @param {boolean} value The boolean value reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function BooleanMirror(value) {
+  %_Call(ValueMirror, this, MirrorType.BOOLEAN_TYPE, value);
+}
+inherits(BooleanMirror, ValueMirror);
+
+
+BooleanMirror.prototype.toText = function() {
+  return this.value_ ? 'true' : 'false';
+};
+
+
+/**
+ * Mirror object for number values.
+ * @param {number} value The number value reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function NumberMirror(value) {
+  %_Call(ValueMirror, this, MirrorType.NUMBER_TYPE, value);
+}
+inherits(NumberMirror, ValueMirror);
+
+
+NumberMirror.prototype.toText = function() {
+  return %_NumberToString(this.value_);
+};
+
+
+/**
+ * Mirror object for string values.
+ * @param {string} value The string value reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function StringMirror(value) {
+  %_Call(ValueMirror, this, MirrorType.STRING_TYPE, value);
+}
+inherits(StringMirror, ValueMirror);
+
+
+StringMirror.prototype.length = function() {
+  return this.value_.length;
+};
+
+StringMirror.prototype.getTruncatedValue = function(maxLength) {
+  if (maxLength != -1 && this.length() > maxLength) {
+    return this.value_.substring(0, maxLength) +
+           '... (length: ' + this.length() + ')';
+  }
+  return this.value_;
+};
+
+StringMirror.prototype.toText = function() {
+  return this.getTruncatedValue(kMaxProtocolStringLength);
+};
+
+
+/**
+ * Mirror object for a Symbol
+ * @param {Object} value The Symbol
+ * @constructor
+ * @extends Mirror
+ */
+function SymbolMirror(value) {
+  %_Call(ValueMirror, this, MirrorType.SYMBOL_TYPE, value);
+}
+inherits(SymbolMirror, ValueMirror);
+
+
+SymbolMirror.prototype.description = function() {
+  return %SymbolDescription(%_ValueOf(this.value_));
+}
+
+
+SymbolMirror.prototype.toText = function() {
+  return %_Call(SymbolToString, this.value_);
+}
+
+
+/**
+ * Mirror object for objects.
+ * @param {object} value The object reflected by this mirror
+ * @param {boolean} transient indicate whether this object is transient with a
+ *    transient handle
+ * @constructor
+ * @extends ValueMirror
+ */
+function ObjectMirror(value, type, transient) {
+  type = type || MirrorType.OBJECT_TYPE;
+  %_Call(ValueMirror, this, type, value, transient);
+}
+inherits(ObjectMirror, ValueMirror);
+
+
+ObjectMirror.prototype.className = function() {
+  return %_ClassOf(this.value_);
+};
+
+
+ObjectMirror.prototype.constructorFunction = function() {
+  return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
+};
+
+
+ObjectMirror.prototype.prototypeObject = function() {
+  return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
+};
+
+
+ObjectMirror.prototype.protoObject = function() {
+  return MakeMirror(%DebugGetPrototype(this.value_));
+};
+
+
+ObjectMirror.prototype.hasNamedInterceptor = function() {
+  // Get information on interceptors for this object.
+  var x = %GetInterceptorInfo(this.value_);
+  return (x & 2) != 0;
+};
+
+
+ObjectMirror.prototype.hasIndexedInterceptor = function() {
+  // Get information on interceptors for this object.
+  var x = %GetInterceptorInfo(this.value_);
+  return (x & 1) != 0;
+};
+
+
+/**
+ * Return the property names for this object.
+ * @param {number} kind Indicate whether named, indexed or both kinds of
+ *     properties are requested
+ * @param {number} limit Limit the number of names returend to the specified
+       value
+ * @return {Array} Property names for this object
+ */
+ObjectMirror.prototype.propertyNames = function() {
+  return %GetOwnPropertyKeys(this.value_, PROPERTY_FILTER_NONE);
+};
+
+
+/**
+ * Return the properties for this object as an array of PropertyMirror objects.
+ * @param {number} kind Indicate whether named, indexed or both kinds of
+ *     properties are requested
+ * @param {number} limit Limit the number of properties returned to the
+       specified value
+ * @return {Array} Property mirrors for this object
+ */
+ObjectMirror.prototype.properties = function() {
+  var names = this.propertyNames();
+  var properties = new GlobalArray(names.length);
+  for (var i = 0; i < names.length; i++) {
+    properties[i] = this.property(names[i]);
+  }
+
+  return properties;
+};
+
+
+/**
+ * Return the internal properties for this object as an array of
+ * InternalPropertyMirror objects.
+ * @return {Array} Property mirrors for this object
+ */
+ObjectMirror.prototype.internalProperties = function() {
+  return ObjectMirror.GetInternalProperties(this.value_);
+}
+
+
+ObjectMirror.prototype.property = function(name) {
+  var details = %DebugGetPropertyDetails(this.value_, TO_NAME(name));
+  if (details) {
+    return new PropertyMirror(this, name, details);
+  }
+
+  // Nothing found.
+  return GetUndefinedMirror();
+};
+
+
+
+/**
+ * Try to find a property from its value.
+ * @param {Mirror} value The property value to look for
+ * @return {PropertyMirror} The property with the specified value. If no
+ *     property was found with the specified value UndefinedMirror is returned
+ */
+ObjectMirror.prototype.lookupProperty = function(value) {
+  var properties = this.properties();
+
+  // Look for property value in properties.
+  for (var i = 0; i < properties.length; i++) {
+
+    // Skip properties which are defined through accessors.
+    var property = properties[i];
+    if (property.propertyType() != PropertyType.AccessorConstant) {
+      if (%_ObjectEquals(property.value_, value.value_)) {
+        return property;
+      }
+    }
+  }
+
+  // Nothing found.
+  return GetUndefinedMirror();
+};
+
+
+/**
+ * Returns objects which has direct references to this object
+ * @param {number} opt_max_objects Optional parameter specifying the maximum
+ *     number of referencing objects to return.
+ * @return {Array} The objects which has direct references to this object.
+ */
+ObjectMirror.prototype.referencedBy = function(opt_max_objects) {
+  // Find all objects with direct references to this object.
+  var result = %DebugReferencedBy(this.value_,
+                                  Mirror.prototype, opt_max_objects || 0);
+
+  // Make mirrors for all the references found.
+  for (var i = 0; i < result.length; i++) {
+    result[i] = MakeMirror(result[i]);
+  }
+
+  return result;
+};
+
+
+ObjectMirror.prototype.toText = function() {
+  var name;
+  var ctor = this.constructorFunction();
+  if (!ctor.isFunction()) {
+    name = this.className();
+  } else {
+    name = ctor.name();
+    if (!name) {
+      name = this.className();
+    }
+  }
+  return '#<' + name + '>';
+};
+
+
+/**
+ * Return the internal properties of the value, such as [[PrimitiveValue]] of
+ * scalar wrapper objects, properties of the bound function and properties of
+ * the promise.
+ * This method is done static to be accessible from Debug API with the bare
+ * values without mirrors.
+ * @return {Array} array (possibly empty) of InternalProperty instances
+ */
+ObjectMirror.GetInternalProperties = function(value) {
+  var properties = %DebugGetInternalProperties(value);
+  var result = [];
+  for (var i = 0; i < properties.length; i += 2) {
+    result.push(new InternalPropertyMirror(properties[i], properties[i + 1]));
+  }
+  return result;
+}
+
+
+/**
+ * Mirror object for functions.
+ * @param {function} value The function object reflected by this mirror.
+ * @constructor
+ * @extends ObjectMirror
+ */
+function FunctionMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.FUNCTION_TYPE);
+  this.resolved_ = true;
+}
+inherits(FunctionMirror, ObjectMirror);
+
+
+/**
+ * Returns whether the function is resolved.
+ * @return {boolean} True if the function is resolved. Unresolved functions can
+ *     only originate as functions from stack frames
+ */
+FunctionMirror.prototype.resolved = function() {
+  return this.resolved_;
+};
+
+
+/**
+ * Returns the name of the function.
+ * @return {string} Name of the function
+ */
+FunctionMirror.prototype.name = function() {
+  return %FunctionGetName(this.value_);
+};
+
+
+/**
+ * Returns the displayName if it is set, otherwise name, otherwise inferred
+ * name.
+ * @return {string} Name of the function
+ */
+FunctionMirror.prototype.debugName = function() {
+  return %FunctionGetDebugName(this.value_);
+}
+
+
+/**
+ * Returns the inferred name of the function.
+ * @return {string} Name of the function
+ */
+FunctionMirror.prototype.inferredName = function() {
+  return %FunctionGetInferredName(this.value_);
+};
+
+
+/**
+ * Returns the source code for the function.
+ * @return {string or undefined} The source code for the function. If the
+ *     function is not resolved undefined will be returned.
+ */
+FunctionMirror.prototype.source = function() {
+  // Return source if function is resolved. Otherwise just fall through to
+  // return undefined.
+  if (this.resolved()) {
+    return %FunctionToString(this.value_);
+  }
+};
+
+
+/**
+ * Returns the script object for the function.
+ * @return {ScriptMirror or undefined} Script object for the function or
+ *     undefined if the function has no script
+ */
+FunctionMirror.prototype.script = function() {
+  // Return script if function is resolved. Otherwise just fall through
+  // to return undefined.
+  if (this.resolved()) {
+    if (this.script_) {
+      return this.script_;
+    }
+    var script = %FunctionGetScript(this.value_);
+    if (script) {
+      return this.script_ = MakeMirror(script);
+    }
+  }
+};
+
+
+/**
+ * Returns the script source position for the function. Only makes sense
+ * for functions which has a script defined.
+ * @return {Number or undefined} in-script position for the function
+ */
+FunctionMirror.prototype.sourcePosition_ = function() {
+  // Return position if function is resolved. Otherwise just fall
+  // through to return undefined.
+  if (this.resolved()) {
+    return %FunctionGetScriptSourcePosition(this.value_);
+  }
+};
+
+
+/**
+ * Returns the script source location object for the function. Only makes sense
+ * for functions which has a script defined.
+ * @return {Location or undefined} in-script location for the function begin
+ */
+FunctionMirror.prototype.sourceLocation = function() {
+  if (this.resolved()) {
+    var script = this.script();
+    if (script) {
+      return script.locationFromPosition(this.sourcePosition_(), true);
+    }
+  }
+};
+
+
+/**
+ * Returns objects constructed by this function.
+ * @param {number} opt_max_instances Optional parameter specifying the maximum
+ *     number of instances to return.
+ * @return {Array or undefined} The objects constructed by this function.
+ */
+FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
+  if (this.resolved()) {
+    // Find all objects constructed from this function.
+    var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
+
+    // Make mirrors for all the instances found.
+    for (var i = 0; i < result.length; i++) {
+      result[i] = MakeMirror(result[i]);
+    }
+
+    return result;
+  } else {
+    return [];
+  }
+};
+
+
+FunctionMirror.prototype.scopeCount = function() {
+  if (this.resolved()) {
+    if (IS_UNDEFINED(this.scopeCount_)) {
+      this.scopeCount_ = %GetFunctionScopeCount(this.value());
+    }
+    return this.scopeCount_;
+  } else {
+    return 0;
+  }
+};
+
+
+FunctionMirror.prototype.scope = function(index) {
+  if (this.resolved()) {
+    return new ScopeMirror(UNDEFINED, this, index);
+  }
+};
+
+
+FunctionMirror.prototype.toText = function() {
+  return this.source();
+};
+
+
+/**
+ * Mirror object for unresolved functions.
+ * @param {string} value The name for the unresolved function reflected by this
+ *     mirror.
+ * @constructor
+ * @extends ObjectMirror
+ */
+function UnresolvedFunctionMirror(value) {
+  // Construct this using the ValueMirror as an unresolved function is not a
+  // real object but just a string.
+  %_Call(ValueMirror, this, MirrorType.FUNCTION_TYPE, value);
+  this.propertyCount_ = 0;
+  this.elementCount_ = 0;
+  this.resolved_ = false;
+}
+inherits(UnresolvedFunctionMirror, FunctionMirror);
+
+
+UnresolvedFunctionMirror.prototype.className = function() {
+  return 'Function';
+};
+
+
+UnresolvedFunctionMirror.prototype.constructorFunction = function() {
+  return GetUndefinedMirror();
+};
+
+
+UnresolvedFunctionMirror.prototype.prototypeObject = function() {
+  return GetUndefinedMirror();
+};
+
+
+UnresolvedFunctionMirror.prototype.protoObject = function() {
+  return GetUndefinedMirror();
+};
+
+
+UnresolvedFunctionMirror.prototype.name = function() {
+  return this.value_;
+};
+
+
+UnresolvedFunctionMirror.prototype.inferredName = function() {
+  return UNDEFINED;
+};
+
+
+UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
+  return [];
+};
+
+
+/**
+ * Mirror object for arrays.
+ * @param {Array} value The Array object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function ArrayMirror(value) {
+  %_Call(ObjectMirror, this, value);
+}
+inherits(ArrayMirror, ObjectMirror);
+
+
+ArrayMirror.prototype.length = function() {
+  return this.value_.length;
+};
+
+
+ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index,
+                                                            opt_to_index) {
+  var from_index = opt_from_index || 0;
+  var to_index = opt_to_index || this.length() - 1;
+  if (from_index > to_index) return new GlobalArray();
+  var values = new GlobalArray(to_index - from_index + 1);
+  for (var i = from_index; i <= to_index; i++) {
+    var details = %DebugGetPropertyDetails(this.value_, TO_STRING(i));
+    var value;
+    if (details) {
+      value = new PropertyMirror(this, i, details);
+    } else {
+      value = GetUndefinedMirror();
+    }
+    values[i - from_index] = value;
+  }
+  return values;
+};
+
+
+/**
+ * Mirror object for dates.
+ * @param {Date} value The Date object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function DateMirror(value) {
+  %_Call(ObjectMirror, this, value);
+}
+inherits(DateMirror, ObjectMirror);
+
+
+DateMirror.prototype.toText = function() {
+  var s = JSONStringify(this.value_);
+  return s.substring(1, s.length - 1);  // cut quotes
+};
+
+
+/**
+ * Mirror object for regular expressions.
+ * @param {RegExp} value The RegExp object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function RegExpMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.REGEXP_TYPE);
+}
+inherits(RegExpMirror, ObjectMirror);
+
+
+/**
+ * Returns the source to the regular expression.
+ * @return {string or undefined} The source to the regular expression
+ */
+RegExpMirror.prototype.source = function() {
+  return this.value_.source;
+};
+
+
+/**
+ * Returns whether this regular expression has the global (g) flag set.
+ * @return {boolean} Value of the global flag
+ */
+RegExpMirror.prototype.global = function() {
+  return this.value_.global;
+};
+
+
+/**
+ * Returns whether this regular expression has the ignore case (i) flag set.
+ * @return {boolean} Value of the ignore case flag
+ */
+RegExpMirror.prototype.ignoreCase = function() {
+  return this.value_.ignoreCase;
+};
+
+
+/**
+ * Returns whether this regular expression has the multiline (m) flag set.
+ * @return {boolean} Value of the multiline flag
+ */
+RegExpMirror.prototype.multiline = function() {
+  return this.value_.multiline;
+};
+
+
+/**
+ * Returns whether this regular expression has the sticky (y) flag set.
+ * @return {boolean} Value of the sticky flag
+ */
+RegExpMirror.prototype.sticky = function() {
+  return this.value_.sticky;
+};
+
+
+/**
+ * Returns whether this regular expression has the unicode (u) flag set.
+ * @return {boolean} Value of the unicode flag
+ */
+RegExpMirror.prototype.unicode = function() {
+  return this.value_.unicode;
+};
+
+
+RegExpMirror.prototype.toText = function() {
+  // Simpel to text which is used when on specialization in subclass.
+  return "/" + this.source() + "/";
+};
+
+
+/**
+ * Mirror object for error objects.
+ * @param {Error} value The error object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function ErrorMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.ERROR_TYPE);
+}
+inherits(ErrorMirror, ObjectMirror);
+
+
+/**
+ * Returns the message for this eror object.
+ * @return {string or undefined} The message for this eror object
+ */
+ErrorMirror.prototype.message = function() {
+  return this.value_.message;
+};
+
+
+ErrorMirror.prototype.toText = function() {
+  // Use the same text representation as in messages.js.
+  var text;
+  try {
+    text = %_Call(ErrorToString, this.value_);
+  } catch (e) {
+    text = '#<Error>';
+  }
+  return text;
+};
+
+
+/**
+ * Mirror object for a Promise object.
+ * @param {Object} value The Promise object
+ * @constructor
+ * @extends ObjectMirror
+ */
+function PromiseMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.PROMISE_TYPE);
+}
+inherits(PromiseMirror, ObjectMirror);
+
+
+function PromiseGetStatus_(value) {
+  var status = %DebugGetProperty(value, promiseStatusSymbol);
+  if (status == 0) return "pending";
+  if (status == 1) return "resolved";
+  return "rejected";
+}
+
+
+function PromiseGetValue_(value) {
+  return %DebugGetProperty(value, promiseValueSymbol);
+}
+
+
+PromiseMirror.prototype.status = function() {
+  return PromiseGetStatus_(this.value_);
+};
+
+
+PromiseMirror.prototype.promiseValue = function() {
+  return MakeMirror(PromiseGetValue_(this.value_));
+};
+
+
+function MapMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.MAP_TYPE);
+}
+inherits(MapMirror, ObjectMirror);
+
+
+/**
+ * Returns an array of key/value pairs of a map.
+ * This will keep keys alive for WeakMaps.
+ *
+ * @param {number=} opt_limit Max elements to return.
+ * @returns {Array.<Object>} Array of key/value pairs of a map.
+ */
+MapMirror.prototype.entries = function(opt_limit) {
+  var result = [];
+
+  if (IS_WEAKMAP(this.value_)) {
+    var entries = %GetWeakMapEntries(this.value_, opt_limit || 0);
+    for (var i = 0; i < entries.length; i += 2) {
+      result.push({
+        key: entries[i],
+        value: entries[i + 1]
+      });
+    }
+    return result;
+  }
+
+  var iter = %_Call(MapEntries, this.value_);
+  var next;
+  while ((!opt_limit || result.length < opt_limit) &&
+         !(next = iter.next()).done) {
+    result.push({
+      key: next.value[0],
+      value: next.value[1]
+    });
+  }
+  return result;
+};
+
+
+function SetMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.SET_TYPE);
+}
+inherits(SetMirror, ObjectMirror);
+
+
+function IteratorGetValues_(iter, next_function, opt_limit) {
+  var result = [];
+  var next;
+  while ((!opt_limit || result.length < opt_limit) &&
+         !(next = %_Call(next_function, iter)).done) {
+    result.push(next.value);
+  }
+  return result;
+}
+
+
+/**
+ * Returns an array of elements of a set.
+ * This will keep elements alive for WeakSets.
+ *
+ * @param {number=} opt_limit Max elements to return.
+ * @returns {Array.<Object>} Array of elements of a set.
+ */
+SetMirror.prototype.values = function(opt_limit) {
+  if (IS_WEAKSET(this.value_)) {
+    return %GetWeakSetValues(this.value_, opt_limit || 0);
+  }
+
+  var iter = %_Call(SetValues, this.value_);
+  return IteratorGetValues_(iter, SetIteratorNext, opt_limit);
+};
+
+
+function IteratorMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.ITERATOR_TYPE);
+}
+inherits(IteratorMirror, ObjectMirror);
+
+
+/**
+ * Returns a preview of elements of an iterator.
+ * Does not change the backing iterator state.
+ *
+ * @param {number=} opt_limit Max elements to return.
+ * @returns {Array.<Object>} Array of elements of an iterator.
+ */
+IteratorMirror.prototype.preview = function(opt_limit) {
+  if (IS_MAP_ITERATOR(this.value_)) {
+    return IteratorGetValues_(%MapIteratorClone(this.value_),
+                              MapIteratorNext,
+                              opt_limit);
+  } else if (IS_SET_ITERATOR(this.value_)) {
+    return IteratorGetValues_(%SetIteratorClone(this.value_),
+                              SetIteratorNext,
+                              opt_limit);
+  }
+};
+
+
+/**
+ * Mirror object for a Generator object.
+ * @param {Object} data The Generator object
+ * @constructor
+ * @extends Mirror
+ */
+function GeneratorMirror(value) {
+  %_Call(ObjectMirror, this, value, MirrorType.GENERATOR_TYPE);
+}
+inherits(GeneratorMirror, ObjectMirror);
+
+
+function GeneratorGetStatus_(value) {
+  var continuation = %GeneratorGetContinuation(value);
+  if (continuation < 0) return "running";
+  if (continuation == 0) return "closed";
+  return "suspended";
+}
+
+
+GeneratorMirror.prototype.status = function() {
+  return GeneratorGetStatus_(this.value_);
+};
+
+
+GeneratorMirror.prototype.sourcePosition_ = function() {
+  return %GeneratorGetSourcePosition(this.value_);
+};
+
+
+GeneratorMirror.prototype.sourceLocation = function() {
+  var pos = this.sourcePosition_();
+  if (!IS_UNDEFINED(pos)) {
+    var script = this.func().script();
+    if (script) {
+      return script.locationFromPosition(pos, true);
+    }
+  }
+};
+
+
+GeneratorMirror.prototype.func = function() {
+  if (!this.func_) {
+    this.func_ = MakeMirror(%GeneratorGetFunction(this.value_));
+  }
+  return this.func_;
+};
+
+
+GeneratorMirror.prototype.context = function() {
+  if (!this.context_) {
+    this.context_ = new ContextMirror(%GeneratorGetContext(this.value_));
+  }
+  return this.context_;
+};
+
+
+GeneratorMirror.prototype.receiver = function() {
+  if (!this.receiver_) {
+    this.receiver_ = MakeMirror(%GeneratorGetReceiver(this.value_));
+  }
+  return this.receiver_;
+};
+
+
+/**
+ * Base mirror object for properties.
+ * @param {ObjectMirror} mirror The mirror object having this property
+ * @param {string} name The name of the property
+ * @param {Array} details Details about the property
+ * @constructor
+ * @extends Mirror
+ */
+function PropertyMirror(mirror, name, details) {
+  %_Call(Mirror, this, MirrorType.PROPERTY_TYPE);
+  this.mirror_ = mirror;
+  this.name_ = name;
+  this.value_ = details[0];
+  this.details_ = details[1];
+  this.is_interceptor_ = details[2];
+  if (details.length > 3) {
+    this.exception_ = details[3];
+    this.getter_ = details[4];
+    this.setter_ = details[5];
+  }
+}
+inherits(PropertyMirror, Mirror);
+
+
+PropertyMirror.prototype.isReadOnly = function() {
+  return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
+};
+
+
+PropertyMirror.prototype.isEnum = function() {
+  return (this.attributes() & PropertyAttribute.DontEnum) == 0;
+};
+
+
+PropertyMirror.prototype.canDelete = function() {
+  return (this.attributes() & PropertyAttribute.DontDelete) == 0;
+};
+
+
+PropertyMirror.prototype.name = function() {
+  return this.name_;
+};
+
+
+PropertyMirror.prototype.isIndexed = function() {
+  for (var i = 0; i < this.name_.length; i++) {
+    if (this.name_[i] < '0' || '9' < this.name_[i]) {
+      return false;
+    }
+  }
+  return true;
+};
+
+
+PropertyMirror.prototype.value = function() {
+  return MakeMirror(this.value_, false);
+};
+
+
+/**
+ * Returns whether this property value is an exception.
+ * @return {booolean} True if this property value is an exception
+ */
+PropertyMirror.prototype.isException = function() {
+  return this.exception_ ? true : false;
+};
+
+
+PropertyMirror.prototype.attributes = function() {
+  return %DebugPropertyAttributesFromDetails(this.details_);
+};
+
+
+PropertyMirror.prototype.propertyType = function() {
+  return %DebugPropertyTypeFromDetails(this.details_);
+};
+
+
+PropertyMirror.prototype.insertionIndex = function() {
+  return %DebugPropertyIndexFromDetails(this.details_);
+};
+
+
+/**
+ * Returns whether this property has a getter defined through __defineGetter__.
+ * @return {booolean} True if this property has a getter
+ */
+PropertyMirror.prototype.hasGetter = function() {
+  return this.getter_ ? true : false;
+};
+
+
+/**
+ * Returns whether this property has a setter defined through __defineSetter__.
+ * @return {booolean} True if this property has a setter
+ */
+PropertyMirror.prototype.hasSetter = function() {
+  return this.setter_ ? true : false;
+};
+
+
+/**
+ * Returns the getter for this property defined through __defineGetter__.
+ * @return {Mirror} FunctionMirror reflecting the getter function or
+ *     UndefinedMirror if there is no getter for this property
+ */
+PropertyMirror.prototype.getter = function() {
+  if (this.hasGetter()) {
+    return MakeMirror(this.getter_);
+  } else {
+    return GetUndefinedMirror();
+  }
+};
+
+
+/**
+ * Returns the setter for this property defined through __defineSetter__.
+ * @return {Mirror} FunctionMirror reflecting the setter function or
+ *     UndefinedMirror if there is no setter for this property
+ */
+PropertyMirror.prototype.setter = function() {
+  if (this.hasSetter()) {
+    return MakeMirror(this.setter_);
+  } else {
+    return GetUndefinedMirror();
+  }
+};
+
+
+/**
+ * Returns whether this property is natively implemented by the host or a set
+ * through JavaScript code.
+ * @return {boolean} True if the property is
+ *     UndefinedMirror if there is no setter for this property
+ */
+PropertyMirror.prototype.isNative = function() {
+  return this.is_interceptor_ ||
+         ((this.propertyType() == PropertyType.AccessorConstant) &&
+          !this.hasGetter() && !this.hasSetter());
+};
+
+
+/**
+ * Mirror object for internal properties. Internal property reflects properties
+ * not accessible from user code such as [[BoundThis]] in bound function.
+ * Their names are merely symbolic.
+ * @param {string} name The name of the property
+ * @param {value} property value
+ * @constructor
+ * @extends Mirror
+ */
+function InternalPropertyMirror(name, value) {
+  %_Call(Mirror, this, MirrorType.INTERNAL_PROPERTY_TYPE);
+  this.name_ = name;
+  this.value_ = value;
+}
+inherits(InternalPropertyMirror, Mirror);
+
+
+InternalPropertyMirror.prototype.name = function() {
+  return this.name_;
+};
+
+
+InternalPropertyMirror.prototype.value = function() {
+  return MakeMirror(this.value_, false);
+};
+
+
+var kFrameDetailsFrameIdIndex = 0;
+var kFrameDetailsReceiverIndex = 1;
+var kFrameDetailsFunctionIndex = 2;
+var kFrameDetailsArgumentCountIndex = 3;
+var kFrameDetailsLocalCountIndex = 4;
+var kFrameDetailsSourcePositionIndex = 5;
+var kFrameDetailsConstructCallIndex = 6;
+var kFrameDetailsAtReturnIndex = 7;
+var kFrameDetailsFlagsIndex = 8;
+var kFrameDetailsFirstDynamicIndex = 9;
+
+var kFrameDetailsNameIndex = 0;
+var kFrameDetailsValueIndex = 1;
+var kFrameDetailsNameValueSize = 2;
+
+var kFrameDetailsFlagDebuggerFrameMask = 1 << 0;
+var kFrameDetailsFlagOptimizedFrameMask = 1 << 1;
+var kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2;
+
+/**
+ * Wrapper for the frame details information retreived from the VM. The frame
+ * details from the VM is an array with the following content. See runtime.cc
+ * Runtime_GetFrameDetails.
+ *     0: Id
+ *     1: Receiver
+ *     2: Function
+ *     3: Argument count
+ *     4: Local count
+ *     5: Source position
+ *     6: Construct call
+ *     7: Is at return
+ *     8: Flags (debugger frame, optimized frame, inlined frame index)
+ *     Arguments name, value
+ *     Locals name, value
+ *     Return value if any
+ * @param {number} break_id Current break id
+ * @param {number} index Frame number
+ * @constructor
+ */
+function FrameDetails(break_id, index) {
+  this.break_id_ = break_id;
+  this.details_ = %GetFrameDetails(break_id, index);
+}
+
+
+FrameDetails.prototype.frameId = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsFrameIdIndex];
+};
+
+
+FrameDetails.prototype.receiver = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsReceiverIndex];
+};
+
+
+FrameDetails.prototype.func = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsFunctionIndex];
+};
+
+
+FrameDetails.prototype.isConstructCall = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsConstructCallIndex];
+};
+
+
+FrameDetails.prototype.isAtReturn = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsAtReturnIndex];
+};
+
+
+FrameDetails.prototype.isDebuggerFrame = function() {
+  %CheckExecutionState(this.break_id_);
+  var f = kFrameDetailsFlagDebuggerFrameMask;
+  return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
+};
+
+
+FrameDetails.prototype.isOptimizedFrame = function() {
+  %CheckExecutionState(this.break_id_);
+  var f = kFrameDetailsFlagOptimizedFrameMask;
+  return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
+};
+
+
+FrameDetails.prototype.isInlinedFrame = function() {
+  return this.inlinedFrameIndex() > 0;
+};
+
+
+FrameDetails.prototype.inlinedFrameIndex = function() {
+  %CheckExecutionState(this.break_id_);
+  var f = kFrameDetailsFlagInlinedFrameIndexMask;
+  return (this.details_[kFrameDetailsFlagsIndex] & f) >> 2;
+};
+
+
+FrameDetails.prototype.argumentCount = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsArgumentCountIndex];
+};
+
+
+FrameDetails.prototype.argumentName = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.argumentCount()) {
+    return this.details_[kFrameDetailsFirstDynamicIndex +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsNameIndex];
+  }
+};
+
+
+FrameDetails.prototype.argumentValue = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.argumentCount()) {
+    return this.details_[kFrameDetailsFirstDynamicIndex +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsValueIndex];
+  }
+};
+
+
+FrameDetails.prototype.localCount = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsLocalCountIndex];
+};
+
+
+FrameDetails.prototype.sourcePosition = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsSourcePositionIndex];
+};
+
+
+FrameDetails.prototype.localName = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.localCount()) {
+    var locals_offset = kFrameDetailsFirstDynamicIndex +
+                        this.argumentCount() * kFrameDetailsNameValueSize;
+    return this.details_[locals_offset +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsNameIndex];
+  }
+};
+
+
+FrameDetails.prototype.localValue = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.localCount()) {
+    var locals_offset = kFrameDetailsFirstDynamicIndex +
+                        this.argumentCount() * kFrameDetailsNameValueSize;
+    return this.details_[locals_offset +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsValueIndex];
+  }
+};
+
+
+FrameDetails.prototype.returnValue = function() {
+  %CheckExecutionState(this.break_id_);
+  var return_value_offset =
+      kFrameDetailsFirstDynamicIndex +
+      (this.argumentCount() + this.localCount()) * kFrameDetailsNameValueSize;
+  if (this.details_[kFrameDetailsAtReturnIndex]) {
+    return this.details_[return_value_offset];
+  }
+};
+
+
+FrameDetails.prototype.scopeCount = function() {
+  if (IS_UNDEFINED(this.scopeCount_)) {
+    this.scopeCount_ = %GetScopeCount(this.break_id_, this.frameId());
+  }
+  return this.scopeCount_;
+};
+
+
+FrameDetails.prototype.stepInPositionsImpl = function() {
+  return %GetStepInPositions(this.break_id_, this.frameId());
+};
+
+
+/**
+ * Mirror object for stack frames.
+ * @param {number} break_id The break id in the VM for which this frame is
+       valid
+ * @param {number} index The frame index (top frame is index 0)
+ * @constructor
+ * @extends Mirror
+ */
+function FrameMirror(break_id, index) {
+  %_Call(Mirror, this, MirrorType.FRAME_TYPE);
+  this.break_id_ = break_id;
+  this.index_ = index;
+  this.details_ = new FrameDetails(break_id, index);
+}
+inherits(FrameMirror, Mirror);
+
+
+FrameMirror.prototype.details = function() {
+  return this.details_;
+};
+
+
+FrameMirror.prototype.index = function() {
+  return this.index_;
+};
+
+
+FrameMirror.prototype.func = function() {
+  if (this.func_) {
+    return this.func_;
+  }
+
+  // Get the function for this frame from the VM.
+  var f = this.details_.func();
+
+  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
+  // value returned from the VM might be a string if the function for the
+  // frame is unresolved.
+  if (IS_FUNCTION(f)) {
+    return this.func_ = MakeMirror(f);
+  } else {
+    return new UnresolvedFunctionMirror(f);
+  }
+};
+
+
+FrameMirror.prototype.receiver = function() {
+  return MakeMirror(this.details_.receiver());
+};
+
+
+FrameMirror.prototype.isConstructCall = function() {
+  return this.details_.isConstructCall();
+};
+
+
+FrameMirror.prototype.isAtReturn = function() {
+  return this.details_.isAtReturn();
+};
+
+
+FrameMirror.prototype.isDebuggerFrame = function() {
+  return this.details_.isDebuggerFrame();
+};
+
+
+FrameMirror.prototype.isOptimizedFrame = function() {
+  return this.details_.isOptimizedFrame();
+};
+
+
+FrameMirror.prototype.isInlinedFrame = function() {
+  return this.details_.isInlinedFrame();
+};
+
+
+FrameMirror.prototype.inlinedFrameIndex = function() {
+  return this.details_.inlinedFrameIndex();
+};
+
+
+FrameMirror.prototype.argumentCount = function() {
+  return this.details_.argumentCount();
+};
+
+
+FrameMirror.prototype.argumentName = function(index) {
+  return this.details_.argumentName(index);
+};
+
+
+FrameMirror.prototype.argumentValue = function(index) {
+  return MakeMirror(this.details_.argumentValue(index));
+};
+
+
+FrameMirror.prototype.localCount = function() {
+  return this.details_.localCount();
+};
+
+
+FrameMirror.prototype.localName = function(index) {
+  return this.details_.localName(index);
+};
+
+
+FrameMirror.prototype.localValue = function(index) {
+  return MakeMirror(this.details_.localValue(index));
+};
+
+
+FrameMirror.prototype.returnValue = function() {
+  return MakeMirror(this.details_.returnValue());
+};
+
+
+FrameMirror.prototype.sourcePosition = function() {
+  return this.details_.sourcePosition();
+};
+
+
+FrameMirror.prototype.sourceLocation = function() {
+  var func = this.func();
+  if (func.resolved()) {
+    var script = func.script();
+    if (script) {
+      return script.locationFromPosition(this.sourcePosition(), true);
+    }
+  }
+};
+
+
+FrameMirror.prototype.sourceLine = function() {
+  var location = this.sourceLocation();
+  if (location) {
+    return location.line;
+  }
+};
+
+
+FrameMirror.prototype.sourceColumn = function() {
+  var location = this.sourceLocation();
+  if (location) {
+    return location.column;
+  }
+};
+
+
+FrameMirror.prototype.sourceLineText = function() {
+  var location = this.sourceLocation();
+  if (location) {
+    return location.sourceText();
+  }
+};
+
+
+FrameMirror.prototype.scopeCount = function() {
+  return this.details_.scopeCount();
+};
+
+
+FrameMirror.prototype.scope = function(index) {
+  return new ScopeMirror(this, UNDEFINED, index);
+};
+
+
+FrameMirror.prototype.allScopes = function(opt_ignore_nested_scopes) {
+  var scopeDetails = %GetAllScopesDetails(this.break_id_,
+                                          this.details_.frameId(),
+                                          this.details_.inlinedFrameIndex(),
+                                          !!opt_ignore_nested_scopes);
+  var result = [];
+  for (var i = 0; i < scopeDetails.length; ++i) {
+    result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i]));
+  }
+  return result;
+};
+
+
+FrameMirror.prototype.stepInPositions = function() {
+  var script = this.func().script();
+  var funcOffset = this.func().sourcePosition_();
+
+  var stepInRaw = this.details_.stepInPositionsImpl();
+  var result = [];
+  if (stepInRaw) {
+    for (var i = 0; i < stepInRaw.length; i++) {
+      var posStruct = {};
+      var offset = script.locationFromPosition(funcOffset + stepInRaw[i],
+                                               true);
+      serializeLocationFields(offset, posStruct);
+      var item = {
+        position: posStruct
+      };
+      result.push(item);
+    }
+  }
+
+  return result;
+};
+
+
+FrameMirror.prototype.evaluate = function(source, disable_break,
+                                          opt_context_object) {
+  return MakeMirror(%DebugEvaluate(this.break_id_,
+                                   this.details_.frameId(),
+                                   this.details_.inlinedFrameIndex(),
+                                   source,
+                                   TO_BOOLEAN(disable_break),
+                                   opt_context_object));
+};
+
+
+FrameMirror.prototype.invocationText = function() {
+  // Format frame invoaction (receiver, function and arguments).
+  var result = '';
+  var func = this.func();
+  var receiver = this.receiver();
+  if (this.isConstructCall()) {
+    // For constructor frames display new followed by the function name.
+    result += 'new ';
+    result += func.name() ? func.name() : '[anonymous]';
+  } else if (this.isDebuggerFrame()) {
+    result += '[debugger]';
+  } else {
+    // If the receiver has a className which is 'global' don't display it.
+    var display_receiver =
+      !receiver.className || (receiver.className() != 'global');
+    if (display_receiver) {
+      result += receiver.toText();
+    }
+    // Try to find the function as a property in the receiver. Include the
+    // prototype chain in the lookup.
+    var property = GetUndefinedMirror();
+    if (receiver.isObject()) {
+      for (var r = receiver;
+           !r.isNull() && property.isUndefined();
+           r = r.protoObject()) {
+        property = r.lookupProperty(func);
+      }
+    }
+    if (!property.isUndefined()) {
+      // The function invoked was found on the receiver. Use the property name
+      // for the backtrace.
+      if (!property.isIndexed()) {
+        if (display_receiver) {
+          result += '.';
+        }
+        result += property.name();
+      } else {
+        result += '[';
+        result += property.name();
+        result += ']';
+      }
+      // Also known as - if the name in the function doesn't match the name
+      // under which it was looked up.
+      if (func.name() && func.name() != property.name()) {
+        result += '(aka ' + func.name() + ')';
+      }
+    } else {
+      // The function invoked was not found on the receiver. Use the function
+      // name if available for the backtrace.
+      if (display_receiver) {
+        result += '.';
+      }
+      result += func.name() ? func.name() : '[anonymous]';
+    }
+  }
+
+  // Render arguments for normal frames.
+  if (!this.isDebuggerFrame()) {
+    result += '(';
+    for (var i = 0; i < this.argumentCount(); i++) {
+      if (i != 0) result += ', ';
+      if (this.argumentName(i)) {
+        result += this.argumentName(i);
+        result += '=';
+      }
+      result += this.argumentValue(i).toText();
+    }
+    result += ')';
+  }
+
+  if (this.isAtReturn()) {
+    result += ' returning ';
+    result += this.returnValue().toText();
+  }
+
+  return result;
+};
+
+
+FrameMirror.prototype.sourceAndPositionText = function() {
+  // Format source and position.
+  var result = '';
+  var func = this.func();
+  if (func.resolved()) {
+    var script = func.script();
+    if (script) {
+      if (script.name()) {
+        result += script.name();
+      } else {
+        result += '[unnamed]';
+      }
+      if (!this.isDebuggerFrame()) {
+        var location = this.sourceLocation();
+        result += ' line ';
+        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
+        result += ' column ';
+        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
+        if (!IS_UNDEFINED(this.sourcePosition())) {
+          result += ' (position ' + (this.sourcePosition() + 1) + ')';
+        }
+      }
+    } else {
+      result += '[no source]';
+    }
+  } else {
+    result += '[unresolved]';
+  }
+
+  return result;
+};
+
+
+FrameMirror.prototype.localsText = function() {
+  // Format local variables.
+  var result = '';
+  var locals_count = this.localCount();
+  if (locals_count > 0) {
+    for (var i = 0; i < locals_count; ++i) {
+      result += '      var ';
+      result += this.localName(i);
+      result += ' = ';
+      result += this.localValue(i).toText();
+      if (i < locals_count - 1) result += '\n';
+    }
+  }
+
+  return result;
+};
+
+
+FrameMirror.prototype.restart = function() {
+  var result = %LiveEditRestartFrame(this.break_id_, this.index_);
+  if (IS_UNDEFINED(result)) {
+    result = "Failed to find requested frame";
+  }
+  return result;
+};
+
+
+FrameMirror.prototype.toText = function(opt_locals) {
+  var result = '';
+  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
+  result += ' ';
+  result += this.invocationText();
+  result += ' ';
+  result += this.sourceAndPositionText();
+  if (opt_locals) {
+    result += '\n';
+    result += this.localsText();
+  }
+  return result;
+};
+
+
+// This indexes correspond definitions in debug-scopes.h.
+var kScopeDetailsTypeIndex = 0;
+var kScopeDetailsObjectIndex = 1;
+var kScopeDetailsNameIndex = 2;
+
+function ScopeDetails(frame, fun, index, opt_details) {
+  if (frame) {
+    this.break_id_ = frame.break_id_;
+    this.details_ = opt_details ||
+                    %GetScopeDetails(frame.break_id_,
+                                     frame.details_.frameId(),
+                                     frame.details_.inlinedFrameIndex(),
+                                     index);
+    this.frame_id_ = frame.details_.frameId();
+    this.inlined_frame_id_ = frame.details_.inlinedFrameIndex();
+  } else {
+    this.details_ = opt_details || %GetFunctionScopeDetails(fun.value(), index);
+    this.fun_value_ = fun.value();
+    this.break_id_ = UNDEFINED;
+  }
+  this.index_ = index;
+}
+
+
+ScopeDetails.prototype.type = function() {
+  if (!IS_UNDEFINED(this.break_id_)) {
+    %CheckExecutionState(this.break_id_);
+  }
+  return this.details_[kScopeDetailsTypeIndex];
+};
+
+
+ScopeDetails.prototype.object = function() {
+  if (!IS_UNDEFINED(this.break_id_)) {
+    %CheckExecutionState(this.break_id_);
+  }
+  return this.details_[kScopeDetailsObjectIndex];
+};
+
+
+ScopeDetails.prototype.name = function() {
+  if (!IS_UNDEFINED(this.break_id_)) {
+    %CheckExecutionState(this.break_id_);
+  }
+  return this.details_[kScopeDetailsNameIndex];
+};
+
+
+ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
+  var raw_res;
+  if (!IS_UNDEFINED(this.break_id_)) {
+    %CheckExecutionState(this.break_id_);
+    raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_,
+        this.inlined_frame_id_, this.index_, name, new_value);
+  } else {
+    raw_res = %SetScopeVariableValue(this.fun_value_, null, null, this.index_,
+        name, new_value);
+  }
+  if (!raw_res) throw MakeError(kDebugger, "Failed to set variable value");
+};
+
+
+/**
+ * Mirror object for scope of frame or function. Either frame or function must
+ * be specified.
+ * @param {FrameMirror} frame The frame this scope is a part of
+ * @param {FunctionMirror} function The function this scope is a part of
+ * @param {number} index The scope index in the frame
+ * @param {Array=} opt_details Raw scope details data
+ * @constructor
+ * @extends Mirror
+ */
+function ScopeMirror(frame, fun, index, opt_details) {
+  %_Call(Mirror, this, MirrorType.SCOPE_TYPE);
+  if (frame) {
+    this.frame_index_ = frame.index_;
+  } else {
+    this.frame_index_ = UNDEFINED;
+  }
+  this.scope_index_ = index;
+  this.details_ = new ScopeDetails(frame, fun, index, opt_details);
+}
+inherits(ScopeMirror, Mirror);
+
+
+ScopeMirror.prototype.details = function() {
+  return this.details_;
+};
+
+
+ScopeMirror.prototype.frameIndex = function() {
+  return this.frame_index_;
+};
+
+
+ScopeMirror.prototype.scopeIndex = function() {
+  return this.scope_index_;
+};
+
+
+ScopeMirror.prototype.scopeType = function() {
+  return this.details_.type();
+};
+
+
+ScopeMirror.prototype.scopeObject = function() {
+  // For local, closure and script scopes create a transient mirror
+  // as these objects are created on the fly materializing the local
+  // or closure scopes and therefore will not preserve identity.
+  var transient = this.scopeType() == ScopeType.Local ||
+                  this.scopeType() == ScopeType.Closure ||
+                  this.scopeType() == ScopeType.Script;
+  return MakeMirror(this.details_.object(), transient);
+};
+
+
+ScopeMirror.prototype.setVariableValue = function(name, new_value) {
+  this.details_.setVariableValueImpl(name, new_value);
+};
+
+
+/**
+ * Mirror object for script source.
+ * @param {Script} script The script object
+ * @constructor
+ * @extends Mirror
+ */
+function ScriptMirror(script) {
+  %_Call(Mirror, this, MirrorType.SCRIPT_TYPE);
+  this.script_ = script;
+  this.context_ = new ContextMirror(script.context_data);
+  this.allocateHandle_();
+}
+inherits(ScriptMirror, Mirror);
+
+
+ScriptMirror.prototype.value = function() {
+  return this.script_;
+};
+
+
+ScriptMirror.prototype.name = function() {
+  return this.script_.name || this.script_.nameOrSourceURL();
+};
+
+
+ScriptMirror.prototype.id = function() {
+  return this.script_.id;
+};
+
+
+ScriptMirror.prototype.source = function() {
+  return this.script_.source;
+};
+
+
+ScriptMirror.prototype.setSource = function(source) {
+  %DebugSetScriptSource(this.script_, source);
+};
+
+
+ScriptMirror.prototype.lineOffset = function() {
+  return this.script_.line_offset;
+};
+
+
+ScriptMirror.prototype.columnOffset = function() {
+  return this.script_.column_offset;
+};
+
+
+ScriptMirror.prototype.data = function() {
+  return this.script_.data;
+};
+
+
+ScriptMirror.prototype.scriptType = function() {
+  return this.script_.type;
+};
+
+
+ScriptMirror.prototype.compilationType = function() {
+  return this.script_.compilation_type;
+};
+
+
+ScriptMirror.prototype.lineCount = function() {
+  return this.script_.lineCount();
+};
+
+
+ScriptMirror.prototype.locationFromPosition = function(
+    position, include_resource_offset) {
+  return this.script_.locationFromPosition(position, include_resource_offset);
+};
+
+
+ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
+  return this.script_.sourceSlice(opt_from_line, opt_to_line);
+};
+
+
+ScriptMirror.prototype.context = function() {
+  return this.context_;
+};
+
+
+ScriptMirror.prototype.evalFromScript = function() {
+  return MakeMirror(this.script_.eval_from_script);
+};
+
+
+ScriptMirror.prototype.evalFromFunctionName = function() {
+  return MakeMirror(this.script_.eval_from_function_name);
+};
+
+
+ScriptMirror.prototype.evalFromLocation = function() {
+  var eval_from_script = this.evalFromScript();
+  if (!eval_from_script.isUndefined()) {
+    var position = this.script_.eval_from_script_position;
+    return eval_from_script.locationFromPosition(position, true);
+  }
+};
+
+
+ScriptMirror.prototype.toText = function() {
+  var result = '';
+  result += this.name();
+  result += ' (lines: ';
+  if (this.lineOffset() > 0) {
+    result += this.lineOffset();
+    result += '-';
+    result += this.lineOffset() + this.lineCount() - 1;
+  } else {
+    result += this.lineCount();
+  }
+  result += ')';
+  return result;
+};
+
+
+/**
+ * Mirror object for context.
+ * @param {Object} data The context data
+ * @constructor
+ * @extends Mirror
+ */
+function ContextMirror(data) {
+  %_Call(Mirror, this, MirrorType.CONTEXT_TYPE);
+  this.data_ = data;
+  this.allocateHandle_();
+}
+inherits(ContextMirror, Mirror);
+
+
+ContextMirror.prototype.data = function() {
+  return this.data_;
+};
+
+
+/**
+ * Returns a mirror serializer
+ *
+ * @param {boolean} details Set to true to include details
+ * @param {Object} options Options comtrolling the serialization
+ *     The following options can be set:
+ *       includeSource: include ths full source of scripts
+ * @returns {MirrorSerializer} mirror serializer
+ */
+function MakeMirrorSerializer(details, options) {
+  return new JSONProtocolSerializer(details, options);
+}
+
+
+/**
+ * Object for serializing a mirror objects and its direct references.
+ * @param {boolean} details Indicates whether to include details for the mirror
+ *     serialized
+ * @constructor
+ */
+function JSONProtocolSerializer(details, options) {
+  this.details_ = details;
+  this.options_ = options;
+  this.mirrors_ = [ ];
+}
+
+
+/**
+ * Returns a serialization of an object reference. The referenced object are
+ * added to the serialization state.
+ *
+ * @param {Mirror} mirror The mirror to serialize
+ * @returns {String} JSON serialization
+ */
+JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
+  return this.serialize_(mirror, true, true);
+};
+
+
+/**
+ * Returns a serialization of an object value. The referenced objects are
+ * added to the serialization state.
+ *
+ * @param {Mirror} mirror The mirror to serialize
+ * @returns {String} JSON serialization
+ */
+JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
+  var json = this.serialize_(mirror, false, true);
+  return json;
+};
+
+
+/**
+ * Returns a serialization of all the objects referenced.
+ *
+ * @param {Mirror} mirror The mirror to serialize.
+ * @returns {Array.<Object>} Array of the referenced objects converted to
+ *     protcol objects.
+ */
+JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
+  // Collect the protocol representation of the referenced objects in an array.
+  var content = [];
+
+  // Get the number of referenced objects.
+  var count = this.mirrors_.length;
+
+  for (var i = 0; i < count; i++) {
+    content.push(this.serialize_(this.mirrors_[i], false, false));
+  }
+
+  return content;
+};
+
+
+JSONProtocolSerializer.prototype.includeSource_ = function() {
+  return this.options_ && this.options_.includeSource;
+};
+
+
+JSONProtocolSerializer.prototype.inlineRefs_ = function() {
+  return this.options_ && this.options_.inlineRefs;
+};
+
+
+JSONProtocolSerializer.prototype.maxStringLength_ = function() {
+  if (IS_UNDEFINED(this.options_) ||
+      IS_UNDEFINED(this.options_.maxStringLength)) {
+    return kMaxProtocolStringLength;
+  }
+  return this.options_.maxStringLength;
+};
+
+
+JSONProtocolSerializer.prototype.add_ = function(mirror) {
+  // If this mirror is already in the list just return.
+  for (var i = 0; i < this.mirrors_.length; i++) {
+    if (this.mirrors_[i] === mirror) {
+      return;
+    }
+  }
+
+  // Add the mirror to the list of mirrors to be serialized.
+  this.mirrors_.push(mirror);
+};
+
+
+/**
+ * Formats mirror object to protocol reference object with some data that can
+ * be used to display the value in debugger.
+ * @param {Mirror} mirror Mirror to serialize.
+ * @return {Object} Protocol reference object.
+ */
+JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
+    function(mirror) {
+  var o = {};
+  o.ref = mirror.handle();
+  o.type = mirror.type();
+  switch (mirror.type()) {
+    case MirrorType.UNDEFINED_TYPE:
+    case MirrorType.NULL_TYPE:
+    case MirrorType.BOOLEAN_TYPE:
+    case MirrorType.NUMBER_TYPE:
+      o.value = mirror.value();
+      break;
+    case MirrorType.STRING_TYPE:
+      o.value = mirror.getTruncatedValue(this.maxStringLength_());
+      break;
+    case MirrorType.SYMBOL_TYPE:
+      o.description = mirror.description();
+      break;
+    case MirrorType.FUNCTION_TYPE:
+      o.name = mirror.name();
+      o.inferredName = mirror.inferredName();
+      if (mirror.script()) {
+        o.scriptId = mirror.script().id();
+      }
+      break;
+    case MirrorType.ERROR_TYPE:
+    case MirrorType.REGEXP_TYPE:
+      o.value = mirror.toText();
+      break;
+    case MirrorType.OBJECT_TYPE:
+      o.className = mirror.className();
+      break;
+  }
+  return o;
+};
+
+
+JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
+                                                       details) {
+  // If serializing a reference to a mirror just return the reference and add
+  // the mirror to the referenced mirrors.
+  if (reference &&
+      (mirror.isValue() || mirror.isScript() || mirror.isContext())) {
+    if (this.inlineRefs_() && mirror.isValue()) {
+      return this.serializeReferenceWithDisplayData_(mirror);
+    } else {
+      this.add_(mirror);
+      return {'ref' : mirror.handle()};
+    }
+  }
+
+  // Collect the JSON property/value pairs.
+  var content = {};
+
+  // Add the mirror handle.
+  if (mirror.isValue() || mirror.isScript() || mirror.isContext()) {
+    content.handle = mirror.handle();
+  }
+
+  // Always add the type.
+  content.type = mirror.type();
+
+  switch (mirror.type()) {
+    case MirrorType.UNDEFINED_TYPE:
+    case MirrorType.NULL_TYPE:
+      // Undefined and null are represented just by their type.
+      break;
+
+    case MirrorType.BOOLEAN_TYPE:
+      // Boolean values are simply represented by their value.
+      content.value = mirror.value();
+      break;
+
+    case MirrorType.NUMBER_TYPE:
+      // Number values are simply represented by their value.
+      content.value = NumberToJSON_(mirror.value());
+      break;
+
+    case MirrorType.STRING_TYPE:
+      // String values might have their value cropped to keep down size.
+      if (this.maxStringLength_() != -1 &&
+          mirror.length() > this.maxStringLength_()) {
+        var str = mirror.getTruncatedValue(this.maxStringLength_());
+        content.value = str;
+        content.fromIndex = 0;
+        content.toIndex = this.maxStringLength_();
+      } else {
+        content.value = mirror.value();
+      }
+      content.length = mirror.length();
+      break;
+
+    case MirrorType.SYMBOL_TYPE:
+      content.description = mirror.description();
+      break;
+
+    case MirrorType.OBJECT_TYPE:
+    case MirrorType.FUNCTION_TYPE:
+    case MirrorType.ERROR_TYPE:
+    case MirrorType.REGEXP_TYPE:
+    case MirrorType.PROMISE_TYPE:
+    case MirrorType.GENERATOR_TYPE:
+      // Add object representation.
+      this.serializeObject_(mirror, content, details);
+      break;
+
+    case MirrorType.PROPERTY_TYPE:
+    case MirrorType.INTERNAL_PROPERTY_TYPE:
+      throw MakeError(kDebugger,
+                     'PropertyMirror cannot be serialized independently');
+      break;
+
+    case MirrorType.FRAME_TYPE:
+      // Add object representation.
+      this.serializeFrame_(mirror, content);
+      break;
+
+    case MirrorType.SCOPE_TYPE:
+      // Add object representation.
+      this.serializeScope_(mirror, content);
+      break;
+
+    case MirrorType.SCRIPT_TYPE:
+      // Script is represented by id, name and source attributes.
+      if (mirror.name()) {
+        content.name = mirror.name();
+      }
+      content.id = mirror.id();
+      content.lineOffset = mirror.lineOffset();
+      content.columnOffset = mirror.columnOffset();
+      content.lineCount = mirror.lineCount();
+      if (mirror.data()) {
+        content.data = mirror.data();
+      }
+      if (this.includeSource_()) {
+        content.source = mirror.source();
+      } else {
+        var sourceStart = mirror.source().substring(0, 80);
+        content.sourceStart = sourceStart;
+      }
+      content.sourceLength = mirror.source().length;
+      content.scriptType = mirror.scriptType();
+      content.compilationType = mirror.compilationType();
+      // For compilation type eval emit information on the script from which
+      // eval was called if a script is present.
+      if (mirror.compilationType() == 1 &&
+          mirror.evalFromScript()) {
+        content.evalFromScript =
+            this.serializeReference(mirror.evalFromScript());
+        var evalFromLocation = mirror.evalFromLocation();
+        if (evalFromLocation) {
+          content.evalFromLocation = { line: evalFromLocation.line,
+                                       column: evalFromLocation.column };
+        }
+        if (mirror.evalFromFunctionName()) {
+          content.evalFromFunctionName = mirror.evalFromFunctionName();
+        }
+      }
+      if (mirror.context()) {
+        content.context = this.serializeReference(mirror.context());
+      }
+      break;
+
+    case MirrorType.CONTEXT_TYPE:
+      content.data = mirror.data();
+      break;
+  }
+
+  // Always add the text representation.
+  content.text = mirror.toText();
+
+  // Create and return the JSON string.
+  return content;
+};
+
+
+/**
+ * Serialize object information to the following JSON format.
+ *
+ *   {"className":"<class name>",
+ *    "constructorFunction":{"ref":<number>},
+ *    "protoObject":{"ref":<number>},
+ *    "prototypeObject":{"ref":<number>},
+ *    "namedInterceptor":<boolean>,
+ *    "indexedInterceptor":<boolean>,
+ *    "properties":[<properties>],
+ *    "internalProperties":[<internal properties>]}
+ */
+JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
+                                                             details) {
+  // Add general object properties.
+  content.className = mirror.className();
+  content.constructorFunction =
+      this.serializeReference(mirror.constructorFunction());
+  content.protoObject = this.serializeReference(mirror.protoObject());
+  content.prototypeObject = this.serializeReference(mirror.prototypeObject());
+
+  // Add flags to indicate whether there are interceptors.
+  if (mirror.hasNamedInterceptor()) {
+    content.namedInterceptor = true;
+  }
+  if (mirror.hasIndexedInterceptor()) {
+    content.indexedInterceptor = true;
+  }
+
+  if (mirror.isFunction()) {
+    // Add function specific properties.
+    content.name = mirror.name();
+    if (!IS_UNDEFINED(mirror.inferredName())) {
+      content.inferredName = mirror.inferredName();
+    }
+    content.resolved = mirror.resolved();
+    if (mirror.resolved()) {
+      content.source = mirror.source();
+    }
+    if (mirror.script()) {
+      content.script = this.serializeReference(mirror.script());
+      content.scriptId = mirror.script().id();
+
+      serializeLocationFields(mirror.sourceLocation(), content);
+    }
+
+    content.scopes = [];
+    for (var i = 0; i < mirror.scopeCount(); i++) {
+      var scope = mirror.scope(i);
+      content.scopes.push({
+        type: scope.scopeType(),
+        index: i
+      });
+    }
+  }
+
+  if (mirror.isGenerator()) {
+    // Add generator specific properties.
+
+    // Either 'running', 'closed', or 'suspended'.
+    content.status = mirror.status();
+
+    content.func = this.serializeReference(mirror.func())
+    content.receiver = this.serializeReference(mirror.receiver())
+
+    // If the generator is suspended, the content add line/column properties.
+    serializeLocationFields(mirror.sourceLocation(), content);
+
+    // TODO(wingo): Also serialize a reference to the context (scope chain).
+  }
+
+  if (mirror.isDate()) {
+    // Add date specific properties.
+    content.value = mirror.value();
+  }
+
+  if (mirror.isPromise()) {
+    // Add promise specific properties.
+    content.status = mirror.status();
+    content.promiseValue = this.serializeReference(mirror.promiseValue());
+  }
+
+  // Add actual properties - named properties followed by indexed properties.
+  var properties = mirror.propertyNames();
+  for (var i = 0; i < properties.length; i++) {
+    var propertyMirror = mirror.property(properties[i]);
+    properties[i] = this.serializeProperty_(propertyMirror);
+    if (details) {
+      this.add_(propertyMirror.value());
+    }
+  }
+  content.properties = properties;
+
+  var internalProperties = mirror.internalProperties();
+  if (internalProperties.length > 0) {
+    var ip = [];
+    for (var i = 0; i < internalProperties.length; i++) {
+      ip.push(this.serializeInternalProperty_(internalProperties[i]));
+    }
+    content.internalProperties = ip;
+  }
+};
+
+
+/**
+ * Serialize location information to the following JSON format:
+ *
+ *   "position":"<position>",
+ *   "line":"<line>",
+ *   "column":"<column>",
+ *
+ * @param {SourceLocation} location The location to serialize, may be undefined.
+ */
+function serializeLocationFields (location, content) {
+  if (!location) {
+    return;
+  }
+  content.position = location.position;
+  var line = location.line;
+  if (!IS_UNDEFINED(line)) {
+    content.line = line;
+  }
+  var column = location.column;
+  if (!IS_UNDEFINED(column)) {
+    content.column = column;
+  }
+}
+
+
+/**
+ * Serialize property information to the following JSON format for building the
+ * array of properties.
+ *
+ *   {"name":"<property name>",
+ *    "attributes":<number>,
+ *    "propertyType":<number>,
+ *    "ref":<number>}
+ *
+ * If the attribute for the property is PropertyAttribute.None it is not added.
+ * Here are a couple of examples.
+ *
+ *   {"name":"hello","propertyType":0,"ref":1}
+ *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
+ *
+ * @param {PropertyMirror} propertyMirror The property to serialize.
+ * @returns {Object} Protocol object representing the property.
+ */
+JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
+  var result = {};
+
+  result.name = propertyMirror.name();
+  var propertyValue = propertyMirror.value();
+  if (this.inlineRefs_() && propertyValue.isValue()) {
+    result.value = this.serializeReferenceWithDisplayData_(propertyValue);
+  } else {
+    if (propertyMirror.attributes() != PropertyAttribute.None) {
+      result.attributes = propertyMirror.attributes();
+    }
+    result.propertyType = propertyMirror.propertyType();
+    result.ref = propertyValue.handle();
+  }
+  return result;
+};
+
+
+/**
+ * Serialize internal property information to the following JSON format for
+ * building the array of properties.
+ *
+ *   {"name":"<property name>",
+ *    "ref":<number>}
+ *
+ *   {"name":"[[BoundThis]]","ref":117}
+ *
+ * @param {InternalPropertyMirror} propertyMirror The property to serialize.
+ * @returns {Object} Protocol object representing the property.
+ */
+JSONProtocolSerializer.prototype.serializeInternalProperty_ =
+    function(propertyMirror) {
+  var result = {};
+
+  result.name = propertyMirror.name();
+  var propertyValue = propertyMirror.value();
+  if (this.inlineRefs_() && propertyValue.isValue()) {
+    result.value = this.serializeReferenceWithDisplayData_(propertyValue);
+  } else {
+    result.ref = propertyValue.handle();
+  }
+  return result;
+};
+
+
+JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
+  content.index = mirror.index();
+  content.receiver = this.serializeReference(mirror.receiver());
+  var func = mirror.func();
+  content.func = this.serializeReference(func);
+  var script = func.script();
+  if (script) {
+    content.script = this.serializeReference(script);
+  }
+  content.constructCall = mirror.isConstructCall();
+  content.atReturn = mirror.isAtReturn();
+  if (mirror.isAtReturn()) {
+    content.returnValue = this.serializeReference(mirror.returnValue());
+  }
+  content.debuggerFrame = mirror.isDebuggerFrame();
+  var x = new GlobalArray(mirror.argumentCount());
+  for (var i = 0; i < mirror.argumentCount(); i++) {
+    var arg = {};
+    var argument_name = mirror.argumentName(i);
+    if (argument_name) {
+      arg.name = argument_name;
+    }
+    arg.value = this.serializeReference(mirror.argumentValue(i));
+    x[i] = arg;
+  }
+  content.arguments = x;
+  var x = new GlobalArray(mirror.localCount());
+  for (var i = 0; i < mirror.localCount(); i++) {
+    var local = {};
+    local.name = mirror.localName(i);
+    local.value = this.serializeReference(mirror.localValue(i));
+    x[i] = local;
+  }
+  content.locals = x;
+  serializeLocationFields(mirror.sourceLocation(), content);
+  var source_line_text = mirror.sourceLineText();
+  if (!IS_UNDEFINED(source_line_text)) {
+    content.sourceLineText = source_line_text;
+  }
+
+  content.scopes = [];
+  for (var i = 0; i < mirror.scopeCount(); i++) {
+    var scope = mirror.scope(i);
+    content.scopes.push({
+      type: scope.scopeType(),
+      index: i
+    });
+  }
+};
+
+
+JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) {
+  content.index = mirror.scopeIndex();
+  content.frameIndex = mirror.frameIndex();
+  content.type = mirror.scopeType();
+  content.object = this.inlineRefs_() ?
+                   this.serializeValue(mirror.scopeObject()) :
+                   this.serializeReference(mirror.scopeObject());
+};
+
+
+/**
+ * Convert a number to a protocol value. For all finite numbers the number
+ * itself is returned. For non finite numbers NaN, Infinite and
+ * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
+ * (not including the quotes) is returned.
+ *
+ * @param {number} value The number value to convert to a protocol value.
+ * @returns {number|string} Protocol value.
+ */
+function NumberToJSON_(value) {
+  if (IsNaN(value)) {
+    return 'NaN';
+  }
+  if (!NUMBER_IS_FINITE(value)) {
+    if (value > 0) {
+      return 'Infinity';
+    } else {
+      return '-Infinity';
+    }
+  }
+  return value;
+}
+
+// ----------------------------------------------------------------------------
+// Exports
+
+utils.InstallFunctions(global, DONT_ENUM, [
+  "MakeMirror", MakeMirror,
+  "MakeMirrorSerializer", MakeMirrorSerializer,
+  "LookupMirror", LookupMirror,
+  "ToggleMirrorCache", ToggleMirrorCache,
+  "MirrorCacheIsEmpty", MirrorCacheIsEmpty,
+]);
+
+utils.InstallConstants(global, [
+  "ScopeType", ScopeType,
+  "PropertyType", PropertyType,
+  "PropertyAttribute", PropertyAttribute,
+  "Mirror", Mirror,
+  "ValueMirror", ValueMirror,
+  "UndefinedMirror", UndefinedMirror,
+  "NullMirror", NullMirror,
+  "BooleanMirror", BooleanMirror,
+  "NumberMirror", NumberMirror,
+  "StringMirror", StringMirror,
+  "SymbolMirror", SymbolMirror,
+  "ObjectMirror", ObjectMirror,
+  "FunctionMirror", FunctionMirror,
+  "UnresolvedFunctionMirror", UnresolvedFunctionMirror,
+  "ArrayMirror", ArrayMirror,
+  "DateMirror", DateMirror,
+  "RegExpMirror", RegExpMirror,
+  "ErrorMirror", ErrorMirror,
+  "PromiseMirror", PromiseMirror,
+  "MapMirror", MapMirror,
+  "SetMirror", SetMirror,
+  "IteratorMirror", IteratorMirror,
+  "GeneratorMirror", GeneratorMirror,
+  "PropertyMirror", PropertyMirror,
+  "InternalPropertyMirror", InternalPropertyMirror,
+  "FrameMirror", FrameMirror,
+  "ScriptMirror", ScriptMirror,
+  "ScopeMirror", ScopeMirror,
+  "FrameDetails", FrameDetails,
+]);
+
+// Functions needed by the debugger runtime.
+utils.InstallFunctions(utils, DONT_ENUM, [
+  "ClearMirrorCache", ClearMirrorCache
+]);
+
+// Export to debug.js
+utils.Export(function(to) {
+  to.MirrorType = MirrorType;
+});
+})
diff --git a/src/debug/ppc/OWNERS b/src/debug/ppc/OWNERS
new file mode 100644
index 0000000..eb007cb
--- /dev/null
+++ b/src/debug/ppc/OWNERS
@@ -0,0 +1,5 @@
+jyan@ca.ibm.com
+dstence@us.ibm.com
+joransiu@ca.ibm.com
+mbrandy@us.ibm.com
+michael_dawson@ca.ibm.com
diff --git a/src/debug/ppc/debug-ppc.cc b/src/debug/ppc/debug-ppc.cc
new file mode 100644
index 0000000..c5ddab8
--- /dev/null
+++ b/src/debug/ppc/debug-ppc.cc
@@ -0,0 +1,151 @@
+// Copyright 2014 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.
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_size;
+  __ bind(&check_size);
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
+  }
+  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+            masm->InstructionsGeneratedSince(&check_size));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the trampoline pool in the debug break slot code.
+  Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
+  // Patch the code changing the debug break slot code from
+  //
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //
+  // to a call to the debug break code, using a FIXED_SEQUENCE.
+  //
+  //   mov r0, <address>
+  //   mtlr r0
+  //   blrl
+  //
+  Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
+  patcher.masm()->mov(v8::internal::r0,
+                      Operand(reinterpret_cast<intptr_t>(code->entry())));
+  patcher.masm()->mtctr(v8::internal::r0);
+  patcher.masm()->bctrl();
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingValue));
+    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
+      __ push(ip);
+    }
+    __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
+    __ push(ip);
+
+    if (mode == SAVE_RESULT_REGISTER) __ push(r3);
+
+    __ mov(r3, Operand::Zero());  // no arguments
+    __ mov(r4,
+           Operand(ExternalReference(
+               Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ mov(reg, Operand(kDebugZapValue));
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ pop(r3);
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ mov(ip, Operand(after_break_target));
+  __ LoadP(ip, MemOperand(ip));
+  __ JumpToJSEntry(ip);
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // Load the function pointer off of our current stack frame.
+  __ LoadP(r4, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset -
+                                  kPointerSize));
+
+  // Pop return address and frame
+  __ LeaveFrame(StackFrame::INTERNAL);
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(r4, no_reg, dummy, dummy);
+
+  // Load context from the function.
+  __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+  // Clear new.target as a safety measure.
+  __ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
+
+  // Get function code.
+  __ LoadP(ip, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
+  __ addi(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // Re-run JSFunction, r4 is function, cp is context.
+  __ Jump(ip);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/debug/x64/debug-x64.cc b/src/debug/x64/debug-x64.cc
new file mode 100644
index 0000000..0d56ea7
--- /dev/null
+++ b/src/debug/x64/debug-x64.cc
@@ -0,0 +1,141 @@
+// Copyright 2012 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.
+
+#if V8_TARGET_ARCH_X64
+
+#include "src/assembler.h"
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_codesize;
+  __ bind(&check_codesize);
+  __ Nop(Assembler::kDebugBreakSlotLength);
+  DCHECK_EQ(Assembler::kDebugBreakSlotLength,
+            masm->SizeOfCodeGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction.
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  static const int kSize = Assembler::kDebugBreakSlotLength;
+  CodePatcher patcher(isolate, pc, kSize);
+  Label check_codesize;
+  patcher.masm()->bind(&check_codesize);
+  patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(code->entry()),
+                       Assembler::RelocInfoNone());
+  patcher.masm()->call(kScratchRegister);
+  // Check that the size of the code generated is as expected.
+  DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+
+  // Enter an internal frame.
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
+      __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue));
+    }
+    __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
+
+    if (mode == SAVE_RESULT_REGISTER) __ Push(rax);
+
+    __ Set(rax, 0);  // No arguments (argc == 0).
+    __ Move(rbx, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
+                                   masm->isolate()));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; ++i) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ Set(reg, kDebugZapValue);
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ Pop(rax);
+
+    // Read current padding counter and skip corresponding number of words.
+    __ Pop(kScratchRegister);
+    __ SmiToInteger32(kScratchRegister, kScratchRegister);
+    __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
+
+    // Get rid of the internal frame.
+  }
+
+  // This call did not replace a call , so there will be an unwanted
+  // return address left on the stack. Here we get rid of that.
+  __ addp(rsp, Immediate(kPCOnStackSize));
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ Move(kScratchRegister, after_break_target);
+  __ Jump(Operand(kScratchRegister, 0));
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // We do not know our frame height, but set rsp based on rbp.
+  __ leap(rsp, Operand(rbp, -1 * kPointerSize));
+
+  __ Pop(rdi);  // Function.
+  __ popq(rbp);
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(rdi, no_reg, dummy, dummy);
+
+  // Load context from the function.
+  __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+  // Clear new.target as a safety measure.
+  __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+
+  // Get function code.
+  __ movp(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+  __ movp(rbx, FieldOperand(rbx, SharedFunctionInfo::kCodeOffset));
+  __ leap(rbx, FieldOperand(rbx, Code::kHeaderSize));
+
+  // Re-run JSFunction, rdi is function, rsi is context.
+  __ jmp(rbx);
+}
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_X64
diff --git a/src/debug/x87/OWNERS b/src/debug/x87/OWNERS
new file mode 100644
index 0000000..dd9998b
--- /dev/null
+++ b/src/debug/x87/OWNERS
@@ -0,0 +1 @@
+weiliang.lin@intel.com
diff --git a/src/debug/x87/debug-x87.cc b/src/debug/x87/debug-x87.cc
new file mode 100644
index 0000000..8c04e02
--- /dev/null
+++ b/src/debug/x87/debug-x87.cc
@@ -0,0 +1,141 @@
+// Copyright 2012 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.
+
+#if V8_TARGET_ARCH_X87
+
+#include "src/codegen.h"
+#include "src/debug/debug.h"
+#include "src/x87/frames-x87.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+  Label check_codesize;
+  __ bind(&check_codesize);
+  __ Nop(Assembler::kDebugBreakSlotLength);
+  DCHECK_EQ(Assembler::kDebugBreakSlotLength,
+            masm->SizeOfCodeGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
+  // Generate enough nop's to make space for a call instruction.
+  masm->RecordDebugBreakSlot(mode);
+  EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
+  CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
+  EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
+                                       Handle<Code> code) {
+  DCHECK_EQ(Code::BUILTIN, code->kind());
+  static const int kSize = Assembler::kDebugBreakSlotLength;
+  CodePatcher patcher(isolate, pc, kSize);
+
+  // Add a label for checking the size of the code used for returning.
+  Label check_codesize;
+  patcher.masm()->bind(&check_codesize);
+  patcher.masm()->call(code->entry(), RelocInfo::NONE32);
+  // Check that the size of the code generated is as expected.
+  DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+                                          DebugBreakCallHelperMode mode) {
+  __ RecordComment("Debug break");
+
+  // Enter an internal frame.
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
+      __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue)));
+    }
+    __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
+
+    if (mode == SAVE_RESULT_REGISTER) __ push(eax);
+
+    __ Move(eax, Immediate(0));  // No arguments.
+    __ mov(ebx,
+           Immediate(ExternalReference(
+               Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    if (FLAG_debug_code) {
+      for (int i = 0; i < kNumJSCallerSaved; ++i) {
+        Register reg = {JSCallerSavedCode(i)};
+        __ Move(reg, Immediate(kDebugZapValue));
+      }
+    }
+
+    if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
+
+    __ pop(ebx);
+    // We divide stored value by 2 (untagging) and multiply it by word's size.
+    STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
+    __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0));
+
+    // Get rid of the internal frame.
+  }
+
+  // This call did not replace a call , so there will be an unwanted
+  // return address left on the stack. Here we get rid of that.
+  __ add(esp, Immediate(kPointerSize));
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ jmp(Operand::StaticVariable(after_break_target));
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  // We do not know our frame height, but set esp based on ebp.
+  __ lea(esp, Operand(ebp, -1 * kPointerSize));
+
+  __ pop(edi);  // Function.
+  __ pop(ebp);
+
+  ParameterCount dummy(0);
+  __ FloodFunctionIfStepping(edi, no_reg, dummy, dummy);
+
+  // Load context from the function.
+  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+  // Clear new.target register as a safety measure.
+  __ mov(edx, masm->isolate()->factory()->undefined_value());
+
+  // Get function code.
+  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
+  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
+
+  // Re-run JSFunction, edi is function, esi is context.
+  __ jmp(ebx);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_X87