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/d8.cc b/src/d8.cc
index 7157cb8..c58c172 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -19,6 +19,7 @@
 
 #ifndef V8_SHARED
 #include <algorithm>
+#include <vector>
 #endif  // !V8_SHARED
 
 #ifdef V8_SHARED
@@ -43,9 +44,8 @@
 #include "src/base/platform/platform.h"
 #include "src/base/sys-info.h"
 #include "src/basic-block-profiler.h"
-#include "src/d8-debug.h"
-#include "src/debug.h"
-#include "src/natives.h"
+#include "src/snapshot/natives.h"
+#include "src/utils.h"
 #include "src/v8.h"
 #endif  // !V8_SHARED
 
@@ -62,14 +62,150 @@
 #define DCHECK(condition) assert(condition)
 #endif
 
+#ifndef CHECK
+#define CHECK(condition) assert(condition)
+#endif
+
 namespace v8 {
 
+namespace {
 
-static Handle<Value> Throw(Isolate* isolate, const char* message) {
-  return isolate->ThrowException(String::NewFromUtf8(isolate, message));
+const int MB = 1024 * 1024;
+#ifndef V8_SHARED
+const int kMaxWorkers = 50;
+#endif
+
+
+class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+ public:
+  virtual void* Allocate(size_t length) {
+    void* data = AllocateUninitialized(length);
+    return data == NULL ? data : memset(data, 0, length);
+  }
+  virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
+  virtual void Free(void* data, size_t) { free(data); }
+};
+
+
+class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+ public:
+  void* Allocate(size_t length) override {
+    size_t actual_length = length > 10 * MB ? 1 : length;
+    void* data = AllocateUninitialized(actual_length);
+    return data == NULL ? data : memset(data, 0, actual_length);
+  }
+  void* AllocateUninitialized(size_t length) override {
+    return length > 10 * MB ? malloc(1) : malloc(length);
+  }
+  void Free(void* p, size_t) override { free(p); }
+};
+
+
+#ifndef V8_SHARED
+// Predictable v8::Platform implementation. All background and foreground
+// tasks are run immediately, delayed tasks are not executed at all.
+class PredictablePlatform : public Platform {
+ public:
+  PredictablePlatform() {}
+
+  void CallOnBackgroundThread(Task* task,
+                              ExpectedRuntime expected_runtime) override {
+    task->Run();
+    delete task;
+  }
+
+  void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
+    task->Run();
+    delete task;
+  }
+
+  void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
+                                     double delay_in_seconds) override {
+    delete task;
+  }
+
+  void CallIdleOnForegroundThread(v8::Isolate* isolate,
+                                  IdleTask* task) override {
+    UNREACHABLE();
+  }
+
+  bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
+
+  double MonotonicallyIncreasingTime() override {
+    return synthetic_time_in_sec_ += 0.00001;
+  }
+
+  uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
+                         const char* name, uint64_t id, uint64_t bind_id,
+                         int numArgs, const char** argNames,
+                         const uint8_t* argTypes, const uint64_t* argValues,
+                         unsigned int flags) override {
+    return 0;
+  }
+
+  void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
+                                const char* name, uint64_t handle) override {}
+
+  const uint8_t* GetCategoryGroupEnabled(const char* name) override {
+    static uint8_t no = 0;
+    return &no;
+  }
+
+  const char* GetCategoryGroupName(
+      const uint8_t* categoryEnabledFlag) override {
+    static const char* dummy = "dummy";
+    return dummy;
+  }
+
+ private:
+  double synthetic_time_in_sec_ = 0.0;
+
+  DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
+};
+#endif  // !V8_SHARED
+
+
+v8::Platform* g_platform = NULL;
+
+
+static Local<Value> Throw(Isolate* isolate, const char* message) {
+  return isolate->ThrowException(
+      String::NewFromUtf8(isolate, message, NewStringType::kNormal)
+          .ToLocalChecked());
 }
 
 
+#ifndef V8_SHARED
+bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
+  for (int i = 0; i < list.length(); ++i) {
+    if (list[i]->StrictEquals(object)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
+  if (object->InternalFieldCount() != 1) {
+    Throw(isolate, "this is not a Worker");
+    return NULL;
+  }
+
+  Worker* worker =
+      static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
+  if (worker == NULL) {
+    Throw(isolate, "Worker is defunct because main thread is terminating");
+    return NULL;
+  }
+
+  return worker;
+}
+#endif  // !V8_SHARED
+
+
+}  // namespace
+
 
 class PerIsolateData {
  public:
@@ -101,64 +237,36 @@
   int realm_count_;
   int realm_current_;
   int realm_switch_;
-  Persistent<Context>* realms_;
-  Persistent<Value> realm_shared_;
+  Global<Context>* realms_;
+  Global<Value> realm_shared_;
 
   int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
                         int arg_offset);
-  int RealmFind(Handle<Context> context);
+  int RealmFind(Local<Context> context);
 };
 
 
-LineEditor *LineEditor::current_ = NULL;
-
-
-LineEditor::LineEditor(Type type, const char* name)
-    : type_(type), name_(name) {
-  if (current_ == NULL || current_->type_ < type) current_ = this;
-}
-
-
-class DumbLineEditor: public LineEditor {
- public:
-  explicit DumbLineEditor(Isolate* isolate)
-      : LineEditor(LineEditor::DUMB, "dumb"), isolate_(isolate) { }
-  virtual Handle<String> Prompt(const char* prompt);
- private:
-  Isolate* isolate_;
-};
-
-
-Handle<String> DumbLineEditor::Prompt(const char* prompt) {
-  printf("%s", prompt);
-#if defined(__native_client__)
-  // Native Client libc is used to being embedded in Chrome and
-  // has trouble recognizing when to flush.
-  fflush(stdout);
-#endif
-  return Shell::ReadFromStdin(isolate_);
-}
-
-
 #ifndef V8_SHARED
 CounterMap* Shell::counter_map_;
 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
 CounterCollection Shell::local_counters_;
 CounterCollection* Shell::counters_ = &local_counters_;
-base::Mutex Shell::context_mutex_;
+base::LazyMutex Shell::context_mutex_;
 const base::TimeTicks Shell::kInitialTicks =
     base::TimeTicks::HighResolutionNow();
-Persistent<Context> Shell::utility_context_;
+Global<Context> Shell::utility_context_;
+base::LazyMutex Shell::workers_mutex_;
+bool Shell::allow_new_workers_ = true;
+i::List<Worker*> Shell::workers_;
+i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
 #endif  // !V8_SHARED
 
-Persistent<Context> Shell::evaluation_context_;
+Global<Context> Shell::evaluation_context_;
+ArrayBuffer::Allocator* Shell::array_buffer_allocator;
 ShellOptions Shell::options;
-const char* Shell::kPrompt = "d8> ";
-
+base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
 
 #ifndef V8_SHARED
-const int MB = 1024 * 1024;
-
 bool CounterMap::Match(void* key1, void* key2) {
   const char* name1 = reinterpret_cast<const char*>(key1);
   const char* name2 = reinterpret_cast<const char*>(key2);
@@ -187,25 +295,30 @@
     name_buffer = new uint16_t[name_length];
     name_string->Write(name_buffer, 0, name_length);
   }
-  Isolate* temp_isolate = Isolate::New();
+  Isolate::CreateParams create_params;
+  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
+  Isolate* temp_isolate = Isolate::New(create_params);
   ScriptCompiler::CachedData* result = NULL;
   {
     Isolate::Scope isolate_scope(temp_isolate);
     HandleScope handle_scope(temp_isolate);
     Context::Scope context_scope(Context::New(temp_isolate));
-    Local<String> source_copy = v8::String::NewFromTwoByte(
-        temp_isolate, source_buffer, v8::String::kNormalString, source_length);
+    Local<String> source_copy =
+        v8::String::NewFromTwoByte(temp_isolate, source_buffer,
+                                   v8::NewStringType::kNormal,
+                                   source_length).ToLocalChecked();
     Local<Value> name_copy;
     if (name_buffer) {
-      name_copy = v8::String::NewFromTwoByte(
-          temp_isolate, name_buffer, v8::String::kNormalString, name_length);
+      name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer,
+                                             v8::NewStringType::kNormal,
+                                             name_length).ToLocalChecked();
     } else {
       name_copy = v8::Undefined(temp_isolate);
     }
     ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
