LCOV - code coverage report
Current view: top level - src - d8.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1230 1636 75.2 %
Date: 2019-01-20 Functions: 147 204 72.1 %

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

Generated by: LCOV version 1.10