LCOV - code coverage report
Current view: top level - src - d8.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1276 1697 75.2 %
Date: 2019-04-17 Functions: 140 201 69.7 %

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

Generated by: LCOV version 1.10