-    ScriptCompiler::CompileUnbound(temp_isolate, &script_source,
-                                   compile_options);
-    if (script_source.GetCachedData()) {
+    if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
+                                              compile_options).IsEmpty() &&
+        script_source.GetCachedData()) {
       int length = script_source.GetCachedData()->length;
       uint8_t* cache = new uint8_t[length];
       memcpy(cache, script_source.GetCachedData()->data, length);
@@ -221,14 +334,18 @@
 
 
 // Compile a string within the current v8 context.
-Local<UnboundScript> Shell::CompileString(
+MaybeLocal<Script> Shell::CompileString(
     Isolate* isolate, Local<String> source, Local<Value> name,
-    ScriptCompiler::CompileOptions compile_options) {
+    ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
+  Local<Context> context(isolate->GetCurrentContext());
   ScriptOrigin origin(name);
   if (compile_options == ScriptCompiler::kNoCompileOptions) {
     ScriptCompiler::Source script_source(source, origin);
-    return ScriptCompiler::CompileUnbound(isolate, &script_source,
-                                          compile_options);
+    return source_type == SCRIPT
+               ? ScriptCompiler::Compile(context, &script_source,
+                                         compile_options)
+               : ScriptCompiler::CompileModule(context, &script_source,
+                                               compile_options);
   }
 
   ScriptCompiler::CachedData* data =
@@ -242,85 +359,85 @@
     DCHECK(false);  // A new compile option?
   }
   if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
-  return ScriptCompiler::CompileUnbound(isolate, &cached_source,
-                                        compile_options);
+  MaybeLocal<Script> result =
+      source_type == SCRIPT
+          ? ScriptCompiler::Compile(context, &cached_source, compile_options)
+          : ScriptCompiler::CompileModule(context, &cached_source,
+                                          compile_options);
+  CHECK(data == NULL || !data->rejected);
+  return result;
 }
 
 
 // Executes a string within the current v8 context.
-bool Shell::ExecuteString(Isolate* isolate,
-                          Handle<String> source,
-                          Handle<Value> name,
-                          bool print_result,
-                          bool report_exceptions) {
-#ifndef V8_SHARED
-  bool FLAG_debugger = i::FLAG_debugger;
-#else
-  bool FLAG_debugger = false;
-#endif  // !V8_SHARED
+bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
+                          Local<Value> name, bool print_result,
+                          bool report_exceptions, SourceType source_type) {
   HandleScope handle_scope(isolate);
-  TryCatch try_catch;
-  options.script_executed = true;
-  if (FLAG_debugger) {
-    // When debugging make exceptions appear to be uncaught.
-    try_catch.SetVerbose(true);
-  }
+  TryCatch try_catch(isolate);
 
-  Handle<UnboundScript> script =
-      Shell::CompileString(isolate, source, name, options.compile_options);
-  if (script.IsEmpty()) {
-    // Print errors that happened during compilation.
-    if (report_exceptions && !FLAG_debugger)
-      ReportException(isolate, &try_catch);
-    return false;
-  } else {
+  MaybeLocal<Value> maybe_result;
+  {
     PerIsolateData* data = PerIsolateData::Get(isolate);
     Local<Context> realm =
         Local<Context>::New(isolate, data->realms_[data->realm_current_]);
-    realm->Enter();
-    Handle<Value> result = script->BindToCurrentContext()->Run();
-    realm->Exit();
-    data->realm_current_ = data->realm_switch_;
-    if (result.IsEmpty()) {
-      DCHECK(try_catch.HasCaught());
-      // Print errors that happened during execution.
-      if (report_exceptions && !FLAG_debugger)
-        ReportException(isolate, &try_catch);
+    Context::Scope context_scope(realm);
+    Local<Script> script;
+    if (!Shell::CompileString(isolate, source, name, options.compile_options,
+                              source_type).ToLocal(&script)) {
+      // Print errors that happened during compilation.
+      if (report_exceptions) ReportException(isolate, &try_catch);
       return false;
-    } else {
-      DCHECK(!try_catch.HasCaught());
-      if (print_result) {
-#if !defined(V8_SHARED)
-        if (options.test_shell) {
-#endif
-          if (!result->IsUndefined()) {
-            // If all went well and the result wasn't undefined then print
-            // the returned value.
-            v8::String::Utf8Value str(result);
-            fwrite(*str, sizeof(**str), str.length(), stdout);
-            printf("\n");
-          }
-#if !defined(V8_SHARED)
-        } else {
-          v8::TryCatch try_catch;
-          v8::Local<v8::Context> context =
-              v8::Local<v8::Context>::New(isolate, utility_context_);
-          v8::Context::Scope context_scope(context);
-          Handle<Object> global = context->Global();
-          Handle<Value> fun =
-              global->Get(String::NewFromUtf8(isolate, "Stringify"));
-          Handle<Value> argv[1] = { result };
-          Handle<Value> s = Handle<Function>::Cast(fun)->Call(global, 1, argv);
-          if (try_catch.HasCaught()) return true;
-          v8::String::Utf8Value str(s);
-          fwrite(*str, sizeof(**str), str.length(), stdout);
-          printf("\n");
-        }
-#endif
-      }
-      return true;
     }
+    maybe_result = script->Run(realm);
+    EmptyMessageQueues(isolate);
+    data->realm_current_ = data->realm_switch_;
   }
+  Local<Value> result;
+  if (!maybe_result.ToLocal(&result)) {
+    DCHECK(try_catch.HasCaught());
+    // Print errors that happened during execution.
+    if (report_exceptions) ReportException(isolate, &try_catch);
+    return false;
+  }
+  DCHECK(!try_catch.HasCaught());
+  if (print_result) {
+#if !defined(V8_SHARED)
+    if (options.test_shell) {
+#endif
+      if (!result->IsUndefined()) {
+        // If all went well and the result wasn't undefined then print
+        // the returned value.
+        v8::String::Utf8Value str(result);
+        fwrite(*str, sizeof(**str), str.length(), stdout);
+        printf("\n");
+      }
+#if !defined(V8_SHARED)
+    } else {
+      v8::TryCatch try_catch(isolate);
+      v8::Local<v8::Context> context =
+          v8::Local<v8::Context>::New(isolate, utility_context_);
+      v8::Context::Scope context_scope(context);
+      Local<Object> global = context->Global();
+      Local<Value> fun =
+          global->Get(context, String::NewFromUtf8(isolate, "Stringify",
+                                                   v8::NewStringType::kNormal)
+                                   .ToLocalChecked()).ToLocalChecked();
+      Local<Value> argv[1] = {result};
+      Local<Value> s;
+      if (!Local<Function>::Cast(fun)
+               ->Call(context, global, 1, argv)
+               .ToLocal(&s)) {
+        return true;
+      }
+      DCHECK(!try_catch.HasCaught());
+      v8::String::Utf8Value str(s);
+      fwrite(*str, sizeof(**str), str.length(), stdout);
+      printf("\n");
+    }
+#endif
+  }
+  return true;
 }
 
 
@@ -328,7 +445,7 @@
   data_->realm_count_ = 1;
   data_->realm_current_ = 0;
   data_->realm_switch_ = 0;
-  data_->realms_ = new Persistent<Context>[1];
+  data_->realms_ = new Global<Context>[1];
   data_->realms_[0].Reset(data_->isolate_,
                           data_->isolate_->GetEnteredContext());
 }
@@ -344,7 +461,7 @@
 }
 
 
-int PerIsolateData::RealmFind(Handle<Context> context) {
+int PerIsolateData::RealmFind(Local<Context> context) {
   for (int i = 0; i < realm_count_; ++i) {
     if (realms_[i] == context) return i;
   }
@@ -359,10 +476,10 @@
     Throw(args.GetIsolate(), "Invalid argument");
     return -1;
   }
-  int index = args[arg_offset]->Int32Value();
-  if (index < 0 ||
-      index >= realm_count_ ||
-      realms_[index].IsEmpty()) {
+  int index = args[arg_offset]
+                  ->Int32Value(args.GetIsolate()->GetCurrentContext())
+                  .FromMaybe(-1);
+  if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
     Throw(args.GetIsolate(), "Invalid realm index");
     return -1;
   }
@@ -372,13 +489,11 @@
 
 #ifndef V8_SHARED
 // performance.now() returns a time stamp as double, measured in milliseconds.
-// When FLAG_verify_predictable mode is enabled it returns current value
-// of Heap::allocations_count().
+// When FLAG_verify_predictable mode is enabled it returns result of
+// v8::Platform::MonotonicallyIncreasingTime().
 void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
   if (i::FLAG_verify_predictable) {
-    Isolate* v8_isolate = args.GetIsolate();
-    i::Heap* heap = reinterpret_cast<i::Isolate*>(v8_isolate)->heap();
-    args.GetReturnValue().Set(heap->synthetic_time());
+    args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
   } else {
     base::TimeDelta delta =
         base::TimeTicks::HighResolutionNow() - kInitialTicks;
@@ -406,7 +521,10 @@
     Throw(args.GetIsolate(), "Invalid argument");
     return;
   }
-  int index = data->RealmFind(args[0]->ToObject(isolate)->CreationContext());
+  int index = data->RealmFind(args[0]
+                                  ->ToObject(isolate->GetCurrentContext())
+                                  .ToLocalChecked()
+                                  ->CreationContext());
   if (index == -1) return;
   args.GetReturnValue().Set(index);
 }
@@ -426,17 +544,24 @@
 // Realm.create() creates a new realm and returns its index.
 void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   Isolate* isolate = args.GetIsolate();
+  TryCatch try_catch(isolate);
   PerIsolateData* data = PerIsolateData::Get(isolate);
-  Persistent<Context>* old_realms = data->realms_;
+  Global<Context>* old_realms = data->realms_;
   int index = data->realm_count_;
-  data->realms_ = new Persistent<Context>[++data->realm_count_];
+  data->realms_ = new Global<Context>[++data->realm_count_];
   for (int i = 0; i < index; ++i) {
     data->realms_[i].Reset(isolate, old_realms[i]);
+    old_realms[i].Reset();
   }
   delete[] old_realms;
-  Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
-  data->realms_[index].Reset(
-      isolate, Context::New(isolate, NULL, global_template));
+  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
+  Local<Context> context = Context::New(isolate, NULL, global_template);
+  if (context.IsEmpty()) {
+    DCHECK(try_catch.HasCaught());
+    try_catch.ReThrow();
+    return;
+  }
+  data->realms_[index].Reset(isolate, context);
   args.GetReturnValue().Set(index);
 }
 
@@ -453,6 +578,8 @@
     return;
   }
   data->realms_[index].Reset();
+  isolate->ContextDisposedNotification();
+  isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
 }
 
 
@@ -476,13 +603,20 @@
     Throw(args.GetIsolate(), "Invalid argument");
     return;
   }
-  ScriptCompiler::Source script_source(args[1]->ToString(isolate));
-  Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
-      isolate, &script_source);
-  if (script.IsEmpty()) return;
+  ScriptCompiler::Source script_source(
+      args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
+  Local<UnboundScript> script;
+  if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
+           .ToLocal(&script)) {
+    return;
+  }
   Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
   realm->Enter();
-  Handle<Value> result = script->BindToCurrentContext()->Run();
+  Local<Value> result;
+  if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
+    realm->Exit();
+    return;
+  }
   realm->Exit();
   args.GetReturnValue().Set(result);
 }
@@ -521,9 +655,15 @@
     }
 
     // Explicitly catch potential exceptions in toString().
-    v8::TryCatch try_catch;
-    Handle<String> str_obj = args[i]->ToString(args.GetIsolate());
-    if (try_catch.HasCaught()) {
+    v8::TryCatch try_catch(args.GetIsolate());
+    Local<Value> arg = args[i];
+    Local<String> str_obj;
+
+    if (arg->IsSymbol()) {
+      arg = Local<Symbol>::Cast(arg)->Name();
+    }
+    if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
+             .ToLocal(&str_obj)) {
       try_catch.ReThrow();
       return;
     }
