Merge V8 5.2.361.47  DO NOT MERGE

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

FPIIM-449

Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/debug/debug-evaluate.cc b/src/debug/debug-evaluate.cc
index 1729408..d5ebaa5 100644
--- a/src/debug/debug-evaluate.cc
+++ b/src/debug/debug-evaluate.cc
@@ -95,11 +95,12 @@
   }
 
   Handle<JSFunction> eval_fun;
-  ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
-                             Compiler::GetFunctionFromEval(
-                                 source, outer_info, context, SLOPPY,
-                                 NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
-                             Object);
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, eval_fun,
+      Compiler::GetFunctionFromEval(
+          source, outer_info, context, SLOPPY, NO_PARSE_RESTRICTION,
+          RelocInfo::kNoPosition, RelocInfo::kNoPosition),
+      Object);
 
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION(
@@ -182,7 +183,8 @@
         context_chain_element.wrapped_context = current_context;
       }
       context_chain_.Add(context_chain_element);
-    } else if (scope_type == ScopeIterator::ScopeTypeBlock) {
+    } else if (scope_type == ScopeIterator::ScopeTypeBlock ||
+               scope_type == ScopeIterator::ScopeTypeEval) {
       Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
       frame_inspector.MaterializeStackLocals(materialized,
                                              it.CurrentScopeInfo());
@@ -247,7 +249,8 @@
     // 'this' is allocated in an outer context and is is already being
     // referenced by the current function, so it can be correctly resolved.
     return;
-  } else if (local_function->shared()->scope_info()->HasReceiver()) {
+  } else if (local_function->shared()->scope_info()->HasReceiver() &&
+             !frame_->receiver()->IsTheHole()) {
     recv = handle(frame_->receiver(), isolate_);
   }
   JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
diff --git a/src/debug/debug-frames.cc b/src/debug/debug-frames.cc
index a7956ff..453a77d 100644
--- a/src/debug/debug-frames.cc
+++ b/src/debug/debug-frames.cc
@@ -72,8 +72,7 @@
     return deoptimized_frame_->GetSourcePosition();
   } else if (is_interpreted_) {
     InterpretedFrame* frame = reinterpret_cast<InterpretedFrame*>(frame_);
-    BytecodeArray* bytecode_array =
-        frame->function()->shared()->bytecode_array();
+    BytecodeArray* bytecode_array = frame->GetBytecodeArray();
     return bytecode_array->SourcePosition(frame->GetBytecodeOffset());
   } else {
     Code* code = frame_->LookupCode();
@@ -117,6 +116,7 @@
     // TODO(yangguo): check whether this is necessary, now that we materialize
     //                context locals as well.
     Handle<String> name(scope_info->ParameterName(i));
+    if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
 
     Handle<Object> value =
@@ -130,8 +130,8 @@
 
   // 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));
+    if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i));
     // TODO(yangguo): We convert optimized out values to {undefined} when they
     // are passed to the debugger. Eventually we should handle them somehow.
@@ -163,6 +163,7 @@
   for (int i = 0; i < scope_info->ParameterCount(); ++i) {
     // Shadowed parameters were not materialized.
     Handle<String> name(scope_info->ParameterName(i));
+    if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
 
     DCHECK(!frame_->GetParameter(i)->IsTheHole());
@@ -173,13 +174,12 @@
 
   // Stack locals.
   for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    if (scope_info->LocalIsSynthetic(i)) continue;
+    Handle<String> name(scope_info->StackLocalName(i));
+    if (ScopeInfo::VariableIsSynthetic(*name)) 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();
+        Object::GetPropertyOrElement(target, name).ToHandleChecked();
     frame_->SetExpression(index, *value);
   }
 }
diff --git a/src/debug/debug-scopes.cc b/src/debug/debug-scopes.cc
index d9c615b..1602711 100644
--- a/src/debug/debug-scopes.cc
+++ b/src/debug/debug-scopes.cc
@@ -5,6 +5,7 @@
 #include "src/debug/debug-scopes.h"
 
 #include "src/ast/scopes.h"
+#include "src/compiler.h"
 #include "src/debug/debug.h"
 #include "src/frames-inl.h"
 #include "src/globals.h"
@@ -80,34 +81,29 @@
   }
 
   // Reparse the code and analyze the scopes.
-  Scope* scope = NULL;
   // Check whether we are in global, eval or function code.
   Zone zone(isolate->allocator());
