Home | History | Annotate | Download | only in src
      1 /// Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <errno.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <sys/stat.h>
      9 
     10 #include <algorithm>
     11 #include <fstream>
     12 #include <unordered_map>
     13 #include <utility>
     14 #include <vector>
     15 
     16 #ifdef ENABLE_VTUNE_JIT_INTERFACE
     17 #include "src/third_party/vtune/v8-vtune.h"
     18 #endif
     19 
     20 #include "src/d8-console.h"
     21 #include "src/d8.h"
     22 #include "src/ostreams.h"
     23 
     24 #include "include/libplatform/libplatform.h"
     25 #include "include/libplatform/v8-tracing.h"
     26 #include "include/v8-inspector.h"
     27 #include "src/api-inl.h"
     28 #include "src/base/cpu.h"
     29 #include "src/base/logging.h"
     30 #include "src/base/platform/platform.h"
     31 #include "src/base/platform/time.h"
     32 #include "src/base/sys-info.h"
     33 #include "src/basic-block-profiler.h"
     34 #include "src/debug/debug-interface.h"
     35 #include "src/interpreter/interpreter.h"
     36 #include "src/msan.h"
     37 #include "src/objects-inl.h"
     38 #include "src/objects.h"
     39 #include "src/snapshot/natives.h"
     40 #include "src/trap-handler/trap-handler.h"
     41 #include "src/utils.h"
     42 #include "src/v8.h"
     43 #include "src/wasm/wasm-engine.h"
     44 
     45 #if !defined(_WIN32) && !defined(_WIN64)
     46 #include <unistd.h>  // NOLINT
     47 #else
     48 #include <windows.h>  // NOLINT
     49 #endif               // !defined(_WIN32) && !defined(_WIN64)
     50 
     51 #ifndef DCHECK
     52 #define DCHECK(condition) assert(condition)
     53 #endif
     54 
     55 #ifndef CHECK
     56 #define CHECK(condition) assert(condition)
     57 #endif
     58 
     59 namespace v8 {
     60 
     61 namespace {
     62 
     63 const int kMB = 1024 * 1024;
     64 
     65 const int kMaxWorkers = 50;
     66 const int kMaxSerializerMemoryUsage =
     67     1 * kMB;  // Arbitrary maximum for testing.
     68 
     69 // Base class for shell ArrayBuffer allocators. It forwards all opertions to
     70 // the default v8 allocator.
     71 class ArrayBufferAllocatorBase : public v8::ArrayBuffer::Allocator {
     72  public:
     73   void* Allocate(size_t length) override {
     74     return allocator_->Allocate(length);
     75   }
     76 
     77   void* AllocateUninitialized(size_t length) override {
     78     return allocator_->AllocateUninitialized(length);
     79   }
     80 
     81   void Free(void* data, size_t length) override {
     82     allocator_->Free(data, length);
     83   }
     84 
     85  private:
     86   std::unique_ptr<Allocator> allocator_ =
     87       std::unique_ptr<Allocator>(NewDefaultAllocator());
     88 };
     89 
     90 // ArrayBuffer allocator that can use virtual memory to improve performance.
     91 class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
     92  public:
     93   void* Allocate(size_t length) override {
     94     if (length >= kVMThreshold) return AllocateVM(length);
     95     return ArrayBufferAllocatorBase::Allocate(length);
     96   }
     97 
     98   void* AllocateUninitialized(size_t length) override {
     99     if (length >= kVMThreshold) return AllocateVM(length);
    100     return ArrayBufferAllocatorBase::AllocateUninitialized(length);
    101   }
    102 
    103   void Free(void* data, size_t length) override {
    104     if (length >= kVMThreshold) {
    105       FreeVM(data, length);
    106     } else {
    107       ArrayBufferAllocatorBase::Free(data, length);
    108     }
    109   }
    110 
    111  private:
    112   static constexpr size_t kVMThreshold = 65536;
    113   static constexpr size_t kTwoGB = 2u * 1024u * 1024u * 1024u;
    114 
    115   void* AllocateVM(size_t length) {
    116     DCHECK_LE(kVMThreshold, length);
    117     // TODO(titzer): allocations should fail if >= 2gb because array buffers
    118     // store their lengths as a SMI internally.
    119     if (length >= kTwoGB) return nullptr;
    120 
    121     size_t page_size = i::AllocatePageSize();
    122     size_t allocated = RoundUp(length, page_size);
    123     // Rounding up could go over the limit.
    124     if (allocated >= kTwoGB) return nullptr;
    125     return i::AllocatePages(nullptr, allocated, page_size,
    126                             PageAllocator::kReadWrite);
    127   }
    128 
    129   void FreeVM(void* data, size_t length) {
    130     size_t page_size = i::AllocatePageSize();
    131     size_t allocated = RoundUp(length, page_size);
    132     CHECK(i::FreePages(data, allocated));
    133   }
    134 };
    135 
    136 // ArrayBuffer allocator that never allocates over 10MB.
    137 class MockArrayBufferAllocator : public ArrayBufferAllocatorBase {
    138   void* Allocate(size_t length) override {
    139     return ArrayBufferAllocatorBase::Allocate(Adjust(length));
    140   }
    141 
    142   void* AllocateUninitialized(size_t length) override {
    143     return ArrayBufferAllocatorBase::AllocateUninitialized(Adjust(length));
    144   }
    145 
    146   void Free(void* data, size_t length) override {
    147     return ArrayBufferAllocatorBase::Free(data, Adjust(length));
    148   }
    149 
    150  private:
    151   size_t Adjust(size_t length) {
    152     const size_t kAllocationLimit = 10 * kMB;
    153     return length > kAllocationLimit ? i::AllocatePageSize() : length;
    154   }
    155 };
    156 
    157 // Predictable v8::Platform implementation. Worker threads are disabled, idle
    158 // tasks are disallowed, and the time reported by {MonotonicallyIncreasingTime}
    159 // is deterministic.
    160 class PredictablePlatform : public Platform {
    161  public:
    162   explicit PredictablePlatform(std::unique_ptr<Platform> platform)
    163       : platform_(std::move(platform)) {
    164     DCHECK_NOT_NULL(platform_);
    165   }
    166 
    167   PageAllocator* GetPageAllocator() override {
    168     return platform_->GetPageAllocator();
    169   }
    170 
    171   void OnCriticalMemoryPressure() override {
    172     platform_->OnCriticalMemoryPressure();
    173   }
    174 
    175   bool OnCriticalMemoryPressure(size_t length) override {
    176     return platform_->OnCriticalMemoryPressure(length);
    177   }
    178 
    179   std::shared_ptr<TaskRunner> GetForegroundTaskRunner(
    180       v8::Isolate* isolate) override {
    181     return platform_->GetForegroundTaskRunner(isolate);
    182   }
    183 
    184   int NumberOfWorkerThreads() override { return 0; }
    185 
    186   void CallOnWorkerThread(std::unique_ptr<Task> task) override {
    187     // It's not defined when background tasks are being executed, so we can just
    188     // execute them right away.
    189     task->Run();
    190   }
    191 
    192   void CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
    193                                  double delay_in_seconds) override {
    194     // Never run delayed tasks.
    195   }
    196 
    197   void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
    198     platform_->CallOnForegroundThread(isolate, task);
    199   }
    200 
    201   void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
    202                                      double delay_in_seconds) override {
    203     platform_->CallDelayedOnForegroundThread(isolate, task, delay_in_seconds);
    204   }
    205 
    206   void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override {
    207     UNREACHABLE();
    208   }
    209 
    210   bool IdleTasksEnabled(Isolate* isolate) override { return false; }
    211 
    212   double MonotonicallyIncreasingTime() override {
    213     return synthetic_time_in_sec_ += 0.00001;
    214   }
    215 
    216   double CurrentClockTimeMillis() override {
    217     return MonotonicallyIncreasingTime() * base::Time::kMillisecondsPerSecond;
    218   }
    219 
    220   v8::TracingController* GetTracingController() override {
    221     return platform_->GetTracingController();
    222   }
    223 
    224   Platform* platform() const { return platform_.get(); }
    225 
    226  private:
    227   double synthetic_time_in_sec_ = 0.0;
    228   std::unique_ptr<Platform> platform_;
    229 
    230   DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
    231 };
    232 
    233 std::unique_ptr<v8::Platform> g_platform;
    234 
    235 v8::Platform* GetDefaultPlatform() {
    236   return i::FLAG_verify_predictable
    237              ? static_cast<PredictablePlatform*>(g_platform.get())->platform()
    238              : g_platform.get();
    239 }
    240 
    241 static Local<Value> Throw(Isolate* isolate, const char* message) {
    242   return isolate->ThrowException(
    243       String::NewFromUtf8(isolate, message, NewStringType::kNormal)
    244           .ToLocalChecked());
    245 }
    246 
    247 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
    248   if (object->InternalFieldCount() != 1) {
    249     Throw(isolate, "this is not a Worker");
    250     return nullptr;
    251   }
    252 
    253   Worker* worker =
    254       static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
    255   if (worker == nullptr) {
    256     Throw(isolate, "Worker is defunct because main thread is terminating");
    257     return nullptr;
    258   }
    259 
    260   return worker;
    261 }
    262 
    263 base::Thread::Options GetThreadOptions(const char* name) {
    264   // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
    265   // which is not enough to parse the big literal expressions used in tests.
    266   // The stack size should be at least StackGuard::kLimitSize + some
    267   // OS-specific padding for thread startup code.  2Mbytes seems to be enough.
    268   return base::Thread::Options(name, 2 * kMB);
    269 }
    270 
    271 }  // namespace
    272 
    273 namespace tracing {
    274 
    275 namespace {
    276 
    277 // String options that can be used to initialize TraceOptions.
    278 const char kRecordUntilFull[] = "record-until-full";
    279 const char kRecordContinuously[] = "record-continuously";
    280 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
    281 
    282 const char kRecordModeParam[] = "record_mode";
    283 const char kEnableSystraceParam[] = "enable_systrace";
    284 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
    285 const char kIncludedCategoriesParam[] = "included_categories";
    286 
    287 class TraceConfigParser {
    288  public:
    289   static void FillTraceConfig(v8::Isolate* isolate,
    290                               platform::tracing::TraceConfig* trace_config,
    291                               const char* json_str) {
    292     HandleScope outer_scope(isolate);
    293     Local<Context> context = Context::New(isolate);
    294     Context::Scope context_scope(context);
    295     HandleScope inner_scope(isolate);
    296 
    297     Local<String> source =
    298         String::NewFromUtf8(isolate, json_str, NewStringType::kNormal)
    299             .ToLocalChecked();
    300     Local<Value> result = JSON::Parse(context, source).ToLocalChecked();
    301     Local<v8::Object> trace_config_object = Local<v8::Object>::Cast(result);
    302 
    303     trace_config->SetTraceRecordMode(
    304         GetTraceRecordMode(isolate, context, trace_config_object));
    305     if (GetBoolean(isolate, context, trace_config_object,
    306                    kEnableSystraceParam)) {
    307       trace_config->EnableSystrace();
    308     }
    309     if (GetBoolean(isolate, context, trace_config_object,
    310                    kEnableArgumentFilterParam)) {
    311       trace_config->EnableArgumentFilter();
    312     }
    313     UpdateIncludedCategoriesList(isolate, context, trace_config_object,
    314                                  trace_config);
    315   }
    316 
    317  private:
    318   static bool GetBoolean(v8::Isolate* isolate, Local<Context> context,
    319                          Local<v8::Object> object, const char* property) {
    320     Local<Value> value = GetValue(isolate, context, object, property);
    321     if (value->IsNumber()) {
    322       Local<Boolean> v8_boolean = value->ToBoolean(context).ToLocalChecked();
    323       return v8_boolean->Value();
    324     }
    325     return false;
    326   }
    327 
    328   static int UpdateIncludedCategoriesList(
    329       v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object,
    330       platform::tracing::TraceConfig* trace_config) {
    331     Local<Value> value =
    332         GetValue(isolate, context, object, kIncludedCategoriesParam);
    333     if (value->IsArray()) {
    334       Local<Array> v8_array = Local<Array>::Cast(value);
    335       for (int i = 0, length = v8_array->Length(); i < length; ++i) {
    336         Local<Value> v = v8_array->Get(context, i)
    337                              .ToLocalChecked()
    338                              ->ToString(context)
    339                              .ToLocalChecked();
    340         String::Utf8Value str(isolate, v->ToString(context).ToLocalChecked());
    341         trace_config->AddIncludedCategory(*str);
    342       }
    343       return v8_array->Length();
    344     }
    345     return 0;
    346   }
    347 
    348   static platform::tracing::TraceRecordMode GetTraceRecordMode(
    349       v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object) {
    350     Local<Value> value = GetValue(isolate, context, object, kRecordModeParam);
    351     if (value->IsString()) {
    352       Local<String> v8_string = value->ToString(context).ToLocalChecked();
    353       String::Utf8Value str(isolate, v8_string);
    354       if (strcmp(kRecordUntilFull, *str) == 0) {
    355         return platform::tracing::TraceRecordMode::RECORD_UNTIL_FULL;
    356       } else if (strcmp(kRecordContinuously, *str) == 0) {
    357         return platform::tracing::TraceRecordMode::RECORD_CONTINUOUSLY;
    358       } else if (strcmp(kRecordAsMuchAsPossible, *str) == 0) {
    359         return platform::tracing::TraceRecordMode::RECORD_AS_MUCH_AS_POSSIBLE;
    360       }
    361     }
    362     return platform::tracing::TraceRecordMode::RECORD_UNTIL_FULL;
    363   }
    364 
    365   static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
    366                                Local<v8::Object> object, const char* property) {
    367     Local<String> v8_str =
    368         String::NewFromUtf8(isolate, property, NewStringType::kNormal)
    369             .ToLocalChecked();
    370     return object->Get(context, v8_str).ToLocalChecked();
    371   }
    372 };
    373 
    374 }  // namespace
    375 
    376 static platform::tracing::TraceConfig* CreateTraceConfigFromJSON(
    377     v8::Isolate* isolate, const char* json_str) {
    378   platform::tracing::TraceConfig* trace_config =
    379       new platform::tracing::TraceConfig();
    380   TraceConfigParser::FillTraceConfig(isolate, trace_config, json_str);
    381   return trace_config;
    382 }
    383 
    384 }  // namespace tracing
    385 
    386 
    387 class ExternalOwningOneByteStringResource
    388     : public String::ExternalOneByteStringResource {
    389  public:
    390   ExternalOwningOneByteStringResource() : length_(0) {}
    391   ExternalOwningOneByteStringResource(std::unique_ptr<const char[]> data,
    392                                       size_t length)
    393       : data_(std::move(data)), length_(length) {}
    394   const char* data() const override { return data_.get(); }
    395   size_t length() const override { return length_; }
    396 
    397  private:
    398   std::unique_ptr<const char[]> data_;
    399   size_t length_;
    400 };
    401 
    402 CounterMap* Shell::counter_map_;
    403 base::OS::MemoryMappedFile* Shell::counters_file_ = nullptr;
    404 CounterCollection Shell::local_counters_;
    405 CounterCollection* Shell::counters_ = &local_counters_;
    406 base::LazyMutex Shell::context_mutex_;
    407 const base::TimeTicks Shell::kInitialTicks =
    408     base::TimeTicks::HighResolutionNow();
    409 Global<Function> Shell::stringify_function_;
    410 base::LazyMutex Shell::workers_mutex_;
    411 bool Shell::allow_new_workers_ = true;
    412 std::vector<Worker*> Shell::workers_;
    413 std::vector<ExternalizedContents> Shell::externalized_contents_;
    414 std::atomic<bool> Shell::script_executed_{false};
    415 base::LazyMutex Shell::isolate_status_lock_;
    416 std::map<v8::Isolate*, bool> Shell::isolate_status_;
    417 base::LazyMutex Shell::cached_code_mutex_;
    418 std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
    419     Shell::cached_code_map_;
    420 
    421 Global<Context> Shell::evaluation_context_;
    422 ArrayBuffer::Allocator* Shell::array_buffer_allocator;
    423 ShellOptions Shell::options;
    424 base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
    425 
    426 // Dummy external source stream which returns the whole source in one go.
    427 class DummySourceStream : public v8::ScriptCompiler::ExternalSourceStream {
    428  public:
    429   DummySourceStream(Local<String> source, Isolate* isolate) : done_(false) {
    430     source_length_ = source->Utf8Length(isolate);
    431     source_buffer_.reset(new uint8_t[source_length_]);
    432     source->WriteUtf8(isolate, reinterpret_cast<char*>(source_buffer_.get()),
    433                       source_length_);
    434   }
    435 
    436   virtual size_t GetMoreData(const uint8_t** src) {
    437     if (done_) {
    438       return 0;
    439     }
    440     *src = source_buffer_.release();
    441     done_ = true;
    442 
    443     return source_length_;
    444   }
    445 
    446  private:
    447   int source_length_;
    448   std::unique_ptr<uint8_t[]> source_buffer_;
    449   bool done_;
    450 };
    451 
    452 class BackgroundCompileThread : public base::Thread {
    453  public:
    454   BackgroundCompileThread(Isolate* isolate, Local<String> source)
    455       : base::Thread(GetThreadOptions("BackgroundCompileThread")),
    456         source_(source),
    457         streamed_source_(new DummySourceStream(source, isolate),
    458                          v8::ScriptCompiler::StreamedSource::UTF8),
    459         task_(v8::ScriptCompiler::StartStreamingScript(isolate,
    460                                                        &streamed_source_)) {}
    461 
    462   void Run() override { task_->Run(); }
    463 
    464   v8::ScriptCompiler::StreamedSource* streamed_source() {
    465     return &streamed_source_;
    466   }
    467 
    468  private:
    469   Local<String> source_;
    470   v8::ScriptCompiler::StreamedSource streamed_source_;
    471   std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task_;
    472 };
    473 
    474 ScriptCompiler::CachedData* Shell::LookupCodeCache(Isolate* isolate,
    475                                                    Local<Value> source) {
    476   base::LockGuard<base::Mutex> lock_guard(cached_code_mutex_.Pointer());
    477   CHECK(source->IsString());
    478   v8::String::Utf8Value key(isolate, source);
    479   DCHECK(*key);
    480   auto entry = cached_code_map_.find(*key);
    481   if (entry != cached_code_map_.end() && entry->second) {
    482     int length = entry->second->length;
    483     uint8_t* cache = new uint8_t[length];
    484     memcpy(cache, entry->second->data, length);
    485     ScriptCompiler::CachedData* cached_data = new ScriptCompiler::CachedData(
    486         cache, length, ScriptCompiler::CachedData::BufferOwned);
    487     return cached_data;
    488   }
    489   return nullptr;
    490 }
    491 
    492 void Shell::StoreInCodeCache(Isolate* isolate, Local<Value> source,
    493                              const ScriptCompiler::CachedData* cache_data) {
    494   base::LockGuard<base::Mutex> lock_guard(cached_code_mutex_.Pointer());
    495   CHECK(source->IsString());
    496   if (cache_data == nullptr) return;
    497   v8::String::Utf8Value key(isolate, source);
    498   DCHECK(*key);
    499   int length = cache_data->length;
    500   uint8_t* cache = new uint8_t[length];
    501   memcpy(cache, cache_data->data, length);
    502   cached_code_map_[*key] = std::unique_ptr<ScriptCompiler::CachedData>(
    503       new ScriptCompiler::CachedData(cache, length,
    504                                      ScriptCompiler::CachedData::BufferOwned));
    505 }
    506 
    507 // Executes a string within the current v8 context.
    508 bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
    509                           Local<Value> name, PrintResult print_result,
    510                           ReportExceptions report_exceptions,
    511                           ProcessMessageQueue process_message_queue) {
    512   HandleScope handle_scope(isolate);
    513   TryCatch try_catch(isolate);
    514   try_catch.SetVerbose(true);
    515 
    516   MaybeLocal<Value> maybe_result;
    517   bool success = true;
    518   {
    519     PerIsolateData* data = PerIsolateData::Get(isolate);
    520     Local<Context> realm =
    521         Local<Context>::New(isolate, data->realms_[data->realm_current_]);
    522     Context::Scope context_scope(realm);
    523     MaybeLocal<Script> maybe_script;
    524     Local<Context> context(isolate->GetCurrentContext());
    525     ScriptOrigin origin(name);
    526 
    527     DCHECK(options.compile_options != ScriptCompiler::kProduceParserCache);
    528     DCHECK(options.compile_options != ScriptCompiler::kConsumeParserCache);
    529     if (options.compile_options == ScriptCompiler::kConsumeCodeCache) {
    530       ScriptCompiler::CachedData* cached_code =
    531           LookupCodeCache(isolate, source);
    532       if (cached_code != nullptr) {
    533         ScriptCompiler::Source script_source(source, origin, cached_code);
    534         maybe_script = ScriptCompiler::Compile(context, &script_source,
    535                                                options.compile_options);
    536         CHECK(!cached_code->rejected);
    537       } else {
    538         ScriptCompiler::Source script_source(source, origin);
    539         maybe_script = ScriptCompiler::Compile(
    540             context, &script_source, ScriptCompiler::kNoCompileOptions);
    541       }
    542     } else if (options.stress_background_compile) {
    543       // Start a background thread compiling the script.
    544       BackgroundCompileThread background_compile_thread(isolate, source);
    545       background_compile_thread.Start();
    546 
    547       // In parallel, compile on the main thread to flush out any data races.
    548       {
    549         TryCatch ignore_try_catch(isolate);
    550         ScriptCompiler::Source script_source(source, origin);
    551         USE(ScriptCompiler::Compile(context, &script_source,
    552                                     ScriptCompiler::kNoCompileOptions));
    553       }
    554 
    555       // Join with background thread and finalize compilation.
    556       background_compile_thread.Join();
    557       maybe_script = v8::ScriptCompiler::Compile(
    558           context, background_compile_thread.streamed_source(), source, origin);
    559     } else {
    560       ScriptCompiler::Source script_source(source, origin);
    561       maybe_script = ScriptCompiler::Compile(context, &script_source,
    562                                              options.compile_options);
    563     }
    564 
    565     Local<Script> script;
    566     if (!maybe_script.ToLocal(&script)) {
    567       // Print errors that happened during compilation.
    568       if (report_exceptions) ReportException(isolate, &try_catch);
    569       return false;
    570     }
    571 
    572     if (options.code_cache_options ==
    573         ShellOptions::CodeCacheOptions::kProduceCache) {
    574       // Serialize and store it in memory for the next execution.
    575       ScriptCompiler::CachedData* cached_data =
    576           ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
    577       StoreInCodeCache(isolate, source, cached_data);
    578       delete cached_data;
    579     }
    580     maybe_result = script->Run(realm);
    581     if (options.code_cache_options ==
    582         ShellOptions::CodeCacheOptions::kProduceCacheAfterExecute) {
    583       // Serialize and store it in memory for the next execution.
    584       ScriptCompiler::CachedData* cached_data =
    585           ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
    586       StoreInCodeCache(isolate, source, cached_data);
    587       delete cached_data;
    588     }
    589     if (process_message_queue && !EmptyMessageQueues(isolate)) success = false;
    590     data->realm_current_ = data->realm_switch_;
    591   }
    592   Local<Value> result;
    593   if (!maybe_result.ToLocal(&result)) {
    594     DCHECK(try_catch.HasCaught());
    595     // Print errors that happened during execution.
    596     if (report_exceptions) ReportException(isolate, &try_catch);
    597     return false;
    598   }
    599   DCHECK(!try_catch.HasCaught());
    600   if (print_result) {
    601     if (options.test_shell) {
    602       if (!result->IsUndefined()) {
    603         // If all went well and the result wasn't undefined then print
    604         // the returned value.
    605         v8::String::Utf8Value str(isolate, result);
    606         fwrite(*str, sizeof(**str), str.length(), stdout);
    607         printf("\n");
    608       }
    609     } else {
    610       v8::String::Utf8Value str(isolate, Stringify(isolate, result));
    611       fwrite(*str, sizeof(**str), str.length(), stdout);
    612       printf("\n");
    613     }
    614   }
    615   return success;
    616 }
    617 
    618 namespace {
    619 
    620 std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
    621   String::Utf8Value utf8(isolate, v8_str);
    622   // Should not be able to fail since the input is a String.
    623   CHECK(*utf8);
    624   return *utf8;
    625 }
    626 
    627 bool IsAbsolutePath(const std::string& path) {
    628 #if defined(_WIN32) || defined(_WIN64)
    629   // TODO(adamk): This is an incorrect approximation, but should
    630   // work for all our test-running cases.
    631   return path.find(':') != std::string::npos;
    632 #else
    633   return path[0] == '/';
    634 #endif
    635 }
    636 
    637 std::string GetWorkingDirectory() {
    638 #if defined(_WIN32) || defined(_WIN64)
    639   char system_buffer[MAX_PATH];
    640   // TODO(adamk): Support Unicode paths.
    641   DWORD len = GetCurrentDirectoryA(MAX_PATH, system_buffer);
    642   CHECK_GT(len, 0);
    643   return system_buffer;
    644 #else
    645   char curdir[PATH_MAX];
    646   CHECK_NOT_NULL(getcwd(curdir, PATH_MAX));
    647   return curdir;
    648 #endif
    649 }
    650 
    651 // Returns the directory part of path, without the trailing '/'.
    652 std::string DirName(const std::string& path) {
    653   DCHECK(IsAbsolutePath(path));
    654   size_t last_slash = path.find_last_of('/');
    655   DCHECK(last_slash != std::string::npos);
    656   return path.substr(0, last_slash);
    657 }
    658 
    659 // Resolves path to an absolute path if necessary, and does some
    660 // normalization (eliding references to the current directory
    661 // and replacing backslashes with slashes).
    662 std::string NormalizePath(const std::string& path,
    663                           const std::string& dir_name) {
    664   std::string result;
    665   if (IsAbsolutePath(path)) {
    666     result = path;
    667   } else {
    668     result = dir_name + '/' + path;
    669   }
    670   std::replace(result.begin(), result.end(), '\\', '/');
    671   size_t i;
    672   while ((i = result.find("/./")) != std::string::npos) {
    673     result.erase(i, 2);
    674   }
    675   return result;
    676 }
    677 
    678 // Per-context Module data, allowing sharing of module maps
    679 // across top-level module loads.
    680 class ModuleEmbedderData {
    681  private:
    682   class ModuleGlobalHash {
    683    public:
    684     explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
    685     size_t operator()(const Global<Module>& module) const {
    686       return module.Get(isolate_)->GetIdentityHash();
    687     }
    688 
    689    private:
    690     Isolate* isolate_;
    691   };
    692 
    693  public:
    694   explicit ModuleEmbedderData(Isolate* isolate)
    695       : module_to_specifier_map(10, ModuleGlobalHash(isolate)) {}
    696 
    697   // Map from normalized module specifier to Module.
    698   std::unordered_map<std::string, Global<Module>> specifier_to_module_map;
    699   // Map from Module to its URL as defined in the ScriptOrigin
    700   std::unordered_map<Global<Module>, std::string, ModuleGlobalHash>
    701       module_to_specifier_map;
    702 };
    703 
    704 enum {
    705   kModuleEmbedderDataIndex,
    706   kInspectorClientIndex
    707 };
    708 
    709 void InitializeModuleEmbedderData(Local<Context> context) {
    710   context->SetAlignedPointerInEmbedderData(
    711       kModuleEmbedderDataIndex, new ModuleEmbedderData(context->GetIsolate()));
    712 }
    713 
    714 ModuleEmbedderData* GetModuleDataFromContext(Local<Context> context) {
    715   return static_cast<ModuleEmbedderData*>(
    716       context->GetAlignedPointerFromEmbedderData(kModuleEmbedderDataIndex));
    717 }
    718 
    719 void DisposeModuleEmbedderData(Local<Context> context) {
    720   delete GetModuleDataFromContext(context);
    721   context->SetAlignedPointerInEmbedderData(kModuleEmbedderDataIndex, nullptr);
    722 }
    723 
    724 MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
    725                                          Local<String> specifier,
    726                                          Local<Module> referrer) {
    727   Isolate* isolate = context->GetIsolate();
    728   ModuleEmbedderData* d = GetModuleDataFromContext(context);
    729   auto specifier_it =
    730       d->module_to_specifier_map.find(Global<Module>(isolate, referrer));
    731   CHECK(specifier_it != d->module_to_specifier_map.end());
    732   std::string absolute_path = NormalizePath(ToSTLString(isolate, specifier),
    733                                             DirName(specifier_it->second));
    734   auto module_it = d->specifier_to_module_map.find(absolute_path);
    735   CHECK(module_it != d->specifier_to_module_map.end());
    736   return module_it->second.Get(isolate);
    737 }
    738 
    739 }  // anonymous namespace
    740 
    741 MaybeLocal<Module> Shell::FetchModuleTree(Local<Context> context,
    742                                           const std::string& file_name) {
    743   DCHECK(IsAbsolutePath(file_name));
    744   Isolate* isolate = context->GetIsolate();
    745   Local<String> source_text = ReadFile(isolate, file_name.c_str());
    746   if (source_text.IsEmpty()) {
    747     std::string msg = "Error reading: " + file_name;
    748     Throw(isolate, msg.c_str());
    749     return MaybeLocal<Module>();
    750   }
    751   ScriptOrigin origin(
    752       String::NewFromUtf8(isolate, file_name.c_str(), NewStringType::kNormal)
    753           .ToLocalChecked(),
    754       Local<Integer>(), Local<Integer>(), Local<Boolean>(), Local<Integer>(),
    755       Local<Value>(), Local<Boolean>(), Local<Boolean>(), True(isolate));
    756   ScriptCompiler::Source source(source_text, origin);
    757   Local<Module> module;
    758   if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
    759     return MaybeLocal<Module>();
    760   }
    761 
    762   ModuleEmbedderData* d = GetModuleDataFromContext(context);
    763   CHECK(d->specifier_to_module_map
    764             .insert(std::make_pair(file_name, Global<Module>(isolate, module)))
    765             .second);
    766   CHECK(d->module_to_specifier_map
    767             .insert(std::make_pair(Global<Module>(isolate, module), file_name))
    768             .second);
    769 
    770   std::string dir_name = DirName(file_name);
    771 
    772   for (int i = 0, length = module->GetModuleRequestsLength(); i < length; ++i) {
    773     Local<String> name = module->GetModuleRequest(i);
    774     std::string absolute_path =
    775         NormalizePath(ToSTLString(isolate, name), dir_name);
    776     if (!d->specifier_to_module_map.count(absolute_path)) {
    777       if (FetchModuleTree(context, absolute_path).IsEmpty()) {
    778         return MaybeLocal<Module>();
    779       }
    780     }
    781   }
    782 
    783   return module;
    784 }
    785 
    786 namespace {
    787 
    788 struct DynamicImportData {
    789   DynamicImportData(Isolate* isolate_, Local<String> referrer_,
    790                     Local<String> specifier_,
    791                     Local<Promise::Resolver> resolver_)
    792       : isolate(isolate_) {
    793     referrer.Reset(isolate, referrer_);
    794     specifier.Reset(isolate, specifier_);
    795     resolver.Reset(isolate, resolver_);
    796   }
    797 
    798   Isolate* isolate;
    799   Global<String> referrer;
    800   Global<String> specifier;
    801   Global<Promise::Resolver> resolver;
    802 };
    803 
    804 }  // namespace
    805 
    806 MaybeLocal<Promise> Shell::HostImportModuleDynamically(
    807     Local<Context> context, Local<ScriptOrModule> referrer,
    808     Local<String> specifier) {
    809   Isolate* isolate = context->GetIsolate();
    810 
    811   MaybeLocal<Promise::Resolver> maybe_resolver =
    812       Promise::Resolver::New(context);
    813   Local<Promise::Resolver> resolver;
    814   if (maybe_resolver.ToLocal(&resolver)) {
    815     DynamicImportData* data = new DynamicImportData(
    816         isolate, Local<String>::Cast(referrer->GetResourceName()), specifier,
    817         resolver);
    818     isolate->EnqueueMicrotask(Shell::DoHostImportModuleDynamically, data);
    819     return resolver->GetPromise();
    820   }
    821 
    822   return MaybeLocal<Promise>();
    823 }
    824 
    825 void Shell::HostInitializeImportMetaObject(Local<Context> context,
    826                                            Local<Module> module,
    827                                            Local<Object> meta) {
    828   Isolate* isolate = context->GetIsolate();
    829   HandleScope handle_scope(isolate);
    830 
    831   ModuleEmbedderData* d = GetModuleDataFromContext(context);
    832   auto specifier_it =
    833       d->module_to_specifier_map.find(Global<Module>(isolate, module));
    834   CHECK(specifier_it != d->module_to_specifier_map.end());
    835 
    836   Local<String> url_key =
    837       String::NewFromUtf8(isolate, "url", NewStringType::kNormal)
    838           .ToLocalChecked();
    839   Local<String> url = String::NewFromUtf8(isolate, specifier_it->second.c_str(),
    840                                           NewStringType::kNormal)
    841                           .ToLocalChecked();
    842   meta->CreateDataProperty(context, url_key, url).ToChecked();
    843 }
    844 
    845 void Shell::DoHostImportModuleDynamically(void* import_data) {
    846   std::unique_ptr<DynamicImportData> import_data_(
    847       static_cast<DynamicImportData*>(import_data));
    848   Isolate* isolate(import_data_->isolate);
    849   HandleScope handle_scope(isolate);
    850 
    851   Local<String> referrer(import_data_->referrer.Get(isolate));
    852   Local<String> specifier(import_data_->specifier.Get(isolate));
    853   Local<Promise::Resolver> resolver(import_data_->resolver.Get(isolate));
    854 
    855   PerIsolateData* data = PerIsolateData::Get(isolate);
    856   Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
    857   Context::Scope context_scope(realm);
    858 
    859   std::string source_url = ToSTLString(isolate, referrer);
    860   std::string dir_name =
    861       DirName(NormalizePath(source_url, GetWorkingDirectory()));
    862   std::string file_name = ToSTLString(isolate, specifier);
    863   std::string absolute_path = NormalizePath(file_name, dir_name);
    864 
    865   TryCatch try_catch(isolate);
    866   try_catch.SetVerbose(true);
    867 
    868   ModuleEmbedderData* d = GetModuleDataFromContext(realm);
    869   Local<Module> root_module;
    870   auto module_it = d->specifier_to_module_map.find(absolute_path);
    871   if (module_it != d->specifier_to_module_map.end()) {
    872     root_module = module_it->second.Get(isolate);
    873   } else if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) {
    874     CHECK(try_catch.HasCaught());
    875     resolver->Reject(realm, try_catch.Exception()).ToChecked();
    876     return;
    877   }
    878 
    879   MaybeLocal<Value> maybe_result;
    880   if (root_module->InstantiateModule(realm, ResolveModuleCallback)
    881           .FromMaybe(false)) {
    882     maybe_result = root_module->Evaluate(realm);
    883     EmptyMessageQueues(isolate);
    884   }
    885 
    886   Local<Value> module;
    887   if (!maybe_result.ToLocal(&module)) {
    888     DCHECK(try_catch.HasCaught());
    889     resolver->Reject(realm, try_catch.Exception()).ToChecked();
    890     return;
    891   }
    892 
    893   DCHECK(!try_catch.HasCaught());
    894   Local<Value> module_namespace = root_module->GetModuleNamespace();
    895   resolver->Resolve(realm, module_namespace).ToChecked();
    896 }
    897 
    898 bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
    899   HandleScope handle_scope(isolate);
    900 
    901   PerIsolateData* data = PerIsolateData::Get(isolate);
    902   Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
    903   Context::Scope context_scope(realm);
    904 
    905   std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory());
    906 
    907   TryCatch try_catch(isolate);
    908   try_catch.SetVerbose(true);
    909 
    910   Local<Module> root_module;
    911   MaybeLocal<Value> maybe_exception;
    912 
    913   if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) {
    914     CHECK(try_catch.HasCaught());
    915     ReportException(isolate, &try_catch);
    916     return false;
    917   }
    918 
    919   MaybeLocal<Value> maybe_result;
    920   if (root_module->InstantiateModule(realm, ResolveModuleCallback)
    921           .FromMaybe(false)) {
    922     maybe_result = root_module->Evaluate(realm);
    923     EmptyMessageQueues(isolate);
    924   }
    925   Local<Value> result;
    926   if (!maybe_result.ToLocal(&result)) {
    927     DCHECK(try_catch.HasCaught());
    928     // Print errors that happened during execution.
    929     ReportException(isolate, &try_catch);
    930     return false;
    931   }
    932   DCHECK(!try_catch.HasCaught());
    933   return true;
    934 }
    935 
    936 PerIsolateData::PerIsolateData(Isolate* isolate)
    937     : isolate_(isolate), realms_(nullptr) {
    938   isolate->SetData(0, this);
    939   if (i::FLAG_expose_async_hooks) {
    940     async_hooks_wrapper_ = new AsyncHooks(isolate);
    941   }
    942 }
    943 
    944 PerIsolateData::~PerIsolateData() {
    945   isolate_->SetData(0, nullptr);  // Not really needed, just to be sure...
    946   if (i::FLAG_expose_async_hooks) {
    947     delete async_hooks_wrapper_;  // This uses the isolate
    948   }
    949 }
    950 
    951 void PerIsolateData::SetTimeout(Local<Function> callback,
    952                                 Local<Context> context) {
    953   set_timeout_callbacks_.emplace(isolate_, callback);
    954   set_timeout_contexts_.emplace(isolate_, context);
    955 }
    956 
    957 MaybeLocal<Function> PerIsolateData::GetTimeoutCallback() {
    958   if (set_timeout_callbacks_.empty()) return MaybeLocal<Function>();
    959   Local<Function> result = set_timeout_callbacks_.front().Get(isolate_);
    960   set_timeout_callbacks_.pop();
    961   return result;
    962 }
    963 
    964 MaybeLocal<Context> PerIsolateData::GetTimeoutContext() {
    965   if (set_timeout_contexts_.empty()) return MaybeLocal<Context>();
    966   Local<Context> result = set_timeout_contexts_.front().Get(isolate_);
    967   set_timeout_contexts_.pop();
    968   return result;
    969 }
    970 
    971 PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
    972   data_->realm_count_ = 1;
    973   data_->realm_current_ = 0;
    974   data_->realm_switch_ = 0;
    975   data_->realms_ = new Global<Context>[1];
    976   data_->realms_[0].Reset(data_->isolate_,
    977                           data_->isolate_->GetEnteredContext());
    978 }
    979 
    980 
    981 PerIsolateData::RealmScope::~RealmScope() {
    982   // Drop realms to avoid keeping them alive. We don't dispose the
    983   // module embedder data for the first realm here, but instead do
    984   // it in RunShell or in RunMain, if not running in interactive mode
    985   for (int i = 1; i < data_->realm_count_; ++i) {
    986     Global<Context>& realm = data_->realms_[i];
    987     if (realm.IsEmpty()) continue;
    988     DisposeModuleEmbedderData(realm.Get(data_->isolate_));
    989     // TODO(adamk): No need to reset manually, Globals reset when destructed.
    990     realm.Reset();
    991   }
    992   data_->realm_count_ = 0;
    993   delete[] data_->realms_;
    994   // TODO(adamk): No need to reset manually, Globals reset when destructed.
    995   if (!data_->realm_shared_.IsEmpty())
    996     data_->realm_shared_.Reset();
    997 }
    998 
    999 
   1000 int PerIsolateData::RealmFind(Local<Context> context) {
   1001   for (int i = 0; i < realm_count_; ++i) {
   1002     if (realms_[i] == context) return i;
   1003   }
   1004   return -1;
   1005 }
   1006 
   1007 
   1008 int PerIsolateData::RealmIndexOrThrow(
   1009     const v8::FunctionCallbackInfo<v8::Value>& args,
   1010     int arg_offset) {
   1011   if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
   1012     Throw(args.GetIsolate(), "Invalid argument");
   1013     return -1;
   1014   }
   1015   int index = args[arg_offset]
   1016                   ->Int32Value(args.GetIsolate()->GetCurrentContext())
   1017                   .FromMaybe(-1);
   1018   if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
   1019     Throw(args.GetIsolate(), "Invalid realm index");
   1020     return -1;
   1021   }
   1022   return index;
   1023 }
   1024 
   1025 
   1026 // performance.now() returns a time stamp as double, measured in milliseconds.
   1027 // When FLAG_verify_predictable mode is enabled it returns result of
   1028 // v8::Platform::MonotonicallyIncreasingTime().
   1029 void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1030   if (i::FLAG_verify_predictable) {
   1031     args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
   1032   } else {
   1033     base::TimeDelta delta =
   1034         base::TimeTicks::HighResolutionNow() - kInitialTicks;
   1035     args.GetReturnValue().Set(delta.InMillisecondsF());
   1036   }
   1037 }
   1038 
   1039 
   1040 // Realm.current() returns the index of the currently active realm.
   1041 void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1042   Isolate* isolate = args.GetIsolate();
   1043   PerIsolateData* data = PerIsolateData::Get(isolate);
   1044   int index = data->RealmFind(isolate->GetEnteredContext());
   1045   if (index == -1) return;
   1046   args.GetReturnValue().Set(index);
   1047 }
   1048 
   1049 
   1050 // Realm.owner(o) returns the index of the realm that created o.
   1051 void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1052   Isolate* isolate = args.GetIsolate();
   1053   PerIsolateData* data = PerIsolateData::Get(isolate);
   1054   if (args.Length() < 1 || !args[0]->IsObject()) {
   1055     Throw(args.GetIsolate(), "Invalid argument");
   1056     return;
   1057   }
   1058   int index = data->RealmFind(args[0]
   1059                                   ->ToObject(isolate->GetCurrentContext())
   1060                                   .ToLocalChecked()
   1061                                   ->CreationContext());
   1062   if (index == -1) return;
   1063   args.GetReturnValue().Set(index);
   1064 }
   1065 
   1066 
   1067 // Realm.global(i) returns the global object of realm i.
   1068 // (Note that properties of global objects cannot be read/written cross-realm.)
   1069 void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1070   PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
   1071   int index = data->RealmIndexOrThrow(args, 0);
   1072   if (index == -1) return;
   1073   args.GetReturnValue().Set(
   1074       Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
   1075 }
   1076 
   1077 MaybeLocal<Context> Shell::CreateRealm(
   1078     const v8::FunctionCallbackInfo<v8::Value>& args, int index,
   1079     v8::MaybeLocal<Value> global_object) {
   1080   Isolate* isolate = args.GetIsolate();
   1081   TryCatch try_catch(isolate);
   1082   PerIsolateData* data = PerIsolateData::Get(isolate);
   1083   if (index < 0) {
   1084     Global<Context>* old_realms = data->realms_;
   1085     index = data->realm_count_;
   1086     data->realms_ = new Global<Context>[++data->realm_count_];
   1087     for (int i = 0; i < index; ++i) {
   1088       data->realms_[i].Reset(isolate, old_realms[i]);
   1089       old_realms[i].Reset();
   1090     }
   1091     delete[] old_realms;
   1092   }
   1093   Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
   1094   Local<Context> context =
   1095       Context::New(isolate, nullptr, global_template, global_object);
   1096   DCHECK(!try_catch.HasCaught());
   1097   if (context.IsEmpty()) return MaybeLocal<Context>();
   1098   InitializeModuleEmbedderData(context);
   1099   data->realms_[index].Reset(isolate, context);
   1100   args.GetReturnValue().Set(index);
   1101   return context;
   1102 }
   1103 
   1104 void Shell::DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
   1105                          int index) {
   1106   Isolate* isolate = args.GetIsolate();
   1107   PerIsolateData* data = PerIsolateData::Get(isolate);
   1108   DisposeModuleEmbedderData(data->realms_[index].Get(isolate));
   1109   data->realms_[index].Reset();
   1110   isolate->ContextDisposedNotification();
   1111   isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
   1112 }
   1113 
   1114 // Realm.create() creates a new realm with a distinct security token
   1115 // and returns its index.
   1116 void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1117   CreateRealm(args, -1, v8::MaybeLocal<Value>());
   1118 }
   1119 
   1120 // Realm.createAllowCrossRealmAccess() creates a new realm with the same
   1121 // security token as the current realm.
   1122 void Shell::RealmCreateAllowCrossRealmAccess(
   1123     const v8::FunctionCallbackInfo<v8::Value>& args) {
   1124   Local<Context> context;
   1125   if (CreateRealm(args, -1, v8::MaybeLocal<Value>()).ToLocal(&context)) {
   1126     context->SetSecurityToken(
   1127         args.GetIsolate()->GetEnteredContext()->GetSecurityToken());
   1128   }
   1129 }
   1130 
   1131 // Realm.navigate(i) creates a new realm with a distinct security token
   1132 // in place of realm i.
   1133 void Shell::RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1134   Isolate* isolate = args.GetIsolate();
   1135   PerIsolateData* data = PerIsolateData::Get(isolate);
   1136   int index = data->RealmIndexOrThrow(args, 0);
   1137   if (index == -1) return;
   1138   if (index == 0 || index == data->realm_current_ ||
   1139       index == data->realm_switch_) {
   1140     Throw(args.GetIsolate(), "Invalid realm index");
   1141     return;
   1142   }
   1143 
   1144   Local<Context> context = Local<Context>::New(isolate, data->realms_[index]);
   1145   v8::MaybeLocal<Value> global_object = context->Global();
   1146   DisposeRealm(args, index);
   1147   CreateRealm(args, index, global_object);
   1148 }
   1149 
   1150 // Realm.dispose(i) disposes the reference to the realm i.
   1151 void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1152   Isolate* isolate = args.GetIsolate();
   1153   PerIsolateData* data = PerIsolateData::Get(isolate);
   1154   int index = data->RealmIndexOrThrow(args, 0);
   1155   if (index == -1) return;
   1156   if (index == 0 ||
   1157       index == data->realm_current_ || index == data->realm_switch_) {
   1158     Throw(args.GetIsolate(), "Invalid realm index");
   1159     return;
   1160   }
   1161   DisposeRealm(args, index);
   1162 }
   1163 
   1164 
   1165 // Realm.switch(i) switches to the realm i for consecutive interactive inputs.
   1166 void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1167   Isolate* isolate = args.GetIsolate();
   1168   PerIsolateData* data = PerIsolateData::Get(isolate);
   1169   int index = data->RealmIndexOrThrow(args, 0);
   1170   if (index == -1) return;
   1171   data->realm_switch_ = index;
   1172 }
   1173 
   1174 
   1175 // Realm.eval(i, s) evaluates s in realm i and returns the result.
   1176 void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1177   Isolate* isolate = args.GetIsolate();
   1178   PerIsolateData* data = PerIsolateData::Get(isolate);
   1179   int index = data->RealmIndexOrThrow(args, 0);
   1180   if (index == -1) return;
   1181   if (args.Length() < 2 || !args[1]->IsString()) {
   1182     Throw(args.GetIsolate(), "Invalid argument");
   1183     return;
   1184   }
   1185   ScriptCompiler::Source script_source(
   1186       args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
   1187   Local<UnboundScript> script;
   1188   if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
   1189            .ToLocal(&script)) {
   1190     return;
   1191   }
   1192   Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
   1193   realm->Enter();
   1194   int previous_index = data->realm_current_;
   1195   data->realm_current_ = data->realm_switch_ = index;
   1196   Local<Value> result;
   1197   if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
   1198     realm->Exit();
   1199     data->realm_current_ = data->realm_switch_ = previous_index;
   1200     return;
   1201   }
   1202   realm->Exit();
   1203   data->realm_current_ = data->realm_switch_ = previous_index;
   1204   args.GetReturnValue().Set(result);
   1205 }
   1206 
   1207 
   1208 // Realm.shared is an accessor for a single shared value across realms.
   1209 void Shell::RealmSharedGet(Local<String> property,
   1210                            const PropertyCallbackInfo<Value>& info) {
   1211   Isolate* isolate = info.GetIsolate();
   1212   PerIsolateData* data = PerIsolateData::Get(isolate);
   1213   if (data->realm_shared_.IsEmpty()) return;
   1214   info.GetReturnValue().Set(data->realm_shared_);
   1215 }
   1216 
   1217 void Shell::RealmSharedSet(Local<String> property,
   1218                            Local<Value> value,
   1219                            const PropertyCallbackInfo<void>& info) {
   1220   Isolate* isolate = info.GetIsolate();
   1221   PerIsolateData* data = PerIsolateData::Get(isolate);
   1222   data->realm_shared_.Reset(isolate, value);
   1223 }
   1224 
   1225 // async_hooks.createHook() registers functions to be called for different
   1226 // lifetime events of each async operation.
   1227 void Shell::AsyncHooksCreateHook(
   1228     const v8::FunctionCallbackInfo<v8::Value>& args) {
   1229   Local<Object> wrap =
   1230       PerIsolateData::Get(args.GetIsolate())->GetAsyncHooks()->CreateHook(args);
   1231   args.GetReturnValue().Set(wrap);
   1232 }
   1233 
   1234 // async_hooks.executionAsyncId() returns the asyncId of the current execution
   1235 // context.
   1236 void Shell::AsyncHooksExecutionAsyncId(
   1237     const v8::FunctionCallbackInfo<v8::Value>& args) {
   1238   Isolate* isolate = args.GetIsolate();
   1239   HandleScope handle_scope(isolate);
   1240   args.GetReturnValue().Set(v8::Number::New(
   1241       isolate,
   1242       PerIsolateData::Get(isolate)->GetAsyncHooks()->GetExecutionAsyncId()));
   1243 }
   1244 
   1245 void Shell::AsyncHooksTriggerAsyncId(
   1246     const v8::FunctionCallbackInfo<v8::Value>& args) {
   1247   Isolate* isolate = args.GetIsolate();
   1248   HandleScope handle_scope(isolate);
   1249   args.GetReturnValue().Set(v8::Number::New(
   1250       isolate,
   1251       PerIsolateData::Get(isolate)->GetAsyncHooks()->GetTriggerAsyncId()));
   1252 }
   1253 
   1254 void WriteToFile(FILE* file, const v8::FunctionCallbackInfo<v8::Value>& args) {
   1255   for (int i = 0; i < args.Length(); i++) {
   1256     HandleScope handle_scope(args.GetIsolate());
   1257     if (i != 0) {
   1258       fprintf(file, " ");
   1259     }
   1260 
   1261     // Explicitly catch potential exceptions in toString().
   1262     v8::TryCatch try_catch(args.GetIsolate());
   1263     Local<Value> arg = args[i];
   1264     Local<String> str_obj;
   1265 
   1266     if (arg->IsSymbol()) {
   1267       arg = Local<Symbol>::Cast(arg)->Name();
   1268     }
   1269     if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
   1270              .ToLocal(&str_obj)) {
   1271       try_catch.ReThrow();
   1272       return;
   1273     }
   1274 
   1275     v8::String::Utf8Value str(args.GetIsolate(), str_obj);
   1276     int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), file));
   1277     if (n != str.length()) {
   1278       printf("Error in fwrite\n");
   1279       base::OS::ExitProcess(1);
   1280     }
   1281   }
   1282 }
   1283 
   1284 void WriteAndFlush(FILE* file,
   1285                    const v8::FunctionCallbackInfo<v8::Value>& args) {
   1286   WriteToFile(file, args);
   1287   fprintf(file, "\n");
   1288   fflush(file);
   1289 }
   1290 
   1291 void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1292   WriteAndFlush(stdout, args);
   1293 }
   1294 
   1295 void Shell::PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1296   WriteAndFlush(stderr, args);
   1297 }
   1298 
   1299 void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1300   WriteToFile(stdout, args);
   1301 }
   1302 
   1303 void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1304   String::Utf8Value file(args.GetIsolate(), args[0]);
   1305   if (*file == nullptr) {
   1306     Throw(args.GetIsolate(), "Error loading file");
   1307     return;
   1308   }
   1309   if (args.Length() == 2) {
   1310     String::Utf8Value format(args.GetIsolate(), args[1]);
   1311     if (*format && std::strcmp(*format, "binary") == 0) {
   1312       ReadBuffer(args);
   1313       return;
   1314     }
   1315   }
   1316   Local<String> source = ReadFile(args.GetIsolate(), *file);
   1317   if (source.IsEmpty()) {
   1318     Throw(args.GetIsolate(), "Error loading file");
   1319     return;
   1320   }
   1321   args.GetReturnValue().Set(source);
   1322 }
   1323 
   1324 
   1325 Local<String> Shell::ReadFromStdin(Isolate* isolate) {
   1326   static const int kBufferSize = 256;
   1327   char buffer[kBufferSize];
   1328   Local<String> accumulator =
   1329       String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
   1330   int length;
   1331   while (true) {
   1332     // Continue reading if the line ends with an escape '\\' or the line has
   1333     // not been fully read into the buffer yet (does not end with '\n').
   1334     // If fgets gets an error, just give up.
   1335     char* input = nullptr;
   1336     input = fgets(buffer, kBufferSize, stdin);
   1337     if (input == nullptr) return Local<String>();
   1338     length = static_cast<int>(strlen(buffer));
   1339     if (length == 0) {
   1340       return accumulator;
   1341     } else if (buffer[length-1] != '\n') {
   1342       accumulator = String::Concat(
   1343           isolate, accumulator,
   1344           String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
   1345               .ToLocalChecked());
   1346     } else if (length > 1 && buffer[length-2] == '\\') {
   1347       buffer[length-2] = '\n';
   1348       accumulator =
   1349           String::Concat(isolate, accumulator,
   1350                          String::NewFromUtf8(isolate, buffer,
   1351                                              NewStringType::kNormal, length - 1)
   1352                              .ToLocalChecked());
   1353     } else {
   1354       return String::Concat(
   1355           isolate, accumulator,
   1356           String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
   1357                               length - 1)
   1358               .ToLocalChecked());
   1359     }
   1360   }
   1361 }
   1362 
   1363 
   1364 void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1365   for (int i = 0; i < args.Length(); i++) {
   1366     HandleScope handle_scope(args.GetIsolate());
   1367     String::Utf8Value file(args.GetIsolate(), args[i]);
   1368     if (*file == nullptr) {
   1369       Throw(args.GetIsolate(), "Error loading file");
   1370       return;
   1371     }
   1372     Local<String> source = ReadFile(args.GetIsolate(), *file);
   1373     if (source.IsEmpty()) {
   1374       Throw(args.GetIsolate(), "Error loading file");
   1375       return;
   1376     }
   1377     if (!ExecuteString(
   1378             args.GetIsolate(), source,
   1379             String::NewFromUtf8(args.GetIsolate(), *file,
   1380                                 NewStringType::kNormal)
   1381                 .ToLocalChecked(),
   1382             kNoPrintResult,
   1383             options.quiet_load ? kNoReportExceptions : kReportExceptions,
   1384             kNoProcessMessageQueue)) {
   1385       Throw(args.GetIsolate(), "Error executing file");
   1386       return;
   1387     }
   1388   }
   1389 }
   1390 
   1391 void Shell::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1392   Isolate* isolate = args.GetIsolate();
   1393   args.GetReturnValue().Set(v8::Number::New(isolate, 0));
   1394   if (args.Length() == 0 || !args[0]->IsFunction()) return;
   1395   Local<Function> callback = Local<Function>::Cast(args[0]);
   1396   Local<Context> context = isolate->GetCurrentContext();
   1397   PerIsolateData::Get(isolate)->SetTimeout(callback, context);
   1398 }
   1399 
   1400 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1401   Isolate* isolate = args.GetIsolate();
   1402   HandleScope handle_scope(isolate);
   1403   if (args.Length() < 1 || !args[0]->IsString()) {
   1404     Throw(args.GetIsolate(), "1st argument must be string");
   1405     return;
   1406   }
   1407 
   1408   if (!args.IsConstructCall()) {
   1409     Throw(args.GetIsolate(), "Worker must be constructed with new");
   1410     return;
   1411   }
   1412 
   1413   {
   1414     base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   1415     if (workers_.size() >= kMaxWorkers) {
   1416       Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
   1417       return;
   1418     }
   1419 
   1420     // Initialize the embedder field to nullptr; if we return early without
   1421     // creating a new Worker (because the main thread is terminating) we can
   1422     // early-out from the instance calls.
   1423     args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
   1424 
   1425     if (!allow_new_workers_) return;
   1426 
   1427     Worker* worker = new Worker;
   1428     args.Holder()->SetAlignedPointerInInternalField(0, worker);
   1429     workers_.push_back(worker);
   1430 
   1431     String::Utf8Value script(args.GetIsolate(), args[0]);
   1432     if (!*script) {
   1433       Throw(args.GetIsolate(), "Can't get worker script");
   1434       return;
   1435     }
   1436     worker->StartExecuteInThread(*script);
   1437   }
   1438 }
   1439 
   1440 
   1441 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1442   Isolate* isolate = args.GetIsolate();
   1443   HandleScope handle_scope(isolate);
   1444 
   1445   if (args.Length() < 1) {
   1446     Throw(isolate, "Invalid argument");
   1447     return;
   1448   }
   1449 
   1450   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
   1451   if (!worker) {
   1452     return;
   1453   }
   1454 
   1455   Local<Value> message = args[0];
   1456   Local<Value> transfer =
   1457       args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate));
   1458   std::unique_ptr<SerializationData> data =
   1459       Shell::SerializeValue(isolate, message, transfer);
   1460   if (data) {
   1461     worker->PostMessage(std::move(data));
   1462   }
   1463 }
   1464 
   1465 
   1466 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1467   Isolate* isolate = args.GetIsolate();
   1468   HandleScope handle_scope(isolate);
   1469   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
   1470   if (!worker) {
   1471     return;
   1472   }
   1473 
   1474   std::unique_ptr<SerializationData> data = worker->GetMessage();
   1475   if (data) {
   1476     Local<Value> value;
   1477     if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) {
   1478       args.GetReturnValue().Set(value);
   1479     }
   1480   }
   1481 }
   1482 
   1483 
   1484 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1485   Isolate* isolate = args.GetIsolate();
   1486   HandleScope handle_scope(isolate);
   1487   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
   1488   if (!worker) {
   1489     return;
   1490   }
   1491 
   1492   worker->Terminate();
   1493 }
   1494 
   1495 
   1496 void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
   1497   int exit_code = (*args)[0]
   1498                       ->Int32Value(args->GetIsolate()->GetCurrentContext())
   1499                       .FromMaybe(0);
   1500   CleanupWorkers();
   1501   args->GetIsolate()->Exit();
   1502   OnExit(args->GetIsolate());
   1503   base::OS::ExitProcess(exit_code);
   1504 }
   1505 
   1506 
   1507 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1508   base::CallOnce(&quit_once_, &QuitOnce,
   1509                  const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
   1510 }
   1511 
   1512 void Shell::WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1513   SetWaitUntilDone(args.GetIsolate(), true);
   1514 }
   1515 
   1516 void Shell::NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1517   SetWaitUntilDone(args.GetIsolate(), false);
   1518 }
   1519 
   1520 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1521   args.GetReturnValue().Set(
   1522       String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
   1523                           NewStringType::kNormal).ToLocalChecked());
   1524 }
   1525 
   1526 
   1527 void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
   1528   HandleScope handle_scope(isolate);
   1529   Local<Context> context = isolate->GetCurrentContext();
   1530   bool enter_context = context.IsEmpty();
   1531   if (enter_context) {
   1532     context = Local<Context>::New(isolate, evaluation_context_);
   1533     context->Enter();
   1534   }
   1535   // Converts a V8 value to a C string.
   1536   auto ToCString = [](const v8::String::Utf8Value& value) {
   1537     return *value ? *value : "<string conversion failed>";
   1538   };
   1539 
   1540   v8::String::Utf8Value exception(isolate, try_catch->Exception());
   1541   const char* exception_string = ToCString(exception);
   1542   Local<Message> message = try_catch->Message();
   1543   if (message.IsEmpty()) {
   1544     // V8 didn't provide any extra information about this error; just
   1545     // print the exception.
   1546     printf("%s\n", exception_string);
   1547   } else if (message->GetScriptOrigin().Options().IsWasm()) {
   1548     // Print wasm-function[(function index)]:(offset): (message).
   1549     int function_index = message->GetLineNumber(context).FromJust() - 1;
   1550     int offset = message->GetStartColumn(context).FromJust();
   1551     printf("wasm-function[%d]:%d: %s\n", function_index, offset,
   1552            exception_string);
   1553   } else {
   1554     // Print (filename):(line number): (message).
   1555     v8::String::Utf8Value filename(isolate,
   1556                                    message->GetScriptOrigin().ResourceName());
   1557     const char* filename_string = ToCString(filename);
   1558     int linenum = message->GetLineNumber(context).FromMaybe(-1);
   1559     printf("%s:%i: %s\n", filename_string, linenum, exception_string);
   1560     Local<String> sourceline;
   1561     if (message->GetSourceLine(context).ToLocal(&sourceline)) {
   1562       // Print line of source code.
   1563       v8::String::Utf8Value sourcelinevalue(isolate, sourceline);
   1564       const char* sourceline_string = ToCString(sourcelinevalue);
   1565       printf("%s\n", sourceline_string);
   1566       // Print wavy underline (GetUnderline is deprecated).
   1567       int start = message->GetStartColumn(context).FromJust();
   1568       for (int i = 0; i < start; i++) {
   1569         printf(" ");
   1570       }
   1571       int end = message->GetEndColumn(context).FromJust();
   1572       for (int i = start; i < end; i++) {
   1573         printf("^");
   1574       }
   1575       printf("\n");
   1576     }
   1577   }
   1578   Local<Value> stack_trace_string;
   1579   if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
   1580       stack_trace_string->IsString()) {
   1581     v8::String::Utf8Value stack_trace(isolate,
   1582                                       Local<String>::Cast(stack_trace_string));
   1583     printf("%s\n", ToCString(stack_trace));
   1584   }
   1585   printf("\n");
   1586   if (enter_context) context->Exit();
   1587 }
   1588 
   1589 
   1590 int32_t* Counter::Bind(const char* name, bool is_histogram) {
   1591   int i;
   1592   for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
   1593     name_[i] = static_cast<char>(name[i]);
   1594   name_[i] = '\0';
   1595   is_histogram_ = is_histogram;
   1596   return ptr();
   1597 }
   1598 
   1599 
   1600 void Counter::AddSample(int32_t sample) {
   1601   count_++;
   1602   sample_total_ += sample;
   1603 }
   1604 
   1605 
   1606 CounterCollection::CounterCollection() {
   1607   magic_number_ = 0xDEADFACE;
   1608   max_counters_ = kMaxCounters;
   1609   max_name_size_ = Counter::kMaxNameSize;
   1610   counters_in_use_ = 0;
   1611 }
   1612 
   1613 
   1614 Counter* CounterCollection::GetNextCounter() {
   1615   if (counters_in_use_ == kMaxCounters) return nullptr;
   1616   return &counters_[counters_in_use_++];
   1617 }
   1618 
   1619 
   1620 void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
   1621   counters_file_ = base::OS::MemoryMappedFile::create(
   1622       name, sizeof(CounterCollection), &local_counters_);
   1623   void* memory =
   1624       (counters_file_ == nullptr) ? nullptr : counters_file_->memory();
   1625   if (memory == nullptr) {
   1626     printf("Could not map counters file %s\n", name);
   1627     base::OS::ExitProcess(1);
   1628   }
   1629   counters_ = static_cast<CounterCollection*>(memory);
   1630   isolate->SetCounterFunction(LookupCounter);
   1631   isolate->SetCreateHistogramFunction(CreateHistogram);
   1632   isolate->SetAddHistogramSampleFunction(AddHistogramSample);
   1633 }
   1634 
   1635 Counter* Shell::GetCounter(const char* name, bool is_histogram) {
   1636   auto map_entry = counter_map_->find(name);
   1637   Counter* counter =
   1638       map_entry != counter_map_->end() ? map_entry->second : nullptr;
   1639 
   1640   if (counter == nullptr) {
   1641     counter = counters_->GetNextCounter();
   1642     if (counter != nullptr) {
   1643       (*counter_map_)[name] = counter;
   1644       counter->Bind(name, is_histogram);
   1645     }
   1646   } else {
   1647     DCHECK(counter->is_histogram() == is_histogram);
   1648   }
   1649   return counter;
   1650 }
   1651 
   1652 
   1653 int* Shell::LookupCounter(const char* name) {
   1654   Counter* counter = GetCounter(name, false);
   1655 
   1656   if (counter != nullptr) {
   1657     return counter->ptr();
   1658   } else {
   1659     return nullptr;
   1660   }
   1661 }
   1662 
   1663 
   1664 void* Shell::CreateHistogram(const char* name,
   1665                              int min,
   1666                              int max,
   1667                              size_t buckets) {
   1668   return GetCounter(name, true);
   1669 }
   1670 
   1671 
   1672 void Shell::AddHistogramSample(void* histogram, int sample) {
   1673   Counter* counter = reinterpret_cast<Counter*>(histogram);
   1674   counter->AddSample(sample);
   1675 }
   1676 
   1677 // Turn a value into a human-readable string.
   1678 Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
   1679   v8::Local<v8::Context> context =
   1680       v8::Local<v8::Context>::New(isolate, evaluation_context_);
   1681   if (stringify_function_.IsEmpty()) {
   1682     int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
   1683     i::Vector<const char> source_string =
   1684         i::NativesCollection<i::D8>::GetScriptSource(source_index);
   1685     i::Vector<const char> source_name =
   1686         i::NativesCollection<i::D8>::GetScriptName(source_index);
   1687     Local<String> source =
   1688         String::NewFromUtf8(isolate, source_string.start(),
   1689                             NewStringType::kNormal, source_string.length())
   1690             .ToLocalChecked();
   1691     Local<String> name =
   1692         String::NewFromUtf8(isolate, source_name.start(),
   1693                             NewStringType::kNormal, source_name.length())
   1694             .ToLocalChecked();
   1695     ScriptOrigin origin(name);
   1696     Local<Script> script =
   1697         Script::Compile(context, source, &origin).ToLocalChecked();
   1698     stringify_function_.Reset(
   1699         isolate, script->Run(context).ToLocalChecked().As<Function>());
   1700   }
   1701   Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
   1702   Local<Value> argv[1] = {value};
   1703   v8::TryCatch try_catch(isolate);
   1704   MaybeLocal<Value> result = fun->Call(context, Undefined(isolate), 1, argv);
   1705   if (result.IsEmpty()) return String::Empty(isolate);
   1706   return result.ToLocalChecked().As<String>();
   1707 }
   1708 
   1709 
   1710 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   1711   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
   1712   global_template->Set(
   1713       String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
   1714           .ToLocalChecked(),
   1715       FunctionTemplate::New(isolate, Print));
   1716   global_template->Set(
   1717       String::NewFromUtf8(isolate, "printErr", NewStringType::kNormal)
   1718           .ToLocalChecked(),
   1719       FunctionTemplate::New(isolate, PrintErr));
   1720   global_template->Set(
   1721       String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
   1722           .ToLocalChecked(),
   1723       FunctionTemplate::New(isolate, Write));
   1724   global_template->Set(
   1725       String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
   1726           .ToLocalChecked(),
   1727       FunctionTemplate::New(isolate, Read));
   1728   global_template->Set(
   1729       String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
   1730           .ToLocalChecked(),
   1731       FunctionTemplate::New(isolate, ReadBuffer));
   1732   global_template->Set(
   1733       String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
   1734           .ToLocalChecked(),
   1735       FunctionTemplate::New(isolate, ReadLine));
   1736   global_template->Set(
   1737       String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
   1738           .ToLocalChecked(),
   1739       FunctionTemplate::New(isolate, Load));
   1740   global_template->Set(
   1741       String::NewFromUtf8(isolate, "setTimeout", NewStringType::kNormal)
   1742           .ToLocalChecked(),
   1743       FunctionTemplate::New(isolate, SetTimeout));
   1744   // Some Emscripten-generated code tries to call 'quit', which in turn would
   1745   // call C's exit(). This would lead to memory leaks, because there is no way
   1746   // we can terminate cleanly then, so we need a way to hide 'quit'.
   1747   if (!options.omit_quit) {
   1748     global_template->Set(
   1749         String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
   1750             .ToLocalChecked(),
   1751         FunctionTemplate::New(isolate, Quit));
   1752   }
   1753   Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
   1754   global_template->Set(
   1755       String::NewFromUtf8(isolate, "testRunner", NewStringType::kNormal)
   1756           .ToLocalChecked(),
   1757       test_template);
   1758   test_template->Set(
   1759       String::NewFromUtf8(isolate, "notifyDone", NewStringType::kNormal)
   1760           .ToLocalChecked(),
   1761       FunctionTemplate::New(isolate, NotifyDone));
   1762   test_template->Set(
   1763       String::NewFromUtf8(isolate, "waitUntilDone", NewStringType::kNormal)
   1764           .ToLocalChecked(),
   1765       FunctionTemplate::New(isolate, WaitUntilDone));
   1766   global_template->Set(
   1767       String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
   1768           .ToLocalChecked(),
   1769       FunctionTemplate::New(isolate, Version));
   1770   global_template->Set(
   1771       Symbol::GetToStringTag(isolate),
   1772       String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
   1773           .ToLocalChecked());
   1774 
   1775   // Bind the Realm object.
   1776   Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
   1777   realm_template->Set(
   1778       String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
   1779           .ToLocalChecked(),
   1780       FunctionTemplate::New(isolate, RealmCurrent));
   1781   realm_template->Set(
   1782       String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
   1783           .ToLocalChecked(),
   1784       FunctionTemplate::New(isolate, RealmOwner));
   1785   realm_template->Set(
   1786       String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
   1787           .ToLocalChecked(),
   1788       FunctionTemplate::New(isolate, RealmGlobal));
   1789   realm_template->Set(
   1790       String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
   1791           .ToLocalChecked(),
   1792       FunctionTemplate::New(isolate, RealmCreate));
   1793   realm_template->Set(
   1794       String::NewFromUtf8(isolate, "createAllowCrossRealmAccess",
   1795                           NewStringType::kNormal)
   1796           .ToLocalChecked(),
   1797       FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
   1798   realm_template->Set(
   1799       String::NewFromUtf8(isolate, "navigate", NewStringType::kNormal)
   1800           .ToLocalChecked(),
   1801       FunctionTemplate::New(isolate, RealmNavigate));
   1802   realm_template->Set(
   1803       String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
   1804           .ToLocalChecked(),
   1805       FunctionTemplate::New(isolate, RealmDispose));
   1806   realm_template->Set(
   1807       String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
   1808           .ToLocalChecked(),
   1809       FunctionTemplate::New(isolate, RealmSwitch));
   1810   realm_template->Set(
   1811       String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
   1812           .ToLocalChecked(),
   1813       FunctionTemplate::New(isolate, RealmEval));
   1814   realm_template->SetAccessor(
   1815       String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
   1816           .ToLocalChecked(),
   1817       RealmSharedGet, RealmSharedSet);
   1818   global_template->Set(
   1819       String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
   1820           .ToLocalChecked(),
   1821       realm_template);
   1822 
   1823   Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
   1824   performance_template->Set(
   1825       String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
   1826           .ToLocalChecked(),
   1827       FunctionTemplate::New(isolate, PerformanceNow));
   1828   global_template->Set(
   1829       String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
   1830           .ToLocalChecked(),
   1831       performance_template);
   1832 
   1833   Local<FunctionTemplate> worker_fun_template =
   1834       FunctionTemplate::New(isolate, WorkerNew);
   1835   Local<Signature> worker_signature =
   1836       Signature::New(isolate, worker_fun_template);
   1837   worker_fun_template->SetClassName(
   1838       String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
   1839           .ToLocalChecked());
   1840   worker_fun_template->ReadOnlyPrototype();
   1841   worker_fun_template->PrototypeTemplate()->Set(
   1842       String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
   1843           .ToLocalChecked(),
   1844       FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
   1845                             worker_signature));
   1846   worker_fun_template->PrototypeTemplate()->Set(
   1847       String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
   1848           .ToLocalChecked(),
   1849       FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
   1850                             worker_signature));
   1851   worker_fun_template->PrototypeTemplate()->Set(
   1852       String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
   1853           .ToLocalChecked(),
   1854       FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
   1855                             worker_signature));
   1856   worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
   1857   global_template->Set(
   1858       String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
   1859           .ToLocalChecked(),
   1860       worker_fun_template);
   1861 
   1862   Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
   1863   AddOSMethods(isolate, os_templ);
   1864   global_template->Set(
   1865       String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
   1866           .ToLocalChecked(),
   1867       os_templ);
   1868 
   1869   if (i::FLAG_expose_async_hooks) {
   1870     Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
   1871     async_hooks_templ->Set(
   1872         String::NewFromUtf8(isolate, "createHook", NewStringType::kNormal)
   1873             .ToLocalChecked(),
   1874         FunctionTemplate::New(isolate, AsyncHooksCreateHook));
   1875     async_hooks_templ->Set(
   1876         String::NewFromUtf8(isolate, "executionAsyncId", NewStringType::kNormal)
   1877             .ToLocalChecked(),
   1878         FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
   1879     async_hooks_templ->Set(
   1880         String::NewFromUtf8(isolate, "triggerAsyncId", NewStringType::kNormal)
   1881             .ToLocalChecked(),
   1882         FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
   1883     global_template->Set(
   1884         String::NewFromUtf8(isolate, "async_hooks", NewStringType::kNormal)
   1885             .ToLocalChecked(),
   1886         async_hooks_templ);
   1887   }
   1888 
   1889   return global_template;
   1890 }
   1891 
   1892 static void PrintNonErrorsMessageCallback(Local<Message> message,
   1893                                           Local<Value> error) {
   1894   // Nothing to do here for errors, exceptions thrown up to the shell will be
   1895   // reported
   1896   // separately by {Shell::ReportException} after they are caught.
   1897   // Do print other kinds of messages.
   1898   switch (message->ErrorLevel()) {
   1899     case v8::Isolate::kMessageWarning:
   1900     case v8::Isolate::kMessageLog:
   1901     case v8::Isolate::kMessageInfo:
   1902     case v8::Isolate::kMessageDebug: {
   1903       break;
   1904     }
   1905 
   1906     case v8::Isolate::kMessageError: {
   1907       // Ignore errors, printed elsewhere.
   1908       return;
   1909     }
   1910 
   1911     default: {
   1912       UNREACHABLE();
   1913       break;
   1914     }
   1915   }
   1916   // Converts a V8 value to a C string.
   1917   auto ToCString = [](const v8::String::Utf8Value& value) {
   1918     return *value ? *value : "<string conversion failed>";
   1919   };
   1920   Isolate* isolate = Isolate::GetCurrent();
   1921   v8::String::Utf8Value msg(isolate, message->Get());
   1922   const char* msg_string = ToCString(msg);
   1923   // Print (filename):(line number): (message).
   1924   v8::String::Utf8Value filename(isolate,
   1925                                  message->GetScriptOrigin().ResourceName());
   1926   const char* filename_string = ToCString(filename);
   1927   Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
   1928   int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
   1929   printf("%s:%i: %s\n", filename_string, linenum, msg_string);
   1930 }
   1931 
   1932 void Shell::Initialize(Isolate* isolate) {
   1933   // Set up counters
   1934   if (i::StrLength(i::FLAG_map_counters) != 0)
   1935     MapCounters(isolate, i::FLAG_map_counters);
   1936   // Disable default message reporting.
   1937   isolate->AddMessageListenerWithErrorLevel(
   1938       PrintNonErrorsMessageCallback,
   1939       v8::Isolate::kMessageError | v8::Isolate::kMessageWarning |
   1940           v8::Isolate::kMessageInfo | v8::Isolate::kMessageDebug |
   1941           v8::Isolate::kMessageLog);
   1942 }
   1943 
   1944 
   1945 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
   1946   // This needs to be a critical section since this is not thread-safe
   1947   base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
   1948   // Initialize the global objects
   1949   Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
   1950   EscapableHandleScope handle_scope(isolate);
   1951   Local<Context> context = Context::New(isolate, nullptr, global_template);
   1952   DCHECK(!context.IsEmpty());
   1953   InitializeModuleEmbedderData(context);
   1954   Context::Scope scope(context);
   1955 
   1956   i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
   1957   i::JSArguments js_args = i::FLAG_js_arguments;
   1958   i::Handle<i::FixedArray> arguments_array =
   1959       factory->NewFixedArray(js_args.argc);
   1960   for (int j = 0; j < js_args.argc; j++) {
   1961     i::Handle<i::String> arg =
   1962         factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
   1963     arguments_array->set(j, *arg);
   1964   }
   1965   i::Handle<i::JSArray> arguments_jsarray =
   1966       factory->NewJSArrayWithElements(arguments_array);
   1967   context->Global()
   1968       ->Set(context,
   1969             String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
   1970                 .ToLocalChecked(),
   1971             Utils::ToLocal(arguments_jsarray))
   1972       .FromJust();
   1973   return handle_scope.Escape(context);
   1974 }
   1975 
   1976 struct CounterAndKey {
   1977   Counter* counter;
   1978   const char* key;
   1979 };
   1980 
   1981 
   1982 inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
   1983   return strcmp(lhs.key, rhs.key) < 0;
   1984 }
   1985 
   1986 void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
   1987   HandleScope handle_scope(isolate);
   1988   Local<Context> context = Context::New(isolate);
   1989   Context::Scope context_scope(context);
   1990 
   1991   Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
   1992                                         ->interpreter()
   1993                                         ->GetDispatchCountersObject();
   1994   std::ofstream dispatch_counters_stream(
   1995       i::FLAG_trace_ignition_dispatches_output_file);
   1996   dispatch_counters_stream << *String::Utf8Value(
   1997       isolate, JSON::Stringify(context, dispatch_counters).ToLocalChecked());
   1998 }
   1999 
   2000 namespace {
   2001 int LineFromOffset(Local<debug::Script> script, int offset) {
   2002   debug::Location location = script->GetSourceLocation(offset);
   2003   return location.GetLineNumber();
   2004 }
   2005 
   2006 void WriteLcovDataForRange(std::vector<uint32_t>& lines, int start_line,
   2007                            int end_line, uint32_t count) {
   2008   // Ensure space in the array.
   2009   lines.resize(std::max(static_cast<size_t>(end_line + 1), lines.size()), 0);
   2010   // Boundary lines could be shared between two functions with different
   2011   // invocation counts. Take the maximum.
   2012   lines[start_line] = std::max(lines[start_line], count);
   2013   lines[end_line] = std::max(lines[end_line], count);
   2014   // Invocation counts for non-boundary lines are overwritten.
   2015   for (int k = start_line + 1; k < end_line; k++) lines[k] = count;
   2016 }
   2017 
   2018 void WriteLcovDataForNamedRange(std::ostream& sink,
   2019                                 std::vector<uint32_t>& lines, std::string name,
   2020                                 int start_line, int end_line, uint32_t count) {
   2021   WriteLcovDataForRange(lines, start_line, end_line, count);
   2022   sink << "FN:" << start_line + 1 << "," << name << std::endl;
   2023   sink << "FNDA:" << count << "," << name << std::endl;
   2024 }
   2025 }  // namespace
   2026 
   2027 // Write coverage data in LCOV format. See man page for geninfo(1).
   2028 void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) {
   2029   if (!file) return;
   2030   HandleScope handle_scope(isolate);
   2031   debug::Coverage coverage = debug::Coverage::CollectPrecise(isolate);
   2032   std::ofstream sink(file, std::ofstream::app);
   2033   for (size_t i = 0; i < coverage.ScriptCount(); i++) {
   2034     debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
   2035     Local<debug::Script> script = script_data.GetScript();
   2036     // Skip unnamed scripts.
   2037     Local<String> name;
   2038     if (!script->Name().ToLocal(&name)) continue;
   2039     std::string file_name = ToSTLString(isolate, name);
   2040     // Skip scripts not backed by a file.
   2041     if (!std::ifstream(file_name).good()) continue;
   2042     sink << "SF:";
   2043     sink << NormalizePath(file_name, GetWorkingDirectory()) << std::endl;
   2044     std::vector<uint32_t> lines;
   2045     for (size_t j = 0; j < script_data.FunctionCount(); j++) {
   2046       debug::Coverage::FunctionData function_data =
   2047           script_data.GetFunctionData(j);
   2048 
   2049       // Write function stats.
   2050       {
   2051         debug::Location start =
   2052             script->GetSourceLocation(function_data.StartOffset());
   2053         debug::Location end =
   2054             script->GetSourceLocation(function_data.EndOffset());
   2055         int start_line = start.GetLineNumber();
   2056         int end_line = end.GetLineNumber();
   2057         uint32_t count = function_data.Count();
   2058 
   2059         Local<String> name;
   2060         std::stringstream name_stream;
   2061         if (function_data.Name().ToLocal(&name)) {
   2062           name_stream << ToSTLString(isolate, name);
   2063         } else {
   2064           name_stream << "<" << start_line + 1 << "-";
   2065           name_stream << start.GetColumnNumber() << ">";
   2066         }
   2067 
   2068         WriteLcovDataForNamedRange(sink, lines, name_stream.str(), start_line,
   2069                                    end_line, count);
   2070       }
   2071 
   2072       // Process inner blocks.
   2073       for (size_t k = 0; k < function_data.BlockCount(); k++) {
   2074         debug::Coverage::BlockData block_data = function_data.GetBlockData(k);
   2075         int start_line = LineFromOffset(script, block_data.StartOffset());
   2076         int end_line = LineFromOffset(script, block_data.EndOffset() - 1);
   2077         uint32_t count = block_data.Count();
   2078         WriteLcovDataForRange(lines, start_line, end_line, count);
   2079       }
   2080     }
   2081     // Write per-line coverage. LCOV uses 1-based line numbers.
   2082     for (size_t i = 0; i < lines.size(); i++) {
   2083       sink << "DA:" << (i + 1) << "," << lines[i] << std::endl;
   2084     }
   2085     sink << "end_of_record" << std::endl;
   2086   }
   2087 }
   2088 
   2089 void Shell::OnExit(v8::Isolate* isolate) {
   2090   // Dump basic block profiling data.
   2091   if (i::FLAG_turbo_profiling) {
   2092     i::BasicBlockProfiler* profiler = i::BasicBlockProfiler::Get();
   2093     i::StdoutStream{} << *profiler;
   2094   }
   2095   isolate->Dispose();
   2096 
   2097   if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp) {
   2098     const int number_of_counters = static_cast<int>(counter_map_->size());
   2099     CounterAndKey* counters = new CounterAndKey[number_of_counters];
   2100     int j = 0;
   2101     for (auto map_entry : *counter_map_) {
   2102       counters[j].counter = map_entry.second;
   2103       counters[j].key = map_entry.first;
   2104       j++;
   2105     }
   2106     std::sort(counters, counters + number_of_counters);
   2107 
   2108     if (i::FLAG_dump_counters_nvp) {
   2109       // Dump counters as name-value pairs.
   2110       for (j = 0; j < number_of_counters; j++) {
   2111         Counter* counter = counters[j].counter;
   2112         const char* key = counters[j].key;
   2113         if (counter->is_histogram()) {
   2114           printf("\"c:%s\"=%i\n", key, counter->count());
   2115           printf("\"t:%s\"=%i\n", key, counter->sample_total());
   2116         } else {
   2117           printf("\"%s\"=%i\n", key, counter->count());
   2118         }
   2119       }
   2120     } else {
   2121       // Dump counters in formatted boxes.
   2122       printf(
   2123           "+----------------------------------------------------------------+"
   2124           "-------------+\n");
   2125       printf(
   2126           "| Name                                                           |"
   2127           " Value       |\n");
   2128       printf(
   2129           "+----------------------------------------------------------------+"
   2130           "-------------+\n");
   2131       for (j = 0; j < number_of_counters; j++) {
   2132         Counter* counter = counters[j].counter;
   2133         const char* key = counters[j].key;
   2134         if (counter->is_histogram()) {
   2135           printf("| c:%-60s | %11i |\n", key, counter->count());
   2136           printf("| t:%-60s | %11i |\n", key, counter->sample_total());
   2137         } else {
   2138           printf("| %-62s | %11i |\n", key, counter->count());
   2139         }
   2140       }
   2141       printf(
   2142           "+----------------------------------------------------------------+"
   2143           "-------------+\n");
   2144     }
   2145     delete [] counters;
   2146   }
   2147 
   2148   delete counters_file_;
   2149   delete counter_map_;
   2150 }
   2151 
   2152 
   2153 static FILE* FOpen(const char* path, const char* mode) {
   2154 #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
   2155   FILE* result;
   2156   if (fopen_s(&result, path, mode) == 0) {
   2157     return result;
   2158   } else {
   2159     return nullptr;
   2160   }
   2161 #else
   2162   FILE* file = fopen(path, mode);
   2163   if (file == nullptr) return nullptr;
   2164   struct stat file_stat;
   2165   if (fstat(fileno(file), &file_stat) != 0) return nullptr;
   2166   bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
   2167   if (is_regular_file) return file;
   2168   fclose(file);
   2169   return nullptr;
   2170 #endif
   2171 }
   2172 
   2173 static char* ReadChars(const char* name, int* size_out) {
   2174   if (Shell::options.read_from_tcp_port >= 0) {
   2175     return Shell::ReadCharsFromTcpPort(name, size_out);
   2176   }
   2177 
   2178   FILE* file = FOpen(name, "rb");
   2179   if (file == nullptr) return nullptr;
   2180 
   2181   fseek(file, 0, SEEK_END);
   2182   size_t size = ftell(file);
   2183   rewind(file);
   2184 
   2185   char* chars = new char[size + 1];
   2186   chars[size] = '\0';
   2187   for (size_t i = 0; i < size;) {
   2188     i += fread(&chars[i], 1, size - i, file);
   2189     if (ferror(file)) {
   2190       fclose(file);
   2191       delete[] chars;
   2192       return nullptr;
   2193     }
   2194   }
   2195   fclose(file);
   2196   *size_out = static_cast<int>(size);
   2197   return chars;
   2198 }
   2199 
   2200 
   2201 struct DataAndPersistent {
   2202   uint8_t* data;
   2203   int byte_length;
   2204   Global<ArrayBuffer> handle;
   2205 };
   2206 
   2207 
   2208 static void ReadBufferWeakCallback(
   2209     const v8::WeakCallbackInfo<DataAndPersistent>& data) {
   2210   int byte_length = data.GetParameter()->byte_length;
   2211   data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
   2212       -static_cast<intptr_t>(byte_length));
   2213 
   2214   delete[] data.GetParameter()->data;
   2215   data.GetParameter()->handle.Reset();
   2216   delete data.GetParameter();
   2217 }
   2218 
   2219 
   2220 void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
   2221   static_assert(sizeof(char) == sizeof(uint8_t),
   2222                 "char and uint8_t should both have 1 byte");
   2223   Isolate* isolate = args.GetIsolate();
   2224   String::Utf8Value filename(isolate, args[0]);
   2225   int length;
   2226   if (*filename == nullptr) {
   2227     Throw(isolate, "Error loading file");
   2228     return;
   2229   }
   2230 
   2231   DataAndPersistent* data = new DataAndPersistent;
   2232   data->data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
   2233   if (data->data == nullptr) {
   2234     delete data;
   2235     Throw(isolate, "Error reading file");
   2236     return;
   2237   }
   2238   data->byte_length = length;
   2239   Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
   2240   data->handle.Reset(isolate, buffer);
   2241   data->handle.SetWeak(data, ReadBufferWeakCallback,
   2242                        v8::WeakCallbackType::kParameter);
   2243   isolate->AdjustAmountOfExternalAllocatedMemory(length);
   2244 
   2245   args.GetReturnValue().Set(buffer);
   2246 }
   2247 
   2248 // Reads a file into a v8 string.
   2249 Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
   2250   int size = 0;
   2251   char* chars = ReadChars(name, &size);
   2252   if (chars == nullptr) return Local<String>();
   2253   Local<String> result;
   2254   if (i::FLAG_use_external_strings && i::String::IsAscii(chars, size)) {
   2255     String::ExternalOneByteStringResource* resource =
   2256         new ExternalOwningOneByteStringResource(
   2257             std::unique_ptr<const char[]>(chars), size);
   2258     result = String::NewExternalOneByte(isolate, resource).ToLocalChecked();
   2259   } else {
   2260     result = String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
   2261                  .ToLocalChecked();
   2262     delete[] chars;
   2263   }
   2264   return result;
   2265 }
   2266 
   2267 
   2268 void Shell::RunShell(Isolate* isolate) {
   2269   HandleScope outer_scope(isolate);
   2270   v8::Local<v8::Context> context =
   2271       v8::Local<v8::Context>::New(isolate, evaluation_context_);
   2272   v8::Context::Scope context_scope(context);
   2273   PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   2274   Local<String> name =
   2275       String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
   2276           .ToLocalChecked();
   2277   printf("V8 version %s\n", V8::GetVersion());
   2278   while (true) {
   2279     HandleScope inner_scope(isolate);
   2280     printf("d8> ");
   2281     Local<String> input = Shell::ReadFromStdin(isolate);
   2282     if (input.IsEmpty()) break;
   2283     ExecuteString(isolate, input, name, kPrintResult, kReportExceptions,
   2284                   kProcessMessageQueue);
   2285   }
   2286   printf("\n");
   2287   // We need to explicitly clean up the module embedder data for
   2288   // the interative shell context.
   2289   DisposeModuleEmbedderData(context);
   2290 }
   2291 
   2292 class InspectorFrontend final : public v8_inspector::V8Inspector::Channel {
   2293  public:
   2294   explicit InspectorFrontend(Local<Context> context) {
   2295     isolate_ = context->GetIsolate();
   2296     context_.Reset(isolate_, context);
   2297   }
   2298   virtual ~InspectorFrontend() = default;
   2299 
   2300  private:
   2301   void sendResponse(
   2302       int callId,
   2303       std::unique_ptr<v8_inspector::StringBuffer> message) override {
   2304     Send(message->string());
   2305   }
   2306   void sendNotification(
   2307       std::unique_ptr<v8_inspector::StringBuffer> message) override {
   2308     Send(message->string());
   2309   }
   2310   void flushProtocolNotifications() override {}
   2311 
   2312   void Send(const v8_inspector::StringView& string) {
   2313     v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate_);
   2314     int length = static_cast<int>(string.length());
   2315     DCHECK_LT(length, v8::String::kMaxLength);
   2316     Local<String> message =
   2317         (string.is8Bit()
   2318              ? v8::String::NewFromOneByte(
   2319                    isolate_,
   2320                    reinterpret_cast<const uint8_t*>(string.characters8()),
   2321                    v8::NewStringType::kNormal, length)
   2322              : v8::String::NewFromTwoByte(
   2323                    isolate_,
   2324                    reinterpret_cast<const uint16_t*>(string.characters16()),
   2325                    v8::NewStringType::kNormal, length))
   2326             .ToLocalChecked();
   2327     Local<String> callback_name =
   2328         v8::String::NewFromUtf8(isolate_, "receive", v8::NewStringType::kNormal)
   2329             .ToLocalChecked();
   2330     Local<Context> context = context_.Get(isolate_);
   2331     Local<Value> callback =
   2332         context->Global()->Get(context, callback_name).ToLocalChecked();
   2333     if (callback->IsFunction()) {
   2334       v8::TryCatch try_catch(isolate_);
   2335       Local<Value> args[] = {message};
   2336       USE(Local<Function>::Cast(callback)->Call(context, Undefined(isolate_), 1,
   2337                                                 args));
   2338 #ifdef DEBUG
   2339       if (try_catch.HasCaught()) {
   2340         Local<Object> exception = Local<Object>::Cast(try_catch.Exception());
   2341         Local<String> key = v8::String::NewFromUtf8(isolate_, "message",
   2342                                                     v8::NewStringType::kNormal)
   2343                                 .ToLocalChecked();
   2344         Local<String> expected =
   2345             v8::String::NewFromUtf8(isolate_,
   2346                                     "Maximum call stack size exceeded",
   2347                                     v8::NewStringType::kNormal)
   2348                 .ToLocalChecked();
   2349         Local<Value> value = exception->Get(context, key).ToLocalChecked();
   2350         DCHECK(value->StrictEquals(expected));
   2351       }
   2352 #endif
   2353     }
   2354   }
   2355 
   2356   Isolate* isolate_;
   2357   Global<Context> context_;
   2358 };
   2359 
   2360 class InspectorClient : public v8_inspector::V8InspectorClient {
   2361  public:
   2362   InspectorClient(Local<Context> context, bool connect) {
   2363     if (!connect) return;
   2364     isolate_ = context->GetIsolate();
   2365     channel_.reset(new InspectorFrontend(context));
   2366     inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
   2367     session_ =
   2368         inspector_->connect(1, channel_.get(), v8_inspector::StringView());
   2369     context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
   2370     inspector_->contextCreated(v8_inspector::V8ContextInfo(
   2371         context, kContextGroupId, v8_inspector::StringView()));
   2372 
   2373     Local<Value> function =
   2374         FunctionTemplate::New(isolate_, SendInspectorMessage)
   2375             ->GetFunction(context)
   2376             .ToLocalChecked();
   2377     Local<String> function_name =
   2378         String::NewFromUtf8(isolate_, "send", NewStringType::kNormal)
   2379             .ToLocalChecked();
   2380     CHECK(context->Global()->Set(context, function_name, function).FromJust());
   2381 
   2382     context_.Reset(isolate_, context);
   2383   }
   2384 
   2385  private:
   2386   static v8_inspector::V8InspectorSession* GetSession(Local<Context> context) {
   2387     InspectorClient* inspector_client = static_cast<InspectorClient*>(
   2388         context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex));
   2389     return inspector_client->session_.get();
   2390   }
   2391 
   2392   Local<Context> ensureDefaultContextInGroup(int group_id) override {
   2393     DCHECK(isolate_);
   2394     DCHECK_EQ(kContextGroupId, group_id);
   2395     return context_.Get(isolate_);
   2396   }
   2397 
   2398   static void SendInspectorMessage(
   2399       const v8::FunctionCallbackInfo<v8::Value>& args) {
   2400     Isolate* isolate = args.GetIsolate();
   2401     v8::HandleScope handle_scope(isolate);
   2402     Local<Context> context = isolate->GetCurrentContext();
   2403     args.GetReturnValue().Set(Undefined(isolate));
   2404     Local<String> message = args[0]->ToString(context).ToLocalChecked();
   2405     v8_inspector::V8InspectorSession* session =
   2406         InspectorClient::GetSession(context);
   2407     int length = message->Length();
   2408     std::unique_ptr<uint16_t[]> buffer(new uint16_t[length]);
   2409     message->Write(isolate, buffer.get(), 0, length);
   2410     v8_inspector::StringView message_view(buffer.get(), length);
   2411     session->dispatchProtocolMessage(message_view);
   2412     args.GetReturnValue().Set(True(isolate));
   2413   }
   2414 
   2415   static const int kContextGroupId = 1;
   2416 
   2417   std::unique_ptr<v8_inspector::V8Inspector> inspector_;
   2418   std::unique_ptr<v8_inspector::V8InspectorSession> session_;
   2419   std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
   2420   Global<Context> context_;
   2421   Isolate* isolate_;
   2422 };
   2423 
   2424 SourceGroup::~SourceGroup() {
   2425   delete thread_;
   2426   thread_ = nullptr;
   2427 }
   2428 
   2429 bool ends_with(const char* input, const char* suffix) {
   2430   size_t input_length = strlen(input);
   2431   size_t suffix_length = strlen(suffix);
   2432   if (suffix_length <= input_length) {
   2433     return strcmp(input + input_length - suffix_length, suffix) == 0;
   2434   }
   2435   return false;
   2436 }
   2437 
   2438 void SourceGroup::Execute(Isolate* isolate) {
   2439   bool exception_was_thrown = false;
   2440   for (int i = begin_offset_; i < end_offset_; ++i) {
   2441     const char* arg = argv_[i];
   2442     if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
   2443       // Execute argument given to -e option directly.
   2444       HandleScope handle_scope(isolate);
   2445       Local<String> file_name =
   2446           String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
   2447               .ToLocalChecked();
   2448       Local<String> source =
   2449           String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
   2450               .ToLocalChecked();
   2451       Shell::set_script_executed();
   2452       if (!Shell::ExecuteString(isolate, source, file_name,
   2453                                 Shell::kNoPrintResult, Shell::kReportExceptions,
   2454                                 Shell::kNoProcessMessageQueue)) {
   2455         exception_was_thrown = true;
   2456         break;
   2457       }
   2458       ++i;
   2459       continue;
   2460     } else if (ends_with(arg, ".mjs")) {
   2461       Shell::set_script_executed();
   2462       if (!Shell::ExecuteModule(isolate, arg)) {
   2463         exception_was_thrown = true;
   2464         break;
   2465       }
   2466       continue;
   2467     } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
   2468       // Treat the next file as a module.
   2469       arg = argv_[++i];
   2470       Shell::set_script_executed();
   2471       if (!Shell::ExecuteModule(isolate, arg)) {
   2472         exception_was_thrown = true;
   2473         break;
   2474       }
   2475       continue;
   2476     } else if (arg[0] == '-') {
   2477       // Ignore other options. They have been parsed already.
   2478       continue;
   2479     }
   2480 
   2481     // Use all other arguments as names of files to load and run.
   2482     HandleScope handle_scope(isolate);
   2483     Local<String> file_name =
   2484         String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
   2485             .ToLocalChecked();
   2486     Local<String> source = ReadFile(isolate, arg);
   2487     if (source.IsEmpty()) {
   2488       printf("Error reading '%s'\n", arg);
   2489       base::OS::ExitProcess(1);
   2490     }
   2491     Shell::set_script_executed();
   2492     if (!Shell::ExecuteString(isolate, source, file_name, Shell::kNoPrintResult,
   2493                               Shell::kReportExceptions,
   2494                               Shell::kProcessMessageQueue)) {
   2495       exception_was_thrown = true;
   2496       break;
   2497     }
   2498   }
   2499   if (exception_was_thrown != Shell::options.expected_to_throw) {
   2500     base::OS::ExitProcess(1);
   2501   }
   2502 }
   2503 
   2504 Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
   2505   return Shell::ReadFile(isolate, name);
   2506 }
   2507 
   2508 SourceGroup::IsolateThread::IsolateThread(SourceGroup* group)
   2509     : base::Thread(GetThreadOptions("IsolateThread")), group_(group) {}
   2510 
   2511 void SourceGroup::ExecuteInThread() {
   2512   Isolate::CreateParams create_params;
   2513   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   2514   Isolate* isolate = Isolate::New(create_params);
   2515   isolate->SetHostImportModuleDynamicallyCallback(
   2516       Shell::HostImportModuleDynamically);
   2517   isolate->SetHostInitializeImportMetaObjectCallback(
   2518       Shell::HostInitializeImportMetaObject);
   2519   Shell::SetWaitUntilDone(isolate, false);
   2520   D8Console console(isolate);
   2521   debug::SetConsoleDelegate(isolate, &console);
   2522   for (int i = 0; i < Shell::options.stress_runs; ++i) {
   2523     next_semaphore_.Wait();
   2524     {
   2525       Isolate::Scope iscope(isolate);
   2526       PerIsolateData data(isolate);
   2527       {
   2528         HandleScope scope(isolate);
   2529         Local<Context> context = Shell::CreateEvaluationContext(isolate);
   2530         {
   2531           Context::Scope cscope(context);
   2532           InspectorClient inspector_client(context,
   2533                                            Shell::options.enable_inspector);
   2534           PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   2535           Execute(isolate);
   2536           Shell::CompleteMessageLoop(isolate);
   2537         }
   2538         DisposeModuleEmbedderData(context);
   2539       }
   2540       Shell::CollectGarbage(isolate);
   2541     }
   2542     done_semaphore_.Signal();
   2543   }
   2544 
   2545   isolate->Dispose();
   2546 }
   2547 
   2548 
   2549 void SourceGroup::StartExecuteInThread() {
   2550   if (thread_ == nullptr) {
   2551     thread_ = new IsolateThread(this);
   2552     thread_->Start();
   2553   }
   2554   next_semaphore_.Signal();
   2555 }
   2556 
   2557 
   2558 void SourceGroup::WaitForThread() {
   2559   if (thread_ == nullptr) return;
   2560   done_semaphore_.Wait();
   2561 }
   2562 
   2563 
   2564 void SourceGroup::JoinThread() {
   2565   if (thread_ == nullptr) return;
   2566   thread_->Join();
   2567 }
   2568 
   2569 ExternalizedContents::~ExternalizedContents() {
   2570   if (data_ != nullptr) {
   2571     deleter_(data_, length_, deleter_data_);
   2572   }
   2573 }
   2574 
   2575 void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) {
   2576   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   2577   data_.push_back(std::move(data));
   2578 }
   2579 
   2580 bool SerializationDataQueue::Dequeue(
   2581     std::unique_ptr<SerializationData>* out_data) {
   2582   out_data->reset();
   2583   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   2584   if (data_.empty()) return false;
   2585   *out_data = std::move(data_[0]);
   2586   data_.erase(data_.begin());
   2587   return true;
   2588 }
   2589 
   2590 
   2591 bool SerializationDataQueue::IsEmpty() {
   2592   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   2593   return data_.empty();
   2594 }
   2595 
   2596 
   2597 void SerializationDataQueue::Clear() {
   2598   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   2599   data_.clear();
   2600 }
   2601 
   2602 Worker::Worker()
   2603     : in_semaphore_(0),
   2604       out_semaphore_(0),
   2605       thread_(nullptr),
   2606       script_(nullptr),
   2607       running_(false) {}
   2608 
   2609 Worker::~Worker() {
   2610   delete thread_;
   2611   thread_ = nullptr;
   2612   delete[] script_;
   2613   script_ = nullptr;
   2614   in_queue_.Clear();
   2615   out_queue_.Clear();
   2616 }
   2617 
   2618 
   2619 void Worker::StartExecuteInThread(const char* script) {
   2620   running_ = true;
   2621   script_ = i::StrDup(script);
   2622   thread_ = new WorkerThread(this);
   2623   thread_->Start();
   2624 }
   2625 
   2626 void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
   2627   in_queue_.Enqueue(std::move(data));
   2628   in_semaphore_.Signal();
   2629 }
   2630 
   2631 std::unique_ptr<SerializationData> Worker::GetMessage() {
   2632   std::unique_ptr<SerializationData> result;
   2633   while (!out_queue_.Dequeue(&result)) {
   2634     // If the worker is no longer running, and there are no messages in the
   2635     // queue, don't expect any more messages from it.
   2636     if (!base::Relaxed_Load(&running_)) break;
   2637     out_semaphore_.Wait();
   2638   }
   2639   return result;
   2640 }
   2641 
   2642 
   2643 void Worker::Terminate() {
   2644   base::Relaxed_Store(&running_, false);
   2645   // Post nullptr to wake the Worker thread message loop, and tell it to stop
   2646   // running.
   2647   PostMessage(nullptr);
   2648 }
   2649 
   2650 
   2651 void Worker::WaitForThread() {
   2652   Terminate();
   2653   thread_->Join();
   2654 }
   2655 
   2656 
   2657 void Worker::ExecuteInThread() {
   2658   Isolate::CreateParams create_params;
   2659   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   2660   Isolate* isolate = Isolate::New(create_params);
   2661   isolate->SetHostImportModuleDynamicallyCallback(
   2662       Shell::HostImportModuleDynamically);
   2663   isolate->SetHostInitializeImportMetaObjectCallback(
   2664       Shell::HostInitializeImportMetaObject);
   2665   D8Console console(isolate);
   2666   debug::SetConsoleDelegate(isolate, &console);
   2667   {
   2668     Isolate::Scope iscope(isolate);
   2669     {
   2670       HandleScope scope(isolate);
   2671       PerIsolateData data(isolate);
   2672       Local<Context> context = Shell::CreateEvaluationContext(isolate);
   2673       {
   2674         Context::Scope cscope(context);
   2675         PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   2676 
   2677         Local<Object> global = context->Global();
   2678         Local<Value> this_value = External::New(isolate, this);
   2679         Local<FunctionTemplate> postmessage_fun_template =
   2680             FunctionTemplate::New(isolate, PostMessageOut, this_value);
   2681 
   2682         Local<Function> postmessage_fun;
   2683         if (postmessage_fun_template->GetFunction(context)
   2684                 .ToLocal(&postmessage_fun)) {
   2685           global->Set(context, String::NewFromUtf8(isolate, "postMessage",
   2686                                                    NewStringType::kNormal)
   2687                                    .ToLocalChecked(),
   2688                       postmessage_fun).FromJust();
   2689         }
   2690 
   2691         // First run the script
   2692         Local<String> file_name =
   2693             String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
   2694                 .ToLocalChecked();
   2695         Local<String> source =
   2696             String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
   2697                 .ToLocalChecked();
   2698         if (Shell::ExecuteString(
   2699                 isolate, source, file_name, Shell::kNoPrintResult,
   2700                 Shell::kReportExceptions, Shell::kProcessMessageQueue)) {
   2701           // Get the message handler
   2702           Local<Value> onmessage =
   2703               global->Get(context, String::NewFromUtf8(isolate, "onmessage",
   2704                                                        NewStringType::kNormal)
   2705                                        .ToLocalChecked()).ToLocalChecked();
   2706           if (onmessage->IsFunction()) {
   2707             Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
   2708             // Now wait for messages
   2709             while (true) {
   2710               in_semaphore_.Wait();
   2711               std::unique_ptr<SerializationData> data;
   2712               if (!in_queue_.Dequeue(&data)) continue;
   2713               if (!data) {
   2714                 break;
   2715               }
   2716               v8::TryCatch try_catch(isolate);
   2717               Local<Value> value;
   2718               if (Shell::DeserializeValue(isolate, std::move(data))
   2719                       .ToLocal(&value)) {
   2720                 Local<Value> argv[] = {value};
   2721                 MaybeLocal<Value> result =
   2722                     onmessage_fun->Call(context, global, 1, argv);
   2723                 USE(result);
   2724               }
   2725               if (try_catch.HasCaught()) {
   2726                 Shell::ReportException(isolate, &try_catch);
   2727               }
   2728             }
   2729           }
   2730         }
   2731       }
   2732       DisposeModuleEmbedderData(context);
   2733     }
   2734     Shell::CollectGarbage(isolate);
   2735   }
   2736   isolate->Dispose();
   2737 
   2738   // Post nullptr to wake the thread waiting on GetMessage() if there is one.
   2739   out_queue_.Enqueue(nullptr);
   2740   out_semaphore_.Signal();
   2741 }
   2742 
   2743 
   2744 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
   2745   Isolate* isolate = args.GetIsolate();
   2746   HandleScope handle_scope(isolate);
   2747 
   2748   if (args.Length() < 1) {
   2749     Throw(isolate, "Invalid argument");
   2750     return;
   2751   }
   2752 
   2753   Local<Value> message = args[0];
   2754   Local<Value> transfer = Undefined(isolate);
   2755   std::unique_ptr<SerializationData> data =
   2756       Shell::SerializeValue(isolate, message, transfer);
   2757   if (data) {
   2758     DCHECK(args.Data()->IsExternal());
   2759     Local<External> this_value = Local<External>::Cast(args.Data());
   2760     Worker* worker = static_cast<Worker*>(this_value->Value());
   2761     worker->out_queue_.Enqueue(std::move(data));
   2762     worker->out_semaphore_.Signal();
   2763   }
   2764 }
   2765 
   2766 
   2767 void SetFlagsFromString(const char* flags) {
   2768   v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
   2769 }
   2770 
   2771 
   2772 bool Shell::SetOptions(int argc, char* argv[]) {
   2773   bool logfile_per_isolate = false;
   2774   for (int i = 0; i < argc; i++) {
   2775     if (strcmp(argv[i], "--stress-opt") == 0) {
   2776       options.stress_opt = true;
   2777       argv[i] = nullptr;
   2778     } else if (strcmp(argv[i], "--nostress-opt") == 0 ||
   2779                strcmp(argv[i], "--no-stress-opt") == 0) {
   2780       options.stress_opt = false;
   2781       argv[i] = nullptr;
   2782     } else if (strcmp(argv[i], "--stress-deopt") == 0) {
   2783       options.stress_deopt = true;
   2784       argv[i] = nullptr;
   2785     } else if (strcmp(argv[i], "--stress-background-compile") == 0) {
   2786       options.stress_background_compile = true;
   2787       argv[i] = nullptr;
   2788     } else if (strcmp(argv[i], "--nostress-background-compile") == 0 ||
   2789                strcmp(argv[i], "--no-stress-background-compile") == 0) {
   2790       options.stress_background_compile = false;
   2791       argv[i] = nullptr;
   2792     } else if (strcmp(argv[i], "--noalways-opt") == 0 ||
   2793                strcmp(argv[i], "--no-always-opt") == 0) {
   2794       // No support for stressing if we can't use --always-opt.
   2795       options.stress_opt = false;
   2796       options.stress_deopt = false;
   2797     } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
   2798       logfile_per_isolate = true;
   2799       argv[i] = nullptr;
   2800     } else if (strcmp(argv[i], "--shell") == 0) {
   2801       options.interactive_shell = true;
   2802       argv[i] = nullptr;
   2803     } else if (strcmp(argv[i], "--test") == 0) {
   2804       options.test_shell = true;
   2805       argv[i] = nullptr;
   2806     } else if (strcmp(argv[i], "--notest") == 0 ||
   2807                strcmp(argv[i], "--no-test") == 0) {
   2808       options.test_shell = false;
   2809       argv[i] = nullptr;
   2810     } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
   2811       options.send_idle_notification = true;
   2812       argv[i] = nullptr;
   2813     } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
   2814       options.invoke_weak_callbacks = true;
   2815       // TODO(jochen) See issue 3351
   2816       options.send_idle_notification = true;
   2817       argv[i] = nullptr;
   2818     } else if (strcmp(argv[i], "--omit-quit") == 0) {
   2819       options.omit_quit = true;
   2820       argv[i] = nullptr;
   2821     } else if (strcmp(argv[i], "--no-wait-for-wasm") == 0) {
   2822       // TODO(herhut) Remove this flag once wasm compilation is fully
   2823       // isolate-independent.
   2824       options.wait_for_wasm = false;
   2825       argv[i] = nullptr;
   2826     } else if (strcmp(argv[i], "-f") == 0) {
   2827       // Ignore any -f flags for compatibility with other stand-alone
   2828       // JavaScript engines.
   2829       continue;
   2830     } else if (strcmp(argv[i], "--isolate") == 0) {
   2831       options.num_isolates++;
   2832     } else if (strcmp(argv[i], "--throws") == 0) {
   2833       options.expected_to_throw = true;
   2834       argv[i] = nullptr;
   2835     } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
   2836       options.icu_data_file = argv[i] + 16;
   2837       argv[i] = nullptr;
   2838 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   2839     } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
   2840       options.natives_blob = argv[i] + 15;
   2841       argv[i] = nullptr;
   2842     } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
   2843       options.snapshot_blob = argv[i] + 16;
   2844       argv[i] = nullptr;
   2845 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
   2846     } else if (strcmp(argv[i], "--cache") == 0 ||
   2847                strncmp(argv[i], "--cache=", 8) == 0) {
   2848       const char* value = argv[i] + 7;
   2849       if (!*value || strncmp(value, "=code", 6) == 0) {
   2850         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
   2851         options.code_cache_options =
   2852             ShellOptions::CodeCacheOptions::kProduceCache;
   2853       } else if (strncmp(value, "=none", 6) == 0) {
   2854         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
   2855         options.code_cache_options =
   2856             ShellOptions::CodeCacheOptions::kNoProduceCache;
   2857       } else if (strncmp(value, "=after-execute", 15) == 0) {
   2858         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
   2859         options.code_cache_options =
   2860             ShellOptions::CodeCacheOptions::kProduceCacheAfterExecute;
   2861       } else if (strncmp(value, "=full-code-cache", 17) == 0) {
   2862         options.compile_options = v8::ScriptCompiler::kEagerCompile;
   2863         options.code_cache_options =
   2864             ShellOptions::CodeCacheOptions::kProduceCache;
   2865       } else {
   2866         printf("Unknown option to --cache.\n");
   2867         return false;
   2868       }
   2869       argv[i] = nullptr;
   2870     } else if (strcmp(argv[i], "--enable-tracing") == 0) {
   2871       options.trace_enabled = true;
   2872       argv[i] = nullptr;
   2873     } else if (strncmp(argv[i], "--trace-path=", 13) == 0) {
   2874       options.trace_path = argv[i] + 13;
   2875       argv[i] = nullptr;
   2876     } else if (strncmp(argv[i], "--trace-config=", 15) == 0) {
   2877       options.trace_config = argv[i] + 15;
   2878       argv[i] = nullptr;
   2879     } else if (strcmp(argv[i], "--enable-inspector") == 0) {
   2880       options.enable_inspector = true;
   2881       argv[i] = nullptr;
   2882     } else if (strncmp(argv[i], "--lcov=", 7) == 0) {
   2883       options.lcov_file = argv[i] + 7;
   2884       argv[i] = nullptr;
   2885     } else if (strcmp(argv[i], "--disable-in-process-stack-traces") == 0) {
   2886       options.disable_in_process_stack_traces = true;
   2887       argv[i] = nullptr;
   2888 #ifdef V8_OS_POSIX
   2889     } else if (strncmp(argv[i], "--read-from-tcp-port=", 21) == 0) {
   2890       options.read_from_tcp_port = atoi(argv[i] + 21);
   2891       argv[i] = nullptr;
   2892 #endif  // V8_OS_POSIX
   2893     } else if (strcmp(argv[i], "--enable-os-system") == 0) {
   2894       options.enable_os_system = true;
   2895       argv[i] = nullptr;
   2896     } else if (strcmp(argv[i], "--quiet-load") == 0) {
   2897       options.quiet_load = true;
   2898       argv[i] = nullptr;
   2899     } else if (strncmp(argv[i], "--thread-pool-size=", 19) == 0) {
   2900       options.thread_pool_size = atoi(argv[i] + 19);
   2901       argv[i] = nullptr;
   2902     }
   2903   }
   2904 
   2905   v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
   2906   options.mock_arraybuffer_allocator = i::FLAG_mock_arraybuffer_allocator;
   2907 
   2908   // Set up isolated source groups.
   2909   options.isolate_sources = new SourceGroup[options.num_isolates];
   2910   SourceGroup* current = options.isolate_sources;
   2911   current->Begin(argv, 1);
   2912   for (int i = 1; i < argc; i++) {
   2913     const char* str = argv[i];
   2914     if (strcmp(str, "--isolate") == 0) {
   2915       current->End(i);
   2916       current++;
   2917       current->Begin(argv, i + 1);
   2918     } else if (strcmp(str, "--module") == 0) {
   2919       // Pass on to SourceGroup, which understands this option.
   2920     } else if (strncmp(str, "--", 2) == 0) {
   2921       printf("Warning: unknown flag %s.\nTry --help for options\n", str);
   2922     } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
   2923       set_script_executed();
   2924     } else if (strncmp(str, "-", 1) != 0) {
   2925       // Not a flag, so it must be a script to execute.
   2926       set_script_executed();
   2927     }
   2928   }
   2929   current->End(argc);
   2930 
   2931   if (!logfile_per_isolate && options.num_isolates) {
   2932     SetFlagsFromString("--nologfile_per_isolate");
   2933   }
   2934 
   2935   return true;
   2936 }
   2937 
   2938 int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
   2939   for (int i = 1; i < options.num_isolates; ++i) {
   2940     options.isolate_sources[i].StartExecuteInThread();
   2941   }
   2942   {
   2943     SetWaitUntilDone(isolate, false);
   2944     if (options.lcov_file) {
   2945       debug::Coverage::SelectMode(isolate, debug::Coverage::kBlockCount);
   2946     }
   2947     HandleScope scope(isolate);
   2948     Local<Context> context = CreateEvaluationContext(isolate);
   2949     bool use_existing_context = last_run && use_interactive_shell();
   2950     if (use_existing_context) {
   2951       // Keep using the same context in the interactive shell.
   2952       evaluation_context_.Reset(isolate, context);
   2953     }
   2954     {
   2955       Context::Scope cscope(context);
   2956       InspectorClient inspector_client(context, options.enable_inspector);
   2957       PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   2958       options.isolate_sources[0].Execute(isolate);
   2959       CompleteMessageLoop(isolate);
   2960     }
   2961     if (!use_existing_context) {
   2962       DisposeModuleEmbedderData(context);
   2963     }
   2964     WriteLcovData(isolate, options.lcov_file);
   2965   }
   2966   CollectGarbage(isolate);
   2967   for (int i = 1; i < options.num_isolates; ++i) {
   2968     if (last_run) {
   2969       options.isolate_sources[i].JoinThread();
   2970     } else {
   2971       options.isolate_sources[i].WaitForThread();
   2972     }
   2973   }
   2974   CleanupWorkers();
   2975   return 0;
   2976 }
   2977 
   2978 
   2979 void Shell::CollectGarbage(Isolate* isolate) {
   2980   if (options.send_idle_notification) {
   2981     const double kLongIdlePauseInSeconds = 1.0;
   2982     isolate->ContextDisposedNotification();
   2983     isolate->IdleNotificationDeadline(
   2984         g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
   2985   }
   2986   if (options.invoke_weak_callbacks) {
   2987     // By sending a low memory notifications, we will try hard to collect all
   2988     // garbage and will therefore also invoke all weak callbacks of actually
   2989     // unreachable persistent handles.
   2990     isolate->LowMemoryNotification();
   2991   }
   2992 }
   2993 
   2994 void Shell::SetWaitUntilDone(Isolate* isolate, bool value) {
   2995   base::LockGuard<base::Mutex> guard(isolate_status_lock_.Pointer());
   2996   if (isolate_status_.count(isolate) == 0) {
   2997     isolate_status_.insert(std::make_pair(isolate, value));
   2998   } else {
   2999     isolate_status_[isolate] = value;
   3000   }
   3001 }
   3002 
   3003 namespace {
   3004 bool ProcessMessages(Isolate* isolate,
   3005                      std::function<platform::MessageLoopBehavior()> behavior) {
   3006   Platform* platform = GetDefaultPlatform();
   3007   while (true) {
   3008     while (v8::platform::PumpMessageLoop(platform, isolate, behavior())) {
   3009       isolate->RunMicrotasks();
   3010     }
   3011     if (platform->IdleTasksEnabled(isolate)) {
   3012       v8::platform::RunIdleTasks(platform, isolate,
   3013                                  50.0 / base::Time::kMillisecondsPerSecond);
   3014     }
   3015     HandleScope handle_scope(isolate);
   3016     PerIsolateData* data = PerIsolateData::Get(isolate);
   3017     Local<Function> callback;
   3018     if (!data->GetTimeoutCallback().ToLocal(&callback)) break;
   3019     Local<Context> context;
   3020     if (!data->GetTimeoutContext().ToLocal(&context)) break;
   3021     TryCatch try_catch(isolate);
   3022     try_catch.SetVerbose(true);
   3023     Context::Scope context_scope(context);
   3024     if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) {
   3025       Shell::ReportException(isolate, &try_catch);
   3026       return false;
   3027     }
   3028   }
   3029   return true;
   3030 }
   3031 }  // anonymous namespace
   3032 
   3033 void Shell::CompleteMessageLoop(Isolate* isolate) {
   3034   auto get_waiting_behaviour = [isolate]() {
   3035     base::LockGuard<base::Mutex> guard(isolate_status_lock_.Pointer());
   3036     DCHECK_GT(isolate_status_.count(isolate), 0);
   3037     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   3038     i::wasm::WasmEngine* wasm_engine = i_isolate->wasm_engine();
   3039     bool should_wait = (options.wait_for_wasm &&
   3040                         wasm_engine->HasRunningCompileJob(i_isolate)) ||
   3041                        isolate_status_[isolate];
   3042     return should_wait ? platform::MessageLoopBehavior::kWaitForWork
   3043                        : platform::MessageLoopBehavior::kDoNotWait;
   3044   };
   3045   ProcessMessages(isolate, get_waiting_behaviour);
   3046 }
   3047 
   3048 bool Shell::EmptyMessageQueues(Isolate* isolate) {
   3049   return ProcessMessages(
   3050       isolate, []() { return platform::MessageLoopBehavior::kDoNotWait; });
   3051 }
   3052 
   3053 class Serializer : public ValueSerializer::Delegate {
   3054  public:
   3055   explicit Serializer(Isolate* isolate)
   3056       : isolate_(isolate),
   3057         serializer_(isolate, this),
   3058         current_memory_usage_(0) {}
   3059 
   3060   Maybe<bool> WriteValue(Local<Context> context, Local<Value> value,
   3061                          Local<Value> transfer) {
   3062     bool ok;
   3063     DCHECK(!data_);
   3064     data_.reset(new SerializationData);
   3065     if (!PrepareTransfer(context, transfer).To(&ok)) {
   3066       return Nothing<bool>();
   3067     }
   3068     serializer_.WriteHeader();
   3069 
   3070     if (!serializer_.WriteValue(context, value).To(&ok)) {
   3071       data_.reset();
   3072       return Nothing<bool>();
   3073     }
   3074 
   3075     if (!FinalizeTransfer().To(&ok)) {
   3076       return Nothing<bool>();
   3077     }
   3078 
   3079     std::pair<uint8_t*, size_t> pair = serializer_.Release();
   3080     data_->data_.reset(pair.first);
   3081     data_->size_ = pair.second;
   3082     return Just(true);
   3083   }
   3084 
   3085   std::unique_ptr<SerializationData> Release() { return std::move(data_); }
   3086 
   3087   void AppendExternalizedContentsTo(std::vector<ExternalizedContents>* to) {
   3088     to->insert(to->end(),
   3089                std::make_move_iterator(externalized_contents_.begin()),
   3090                std::make_move_iterator(externalized_contents_.end()));
   3091     externalized_contents_.clear();
   3092   }
   3093 
   3094  protected:
   3095   // Implements ValueSerializer::Delegate.
   3096   void ThrowDataCloneError(Local<String> message) override {
   3097     isolate_->ThrowException(Exception::Error(message));
   3098   }
   3099 
   3100   Maybe<uint32_t> GetSharedArrayBufferId(
   3101       Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override {
   3102     DCHECK_NOT_NULL(data_);
   3103     for (size_t index = 0; index < shared_array_buffers_.size(); ++index) {
   3104       if (shared_array_buffers_[index] == shared_array_buffer) {
   3105         return Just<uint32_t>(static_cast<uint32_t>(index));
   3106       }
   3107     }
   3108 
   3109     size_t index = shared_array_buffers_.size();
   3110     shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
   3111     data_->shared_array_buffer_contents_.push_back(
   3112         MaybeExternalize(shared_array_buffer));
   3113     return Just<uint32_t>(static_cast<uint32_t>(index));
   3114   }
   3115 
   3116   Maybe<uint32_t> GetWasmModuleTransferId(
   3117       Isolate* isolate, Local<WasmCompiledModule> module) override {
   3118     DCHECK_NOT_NULL(data_);
   3119     for (size_t index = 0; index < wasm_modules_.size(); ++index) {
   3120       if (wasm_modules_[index] == module) {
   3121         return Just<uint32_t>(static_cast<uint32_t>(index));
   3122       }
   3123     }
   3124 
   3125     size_t index = wasm_modules_.size();
   3126     wasm_modules_.emplace_back(isolate_, module);
   3127     data_->transferrable_modules_.push_back(module->GetTransferrableModule());
   3128     return Just<uint32_t>(static_cast<uint32_t>(index));
   3129   }
   3130 
   3131   void* ReallocateBufferMemory(void* old_buffer, size_t size,
   3132                                size_t* actual_size) override {
   3133     // Not accurate, because we don't take into account reallocated buffers,
   3134     // but this is fine for testing.
   3135     current_memory_usage_ += size;
   3136     if (current_memory_usage_ > kMaxSerializerMemoryUsage) return nullptr;
   3137 
   3138     void* result = realloc(old_buffer, size);
   3139     *actual_size = result ? size : 0;
   3140     return result;
   3141   }
   3142 
   3143   void FreeBufferMemory(void* buffer) override { free(buffer); }
   3144 
   3145  private:
   3146   Maybe<bool> PrepareTransfer(Local<Context> context, Local<Value> transfer) {
   3147     if (transfer->IsArray()) {
   3148       Local<Array> transfer_array = Local<Array>::Cast(transfer);
   3149       uint32_t length = transfer_array->Length();
   3150       for (uint32_t i = 0; i < length; ++i) {
   3151         Local<Value> element;
   3152         if (transfer_array->Get(context, i).ToLocal(&element)) {
   3153           if (!element->IsArrayBuffer()) {
   3154             Throw(isolate_, "Transfer array elements must be an ArrayBuffer");
   3155             return Nothing<bool>();
   3156           }
   3157 
   3158           Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(element);
   3159           serializer_.TransferArrayBuffer(
   3160               static_cast<uint32_t>(array_buffers_.size()), array_buffer);
   3161           array_buffers_.emplace_back(isolate_, array_buffer);
   3162         } else {
   3163           return Nothing<bool>();
   3164         }
   3165       }
   3166       return Just(true);
   3167     } else if (transfer->IsUndefined()) {
   3168       return Just(true);
   3169     } else {
   3170       Throw(isolate_, "Transfer list must be an Array or undefined");
   3171       return Nothing<bool>();
   3172     }
   3173   }
   3174 
   3175   template <typename T>
   3176   typename T::Contents MaybeExternalize(Local<T> array_buffer) {
   3177     if (array_buffer->IsExternal()) {
   3178       return array_buffer->GetContents();
   3179     } else {
   3180       typename T::Contents contents = array_buffer->Externalize();
   3181       externalized_contents_.emplace_back(contents);
   3182       return contents;
   3183     }
   3184   }
   3185 
   3186   Maybe<bool> FinalizeTransfer() {
   3187     for (const auto& global_array_buffer : array_buffers_) {
   3188       Local<ArrayBuffer> array_buffer =
   3189           Local<ArrayBuffer>::New(isolate_, global_array_buffer);
   3190       if (!array_buffer->IsNeuterable()) {
   3191         Throw(isolate_, "ArrayBuffer could not be transferred");
   3192         return Nothing<bool>();
   3193       }
   3194 
   3195       ArrayBuffer::Contents contents = MaybeExternalize(array_buffer);
   3196       array_buffer->Neuter();
   3197       data_->array_buffer_contents_.push_back(contents);
   3198     }
   3199 
   3200     return Just(true);
   3201   }
   3202 
   3203   Isolate* isolate_;
   3204   ValueSerializer serializer_;
   3205   std::unique_ptr<SerializationData> data_;
   3206   std::vector<Global<ArrayBuffer>> array_buffers_;
   3207   std::vector<Global<SharedArrayBuffer>> shared_array_buffers_;
   3208   std::vector<Global<WasmCompiledModule>> wasm_modules_;
   3209   std::vector<ExternalizedContents> externalized_contents_;
   3210   size_t current_memory_usage_;
   3211 
   3212   DISALLOW_COPY_AND_ASSIGN(Serializer);
   3213 };
   3214 
   3215 class Deserializer : public ValueDeserializer::Delegate {
   3216  public:
   3217   Deserializer(Isolate* isolate, std::unique_ptr<SerializationData> data)
   3218       : isolate_(isolate),
   3219         deserializer_(isolate, data->data(), data->size(), this),
   3220         data_(std::move(data)) {
   3221     deserializer_.SetSupportsLegacyWireFormat(true);
   3222   }
   3223 
   3224   MaybeLocal<Value> ReadValue(Local<Context> context) {
   3225     bool read_header;
   3226     if (!deserializer_.ReadHeader(context).To(&read_header)) {
   3227       return MaybeLocal<Value>();
   3228     }
   3229 
   3230     uint32_t index = 0;
   3231     for (const auto& contents : data_->array_buffer_contents()) {
   3232       Local<ArrayBuffer> array_buffer =
   3233           ArrayBuffer::New(isolate_, contents.Data(), contents.ByteLength());
   3234       deserializer_.TransferArrayBuffer(index++, array_buffer);
   3235     }
   3236 
   3237     return deserializer_.ReadValue(context);
   3238   }
   3239 
   3240   MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
   3241       Isolate* isolate, uint32_t clone_id) override {
   3242     DCHECK_NOT_NULL(data_);
   3243     if (clone_id < data_->shared_array_buffer_contents().size()) {
   3244       SharedArrayBuffer::Contents contents =
   3245           data_->shared_array_buffer_contents().at(clone_id);
   3246       return SharedArrayBuffer::New(isolate_, contents.Data(),
   3247                                     contents.ByteLength());
   3248     }
   3249     return MaybeLocal<SharedArrayBuffer>();
   3250   }
   3251 
   3252   MaybeLocal<WasmCompiledModule> GetWasmModuleFromId(
   3253       Isolate* isolate, uint32_t transfer_id) override {
   3254     DCHECK_NOT_NULL(data_);
   3255     if (transfer_id < data_->transferrable_modules().size()) {
   3256       return WasmCompiledModule::FromTransferrableModule(
   3257           isolate_, data_->transferrable_modules().at(transfer_id));
   3258     }
   3259     return MaybeLocal<WasmCompiledModule>();
   3260   }
   3261 
   3262  private:
   3263   Isolate* isolate_;
   3264   ValueDeserializer deserializer_;
   3265   std::unique_ptr<SerializationData> data_;
   3266 
   3267   DISALLOW_COPY_AND_ASSIGN(Deserializer);
   3268 };
   3269 
   3270 std::unique_ptr<SerializationData> Shell::SerializeValue(
   3271     Isolate* isolate, Local<Value> value, Local<Value> transfer) {
   3272   bool ok;
   3273   Local<Context> context = isolate->GetCurrentContext();
   3274   Serializer serializer(isolate);
   3275   std::unique_ptr<SerializationData> data;
   3276   if (serializer.WriteValue(context, value, transfer).To(&ok)) {
   3277     data = serializer.Release();
   3278   }
   3279   // Append externalized contents even when WriteValue fails.
   3280   base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   3281   serializer.AppendExternalizedContentsTo(&externalized_contents_);
   3282   return data;
   3283 }
   3284 
   3285 MaybeLocal<Value> Shell::DeserializeValue(
   3286     Isolate* isolate, std::unique_ptr<SerializationData> data) {
   3287   Local<Value> value;
   3288   Local<Context> context = isolate->GetCurrentContext();
   3289   Deserializer deserializer(isolate, std::move(data));
   3290   return deserializer.ReadValue(context);
   3291 }
   3292 
   3293 
   3294 void Shell::CleanupWorkers() {
   3295   // Make a copy of workers_, because we don't want to call Worker::Terminate
   3296   // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
   3297   // create a new Worker, it would deadlock.
   3298   std::vector<Worker*> workers_copy;
   3299   {
   3300     base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   3301     allow_new_workers_ = false;
   3302     workers_copy.swap(workers_);
   3303   }
   3304 
   3305   for (Worker* worker : workers_copy) {
   3306     worker->WaitForThread();
   3307     delete worker;
   3308   }
   3309 
   3310   // Now that all workers are terminated, we can re-enable Worker creation.
   3311   base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   3312   allow_new_workers_ = true;
   3313   externalized_contents_.clear();
   3314 }
   3315 
   3316 int Shell::Main(int argc, char* argv[]) {
   3317   std::ofstream trace_file;
   3318   v8::base::EnsureConsoleOutput();
   3319   if (!SetOptions(argc, argv)) return 1;
   3320   v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
   3321 
   3322   v8::platform::InProcessStackDumping in_process_stack_dumping =
   3323       options.disable_in_process_stack_traces
   3324           ? v8::platform::InProcessStackDumping::kDisabled
   3325           : v8::platform::InProcessStackDumping::kEnabled;
   3326 
   3327   std::unique_ptr<platform::tracing::TracingController> tracing;
   3328   if (options.trace_enabled && !i::FLAG_verify_predictable) {
   3329     tracing = base::make_unique<platform::tracing::TracingController>();
   3330 
   3331     trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json");
   3332     platform::tracing::TraceBuffer* trace_buffer =
   3333         platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
   3334             platform::tracing::TraceBuffer::kRingBufferChunks,
   3335             platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
   3336     tracing->Initialize(trace_buffer);
   3337   }
   3338 
   3339   platform::tracing::TracingController* tracing_controller = tracing.get();
   3340   g_platform = v8::platform::NewDefaultPlatform(
   3341       options.thread_pool_size, v8::platform::IdleTaskSupport::kEnabled,
   3342       in_process_stack_dumping, std::move(tracing));
   3343   if (i::FLAG_verify_predictable) {
   3344     g_platform.reset(new PredictablePlatform(std::move(g_platform)));
   3345   }
   3346 
   3347   v8::V8::InitializePlatform(g_platform.get());
   3348   v8::V8::Initialize();
   3349   if (options.natives_blob || options.snapshot_blob) {
   3350     v8::V8::InitializeExternalStartupData(options.natives_blob,
   3351                                           options.snapshot_blob);
   3352   } else {
   3353     v8::V8::InitializeExternalStartupData(argv[0]);
   3354   }
   3355   if (i::FLAG_trace_turbo_cfg_file == nullptr) {
   3356     SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
   3357   }
   3358   if (i::FLAG_redirect_code_traces_to == nullptr) {
   3359     SetFlagsFromString("--redirect-code-traces-to=code.asm");
   3360   }
   3361   int result = 0;
   3362   Isolate::CreateParams create_params;
   3363   ShellArrayBufferAllocator shell_array_buffer_allocator;
   3364   MockArrayBufferAllocator mock_arraybuffer_allocator;
   3365   if (options.mock_arraybuffer_allocator) {
   3366     Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
   3367   } else {
   3368     Shell::array_buffer_allocator = &shell_array_buffer_allocator;
   3369   }
   3370   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   3371 #ifdef ENABLE_VTUNE_JIT_INTERFACE
   3372   create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
   3373 #endif
   3374   create_params.constraints.ConfigureDefaults(
   3375       base::SysInfo::AmountOfPhysicalMemory(),
   3376       base::SysInfo::AmountOfVirtualMemory());
   3377 
   3378   Shell::counter_map_ = new CounterMap();
   3379   if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp || i::FLAG_gc_stats) {
   3380     create_params.counter_lookup_callback = LookupCounter;
   3381     create_params.create_histogram_callback = CreateHistogram;
   3382     create_params.add_histogram_sample_callback = AddHistogramSample;
   3383   }
   3384 
   3385   if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
   3386     constexpr bool use_default_trap_handler = true;
   3387     if (!v8::V8::EnableWebAssemblyTrapHandler(use_default_trap_handler)) {
   3388       FATAL("Could not register trap handler");
   3389     }
   3390   }
   3391 
   3392   Isolate* isolate = Isolate::New(create_params);
   3393   isolate->SetHostImportModuleDynamicallyCallback(
   3394       Shell::HostImportModuleDynamically);
   3395   isolate->SetHostInitializeImportMetaObjectCallback(
   3396       Shell::HostInitializeImportMetaObject);
   3397 
   3398   D8Console console(isolate);
   3399   {
   3400     Isolate::Scope scope(isolate);
   3401     Initialize(isolate);
   3402     PerIsolateData data(isolate);
   3403     debug::SetConsoleDelegate(isolate, &console);
   3404 
   3405     if (options.trace_enabled) {
   3406       platform::tracing::TraceConfig* trace_config;
   3407       if (options.trace_config) {
   3408         int size = 0;
   3409         char* trace_config_json_str = ReadChars(options.trace_config, &size);
   3410         trace_config =
   3411             tracing::CreateTraceConfigFromJSON(isolate, trace_config_json_str);
   3412         delete[] trace_config_json_str;
   3413       } else {
   3414         trace_config =
   3415             platform::tracing::TraceConfig::CreateDefaultTraceConfig();
   3416       }
   3417       tracing_controller->StartTracing(trace_config);
   3418     }
   3419 
   3420     if (options.stress_opt || options.stress_deopt) {
   3421       Testing::SetStressRunType(options.stress_opt
   3422                                 ? Testing::kStressTypeOpt
   3423                                 : Testing::kStressTypeDeopt);
   3424       options.stress_runs = Testing::GetStressRuns();
   3425       for (int i = 0; i < options.stress_runs && result == 0; i++) {
   3426         printf("============ Stress %d/%d ============\n", i + 1,
   3427                options.stress_runs);
   3428         Testing::PrepareStressRun(i);
   3429         bool last_run = i == options.stress_runs - 1;
   3430         result = RunMain(isolate, argc, argv, last_run);
   3431       }
   3432       printf("======== Full Deoptimization =======\n");
   3433       Testing::DeoptimizeAll(isolate);
   3434     } else if (i::FLAG_stress_runs > 0) {
   3435       options.stress_runs = i::FLAG_stress_runs;
   3436       for (int i = 0; i < options.stress_runs && result == 0; i++) {
   3437         printf("============ Run %d/%d ============\n", i + 1,
   3438                options.stress_runs);
   3439         bool last_run = i == options.stress_runs - 1;
   3440         result = RunMain(isolate, argc, argv, last_run);
   3441       }
   3442     } else if (options.code_cache_options !=
   3443                ShellOptions::CodeCacheOptions::kNoProduceCache) {
   3444       printf("============ Run: Produce code cache ============\n");
   3445       // First run to produce the cache
   3446       Isolate::CreateParams create_params;
   3447       create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   3448       i::FLAG_hash_seed ^= 1337;  // Use a different hash seed.
   3449       Isolate* isolate2 = Isolate::New(create_params);
   3450       i::FLAG_hash_seed ^= 1337;  // Restore old hash seed.
   3451       isolate2->SetHostImportModuleDynamicallyCallback(
   3452           Shell::HostImportModuleDynamically);
   3453       isolate2->SetHostInitializeImportMetaObjectCallback(
   3454           Shell::HostInitializeImportMetaObject);
   3455       {
   3456         D8Console console(isolate2);
   3457         debug::SetConsoleDelegate(isolate2, &console);
   3458         PerIsolateData data(isolate2);
   3459         Isolate::Scope isolate_scope(isolate2);
   3460 
   3461         result = RunMain(isolate2, argc, argv, false);
   3462       }
   3463       isolate2->Dispose();
   3464 
   3465       // Change the options to consume cache
   3466       DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
   3467              options.compile_options == v8::ScriptCompiler::kNoCompileOptions);
   3468       options.compile_options = v8::ScriptCompiler::kConsumeCodeCache;
   3469 
   3470       printf("============ Run: Consume code cache ============\n");
   3471       // Second run to consume the cache in current isolate
   3472       result = RunMain(isolate, argc, argv, true);
   3473       options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
   3474     } else {
   3475       bool last_run = true;
   3476       result = RunMain(isolate, argc, argv, last_run);
   3477     }
   3478 
   3479     // Run interactive shell if explicitly requested or if no script has been
   3480     // executed, but never on --test
   3481     if (use_interactive_shell()) {
   3482       RunShell(isolate);
   3483     }
   3484 
   3485     if (i::FLAG_trace_ignition_dispatches &&
   3486         i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
   3487       WriteIgnitionDispatchCountersFile(isolate);
   3488     }
   3489 
   3490     // Shut down contexts and collect garbage.
   3491     cached_code_map_.clear();
   3492     evaluation_context_.Reset();
   3493     stringify_function_.Reset();
   3494     CollectGarbage(isolate);
   3495   }
   3496   OnExit(isolate);
   3497   V8::Dispose();
   3498   V8::ShutdownPlatform();
   3499 
   3500   // Delete the platform explicitly here to write the tracing output to the
   3501   // tracing file.
   3502   g_platform.reset();
   3503   return result;
   3504 }
   3505 
   3506 }  // namespace v8
   3507 
   3508 
   3509 #ifndef GOOGLE3
   3510 int main(int argc, char* argv[]) {
   3511   return v8::Shell::Main(argc, argv);
   3512 }
   3513 #endif
   3514 
   3515 #undef CHECK
   3516 #undef DCHECK
   3517