@@ -544,7 +684,7 @@
     Throw(args.GetIsolate(), "Error loading file");
     return;
   }
-  Handle<String> source = ReadFile(args.GetIsolate(), *file);
+  Local<String> source = ReadFile(args.GetIsolate(), *file);
   if (source.IsEmpty()) {
     Throw(args.GetIsolate(), "Error loading file");
     return;
@@ -553,10 +693,11 @@
 }
 
 
-Handle<String> Shell::ReadFromStdin(Isolate* isolate) {
+Local<String> Shell::ReadFromStdin(Isolate* isolate) {
   static const int kBufferSize = 256;
   char buffer[kBufferSize];
-  Handle<String> accumulator = String::NewFromUtf8(isolate, "");
+  Local<String> accumulator =
+      String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
   int length;
   while (true) {
     // Continue reading if the line ends with an escape '\\' or the line has
@@ -564,23 +705,26 @@
     // If fgets gets an error, just give up.
     char* input = NULL;
     input = fgets(buffer, kBufferSize, stdin);
-    if (input == NULL) return Handle<String>();
+    if (input == NULL) return Local<String>();
     length = static_cast<int>(strlen(buffer));
     if (length == 0) {
       return accumulator;
     } else if (buffer[length-1] != '\n') {
       accumulator = String::Concat(
           accumulator,
-          String::NewFromUtf8(isolate, buffer, String::kNormalString, length));
+          String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
+              .ToLocalChecked());
     } else if (length > 1 && buffer[length-2] == '\\') {
       buffer[length-2] = '\n';
       accumulator = String::Concat(
-          accumulator, String::NewFromUtf8(isolate, buffer,
-                                           String::kNormalString, length - 1));
+          accumulator,
+          String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
+                              length - 1).ToLocalChecked());
     } else {
       return String::Concat(
-          accumulator, String::NewFromUtf8(isolate, buffer,
-                                           String::kNormalString, length - 1));
+          accumulator,
+          String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
+                              length - 1).ToLocalChecked());
     }
   }
 }
@@ -594,16 +738,16 @@
       Throw(args.GetIsolate(), "Error loading file");
       return;
     }
-    Handle<String> source = ReadFile(args.GetIsolate(), *file);
+    Local<String> source = ReadFile(args.GetIsolate(), *file);
     if (source.IsEmpty()) {
       Throw(args.GetIsolate(), "Error loading file");
       return;
     }
-    if (!ExecuteString(args.GetIsolate(),
-                       source,
-                       String::NewFromUtf8(args.GetIsolate(), *file),
-                       false,
-                       true)) {
+    if (!ExecuteString(
+            args.GetIsolate(), source,
+            String::NewFromUtf8(args.GetIsolate(), *file,
+                                NewStringType::kNormal).ToLocalChecked(),
+            false, true)) {
       Throw(args.GetIsolate(), "Error executing file");
       return;
     }
@@ -611,23 +755,160 @@
 }
 
 
+#ifndef V8_SHARED
+void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  Isolate* isolate = args.GetIsolate();
+  HandleScope handle_scope(isolate);
+  if (args.Length() < 1 || !args[0]->IsString()) {
+    Throw(args.GetIsolate(), "1st argument must be string");
+    return;
+  }
+
+  if (!args.IsConstructCall()) {
+    Throw(args.GetIsolate(), "Worker must be constructed with new");
+    return;
+  }
+
+  {
+    base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
+    if (workers_.length() >= kMaxWorkers) {
+      Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
+      return;
+    }
+
+    // Initialize the internal field to NULL; if we return early without
+    // creating a new Worker (because the main thread is terminating) we can
+    // early-out from the instance calls.
+    args.Holder()->SetAlignedPointerInInternalField(0, NULL);
+
+    if (!allow_new_workers_) return;
+
+    Worker* worker = new Worker;
+    args.Holder()->SetAlignedPointerInInternalField(0, worker);
+    workers_.Add(worker);
+
+    String::Utf8Value script(args[0]);
+    if (!*script) {
+      Throw(args.GetIsolate(), "Can't get worker script");
+      return;
+    }
+    worker->StartExecuteInThread(*script);
+  }
+}
+
+
+void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  Isolate* isolate = args.GetIsolate();
+  HandleScope handle_scope(isolate);
+  Local<Context> context = isolate->GetCurrentContext();
+
+  if (args.Length() < 1) {
+    Throw(isolate, "Invalid argument");
+    return;
+  }
+
+  Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
+  if (!worker) {
+    return;
+  }
+
+  Local<Value> message = args[0];
+  ObjectList to_transfer;
+  if (args.Length() >= 2) {
+    if (!args[1]->IsArray()) {
+      Throw(isolate, "Transfer list must be an Array");
+      return;
+    }
+
+    Local<Array> transfer = Local<Array>::Cast(args[1]);
+    uint32_t length = transfer->Length();
+    for (uint32_t i = 0; i < length; ++i) {
+      Local<Value> element;
+      if (transfer->Get(context, i).ToLocal(&element)) {
+        if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
+          Throw(isolate,
+                "Transfer array elements must be an ArrayBuffer or "
+                "SharedArrayBuffer.");
+          break;
+        }
+
+        to_transfer.Add(Local<Object>::Cast(element));
+      }
+    }
+  }
+
+  ObjectList seen_objects;
+  SerializationData* data = new SerializationData;
+  if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
+    worker->PostMessage(data);
+  } else {
+    delete data;
+  }
+}
+
+
+void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  Isolate* isolate = args.GetIsolate();
+  HandleScope handle_scope(isolate);
+  Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
+  if (!worker) {
+    return;
+  }
+
+  SerializationData* data = worker->GetMessage();
+  if (data) {
+    int offset = 0;
+    Local<Value> data_value;
+    if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
+      args.GetReturnValue().Set(data_value);
+    }
+    delete data;
+  }
+}
+
+
+void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  Isolate* isolate = args.GetIsolate();
+  HandleScope handle_scope(isolate);
+  Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
+  if (!worker) {
+    return;
+  }
+
+  worker->Terminate();
+}
+#endif  // !V8_SHARED
+
+
+void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
+  int exit_code = (*args)[0]
+                      ->Int32Value(args->GetIsolate()->GetCurrentContext())
+                      .FromMaybe(0);
+#ifndef V8_SHARED
+  CleanupWorkers();
+#endif  // !V8_SHARED
+  OnExit(args->GetIsolate());
+  Exit(exit_code);
+}
+
+
 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
-  int exit_code = args[0]->Int32Value();
-  OnExit(args.GetIsolate());
-  exit(exit_code);
+  base::CallOnce(&quit_once_, &QuitOnce,
+                 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
 }
 
 
 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
   args.GetReturnValue().Set(
-      String::NewFromUtf8(args.GetIsolate(), V8::GetVersion()));
+      String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
+                          NewStringType::kNormal).ToLocalChecked());
 }
 
 
 void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
   HandleScope handle_scope(isolate);
 #ifndef V8_SHARED
