LCOV - code coverage report
Current view: top level - src - d8.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1270 1677 75.7 %
Date: 2019-03-21 Functions: 140 200 70.0 %

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

Generated by: LCOV version 1.10