+  base::SmartPointer<ParseInfo> info;
   if (scope_info->scope_type() != FUNCTION_SCOPE) {
     // Global or eval code.
     Handle<Script> script(Script::cast(shared_info->script()));
-    ParseInfo info(&zone, script);
+    info.Reset(new ParseInfo(&zone, script));
+    info->set_toplevel();
     if (scope_info->scope_type() == SCRIPT_SCOPE) {
-      info.set_global();
+      info->set_global();
     } else {
       DCHECK(scope_info->scope_type() == EVAL_SCOPE);
-      info.set_eval();
-      info.set_context(Handle<Context>(function->context()));
+      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);
+    // Inner function.
+    info.Reset(new ParseInfo(&zone, function));
   }
+  Scope* scope = NULL;
+  if (Compiler::ParseAndAnalyze(info.get())) scope = info->literal()->scope();
+  if (!ignore_nested_scopes) RetrieveScopeChain(scope);
+  if (collect_non_locals) CollectNonLocals(scope);
   UnwrapEvaluationContext();
 }
 
@@ -126,8 +122,6 @@
   while (true) {
     if (context_.is_null()) return;
     if (!context_->IsDebugEvaluateContext()) return;
-    // An existing debug-evaluate context can only be outside the local scope.
-    DCHECK(nested_scope_chain_.is_empty());
     Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX),
                            isolate_);
     if (wrapped->IsContext()) {
@@ -201,11 +195,15 @@
   } else if (nested_scope_chain_.is_empty()) {
     context_ = Handle<Context>(context_->previous(), isolate_);
   } else {
-    if (nested_scope_chain_.last().scope_info->HasContext()) {
-      DCHECK(context_->previous() != NULL);
-      context_ = Handle<Context>(context_->previous(), isolate_);
-    }
-    nested_scope_chain_.RemoveLast();
+    do {
+      if (nested_scope_chain_.last().scope_info->HasContext()) {
+        DCHECK(context_->previous() != NULL);
+        context_ = Handle<Context>(context_->previous(), isolate_);
+      }
+      nested_scope_chain_.RemoveLast();
+      if (nested_scope_chain_.is_empty()) break;
+      // Repeat to skip hidden scopes.
+    } while (nested_scope_chain_.last().is_hidden());
   }
   UnwrapEvaluationContext();
 }
@@ -236,8 +234,10 @@
         DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
         return ScopeTypeBlock;
       case EVAL_SCOPE:
-        UNREACHABLE();
+        DCHECK(!scope_info->HasContext() || context_->IsFunctionContext());
+        return ScopeTypeEval;
     }
+    UNREACHABLE();
   }
   if (context_->IsNativeContext()) {
     DCHECK(context_->global_object()->IsJSGlobalObject());
@@ -284,7 +284,8 @@
       // Materialize the content of the closure scope into a JSObject.
       return MaterializeClosure();
     case ScopeIterator::ScopeTypeBlock:
-      return MaterializeBlockScope();
+    case ScopeIterator::ScopeTypeEval:
+      return MaterializeInnerScope();
     case ScopeIterator::ScopeTypeModule:
       return MaterializeModuleScope();
   }
@@ -295,7 +296,8 @@
 
 bool ScopeIterator::HasContext() {
   ScopeType type = Type();
-  if (type == ScopeTypeBlock || type == ScopeTypeLocal) {
+  if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
+      type == ScopeTypeEval) {
     if (!nested_scope_chain_.is_empty()) {
       return nested_scope_chain_.last().scope_info->HasContext();
     }
@@ -321,7 +323,8 @@
     case ScopeIterator::ScopeTypeScript:
       return SetScriptVariableValue(variable_name, new_value);
     case ScopeIterator::ScopeTypeBlock:
-      return SetBlockVariableValue(variable_name, new_value);
+    case ScopeIterator::ScopeTypeEval:
+      return SetInnerScopeVariableValue(variable_name, new_value);
     case ScopeIterator::ScopeTypeModule:
       // TODO(2399): should we implement it?
       break;
@@ -453,7 +456,7 @@
       global->native_context()->script_context_table());
 
   Handle<JSObject> script_scope =
-      isolate_->factory()->NewJSObject(isolate_->object_function());
+      isolate_->factory()->NewJSObjectWithNullProto();
 
   for (int context_index = 0; context_index < script_contexts->used();
        context_index++) {
@@ -470,7 +473,7 @@
   Handle<JSFunction> function = GetFunction();
 
   Handle<JSObject> local_scope =
-      isolate_->factory()->NewJSObject(isolate_->object_function());
+      isolate_->factory()->NewJSObjectWithNullProto();
   frame_inspector_->MaterializeStackLocals(local_scope, function);
 
   Handle<Context> frame_context =
@@ -482,19 +485,16 @@
 
   if (!scope_info->HasContext()) return local_scope;
 
-  // Third fill all context locals.
+  // Fill all context locals.
   Handle<Context> function_context(frame_context->closure_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,
-        INCLUDE_PROTOS);
-    if (!success) return MaybeHandle<JSObject>();
+    CopyContextExtensionToScopeObject(function_context, local_scope,
+                                      INCLUDE_PROTOS);
   }
 
   return local_scope;
@@ -513,19 +513,14 @@
   // Allocate and initialize a JSObject with all the content of this function
   // closure.
   Handle<JSObject> closure_scope =
-      isolate_->factory()->NewJSObject(isolate_->object_function());
+      isolate_->factory()->NewJSObjectWithNullProto();
 
   // 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, OWN_ONLY);
-    DCHECK(success);
-    USE(success);
-  }
+  CopyContextExtensionToScopeObject(context, closure_scope, OWN_ONLY);
 
   return closure_scope;
 }