-  Handle<Context> utility_context;
+  Local<Context> utility_context;
   bool enter_context = !isolate->InContext();
   if (enter_context) {
     utility_context = Local<Context>::New(isolate, utility_context_);
@@ -636,7 +917,7 @@
 #endif  // !V8_SHARED
   v8::String::Utf8Value exception(try_catch->Exception());
   const char* exception_string = ToCString(exception);
-  Handle<Message> message = try_catch->Message();
+  Local<Message> message = try_catch->Message();
   if (message.IsEmpty()) {
     // V8 didn't provide any extra information about this error; just
     // print the exception.
@@ -645,26 +926,32 @@
     // Print (filename):(line number): (message).
     v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
     const char* filename_string = ToCString(filename);
-    int linenum = message->GetLineNumber();
+    int linenum =
+        message->GetLineNumber(isolate->GetCurrentContext()).FromJust();
     printf("%s:%i: %s\n", filename_string, linenum, exception_string);
     // Print line of source code.
-    v8::String::Utf8Value sourceline(message->GetSourceLine());
+    v8::String::Utf8Value sourceline(
+        message->GetSourceLine(isolate->GetCurrentContext()).ToLocalChecked());
     const char* sourceline_string = ToCString(sourceline);
     printf("%s\n", sourceline_string);
     // Print wavy underline (GetUnderline is deprecated).
-    int start = message->GetStartColumn();
+    int start =
+        message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
     for (int i = 0; i < start; i++) {
       printf(" ");
     }
-    int end = message->GetEndColumn();
+    int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
     for (int i = start; i < end; i++) {
       printf("^");
     }
     printf("\n");
-    v8::String::Utf8Value stack_trace(try_catch->StackTrace());
-    if (stack_trace.length() > 0) {
-      const char* stack_trace_string = ToCString(stack_trace);
-      printf("%s\n", stack_trace_string);
+    Local<Value> stack_trace_string;
+    if (try_catch->StackTrace(isolate->GetCurrentContext())
+            .ToLocal(&stack_trace_string) &&
+        stack_trace_string->IsString()) {
+      v8::String::Utf8Value stack_trace(
+          Local<String>::Cast(stack_trace_string));
+      printf("%s\n", ToCString(stack_trace));
     }
   }
   printf("\n");
@@ -675,57 +962,6 @@
 
 
 #ifndef V8_SHARED
-Handle<Array> Shell::GetCompletions(Isolate* isolate,
-                                    Handle<String> text,
-                                    Handle<String> full) {
-  EscapableHandleScope handle_scope(isolate);
-  v8::Local<v8::Context> utility_context =
-      v8::Local<v8::Context>::New(isolate, utility_context_);
-  v8::Context::Scope context_scope(utility_context);
-  Handle<Object> global = utility_context->Global();
-  Local<Value> fun =
-      global->Get(String::NewFromUtf8(isolate, "GetCompletions"));
-  static const int kArgc = 3;
-  v8::Local<v8::Context> evaluation_context =
-      v8::Local<v8::Context>::New(isolate, evaluation_context_);
-  Handle<Value> argv[kArgc] = { evaluation_context->Global(), text, full };
-  Local<Value> val = Local<Function>::Cast(fun)->Call(global, kArgc, argv);
-  return handle_scope.Escape(Local<Array>::Cast(val));
-}
-
-
-Local<Object> Shell::DebugMessageDetails(Isolate* isolate,
-                                         Handle<String> message) {
-  EscapableHandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context =
-      v8::Local<v8::Context>::New(isolate, utility_context_);
-  v8::Context::Scope context_scope(context);
-  Handle<Object> global = context->Global();
-  Handle<Value> fun =
-      global->Get(String::NewFromUtf8(isolate, "DebugMessageDetails"));
-  static const int kArgc = 1;
-  Handle<Value> argv[kArgc] = { message };
-  Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
-  return handle_scope.Escape(Local<Object>(Handle<Object>::Cast(val)));
-}
-
-
-Local<Value> Shell::DebugCommandToJSONRequest(Isolate* isolate,
-                                              Handle<String> command) {
-  EscapableHandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context =
-      v8::Local<v8::Context>::New(isolate, utility_context_);
-  v8::Context::Scope context_scope(context);
-  Handle<Object> global = context->Global();
-  Handle<Value> fun =
-      global->Get(String::NewFromUtf8(isolate, "DebugCommandToJSONRequest"));
-  static const int kArgc = 1;
-  Handle<Value> argv[kArgc] = { command };
-  Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
-  return handle_scope.Escape(Local<Value>(val));
-}
-
-
 int32_t* Counter::Bind(const char* name, bool is_histogram) {
   int i;
   for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
@@ -824,10 +1060,25 @@
 }
 
 
+class NoUseStrongForUtilityScriptScope {
+ public:
+  NoUseStrongForUtilityScriptScope() : flag_(i::FLAG_use_strong) {
+    i::FLAG_use_strong = false;
+  }
+  ~NoUseStrongForUtilityScriptScope() { i::FLAG_use_strong = flag_; }
+
+ private:
+  bool flag_;
+};
+
+
 void Shell::InstallUtilityScript(Isolate* isolate) {
+  NoUseStrongForUtilityScriptScope no_use_strong;
   HandleScope scope(isolate);
   // If we use the utility context, we have to set the security tokens so that
   // utility, evaluation and debug context can all access each other.
+  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
+  utility_context_.Reset(isolate, Context::New(isolate, NULL, global_template));
   v8::Local<v8::Context> utility_context =
       v8::Local<v8::Context>::New(isolate, utility_context_);
   v8::Local<v8::Context> evaluation_context =
@@ -836,33 +1087,23 @@
   evaluation_context->SetSecurityToken(Undefined(isolate));
   v8::Context::Scope context_scope(utility_context);
 
-  if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
-  // Install the debugger object in the utility scope
-  i::Debug* debug = reinterpret_cast<i::Isolate*>(isolate)->debug();
-  debug->Load();
-  i::Handle<i::Context> debug_context = debug->debug_context();
-  i::Handle<i::JSObject> js_debug
-      = i::Handle<i::JSObject>(debug_context->global_object());
-  utility_context->Global()->Set(String::NewFromUtf8(isolate, "$debug"),
-                                 Utils::ToLocal(js_debug));
-  debug_context->set_security_token(
-      reinterpret_cast<i::Isolate*>(isolate)->heap()->undefined_value());
-
   // Run the d8 shell utility script in the utility context
   int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
   i::Vector<const char> shell_source =
       i::NativesCollection<i::D8>::GetScriptSource(source_index);
   i::Vector<const char> shell_source_name =
       i::NativesCollection<i::D8>::GetScriptName(source_index);
-  Handle<String> source =
-      String::NewFromUtf8(isolate, shell_source.start(), String::kNormalString,
-                          shell_source.length());
-  Handle<String> name =
+  Local<String> source =
+      String::NewFromUtf8(isolate, shell_source.start(), NewStringType::kNormal,
+                          shell_source.length()).ToLocalChecked();
+  Local<String> name =
       String::NewFromUtf8(isolate, shell_source_name.start(),
-                          String::kNormalString, shell_source_name.length());
+                          NewStringType::kNormal,
+                          shell_source_name.length()).ToLocalChecked();
   ScriptOrigin origin(name);
-  Handle<Script> script = Script::Compile(source, &origin);
-  script->Run();
+  Local<Script> script =
+      Script::Compile(utility_context, source, &origin).ToLocalChecked();
+  script->Run(utility_context).ToLocalChecked();
   // Mark the d8 shell script as native to avoid it showing up as normal source
   // in the debugger.
   i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
@@ -871,64 +1112,137 @@
           i::JSFunction::cast(*compiled_script)->shared()->script()))
       : i::Handle<i::Script>(i::Script::cast(
           i::SharedFunctionInfo::cast(*compiled_script)->script()));
-  script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
-
-  // Start the in-process debugger if requested.
-  if (i::FLAG_debugger) v8::Debug::SetDebugEventListener(HandleDebugEvent);
+  script_object->set_type(i::Script::TYPE_EXTENSION);
 }
 #endif  // !V8_SHARED
 
 
-Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
-  Handle<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
-  global_template->Set(String::NewFromUtf8(isolate, "print"),
-                       FunctionTemplate::New(isolate, Print));
-  global_template->Set(String::NewFromUtf8(isolate, "write"),
-                       FunctionTemplate::New(isolate, Write));
-  global_template->Set(String::NewFromUtf8(isolate, "read"),
-                       FunctionTemplate::New(isolate, Read));
-  global_template->Set(String::NewFromUtf8(isolate, "readbuffer"),
-                       FunctionTemplate::New(isolate, ReadBuffer));
-  global_template->Set(String::NewFromUtf8(isolate, "readline"),
-                       FunctionTemplate::New(isolate, ReadLine));
-  global_template->Set(String::NewFromUtf8(isolate, "load"),
-                       FunctionTemplate::New(isolate, Load));
-  global_template->Set(String::NewFromUtf8(isolate, "quit"),
-                       FunctionTemplate::New(isolate, Quit));
-  global_template->Set(String::NewFromUtf8(isolate, "version"),
-                       FunctionTemplate::New(isolate, Version));
+Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
+  Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
+  global_template->Set(
+      String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, Print));
+  global_template->Set(
+      String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, Write));
+  global_template->Set(
+      String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, Read));
+  global_template->Set(
+      String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, ReadBuffer));
+  global_template->Set(
+      String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, ReadLine));
+  global_template->Set(
+      String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, Load));
+  // Some Emscripten-generated code tries to call 'quit', which in turn would
+  // call C's exit(). This would lead to memory leaks, because there is no way
+  // we can terminate cleanly then, so we need a way to hide 'quit'.
+  if (!options.omit_quit) {
+    global_template->Set(
+        String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
+            .ToLocalChecked(),
+        FunctionTemplate::New(isolate, Quit));
+  }
+  global_template->Set(
+      String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, Version));
 
   // Bind the Realm object.
-  Handle<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
-  realm_template->Set(String::NewFromUtf8(isolate, "current"),
-                      FunctionTemplate::New(isolate, RealmCurrent));
-  realm_template->Set(String::NewFromUtf8(isolate, "owner"),
-                      FunctionTemplate::New(isolate, RealmOwner));
-  realm_template->Set(String::NewFromUtf8(isolate, "global"),
-                      FunctionTemplate::New(isolate, RealmGlobal));
-  realm_template->Set(String::NewFromUtf8(isolate, "create"),
-                      FunctionTemplate::New(isolate, RealmCreate));
-  realm_template->Set(String::NewFromUtf8(isolate, "dispose"),
-                      FunctionTemplate::New(isolate, RealmDispose));
-  realm_template->Set(String::NewFromUtf8(isolate, "switch"),
-                      FunctionTemplate::New(isolate, RealmSwitch));
-  realm_template->Set(String::NewFromUtf8(isolate, "eval"),
-                      FunctionTemplate::New(isolate, RealmEval));
-  realm_template->SetAccessor(String::NewFromUtf8(isolate, "shared"),
-                              RealmSharedGet, RealmSharedSet);
-  global_template->Set(String::NewFromUtf8(isolate, "Realm"), realm_template);
+  Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmCurrent));
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmOwner));
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmGlobal));
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmCreate));
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmDispose));
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmSwitch));
+  realm_template->Set(
+      String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, RealmEval));
+  realm_template->SetAccessor(
+      String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
+          .ToLocalChecked(),
+      RealmSharedGet, RealmSharedSet);
+  global_template->Set(
+      String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
+          .ToLocalChecked(),
+      realm_template);
 
 #ifndef V8_SHARED
-  Handle<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
-  performance_template->Set(String::NewFromUtf8(isolate, "now"),
-                            FunctionTemplate::New(isolate, PerformanceNow));
-  global_template->Set(String::NewFromUtf8(isolate, "performance"),
-                       performance_template);
+  Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
+  performance_template->Set(
+      String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, PerformanceNow));
+  global_template->Set(
+      String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
+          .ToLocalChecked(),
+      performance_template);
+
+  Local<FunctionTemplate> worker_fun_template =
+      FunctionTemplate::New(isolate, WorkerNew);
+  Local<Signature> worker_signature =
+      Signature::New(isolate, worker_fun_template);
+  worker_fun_template->SetClassName(
+      String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
+          .ToLocalChecked());
+  worker_fun_template->ReadOnlyPrototype();
+  worker_fun_template->PrototypeTemplate()->Set(
+      String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
+                            worker_signature));
+  worker_fun_template->PrototypeTemplate()->Set(
+      String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
+                            worker_signature));
+  worker_fun_template->PrototypeTemplate()->Set(
+      String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
+          .ToLocalChecked(),
+      FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
+                            worker_signature));
+  worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
+  global_template->Set(
+      String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
+          .ToLocalChecked(),
+      worker_fun_template);
 #endif  // !V8_SHARED
 
-  Handle<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
+  Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
   AddOSMethods(isolate, os_templ);
-  global_template->Set(String::NewFromUtf8(isolate, "os"), os_templ);
+  global_template->Set(
+      String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
+          .ToLocalChecked(),
+      os_templ);
 
   return global_template;
 }
