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

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

Generated by: LCOV version 1.10