@@ -540,7 +535,7 @@
   Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
                                isolate_);
   Handle<JSObject> catch_scope =
-      isolate_->factory()->NewJSObject(isolate_->object_function());
+      isolate_->factory()->NewJSObjectWithNullProto();
   JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
                                            NONE)
       .Check();
@@ -560,14 +555,14 @@
 
 // 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<JSObject> ScopeIterator::MaterializeInnerScope() {
+  Handle<JSObject> inner_scope =
+      isolate_->factory()->NewJSObjectWithNullProto();
 
   Handle<Context> context = Handle<Context>::null();
   if (!nested_scope_chain_.is_empty()) {
     Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
-    frame_inspector_->MaterializeStackLocals(block_scope, scope_info);
+    frame_inspector_->MaterializeStackLocals(inner_scope, scope_info);
     if (scope_info->HasContext()) context = CurrentContext();
   } else {
     context = CurrentContext();
@@ -575,17 +570,10 @@
 
   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, OWN_ONLY);
-      DCHECK(success);
-      USE(success);
-    }
+    CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope);
+    CopyContextExtensionToScopeObject(context, inner_scope, OWN_ONLY);
   }
-  return block_scope;
+  return inner_scope;
 }
 
 
@@ -599,7 +587,7 @@
   // Allocate and initialize a JSObject with all the members of the debugged
   // module.
   Handle<JSObject> module_scope =
-      isolate_->factory()->NewJSObject(isolate_->object_function());
+      isolate_->factory()->NewJSObjectWithNullProto();
 
   // Fill all context locals.
   CopyContextLocalsToScopeObject(scope_info, context, module_scope);
@@ -607,12 +595,43 @@
   return module_scope;
 }
 
+bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
+                                      JavaScriptFrame* frame,
+                                      Handle<String> parameter_name,
+                                      Handle<Object> new_value) {
+  // Setting stack locals of optimized frames is not supported.
+  if (frame->is_optimized()) return false;
+  HandleScope scope(isolate_);
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    if (String::Equals(handle(scope_info->ParameterName(i)), parameter_name)) {
+      frame->SetParameterValue(i, *new_value);
+      return true;
+    }
+  }
+  return false;
+}
 
-// Set the context local variable value.
-bool ScopeIterator::SetContextLocalValue(Handle<ScopeInfo> scope_info,
-                                         Handle<Context> context,
-                                         Handle<String> variable_name,
-                                         Handle<Object> new_value) {
+bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
+                                          JavaScriptFrame* frame,
+                                          Handle<String> variable_name,
+                                          Handle<Object> new_value) {
+  // Setting stack locals of optimized frames is not supported.
+  if (frame->is_optimized()) return false;
+  HandleScope scope(isolate_);
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
+      frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info,
+                                            Handle<Context> context,
+                                            Handle<String> variable_name,
+                                            Handle<Object> new_value) {
+  HandleScope scope(isolate_);
   for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
     Handle<String> next_name(scope_info->ContextLocalName(i));
     if (String::Equals(variable_name, next_name)) {
@@ -626,128 +645,8 @@
     }
   }
 
-  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()));
+    Handle<JSObject> ext(context->extension_object());
     Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
     DCHECK(maybe.IsJust());
     if (maybe.FromJust()) {
@@ -762,6 +661,55 @@
   return false;
 }
 
+bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
+                                          Handle<Object> new_value) {
+  JavaScriptFrame* frame = GetFrame();
+  Handle<ScopeInfo> scope_info(frame->function()->shared()->scope_info());
+
+  // Parameter might be shadowed in context. Don't stop here.
+  bool result = SetParameterValue(scope_info, frame, variable_name, new_value);
+
+  // Stack locals.
+  if (SetStackVariableValue(scope_info, frame, variable_name, new_value)) {
+    return true;
+  }
+
+  if (scope_info->HasContext() &&
+      SetContextVariableValue(scope_info, CurrentContext(), variable_name,
+                              new_value)) {
+    return true;
+  }
+
+  return result;
+}
+
+bool ScopeIterator::SetInnerScopeVariableValue(Handle<String> variable_name,
+                                               Handle<Object> new_value) {
+  Handle<ScopeInfo> scope_info = CurrentScopeInfo();
+  DCHECK(scope_info->scope_type() == BLOCK_SCOPE ||
+         scope_info->scope_type() == EVAL_SCOPE);
+  JavaScriptFrame* frame = GetFrame();
+
+  // Setting stack locals of optimized frames is not supported.
+  if (SetStackVariableValue(scope_info, frame, variable_name, new_value)) {
+    return true;
+  }
+
+  if (HasContext() && SetContextVariableValue(scope_info, CurrentContext(),
+                                              variable_name, new_value)) {
+    return true;
+  }
+
+  return false;
+}
+
+// This method copies structure of MaterializeClosure method above.
+bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
+                                            Handle<Object> new_value) {
+  DCHECK(CurrentContext()->IsFunctionContext());
+  return SetContextVariableValue(CurrentScopeInfo(), CurrentContext(),
+                                 variable_name, new_value);
+}
 
 bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
                                            Handle<Object> new_value) {
@@ -780,7 +728,6 @@
   return false;
 }
 
-
 bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
                                           Handle<Object> new_value) {
   Handle<Context> context = CurrentContext();
@@ -801,48 +748,47 @@
   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;
+    Handle<String> name(scope_info->ContextLocalName(i));
+    if (ScopeInfo::VariableIsSynthetic(*name)) 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)
+    JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
         .Check();
   }
 }
 
-bool ScopeIterator::CopyContextExtensionToScopeObject(
-    Handle<JSObject> extension, Handle<JSObject> scope_object,
+void ScopeIterator::CopyContextExtensionToScopeObject(
+    Handle<Context> context, Handle<JSObject> scope_object,
     KeyCollectionType type) {
-  Handle<FixedArray> keys;
-  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate_, keys, JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS),
-      false);
+  if (context->extension_object() == nullptr) return;
+  Handle<JSObject> extension(context->extension_object());
+  Handle<FixedArray> keys =
+      JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS)
+          .ToHandleChecked();
 
   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);
+    Handle<Object> value =
+        Object::GetPropertyOrElement(extension, key).ToHandleChecked();
+    JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE)
+        .Check();
   }
-  return true;
 }
 
 void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
                                         int position) {
-  if (!scope->is_eval_scope()) {
+  if (scope->is_hidden()) {
+    // We need to add this chain element in case the scope has a context
+    // associated. We need to keep the scope chain and context chain in sync.
+    nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate)));
+  } else {
     nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate),
                                               scope->start_position(),
                                               scope->end_position()));
@@ -851,7 +797,7 @@
     Scope* inner_scope = scope->inner_scopes()->at(i);
     int beg_pos = inner_scope->start_position();
     int end_pos = inner_scope->end_position();
-    DCHECK(beg_pos >= 0 && end_pos >= 0);
+    DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
     if (beg_pos <= position && position < end_pos) {
       GetNestedScopeChain(isolate, inner_scope, position);
       return;
diff --git a/src/debug/debug-scopes.h b/src/debug/debug-scopes.h
index 4e95fc4..9560227 100644
--- a/src/debug/debug-scopes.h
+++ b/src/debug/debug-scopes.h
@@ -25,6 +25,7 @@
     ScopeTypeCatch,
     ScopeTypeBlock,
     ScopeTypeScript,
+    ScopeTypeEval,
     ScopeTypeModule
   };
 
@@ -85,9 +86,12 @@
   struct ExtendedScopeInfo {
     ExtendedScopeInfo(Handle<ScopeInfo> info, int start, int end)
         : scope_info(info), start_position(start), end_position(end) {}
+    explicit ExtendedScopeInfo(Handle<ScopeInfo> info)
+        : scope_info(info), start_position(-1), end_position(-1) {}
     Handle<ScopeInfo> scope_info;
     int start_position;
     int end_position;
+    bool is_hidden() { return start_position == -1 && end_position == -1; }
   };
 
   Isolate* isolate_;
@@ -117,28 +121,37 @@
   MUST_USE_RESULT MaybeHandle<JSObject> MaterializeModuleScope();
   Handle<JSObject> MaterializeClosure();
   Handle<JSObject> MaterializeCatchScope();
-  Handle<JSObject> MaterializeBlockScope();
+  Handle<JSObject> MaterializeInnerScope();
   Handle<JSObject> WithContextExtension();
 
   bool SetLocalVariableValue(Handle<String> variable_name,
                              Handle<Object> new_value);