@@ -936,26 +1250,9 @@
 
 void Shell::Initialize(Isolate* isolate) {
 #ifndef V8_SHARED
-  Shell::counter_map_ = new CounterMap();
   // Set up counters
   if (i::StrLength(i::FLAG_map_counters) != 0)
     MapCounters(isolate, i::FLAG_map_counters);
-  if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
-    isolate->SetCounterFunction(LookupCounter);
-    isolate->SetCreateHistogramFunction(CreateHistogram);
-    isolate->SetAddHistogramSampleFunction(AddHistogramSample);
-  }
-#endif  // !V8_SHARED
-}
-
-
-void Shell::InitializeDebugger(Isolate* isolate) {
-  if (options.test_shell) return;
-#ifndef V8_SHARED
-  HandleScope scope(isolate);
-  Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
-  utility_context_.Reset(isolate,
-                         Context::New(isolate, NULL, global_template));
 #endif  // !V8_SHARED
 }
 
@@ -963,10 +1260,10 @@
 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
 #ifndef V8_SHARED
   // This needs to be a critical section since this is not thread-safe
-  base::LockGuard<base::Mutex> lock_guard(&context_mutex_);
+  base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
 #endif  // !V8_SHARED
   // Initialize the global objects
-  Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
+  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
   EscapableHandleScope handle_scope(isolate);
   Local<Context> context = Context::New(isolate, NULL, global_template);
   DCHECK(!context.IsEmpty());
@@ -984,8 +1281,12 @@
   }
   i::Handle<i::JSArray> arguments_jsarray =
       factory->NewJSArrayWithElements(arguments_array);
-  context->Global()->Set(String::NewFromUtf8(isolate, "arguments"),
-                         Utils::ToLocal(arguments_jsarray));
+  context->Global()
+      ->Set(context,
+            String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
+                .ToLocalChecked(),
+            Utils::ToLocal(arguments_jsarray))
+      .FromJust();
 #endif  // !V8_SHARED
   return handle_scope.Escape(context);
 }
@@ -1014,8 +1315,6 @@
 
 
 void Shell::OnExit(v8::Isolate* isolate) {
-  LineEditor* line_editor = LineEditor::Get();
-  if (line_editor) line_editor->Close();
 #ifndef V8_SHARED
   reinterpret_cast<i::Isolate*>(isolate)->DumpAndResetCompilationStats();
   if (i::FLAG_dump_counters) {
@@ -1083,30 +1382,35 @@
   if (file == NULL) return NULL;
 
   fseek(file, 0, SEEK_END);
-  int size = ftell(file);
+  size_t size = ftell(file);
   rewind(file);
 
   char* chars = new char[size + 1];
   chars[size] = '\0';
-  for (int i = 0; i < size;) {
-    int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
-    i += read;
+  for (size_t i = 0; i < size;) {
+    i += fread(&chars[i], 1, size - i, file);
+    if (ferror(file)) {
+      fclose(file);
+      delete[] chars;
+      return nullptr;
+    }
   }
   fclose(file);
-  *size_out = size;
+  *size_out = static_cast<int>(size);
   return chars;
 }
 
 
 struct DataAndPersistent {
   uint8_t* data;
-  Persistent<ArrayBuffer> handle;
+  int byte_length;
+  Global<ArrayBuffer> handle;
 };
 
 
 static void ReadBufferWeakCallback(
-    const v8::WeakCallbackData<ArrayBuffer, DataAndPersistent>& data) {
-  size_t byte_length = data.GetValue()->ByteLength();
+    const v8::WeakCallbackInfo<DataAndPersistent>& data) {
+  int byte_length = data.GetParameter()->byte_length;
   data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
       -static_cast<intptr_t>(byte_length));
 
@@ -1134,10 +1438,11 @@
     Throw(args.GetIsolate(), "Error reading file");
     return;
   }
-  Handle<v8::ArrayBuffer> buffer =
-      ArrayBuffer::New(isolate, data->data, length);
+  data->byte_length = length;
+  Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
   data->handle.Reset(isolate, buffer);
-  data->handle.SetWeak(data, ReadBufferWeakCallback);
+  data->handle.SetWeak(data, ReadBufferWeakCallback,
+                       v8::WeakCallbackType::kParameter);
   data->handle.MarkIndependent();
   isolate->AdjustAmountOfExternalAllocatedMemory(length);
 
@@ -1146,12 +1451,13 @@
 
 
 // Reads a file into a v8 string.
-Handle<String> Shell::ReadFile(Isolate* isolate, const char* name) {
+Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
   int size = 0;
   char* chars = ReadChars(isolate, name, &size);
-  if (chars == NULL) return Handle<String>();
-  Handle<String> result =
-      String::NewFromUtf8(isolate, chars, String::kNormalString, size);
+  if (chars == NULL) return Local<String>();
+  Local<String> result =
+      String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
+          .ToLocalChecked();
   delete[] chars;
   return result;
 }
@@ -1163,13 +1469,19 @@
       v8::Local<v8::Context>::New(isolate, evaluation_context_);
   v8::Context::Scope context_scope(context);
   PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
-  Handle<String> name = String::NewFromUtf8(isolate, "(d8)");
-  LineEditor* console = LineEditor::Get();
-  printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
-  console->Open(isolate);
+  Local<String> name =
+      String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
+          .ToLocalChecked();
+  printf("V8 version %s\n", V8::GetVersion());
   while (true) {
     HandleScope inner_scope(isolate);
-    Handle<String> input = console->Prompt(Shell::kPrompt);
+    printf("d8> ");
+#if defined(__native_client__)
+    // Native Client libc is used to being embedded in Chrome and
+    // has trouble recognizing when to flush.
+    fflush(stdout);
+#endif
+    Local<String> input = Shell::ReadFromStdin(isolate);
     if (input.IsEmpty()) break;
     ExecuteString(isolate, input, name, true, true);
   }
@@ -1189,31 +1501,47 @@
   bool exception_was_thrown = false;
   for (int i = begin_offset_; i < end_offset_; ++i) {
     const char* arg = argv_[i];
+    Shell::SourceType source_type = Shell::SCRIPT;
     if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
       // Execute argument given to -e option directly.
       HandleScope handle_scope(isolate);
-      Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed");
-      Handle<String> source = String::NewFromUtf8(isolate, argv_[i + 1]);
+      Local<String> file_name =
+          String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
+              .ToLocalChecked();
+      Local<String> source =
+          String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
+              .ToLocalChecked();
+      Shell::options.script_executed = true;
       if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
         exception_was_thrown = true;
         break;
       }
       ++i;
+      continue;
+    } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
+      // Treat the next file as a module.
+      source_type = Shell::MODULE;
+      arg = argv_[++i];
     } else if (arg[0] == '-') {
       // Ignore other options. They have been parsed already.
-    } else {
-      // Use all other arguments as names of files to load and run.
-      HandleScope handle_scope(isolate);
-      Handle<String> file_name = String::NewFromUtf8(isolate, arg);
-      Handle<String> source = ReadFile(isolate, arg);
-      if (source.IsEmpty()) {
-        printf("Error reading '%s'\n", arg);
-        Shell::Exit(1);
-      }
-      if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
-        exception_was_thrown = true;
-        break;
-      }
+      continue;
+    }
+
+    // Use all other arguments as names of files to load and run.
+    HandleScope handle_scope(isolate);
+    Local<String> file_name =
+        String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
+            .ToLocalChecked();
+    Local<String> source = ReadFile(isolate, arg);
+    if (source.IsEmpty()) {
+      printf("Error reading '%s'\n", arg);
+      Shell::Exit(1);
+    }
+    Shell::options.script_executed = true;
+    if (!Shell::ExecuteString(isolate, source, file_name, false, true,
+                              source_type)) {
+      exception_was_thrown = true;
+      break;
     }
   }
   if (exception_was_thrown != Shell::options.expected_to_throw) {
@@ -1222,12 +1550,13 @@
 }
 
 
-Handle<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
+Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
   int size;
   char* chars = ReadChars(isolate, name, &size);
-  if (chars == NULL) return Handle<String>();
-  Handle<String> result =
-      String::NewFromUtf8(isolate, chars, String::kNormalString, size);
+  if (chars == NULL) return Local<String>();
+  Local<String> result =
+      String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
+          .ToLocalChecked();
   delete[] chars;
   return result;
 }
@@ -1244,8 +1573,10 @@
 
 
 void SourceGroup::ExecuteInThread() {
-  Isolate* isolate = Isolate::New();
-  do {
+  Isolate::CreateParams create_params;
+  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
+  Isolate* isolate = Isolate::New(create_params);
+  for (int i = 0; i < Shell::options.stress_runs; ++i) {
     next_semaphore_.Wait();
     {
       Isolate::Scope iscope(isolate);
@@ -1259,20 +1590,10 @@
           Execute(isolate);
         }
       }
-      if (Shell::options.send_idle_notification) {
-        const int kLongIdlePauseInMs = 1000;
-        isolate->ContextDisposedNotification();
-        isolate->IdleNotification(kLongIdlePauseInMs);
-      }
-      if (Shell::options.invoke_weak_callbacks) {
-        // By sending a low memory notifications, we will try hard to collect
-        // all garbage and will therefore also invoke all weak callbacks of
-        // actually unreachable persistent handles.
-        isolate->LowMemoryNotification();
-      }
+      Shell::CollectGarbage(isolate);
     }
     done_semaphore_.Signal();
-  } while (!Shell::options.last_run);
+  }
 
   isolate->Dispose();
 }
@@ -1289,10 +1610,280 @@
 
 void SourceGroup::WaitForThread() {
   if (thread_ == NULL) return;
-  if (Shell::options.last_run) {
-    thread_->Join();
+  done_semaphore_.Wait();
+}
+
+
+void SourceGroup::JoinThread() {
+  if (thread_ == NULL) return;
+  thread_->Join();
+}
+
+
+SerializationData::~SerializationData() {
+  // Any ArrayBuffer::Contents are owned by this SerializationData object if
+  // ownership hasn't been transferred out via ReadArrayBufferContents.
+  // SharedArrayBuffer::Contents may be used by multiple threads, so must be
+  // cleaned up by the main thread in Shell::CleanupWorkers().
+  for (int i = 0; i < array_buffer_contents_.length(); ++i) {
+    ArrayBuffer::Contents& contents = array_buffer_contents_[i];
+    if (contents.Data()) {
+      Shell::array_buffer_allocator->Free(contents.Data(),
+                                          contents.ByteLength());
+    }
+  }
+}
+
+
+void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
+
+
+void SerializationData::WriteMemory(const void* p, int length) {
+  if (length > 0) {
+    i::Vector<uint8_t> block = data_.AddBlock(0, length);
+    memcpy(&block[0], p, length);
+  }
+}
+
+
+void SerializationData::WriteArrayBufferContents(
+    const ArrayBuffer::Contents& contents) {
+  array_buffer_contents_.Add(contents);
+  WriteTag(kSerializationTagTransferredArrayBuffer);
+  int index = array_buffer_contents_.length() - 1;
+  Write(index);
+}
+
+
+void SerializationData::WriteSharedArrayBufferContents(
+    const SharedArrayBuffer::Contents& contents) {
+  shared_array_buffer_contents_.Add(contents);
+  WriteTag(kSerializationTagTransferredSharedArrayBuffer);
+  int index = shared_array_buffer_contents_.length() - 1;
+  Write(index);
+}
+
+
+SerializationTag SerializationData::ReadTag(int* offset) const {
+  return static_cast<SerializationTag>(Read<uint8_t>(offset));
+}
+
+
+void SerializationData::ReadMemory(void* p, int length, int* offset) const {
+  if (length > 0) {
+    memcpy(p, &data_[*offset], length);
+    (*offset) += length;
+  }
+}
+
+
+void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
+                                                int* offset) const {
+  int index = Read<int>(offset);
+  DCHECK(index < array_buffer_contents_.length());
+  *contents = array_buffer_contents_[index];
+  // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
+  // our copy so it won't be double-free'd when this SerializationData is
+  // destroyed.
+  array_buffer_contents_[index] = ArrayBuffer::Contents();
+}
+
+
+void SerializationData::ReadSharedArrayBufferContents(
+    SharedArrayBuffer::Contents* contents, int* offset) const {
+  int index = Read<int>(offset);
+  DCHECK(index < shared_array_buffer_contents_.length());
+  *contents = shared_array_buffer_contents_[index];
+}
+
+
+void SerializationDataQueue::Enqueue(SerializationData* data) {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  data_.Add(data);
+}
+
+
+bool SerializationDataQueue::Dequeue(SerializationData** data) {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  *data = NULL;
+  if (data_.is_empty()) return false;
+  *data = data_.Remove(0);
+  return true;
+}
+
+
+bool SerializationDataQueue::IsEmpty() {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  return data_.is_empty();
+}
+
+
+void SerializationDataQueue::Clear() {
+  base::LockGuard<base::Mutex> lock_guard(&mutex_);
+  for (int i = 0; i < data_.length(); ++i) {
+    delete data_[i];
+  }
+  data_.Clear();
+}
+
+
+Worker::Worker()
+    : in_semaphore_(0),
+      out_semaphore_(0),
+      thread_(NULL),
+      script_(NULL),
+      running_(false) {}
+
+
+Worker::~Worker() {
+  delete thread_;
+  thread_ = NULL;
+  delete[] script_;
+  script_ = NULL;
+  in_queue_.Clear();
+  out_queue_.Clear();
+}
+
+
+void Worker::StartExecuteInThread(const char* script) {
+  running_ = true;
+  script_ = i::StrDup(script);
+  thread_ = new WorkerThread(this);
+  thread_->Start();
+}
+
+
+void Worker::PostMessage(SerializationData* data) {
+  in_queue_.Enqueue(data);
+  in_semaphore_.Signal();
+}
+
+
+SerializationData* Worker::GetMessage() {
+  SerializationData* data = NULL;
+  while (!out_queue_.Dequeue(&data)) {
+    // If the worker is no longer running, and there are no messages in the
+    // queue, don't expect any more messages from it.
+    if (!base::NoBarrier_Load(&running_)) break;
+    out_semaphore_.Wait();
+  }
+  return data;
+}
+
+
+void Worker::Terminate() {
+  base::NoBarrier_Store(&running_, false);
+  // Post NULL to wake the Worker thread message loop, and tell it to stop
+  // running.
+  PostMessage(NULL);
+}
+
+
+void Worker::WaitForThread() {
+  Terminate();
+  thread_->Join();
+}
+
+
+void Worker::ExecuteInThread() {
+  Isolate::CreateParams create_params;
+  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
+  Isolate* isolate = Isolate::New(create_params);
+  {
+    Isolate::Scope iscope(isolate);
+    {
+      HandleScope scope(isolate);
+      PerIsolateData data(isolate);
+      Local<Context> context = Shell::CreateEvaluationContext(isolate);
+      {
+        Context::Scope cscope(context);
+        PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
+
+        Local<Object> global = context->Global();
+        Local<Value> this_value = External::New(isolate, this);
+        Local<FunctionTemplate> postmessage_fun_template =
+            FunctionTemplate::New(isolate, PostMessageOut, this_value);
+
+        Local<Function> postmessage_fun;
+        if (postmessage_fun_template->GetFunction(context)
+                .ToLocal(&postmessage_fun)) {
+          global->Set(context, String::NewFromUtf8(isolate, "postMessage",
+                                                   NewStringType::kNormal)
+                                   .ToLocalChecked(),
+                      postmessage_fun).FromJust();
+        }
+
+        // First run the script
+        Local<String> file_name =
+            String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
+                .ToLocalChecked();
+        Local<String> source =
+            String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
+                .ToLocalChecked();
+        if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
+          // Get the message handler
+          Local<Value> onmessage =
+              global->Get(context, String::NewFromUtf8(isolate, "onmessage",
+                                                       NewStringType::kNormal)
+                                       .ToLocalChecked()).ToLocalChecked();
+          if (onmessage->IsFunction()) {
+            Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
+            // Now wait for messages
+            while (true) {
+              in_semaphore_.Wait();
+              SerializationData* data;
+              if (!in_queue_.Dequeue(&data)) continue;
+              if (data == NULL) {
+                break;
+              }
+              int offset = 0;
+              Local<Value> data_value;
+              if (Shell::DeserializeValue(isolate, *data, &offset)
+                      .ToLocal(&data_value)) {
+                Local<Value> argv[] = {data_value};
+                (void)onmessage_fun->Call(context, global, 1, argv);
+              }
+              delete data;
+            }
+          }
+        }
+      }
+    }
+    Shell::CollectGarbage(isolate);
+  }
+  isolate->Dispose();
+
+  // Post NULL to wake the thread waiting on GetMessage() if there is one.
+  out_queue_.Enqueue(NULL);
+  out_semaphore_.Signal();
+}
+
+
+void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  Isolate* isolate = args.GetIsolate();
+  HandleScope handle_scope(isolate);
+
+  if (args.Length() < 1) {
+    Throw(isolate, "Invalid argument");
+    return;
+  }
+
+  Local<Value> message = args[0];
+
+  // TODO(binji): Allow transferring from worker to main thread?
+  Shell::ObjectList to_transfer;
+
+  Shell::ObjectList seen_objects;
+  SerializationData* data = new SerializationData;
+  if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
+                            data)) {
+    DCHECK(args.Data()->IsExternal());
+    Local<External> this_value = Local<External>::Cast(args.Data());
+    Worker* worker = static_cast<Worker*>(this_value->Value());
+    worker->out_queue_.Enqueue(data);
+    worker->out_semaphore_.Signal();
   } else {
-    done_semaphore_.Wait();
+    delete data;
   }
 }
 #endif  // !V8_SHARED
@@ -1331,6 +1922,10 @@
     } else if (strcmp(argv[i], "--test") == 0) {
       options.test_shell = true;
       argv[i] = NULL;
+    } else if (strcmp(argv[i], "--notest") == 0 ||
+               strcmp(argv[i], "--no-test") == 0) {
+      options.test_shell = false;
+      argv[i] = NULL;
     } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
       options.send_idle_notification = true;
       argv[i] = NULL;
@@ -1339,6 +1934,9 @@
       // TODO(jochen) See issue 3351
       options.send_idle_notification = true;
       argv[i] = NULL;
+    } else if (strcmp(argv[i], "--omit-quit") == 0) {
+      options.omit_quit = true;
+      argv[i] = NULL;
     } else if (strcmp(argv[i], "-f") == 0) {
       // Ignore any -f flags for compatibility with other stand-alone
       // JavaScript engines.
@@ -1367,9 +1965,6 @@
     } else if (strcmp(argv[i], "--dump-counters") == 0) {
       printf("D8 with shared library does not include counters\n");
       return false;
-    } else if (strcmp(argv[i], "--debugger") == 0) {
-      printf("Javascript debugger not included\n");
-      return false;
 #endif  // V8_SHARED
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
     } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
@@ -1398,6 +1993,8 @@
 
   v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
 
+  bool enable_harmony_modules = false;
+
   // Set up isolated source groups.
   options.isolate_sources = new SourceGroup[options.num_isolates];
   SourceGroup* current = options.isolate_sources;
@@ -1408,8 +2005,16 @@
       current->End(i);
       current++;
       current->Begin(argv, i + 1);
+    } else if (strcmp(str, "--module") == 0) {
+      // Pass on to SourceGroup, which understands this option.
+      enable_harmony_modules = true;
     } else if (strncmp(argv[i], "--", 2) == 0) {
       printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
+    } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
+      options.script_executed = true;
+    } else if (strncmp(str, "-", 1) != 0) {
+      // Not a flag, so it must be a script to execute.
+      options.script_executed = true;
     }
   }
   current->End(argc);
@@ -1418,11 +2023,15 @@
     SetFlagsFromString("--nologfile_per_isolate");
   }
 
+  if (enable_harmony_modules) {
+    SetFlagsFromString("--harmony-modules");
+  }
+
   return true;
 }
 
 