-  bool SetBlockVariableValue(Handle<String> variable_name,
-                             Handle<Object> new_value);
+  bool SetInnerScopeVariableValue(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);
+
+  // Helper functions.
+  bool SetParameterValue(Handle<ScopeInfo> scope_info, JavaScriptFrame* frame,
+                         Handle<String> parameter_name,
+                         Handle<Object> new_value);
+  bool SetStackVariableValue(Handle<ScopeInfo> scope_info,
+                             JavaScriptFrame* frame,
+                             Handle<String> variable_name,
+                             Handle<Object> new_value);
+  bool SetContextVariableValue(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,
+  void CopyContextExtensionToScopeObject(Handle<Context> context,
                                          Handle<JSObject> scope_object,
                                          KeyCollectionType type);
 
diff --git a/src/debug/debug.cc b/src/debug/debug.cc
index 6e94012..3b5fb5f 100644
--- a/src/debug/debug.cc
+++ b/src/debug/debug.cc
@@ -260,12 +260,6 @@
   return it->GetBreakLocation();
 }
 
-FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) {
-  List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
-  frame->Summarize(&frames);
-  return frames.first();
-}
-
 int CallOffsetFromCodeOffset(int code_offset, bool is_interpreted) {
   // Code offset points to the instruction after the call. Subtract 1 to
   // exclude that instruction from the search. For bytecode, the code offset
@@ -275,7 +269,7 @@
 
 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
                                        JavaScriptFrame* frame) {
-  FrameSummary summary = GetFirstFrameSummary(frame);
+  FrameSummary summary = FrameSummary::GetFirst(frame);
   int call_offset =
       CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
   return FromCodeOffset(debug_info, call_offset);
@@ -631,7 +625,7 @@
       step_break = location.IsTailCall();
     // Fall through.
     case StepIn: {
-      FrameSummary summary = GetFirstFrameSummary(frame);
+      FrameSummary summary = FrameSummary::GetFirst(frame);
       int offset = summary.code_offset();
       step_break = step_break || location.IsReturn() ||
                    (current_fp != last_fp) ||
@@ -962,6 +956,14 @@
     it.Advance();
   }
 
+  if (last_step_action() == StepNext) {
+    while (!it.done()) {
+      Address current_fp = it.frame()->UnpaddedFP();
+      if (current_fp >= thread_local_.target_fp_) break;
+      it.Advance();
+    }
+  }
+
   // Find the closest Javascript frame we can flood with one-shots.
   while (!it.done() &&
          !it.frame()->function()->shared()->IsSubjectToDebugging()) {
@@ -1011,7 +1013,7 @@
   }
 
   // Get the debug info (create it if it does not exist).
-  FrameSummary summary = GetFirstFrameSummary(frame);
+  FrameSummary summary = FrameSummary::GetFirst(frame);
   Handle<JSFunction> function(summary.function());
   Handle<SharedFunctionInfo> shared(function->shared());
   if (!EnsureDebugInfo(shared, function)) {
@@ -1022,7 +1024,7 @@
   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
   // Refresh frame summary if the code has been recompiled for debugging.
   if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) {
-    summary = GetFirstFrameSummary(frame);
+    summary = FrameSummary::GetFirst(frame);
   }
 
   int call_offset =
@@ -1604,7 +1606,7 @@
   if (!shared->HasDebugInfo()) return false;
 
   DCHECK(!frame->is_optimized());
-  FrameSummary summary = GetFirstFrameSummary(frame);
+  FrameSummary summary = FrameSummary::GetFirst(frame);
 
   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
   BreakLocation location =
@@ -1656,21 +1658,6 @@
 }
 
 
-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()) };
@@ -1911,7 +1898,7 @@
                               exec_state,
                               event_data,
                               event_listener_data_ };
-    Handle<JSReceiver> global(isolate_->global_proxy());
+    Handle<JSReceiver> global = isolate_->global_proxy();
     Execution::TryCall(isolate_, Handle<JSFunction>::cast(event_listener_),
                        global, arraysize(argv), argv);
   }
@@ -2260,7 +2247,7 @@
   JavaScriptFrameIterator iterator(isolate_);
   if (iterator.done()) return;
   JavaScriptFrame* frame = iterator.frame();
-  FrameSummary summary = GetFirstFrameSummary(frame);
+  FrameSummary summary = FrameSummary::GetFirst(frame);
   int source_position =
       summary.abstract_code()->SourcePosition(summary.code_offset());
   Handle<Object> script_obj(summary.function()->shared()->script(), isolate_);
@@ -2271,8 +2258,10 @@
     Handle<Script> script = Handle<Script>::cast(script_obj);
     Handle<String> source(String::cast(script->source()));
     Script::InitLineEnds(script);
-    int line = Script::GetLineNumber(script, source_position);
-    int column = Script::GetColumnNumber(script, source_position);
+    int line =
+        Script::GetLineNumber(script, source_position) - script->line_offset();
+    int column = Script::GetColumnNumber(script, source_position) -
+                 (line == 0 ? script->column_offset() : 0);
     Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
     int line_start =
         line == 0 ? 0 : Smi::cast(line_ends->get(line - 1))->value() + 1;