-int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
+int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
 #ifndef V8_SHARED
   for (int i = 1; i < options.num_isolates; ++i) {
     options.isolate_sources[i].StartExecuteInThread();
@@ -1431,16 +2040,9 @@
   {
     HandleScope scope(isolate);
     Local<Context> context = CreateEvaluationContext(isolate);
-    if (options.last_run && options.use_interactive_shell()) {
+    if (last_run && options.use_interactive_shell()) {
       // Keep using the same context in the interactive shell.
       evaluation_context_.Reset(isolate, context);
-#ifndef V8_SHARED
-      // If the interactive debugger is enabled make sure to activate
-      // it before running the files passed on the command line.
-      if (i::FLAG_debugger) {
-        InstallUtilityScript(isolate);
-      }
-#endif  // !V8_SHARED
     }
     {
       Context::Scope cscope(context);
@@ -1448,10 +2050,27 @@
       options.isolate_sources[0].Execute(isolate);
     }
   }
+  CollectGarbage(isolate);
+#ifndef V8_SHARED
+  for (int i = 1; i < options.num_isolates; ++i) {
+    if (last_run) {
+      options.isolate_sources[i].JoinThread();
+    } else {
+      options.isolate_sources[i].WaitForThread();
+    }
+  }
+  CleanupWorkers();
+#endif  // !V8_SHARED
+  return 0;
+}
+
+
+void Shell::CollectGarbage(Isolate* isolate) {
   if (options.send_idle_notification) {
-    const int kLongIdlePauseInMs = 1000;
+    const double kLongIdlePauseInSeconds = 1.0;
     isolate->ContextDisposedNotification();
-    isolate->IdleNotification(kLongIdlePauseInMs);
+    isolate->IdleNotificationDeadline(
+        g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
   }
   if (options.invoke_weak_callbacks) {
     // By sending a low memory notifications, we will try hard to collect all
@@ -1459,17 +2078,284 @@
     // unreachable persistent handles.
     isolate->LowMemoryNotification();
   }
+}
 
+
+void Shell::EmptyMessageQueues(Isolate* isolate) {
 #ifndef V8_SHARED
-  for (int i = 1; i < options.num_isolates; ++i) {
-    options.isolate_sources[i].WaitForThread();
+  if (!i::FLAG_verify_predictable) {
+#endif
+    while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
+#ifndef V8_SHARED
   }
-#endif  // !V8_SHARED
-  return 0;
+#endif
 }
 
 
 #ifndef V8_SHARED
+bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
+                           const ObjectList& to_transfer,
+                           ObjectList* seen_objects,
+                           SerializationData* out_data) {
+  DCHECK(out_data);
+  Local<Context> context = isolate->GetCurrentContext();
+
+  if (value->IsUndefined()) {
+    out_data->WriteTag(kSerializationTagUndefined);
+  } else if (value->IsNull()) {
+    out_data->WriteTag(kSerializationTagNull);
+  } else if (value->IsTrue()) {
+    out_data->WriteTag(kSerializationTagTrue);
+  } else if (value->IsFalse()) {
+    out_data->WriteTag(kSerializationTagFalse);
+  } else if (value->IsNumber()) {
+    Local<Number> num = Local<Number>::Cast(value);
+    double value = num->Value();
+    out_data->WriteTag(kSerializationTagNumber);
+    out_data->Write(value);
+  } else if (value->IsString()) {
+    v8::String::Utf8Value str(value);
+    out_data->WriteTag(kSerializationTagString);
+    out_data->Write(str.length());
+    out_data->WriteMemory(*str, str.length());
+  } else if (value->IsArray()) {
+    Local<Array> array = Local<Array>::Cast(value);
+    if (FindInObjectList(array, *seen_objects)) {
+      Throw(isolate, "Duplicated arrays not supported");
+      return false;
+    }
+    seen_objects->Add(array);
+    out_data->WriteTag(kSerializationTagArray);
+    uint32_t length = array->Length();
+    out_data->Write(length);
+    for (uint32_t i = 0; i < length; ++i) {
+      Local<Value> element_value;
+      if (array->Get(context, i).ToLocal(&element_value)) {
+        if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
+                            out_data))
+          return false;
+      } else {
+        Throw(isolate, "Failed to serialize array element.");
+        return false;
+      }
+    }
+  } else if (value->IsArrayBuffer()) {
+    Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
+    if (FindInObjectList(array_buffer, *seen_objects)) {
+      Throw(isolate, "Duplicated array buffers not supported");
+      return false;
+    }
+    seen_objects->Add(array_buffer);
+    if (FindInObjectList(array_buffer, to_transfer)) {
+      // Transfer ArrayBuffer
+      if (!array_buffer->IsNeuterable()) {
+        Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
+        return false;
+      }
+
+      ArrayBuffer::Contents contents = array_buffer->IsExternal()
+                                           ? array_buffer->GetContents()
+                                           : array_buffer->Externalize();
+      array_buffer->Neuter();
+      out_data->WriteArrayBufferContents(contents);
+    } else {
+      ArrayBuffer::Contents contents = array_buffer->GetContents();
+      // Clone ArrayBuffer
+      if (contents.ByteLength() > i::kMaxInt) {
+        Throw(isolate, "ArrayBuffer is too big to clone");
+        return false;
+      }
+
+      int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
+      out_data->WriteTag(kSerializationTagArrayBuffer);
+      out_data->Write(byte_length);
+      out_data->WriteMemory(contents.Data(), byte_length);
+    }
+  } else if (value->IsSharedArrayBuffer()) {
+    Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
+    if (FindInObjectList(sab, *seen_objects)) {
+      Throw(isolate, "Duplicated shared array buffers not supported");
+      return false;
+    }
+    seen_objects->Add(sab);
+    if (!FindInObjectList(sab, to_transfer)) {
+      Throw(isolate, "SharedArrayBuffer must be transferred");
+      return false;
+    }
+
+    SharedArrayBuffer::Contents contents;
+    if (sab->IsExternal()) {
+      contents = sab->GetContents();
+    } else {
+      contents = sab->Externalize();
+      base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
+      externalized_shared_contents_.Add(contents);
+    }
+    out_data->WriteSharedArrayBufferContents(contents);
+  } else if (value->IsObject()) {
+    Local<Object> object = Local<Object>::Cast(value);
+    if (FindInObjectList(object, *seen_objects)) {
+      Throw(isolate, "Duplicated objects not supported");
+      return false;
+    }
+    seen_objects->Add(object);
+    Local<Array> property_names;
+    if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
+      Throw(isolate, "Unable to get property names");
+      return false;
+    }
+
+    uint32_t length = property_names->Length();
+    out_data->WriteTag(kSerializationTagObject);
+    out_data->Write(length);
+    for (uint32_t i = 0; i < length; ++i) {
+      Local<Value> name;
+      Local<Value> property_value;
+      if (property_names->Get(context, i).ToLocal(&name) &&
+          object->Get(context, name).ToLocal(&property_value)) {
+        if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
+          return false;
+        if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
+                            out_data))
+          return false;
+      } else {
+        Throw(isolate, "Failed to serialize property.");
+        return false;
+      }
+    }
+  } else {
+    Throw(isolate, "Don't know how to serialize object");
+    return false;
+  }
+
+  return true;
+}
+
+
+MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
+                                          const SerializationData& data,
+                                          int* offset) {
+  DCHECK(offset);
+  EscapableHandleScope scope(isolate);
+  // This function should not use utility_context_ because it is running on a
+  // different thread.
+  Local<Value> result;
+  SerializationTag tag = data.ReadTag(offset);
+
+  switch (tag) {
+    case kSerializationTagUndefined:
+      result = Undefined(isolate);
+      break;
+    case kSerializationTagNull:
+      result = Null(isolate);
+      break;
+    case kSerializationTagTrue:
+      result = True(isolate);
+      break;
+    case kSerializationTagFalse:
+      result = False(isolate);
+      break;
+    case kSerializationTagNumber:
+      result = Number::New(isolate, data.Read<double>(offset));
+      break;
+    case kSerializationTagString: {
+      int length = data.Read<int>(offset);
+      CHECK(length >= 0);
+      std::vector<char> buffer(length + 1);  // + 1 so it is never empty.
+      data.ReadMemory(&buffer[0], length, offset);
+      MaybeLocal<String> str =
+          String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
+                              length).ToLocalChecked();
+      if (!str.IsEmpty()) result = str.ToLocalChecked();
+      break;
+    }
+    case kSerializationTagArray: {
+      uint32_t length = data.Read<uint32_t>(offset);
+      Local<Array> array = Array::New(isolate, length);
+      for (uint32_t i = 0; i < length; ++i) {
+        Local<Value> element_value;
+        CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
+        array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
+      }
+      result = array;
+      break;
+    }
+    case kSerializationTagObject: {
+      int length = data.Read<int>(offset);
+      Local<Object> object = Object::New(isolate);
+      for (int i = 0; i < length; ++i) {
+        Local<Value> property_name;
+        CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
+        Local<Value> property_value;
+        CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
+        object->Set(isolate->GetCurrentContext(), property_name, property_value)
+            .FromJust();
+      }
+      result = object;
+      break;
+    }
+    case kSerializationTagArrayBuffer: {
+      int32_t byte_length = data.Read<int32_t>(offset);
+      Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
+      ArrayBuffer::Contents contents = array_buffer->GetContents();
+      DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
+      data.ReadMemory(contents.Data(), byte_length, offset);
+      result = array_buffer;
+      break;
+    }
+    case kSerializationTagTransferredArrayBuffer: {
+      ArrayBuffer::Contents contents;
+      data.ReadArrayBufferContents(&contents, offset);
+      result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
+                                ArrayBufferCreationMode::kInternalized);
+      break;
+    }
+    case kSerializationTagTransferredSharedArrayBuffer: {
+      SharedArrayBuffer::Contents contents;
+      data.ReadSharedArrayBufferContents(&contents, offset);
+      result = SharedArrayBuffer::New(isolate, contents.Data(),
+                                      contents.ByteLength());
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+
+  return scope.Escape(result);
+}
+
+
+void Shell::CleanupWorkers() {
+  // Make a copy of workers_, because we don't want to call Worker::Terminate
+  // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
+  // create a new Worker, it would deadlock.
+  i::List<Worker*> workers_copy;
+  {
+    base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
+    allow_new_workers_ = false;
+    workers_copy.AddAll(workers_);
+    workers_.Clear();
+  }
+
+  for (int i = 0; i < workers_copy.length(); ++i) {
+    Worker* worker = workers_copy[i];
+    worker->WaitForThread();
+    delete worker;
+  }
+
+  // Now that all workers are terminated, we can re-enable Worker creation.
+  base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
+  allow_new_workers_ = true;
+
+  for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
+    const SharedArrayBuffer::Contents& contents =
+        externalized_shared_contents_[i];
+    Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
+  }
+  externalized_shared_contents_.Clear();
+}
+
+
 static void DumpHeapConstants(i::Isolate* isolate) {
   i::Heap* heap = isolate->heap();
 
@@ -1526,109 +2412,6 @@
 #endif  // !V8_SHARED
 
 
-class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
- public:
-  virtual void* Allocate(size_t length) {
-    void* data = AllocateUninitialized(length);
-    return data == NULL ? data : memset(data, 0, length);
-  }
-  virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
-  virtual void Free(void* data, size_t) { free(data); }
-};
-
-
-class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
- public:
-  void* Allocate(size_t) OVERRIDE { return malloc(0); }
-  void* AllocateUninitialized(size_t length) OVERRIDE { return malloc(0); }
-  void Free(void* p, size_t) OVERRIDE { free(p); }
-};
-
-
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-class StartupDataHandler {
- public:
-  StartupDataHandler(const char* exec_path, const char* natives_blob,
-                     const char* snapshot_blob) {
-    // If we have (at least one) explicitly given blob, use those.
-    // If not, use the default blob locations next to the d8 binary.
-    if (natives_blob || snapshot_blob) {
-      LoadFromFiles(natives_blob, snapshot_blob);
-    } else {
-      char* natives;
-      char* snapshot;
-      LoadFromFiles(RelativePath(&natives, exec_path, "natives_blob.bin"),
-                    RelativePath(&snapshot, exec_path, "snapshot_blob.bin"));
-
-      free(natives);
-      free(snapshot);
-    }
-  }
-
-  ~StartupDataHandler() {
-    delete[] natives_.data;
-    delete[] snapshot_.data;
-  }
-
- private:
-  static char* RelativePath(char** buffer, const char* exec_path,
-                            const char* name) {
-    DCHECK(exec_path);
-    const char* last_slash = strrchr(exec_path, '/');
-    if (last_slash) {
-      int after_slash = last_slash - exec_path + 1;
-      int name_length = static_cast<int>(strlen(name));
-      *buffer =
-          reinterpret_cast<char*>(calloc(after_slash + name_length + 1, 1));
-      strncpy(*buffer, exec_path, after_slash);
-      strncat(*buffer, name, name_length);
-    } else {
-      *buffer = strdup(name);
-    }
-    return *buffer;
-  }
-
-  void LoadFromFiles(const char* natives_blob, const char* snapshot_blob) {
-    Load(natives_blob, &natives_, v8::V8::SetNativesDataBlob);
-    Load(snapshot_blob, &snapshot_, v8::V8::SetSnapshotDataBlob);
-  }
-
-  void Load(const char* blob_file,
-            v8::StartupData* startup_data,
-            void (*setter_fn)(v8::StartupData*)) {
-    startup_data->data = NULL;
-    startup_data->raw_size = 0;
-
-    if (!blob_file)
-      return;
-
-    FILE* file = fopen(blob_file, "rb");
-    if (!file)
-      return;
-
-    fseek(file, 0, SEEK_END);
-    startup_data->raw_size = ftell(file);
-    rewind(file);
-
-    startup_data->data = new char[startup_data->raw_size];
-    int read_size =
-        static_cast<int>(fread(const_cast<char*>(startup_data->data), 1,
-                               startup_data->raw_size, file));
-    fclose(file);
-
-    if (startup_data->raw_size == read_size) (*setter_fn)(startup_data);
-  }
-
-  v8::StartupData natives_;
-  v8::StartupData snapshot_;
-
-  // Disallow copy & assign.
-  StartupDataHandler(const StartupDataHandler& other);
-  void operator=(const StartupDataHandler& other);
-};
-#endif  // V8_USE_EXTERNAL_STARTUP_DATA
-
-
 int Shell::Main(int argc, char* argv[]) {
 #if (defined(_WIN32) || defined(_WIN64))
   UINT new_flags =
@@ -1647,25 +2430,35 @@
 #endif  // defined(_WIN32) || defined(_WIN64)
   if (!SetOptions(argc, argv)) return 1;
   v8::V8::InitializeICU(options.icu_data_file);
-  v8::Platform* platform = v8::platform::CreateDefaultPlatform();
-  v8::V8::InitializePlatform(platform);
+#ifndef V8_SHARED
+  g_platform = i::FLAG_verify_predictable
+                   ? new PredictablePlatform()
+                   : v8::platform::CreateDefaultPlatform();
+#else
+  g_platform = v8::platform::CreateDefaultPlatform();
+#endif  // !V8_SHARED
+
+  v8::V8::InitializePlatform(g_platform);
   v8::V8::Initialize();
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-  StartupDataHandler startup_data(argv[0], options.natives_blob,
-                                  options.snapshot_blob);
-#endif
+  if (options.natives_blob || options.snapshot_blob) {
+    v8::V8::InitializeExternalStartupData(options.natives_blob,
+                                          options.snapshot_blob);
+  } else {
+    v8::V8::InitializeExternalStartupData(argv[0]);
+  }
   SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
   SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
   SetFlagsFromString("--redirect-code-traces-to=code.asm");
-  ShellArrayBufferAllocator array_buffer_allocator;
-  MockArrayBufferAllocator mock_arraybuffer_allocator;
-  if (options.mock_arraybuffer_allocator) {
-    v8::V8::SetArrayBufferAllocator(&mock_arraybuffer_allocator);
-  } else {
-    v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
-  }
   int result = 0;
   Isolate::CreateParams create_params;
+  ShellArrayBufferAllocator shell_array_buffer_allocator;
+  MockArrayBufferAllocator mock_arraybuffer_allocator;
+  if (options.mock_arraybuffer_allocator) {
+    Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
+  } else {
+    Shell::array_buffer_allocator = &shell_array_buffer_allocator;
+  }
+  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
 #if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
   if (i::FLAG_gdbjit) {
     create_params.code_event_handler = i::GDBJITInterface::EventHandler;
@@ -1677,16 +2470,20 @@
 #ifndef V8_SHARED
   create_params.constraints.ConfigureDefaults(
       base::SysInfo::AmountOfPhysicalMemory(),
-      base::SysInfo::AmountOfVirtualMemory(),
-      base::SysInfo::NumberOfProcessors());
+      base::SysInfo::AmountOfVirtualMemory());
+
+  Shell::counter_map_ = new CounterMap();
+  if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
+    create_params.counter_lookup_callback = LookupCounter;
+    create_params.create_histogram_callback = CreateHistogram;
+    create_params.add_histogram_sample_callback = AddHistogramSample;
+  }
 #endif
   Isolate* isolate = Isolate::New(create_params);