diff --git a/src/debug/debug.h b/src/debug/debug.h
index 501de63..2cdc151 100644
--- a/src/debug/debug.h
+++ b/src/debug/debug.h
@@ -498,9 +498,6 @@
   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;
diff --git a/src/debug/debug.js b/src/debug/debug.js
index 7f06ca1..38934b0 100644
--- a/src/debug/debug.js
+++ b/src/debug/debug.js
@@ -894,10 +894,6 @@
   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;
@@ -2173,28 +2169,6 @@
 };
 
 
-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;
 };
@@ -2360,7 +2334,6 @@
     "references":           proto.referencesRequest_,
     "source":               proto.sourceRequest_,
     "scripts":              proto.scriptsRequest_,
-    "threads":              proto.threadsRequest_,
     "suspend":              proto.suspendRequest_,
     "version":              proto.versionRequest_,
     "changelive":           proto.changeLiveRequest_,
diff --git a/src/debug/liveedit.cc b/src/debug/liveedit.cc
index 78ed6f1..50d60a1 100644
--- a/src/debug/liveedit.cc
+++ b/src/debug/liveedit.cc
@@ -13,6 +13,7 @@
 #include "src/deoptimizer.h"
 #include "src/frames-inl.h"
 #include "src/global-handles.h"
+#include "src/interpreter/source-position-table.h"
 #include "src/isolate-inl.h"
 #include "src/messages.h"
 #include "src/parsing/parser.h"
@@ -623,6 +624,8 @@
 
 void FunctionInfoWrapper::SetFunctionCode(Handle<Code> function_code,
                                           Handle<HeapObject> code_scope_info) {
+  // CompileForLiveEdit must deliver full-codegen code.
+  DCHECK(function_code->kind() == Code::FUNCTION);
   Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
   this->SetField(kCodeOffset_, code_wrapper);
 
@@ -688,115 +691,6 @@
 }
 
 
-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(
-        *JSReceiver::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(
-        *JSReceiver::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(
-        *JSReceiver::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;
 }
@@ -832,11 +726,10 @@
                                                  Handle<String> source) {
   Isolate* isolate = script->GetIsolate();
 
-  FunctionInfoListener listener(isolate);
+  MaybeHandle<JSArray> infos;
   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
@@ -845,7 +738,7 @@
     try_catch.SetVerbose(true);
 
     // A logical 'try' section.
-    Compiler::CompileForLiveEdit(script);
+    infos = Compiler::CompileForLiveEdit(script);
   }
 
   // A logical 'catch' section.
@@ -883,11 +776,10 @@
   }
 
   // A logical 'finally' section.
-  isolate->set_active_function_info_listener(NULL);
   script->set_source(*original_source);
 
   if (rethrow_exception.is_null()) {
-    return listener.GetResult();
+    return infos.ToHandleChecked();
   } else {
     return isolate->Throw<JSArray>(rethrow_exception);
   }
@@ -1116,9 +1008,23 @@
 
   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);
+  if (shared_info->is_compiled()) {
+    Handle<Code> new_code = compile_info_wrapper.GetFunctionCode();
+    Handle<Code> old_code(shared_info->code());
+    if (shared_info->HasBytecodeArray()) {
+      // The old code is interpreted. If we clear the bytecode array, the
+      // interpreter entry trampoline will self-heal and go to compiled code.
+      shared_info->ClearBytecodeArray();
+      shared_info->ReplaceCode(*new_code);
+    } else {
+      DCHECK(old_code->kind() == Code::FUNCTION);
+      ReplaceCodeObject(old_code, new_code);
+    }
+    if (shared_info->HasDebugInfo()) {
+      // Existing break points will be re-applied. Reset the debug info here.
+      isolate->debug()->RemoveDebugInfoAndClearFromShared(
+          handle(shared_info->GetDebugInfo()));
+    }
     Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
     if (code_scope_info->IsFixedArray()) {
       shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
@@ -1282,12 +1188,11 @@
   static const int kMaximalBufferSize = 512*MB;
 };
 
-
+namespace {
 // 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) {
+Handle<Code> PatchPositionsInCode(Handle<Code> code,
+                                  Handle<JSArray> position_change_array) {
   Isolate* isolate = code->GetIsolate();
 
   RelocInfoBuffer buffer_writer(code->relocation_size(),
@@ -1328,6 +1233,24 @@
   }
 }
 
+void PatchPositionsInBytecodeArray(Handle<BytecodeArray> bytecode,
+                                   Handle<JSArray> position_change_array) {
+  Isolate* isolate = bytecode->GetIsolate();
+  Zone zone(isolate->allocator());
+  interpreter::SourcePositionTableBuilder builder(isolate, &zone);
+
+  for (interpreter::SourcePositionTableIterator iterator(
+           bytecode->source_position_table());
+       !iterator.done(); iterator.Advance()) {
+    int position = iterator.source_position();
+    int new_position = TranslatePosition(position, position_change_array);
+    builder.AddPosition(iterator.bytecode_offset(), new_position,
+                        iterator.is_statement());
+  }
+
+  bytecode->set_source_position_table(*builder.ToSourcePositionTable());
+}
+}  // namespace
 
 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
                                       Handle<JSArray> position_change_array) {
@@ -1358,6 +1281,9 @@
       // untouched).
       ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
     }
+  } else if (info->HasBytecodeArray()) {
+    PatchPositionsInBytecodeArray(Handle<BytecodeArray>(info->bytecode_array()),
+                                  position_change_array);
   }
 }
 
@@ -1374,8 +1300,7 @@
   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->set_eval_from_position(original->eval_from_position());
 
   // Copy all the flags, but clear compilation state.
   copy->set_flags(original->flags());
@@ -1555,6 +1480,13 @@
     top_frame = frames[top_frame_index - 2];
     *mode = LiveEdit::CURRENTLY_SET_MODE;
     frame_has_padding = false;
+  } else if (pre_top_frame_code->kind() == Code::BYTECODE_HANDLER) {
+    // Interpreted bytecode takes up two stack frames, one for the bytecode
+    // handler and one for the interpreter entry trampoline. Therefore we shift
+    // up by one frame.
+    *mode = LiveEdit::FRAME_DROPPED_IN_DIRECT_CALL;
+    pre_top_frame = frames[top_frame_index - 2];
+    top_frame = frames[top_frame_index - 1];
   } else {
     return "Unknown structure of stack above changing function";
   }
@@ -1792,7 +1724,8 @@
   // 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) {
+    if (frames[i]->type() == StackFrame::JAVA_SCRIPT ||
+        frames[i]->type() == StackFrame::INTERPRETED) {
       new_id = frames[i]->id();
       break;
     }
@@ -2004,40 +1937,107 @@
   return NULL;
 }
 
+Handle<JSArray> LiveEditFunctionTracker::Collect(FunctionLiteral* node,
+                                                 Handle<Script> script,
+                                                 Zone* zone, Isolate* isolate) {
+  LiveEditFunctionTracker visitor(script, zone, isolate);
+  visitor.VisitFunctionLiteral(node);
+  return visitor.result_;
+}
 
-LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
-                                                 FunctionLiteral* fun)
-    : isolate_(isolate) {
-  if (isolate_->active_function_info_listener() != NULL) {
-    isolate_->active_function_info_listener()->FunctionStarted(fun);
+LiveEditFunctionTracker::LiveEditFunctionTracker(Handle<Script> script,
+                                                 Zone* zone, Isolate* isolate)
+    : AstTraversalVisitor(isolate) {
+  current_parent_index_ = -1;
+  isolate_ = isolate;
+  len_ = 0;
+  result_ = isolate->factory()->NewJSArray(10);
+  script_ = script;
+  zone_ = zone;
+}
+
+void LiveEditFunctionTracker::VisitFunctionLiteral(FunctionLiteral* node) {
+  Scope* scope = node->scope();
+
+  // FunctionStarted is called in pre-order.
+  FunctionStarted(node);
+
+  VisitDeclarations(scope->declarations());
+  VisitStatements(node->body());
+
+  // FunctionDone are called in post-order.
+  // TODO(jgruber): If required, replace the (linear cost)
+  // FindSharedFunctionInfo call with a more efficient implementation.
+  Handle<SharedFunctionInfo> info =
+      script_->FindSharedFunctionInfo(node).ToHandleChecked();
+  FunctionDone(info, scope);
+}
+
+void LiveEditFunctionTracker::FunctionStarted(FunctionLiteral* fun) {
+  HandleScope handle_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_++;
+}
+
+// Saves full information about a function: its code, its scope info
+// and a SharedFunctionInfo object.
+void LiveEditFunctionTracker::FunctionDone(Handle<SharedFunctionInfo> shared,
+                                           Scope* scope) {
+  HandleScope handle_scope(isolate_);
+  FunctionInfoWrapper info = FunctionInfoWrapper::cast(
+      *JSReceiver::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);
+  info.SetFunctionScopeInfo(scope_info_list);
+
+  current_parent_index_ = info.GetParentIndex();
+}
+
+Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) {
+  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();
   }
-}
 
-
-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;
+  return scope_info_list;
 }
 
 }  // namespace internal