-  DumbLineEditor dumb_line_editor(isolate);
   {
     Isolate::Scope scope(isolate);
     Initialize(isolate);
     PerIsolateData data(isolate);
-    InitializeDebugger(isolate);
 
 #ifndef V8_SHARED
     if (options.dump_heap_constants) {
@@ -1699,38 +2496,46 @@
       Testing::SetStressRunType(options.stress_opt
                                 ? Testing::kStressTypeOpt
                                 : Testing::kStressTypeDeopt);
-      int stress_runs = Testing::GetStressRuns();
-      for (int i = 0; i < stress_runs && result == 0; i++) {
-        printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
+      options.stress_runs = Testing::GetStressRuns();
+      for (int i = 0; i < options.stress_runs && result == 0; i++) {
+        printf("============ Stress %d/%d ============\n", i + 1,
+               options.stress_runs);
         Testing::PrepareStressRun(i);
-        options.last_run = (i == stress_runs - 1);
-        result = RunMain(isolate, argc, argv);
+        bool last_run = i == options.stress_runs - 1;
+        result = RunMain(isolate, argc, argv, last_run);
       }
       printf("======== Full Deoptimization =======\n");
-      Testing::DeoptimizeAll();
+      Testing::DeoptimizeAll(isolate);
 #if !defined(V8_SHARED)
     } else if (i::FLAG_stress_runs > 0) {
-      int stress_runs = i::FLAG_stress_runs;
-      for (int i = 0; i < stress_runs && result == 0; i++) {
-        printf("============ Run %d/%d ============\n", i + 1, stress_runs);
-        options.last_run = (i == stress_runs - 1);
-        result = RunMain(isolate, argc, argv);
+      options.stress_runs = i::FLAG_stress_runs;
+      for (int i = 0; i < options.stress_runs && result == 0; i++) {
+        printf("============ Run %d/%d ============\n", i + 1,
+               options.stress_runs);
+        bool last_run = i == options.stress_runs - 1;
+        result = RunMain(isolate, argc, argv, last_run);
       }
 #endif
     } else {
-      result = RunMain(isolate, argc, argv);
+      bool last_run = true;
+      result = RunMain(isolate, argc, argv, last_run);
     }
 
     // Run interactive shell if explicitly requested or if no script has been
     // executed, but never on --test
     if (options.use_interactive_shell()) {
 #ifndef V8_SHARED
-      if (!i::FLAG_debugger) {
-        InstallUtilityScript(isolate);
-      }
+      InstallUtilityScript(isolate);
 #endif  // !V8_SHARED
       RunShell(isolate);
     }
+
+    // Shut down contexts and collect garbage.
+    evaluation_context_.Reset();
+#ifndef V8_SHARED
+    utility_context_.Reset();
+#endif  // !V8_SHARED
+    CollectGarbage(isolate);
   }
   OnExit(isolate);
 #ifndef V8_SHARED
@@ -1744,7 +2549,7 @@
   isolate->Dispose();
   V8::Dispose();
   V8::ShutdownPlatform();
-  delete platform;
+  delete g_platform;
 
   return result;
 }