diff --git a/src/debug/liveedit.h b/src/debug/liveedit.h
index 67be70e..af74043 100644
--- a/src/debug/liveedit.h
+++ b/src/debug/liveedit.h
@@ -32,26 +32,39 @@
 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.
+// in a particular script.
 //
 // The primary interest of the Tracker is to record function scope structures
-// in order to analyze whether function code maybe safely patched (with new
+// in order to analyze whether function code may be safely patched (with new
 // code successfully reading existing data from function scopes). The Tracker
 // also collects compiled function codes.
-class LiveEditFunctionTracker {
+class LiveEditFunctionTracker : public AstTraversalVisitor {
  public:
-  explicit LiveEditFunctionTracker(Isolate* isolate, FunctionLiteral* fun);
-  ~LiveEditFunctionTracker();
-  void RecordFunctionInfo(Handle<SharedFunctionInfo> info,
-                          FunctionLiteral* lit, Zone* zone);
-  void RecordRootFunctionInfo(Handle<Code> code);
+  // Traverses the entire AST, and records information about all
+  // FunctionLiterals for further use by LiveEdit code patching. The collected
+  // information is returned as a serialized array.
+  static Handle<JSArray> Collect(FunctionLiteral* node, Handle<Script> script,
+                                 Zone* zone, Isolate* isolate);
 
-  static bool IsActive(Isolate* isolate);
+  virtual ~LiveEditFunctionTracker() {}
+  void VisitFunctionLiteral(FunctionLiteral* node) override;
 
  private:
+  LiveEditFunctionTracker(Handle<Script> script, Zone* zone, Isolate* isolate);
+
+  void FunctionStarted(FunctionLiteral* fun);
+  void FunctionDone(Handle<SharedFunctionInfo> shared, Scope* scope);
+  Handle<Object> SerializeFunctionScope(Scope* scope);
+
+  Handle<Script> script_;
+  Zone* zone_;
   Isolate* isolate_;
+
+  Handle<JSArray> result_;
+  int len_;
+  int current_parent_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(LiveEditFunctionTracker);
 };
 
 
diff --git a/src/debug/mirrors.js b/src/debug/mirrors.js
index 881f303..d098c1c 100644
--- a/src/debug/mirrors.js
+++ b/src/debug/mirrors.js
@@ -16,8 +16,8 @@
 var MapEntries;
 var MapIteratorNext;
 var MathMin = global.Math.min;
-var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
-var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
+var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
+var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
 var SetIteratorNext;
 var SetValues;
 var SymbolToString;
@@ -115,7 +115,7 @@
 
 function ObjectIsPromise(value) {
   return IS_RECEIVER(value) &&
-         !IS_UNDEFINED(%DebugGetProperty(value, promiseStatusSymbol));
+         !IS_UNDEFINED(%DebugGetProperty(value, promiseStateSymbol));
 }
 
 
@@ -256,13 +256,15 @@
 // 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,
+var ScopeType = { Global:  0,
+                  Local:   1,
+                  With:    2,
                   Closure: 3,
-                  Catch: 4,
-                  Block: 5,
-                  Script: 6 };
+                  Catch:   4,
+                  Block:   5,
+                  Script:  6,
+                  Eval:    7,
+                };
 
 /**
  * Base class for all mirror objects.
@@ -1272,7 +1274,7 @@
 
 
 function PromiseGetStatus_(value) {
-  var status = %DebugGetProperty(value, promiseStatusSymbol);
+  var status = %DebugGetProperty(value, promiseStateSymbol);
   if (status == 0) return "pending";
   if (status == 1) return "resolved";
   return "rejected";
@@ -1280,7 +1282,7 @@
 
 
 function PromiseGetValue_(value) {
-  return %DebugGetProperty(value, promiseValueSymbol);
+  return %DebugGetProperty(value, promiseResultSymbol);
 }
 
 
@@ -1408,8 +1410,8 @@
 
 function GeneratorGetStatus_(value) {
   var continuation = %GeneratorGetContinuation(value);
-  if (continuation < 0) return "running";
-  if (continuation == 0) return "closed";
+  if (continuation < -1) return "running";
+  if (continuation == -1) return "closed";
   return "suspended";
 }
 
@@ -1495,6 +1497,12 @@
 };
 
 
+PropertyMirror.prototype.toText = function() {
+  if (IS_SYMBOL(this.name_)) return %SymbolDescriptiveString(this.name_);
+  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]) {
@@ -1529,11 +1537,6 @@
 };
 
 
-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
@@ -2027,10 +2030,10 @@
         if (display_receiver) {
           result += '.';
         }
-        result += property.name();
+        result += property.toText();
       } else {
         result += '[';
-        result += property.name();
+        result += property.toText();
         result += ']';
       }
       // Also known as - if the name in the function doesn't match the name