LCOV - code coverage report
Current view: top level - src - d8.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1227 1640 74.8 %
Date: 2019-02-19 Functions: 146 204 71.6 %

          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      177276 : class ArrayBufferAllocatorBase : public v8::ArrayBuffer::Allocator {
      76             :  public:
      77           0 :   void* Allocate(size_t length) override {
      78      213168 :     return allocator_->Allocate(length);
      79             :   }
      80             : 
      81           0 :   void* AllocateUninitialized(size_t length) override {
      82       11551 :     return allocator_->AllocateUninitialized(length);
      83             :   }
      84             : 
      85           0 :   void Free(void* data, size_t length) override {
      86      224717 :     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       59092 : class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
      96             :  public:
      97      213913 :   void* Allocate(size_t length) override {
      98      213913 :     if (length >= kVMThreshold) return AllocateVM(length);
      99      213071 :     return ArrayBufferAllocatorBase::Allocate(length);
     100             :   }
     101             : 
     102       11569 :   void* AllocateUninitialized(size_t length) override {
     103       11569 :     if (length >= kVMThreshold) return AllocateVM(length);
     104       11551 :     return ArrayBufferAllocatorBase::AllocateUninitialized(length);
     105             :   }
     106             : 
     107      225436 :   void Free(void* data, size_t length) override {
     108      225436 :     if (length >= kVMThreshold) {
     109         818 :       FreeVM(data, length);
     110             :     } else {
     111             :       ArrayBufferAllocatorBase::Free(data, length);
     112             :     }
     113      225441 :   }
     114             : 
     115             :  private:
     116             :   static constexpr size_t kVMThreshold = 65536;
     117             :   static constexpr size_t kTwoGB = 2u * 1024u * 1024u * 1024u;
     118             : 
     119         862 :   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         862 :     if (length >= kTwoGB) return nullptr;
     124             : 
     125         827 :     v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator();
     126         827 :     size_t page_size = page_allocator->AllocatePageSize();
     127         827 :     size_t allocated = RoundUp(length, page_size);
     128             :     // Rounding up could go over the limit.
     129         827 :     if (allocated >= kTwoGB) return nullptr;
     130             :     return i::AllocatePages(page_allocator, nullptr, allocated, page_size,
     131         818 :                             PageAllocator::kReadWrite);
     132             :   }
     133             : 
     134         818 :   void FreeVM(void* data, size_t length) {
     135         818 :     v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator();
     136         818 :     size_t page_size = page_allocator->AllocatePageSize();
     137         818 :     size_t allocated = RoundUp(length, page_size);
     138         818 :     CHECK(i::FreePages(page_allocator, data, allocated));
     139         818 :   }
     140             : };
     141             : 
     142             : // ArrayBuffer allocator that never allocates over 10MB.
     143      118184 : class MockArrayBufferAllocator : public ArrayBufferAllocatorBase {
     144             :  protected:
     145          99 :   void* Allocate(size_t length) override {
     146          99 :     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          99 :   void Free(void* data, size_t length) override {
     154          99 :     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         198 :     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       29546 : class MockArrayBufferAllocatiorWithLimit : public MockArrayBufferAllocator {
     167             :  public:
     168             :   explicit MockArrayBufferAllocatiorWithLimit(size_t allocation_limit)
     169       29546 :       : 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       29546 : std::unique_ptr<v8::Platform> g_platform;
     199             : 
     200        3991 : static Local<Value> Throw(Isolate* isolate, const char* message) {
     201             :   return isolate->ThrowException(
     202             :       String::NewFromUtf8(isolate, message, NewStringType::kNormal)
     203        7982 :           .ToLocalChecked());
     204             : }
     205             : 
     206         614 : static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
     207             :                              Local<v8::Object> object, const char* property) {
     208             :   Local<String> v8_str =
     209             :       String::NewFromUtf8(isolate, property, NewStringType::kNormal)
     210         614 :           .ToLocalChecked();
     211        1228 :   return object->Get(context, v8_str).ToLocalChecked();
     212             : }
     213             : 
     214        2263 : Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
     215        2263 :   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        2263 :   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             :         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             :     trace_config->SetTraceRecordMode(
     271           0 :         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           0 :                              .ToLocalChecked()
     304             :                              ->ToString(context)
     305           0 :                              .ToLocalChecked();
     306           0 :         String::Utf8Value str(isolate, v->ToString(context).ToLocalChecked());
     307           0 :         trace_config->AddIncludedCategory(*str);
     308           0 :       }
     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           0 :       }
     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       29546 : const base::TimeTicks Shell::kInitialTicks =
     367             :     base::TimeTicks::HighResolutionNow();
     368       29546 : Global<Function> Shell::stringify_function_;
     369             : base::LazyMutex Shell::workers_mutex_;
     370             : bool Shell::allow_new_workers_ = true;
     371       29546 : std::vector<Worker*> Shell::workers_;
     372       29546 : std::vector<ExternalizedContents> Shell::externalized_contents_;
     373             : std::atomic<bool> Shell::script_executed_{false};
     374             : base::LazyMutex Shell::isolate_status_lock_;
     375       29546 : 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       29546 :     Shell::cached_code_map_;
     379             : 
     380       29546 : Global<Context> Shell::evaluation_context_;
     381             : ArrayBuffer::Allocator* Shell::array_buffer_allocator;
     382       29546 : 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       38997 : class DummySourceStream : public v8::ScriptCompiler::ExternalSourceStream {
     387             :  public:
     388       25998 :   DummySourceStream(Local<String> source, Isolate* isolate) : done_(false) {
     389       12999 :     source_length_ = source->Utf8Length(isolate);
     390       12999 :     source_buffer_.reset(new uint8_t[source_length_]);
     391             :     source->WriteUtf8(isolate, reinterpret_cast<char*>(source_buffer_.get()),
     392       25998 :                       source_length_);
     393       12999 :   }
     394             : 
     395       25906 :   size_t GetMoreData(const uint8_t** src) override {
     396       25906 :     if (done_) {
     397             :       return 0;
     398             :     }
     399       12999 :     *src = source_buffer_.release();
     400       12999 :     done_ = true;
     401             : 
     402       12999 :     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       25998 : class BackgroundCompileThread : public base::Thread {
     412             :  public:
     413       12999 :   BackgroundCompileThread(Isolate* isolate, Local<String> source)
     414             :       : base::Thread(GetThreadOptions("BackgroundCompileThread")),
     415             :         source_(source),
     416       12999 :         streamed_source_(new DummySourceStream(source, isolate),
     417             :                          v8::ScriptCompiler::StreamedSource::UTF8),
     418             :         task_(v8::ScriptCompiler::StartStreamingScript(isolate,
     419       38997 :                                                        &streamed_source_)) {}
     420             : 
     421       25998 :   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         474 :   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      114311 : 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      114311 :   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             :     parse_info.set_language_mode(
     481           0 :         i::construct_language_mode(i::FLAG_use_strict));
     482             :     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      114311 :   HandleScope handle_scope(isolate);
     493      228622 :   TryCatch try_catch(isolate);
     494      114311 :   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      114311 :         Local<Context>::New(isolate, data->realms_[data->realm_current_]);
     502             :     Context::Scope context_scope(realm);
     503             :     MaybeLocal<Script> maybe_script;
     504      114311 :     Local<Context> context(isolate->GetCurrentContext());
     505             :     ScriptOrigin origin(name);
     506             : 
     507      114311 :     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      114209 :     } else if (options.stress_background_compile) {
     521             :       // Start a background thread compiling the script.
     522       12999 :       BackgroundCompileThread background_compile_thread(isolate, source);
     523       12999 :       background_compile_thread.Start();
     524             : 
     525             :       // In parallel, compile on the main thread to flush out any data races.
     526             :       {
     527       12999 :         TryCatch ignore_try_catch(isolate);
     528             :         ScriptCompiler::Source script_source(source, origin);
     529       12999 :         USE(ScriptCompiler::Compile(context, &script_source,
     530       12999 :                                     ScriptCompiler::kNoCompileOptions));
     531             :       }
     532             : 
     533             :       // Join with background thread and finalize compilation.
     534       12999 :       background_compile_thread.Join();
     535             :       maybe_script = v8::ScriptCompiler::Compile(
     536       12999 :           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      101210 :                                              options.compile_options);
     541             :     }
     542             : 
     543             :     Local<Script> script;
     544      114311 :     if (!maybe_script.ToLocal(&script)) {
     545             :       // Print errors that happened during compilation.
     546        1821 :       if (report_exceptions) ReportException(isolate, &try_catch);
     547             :       return false;
     548             :     }
     549             : 
     550      112490 :     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      112490 :     maybe_result = script->Run(realm);
     559      112490 :     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      112490 :     if (process_message_queue && !EmptyMessageQueues(isolate)) success = false;
     568      112490 :     data->realm_current_ = data->realm_switch_;
     569             :   }
     570             :   Local<Value> result;
     571      112490 :   if (!maybe_result.ToLocal(&result)) {
     572             :     DCHECK(try_catch.HasCaught());
     573             :     // Print errors that happened during execution.
     574        4189 :     if (report_exceptions) ReportException(isolate, &try_catch);
     575             :     return false;
     576             :   }
     577             :   DCHECK(!try_catch.HasCaught());
     578      108301 :   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           0 :         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           0 :       printf("\n");
     591             :     }
     592             :   }
     593      222612 :   return success;
     594             : }
     595             : 
     596             : namespace {
     597             : 
     598        2787 : std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
     599        2787 :   String::Utf8Value utf8(isolate, v8_str);
     600             :   // Should not be able to fail since the input is a String.
     601        2787 :   CHECK(*utf8);
     602        2787 :   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        3462 :   return path[0] == '/';
     612             : #endif
     613             : }
     614             : 
     615        1080 : 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        1080 :   CHECK_NOT_NULL(getcwd(curdir, PATH_MAX));
     625        1080 :   return curdir;
     626             : #endif
     627             : }
     628             : 
     629             : // Returns the directory part of path, without the trailing '/'.
     630        2753 : 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        2753 :   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        3462 : std::string NormalizePath(const std::string& path,
     641             :                           const std::string& dir_name) {
     642             :   std::string result;
     643        3462 :   if (IsAbsolutePath(path)) {
     644             :     result = path;
     645             :   } else {
     646        4746 :     result = dir_name + '/' + path;
     647             :   }
     648        3462 :   std::replace(result.begin(), result.end(), '\\', '/');
     649             :   size_t i;
     650        3823 :   while ((i = result.find("/./")) != std::string::npos) {
     651         361 :     result.erase(i, 2);
     652             :   }
     653        3462 :   return result;
     654             : }
     655             : 
     656             : // Per-context Module data, allowing sharing of module maps
     657             : // across top-level module loads.
     658      104376 : class ModuleEmbedderData {
     659             :  private:
     660             :   class ModuleGlobalHash {
     661             :    public:
     662       52188 :     explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
     663        2366 :     size_t operator()(const Global<Module>& module) const {
     664        4732 :       return module.Get(isolate_)->GetIdentityHash();
     665             :     }
     666             : 
     667             :    private:
     668             :     Isolate* isolate_;
     669             :   };
     670             : 
     671             :  public:
     672       52188 :   explicit ModuleEmbedderData(Isolate* isolate)
     673      104376 :       : 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       52188 : void InitializeModuleEmbedderData(Local<Context> context) {
     688             :   context->SetAlignedPointerInEmbedderData(
     689       52188 :       kModuleEmbedderDataIndex, new ModuleEmbedderData(context->GetIsolate()));
     690       52188 : }
     691             : 
     692             : ModuleEmbedderData* GetModuleDataFromContext(Local<Context> context) {
     693             :   return static_cast<ModuleEmbedderData*>(
     694             :       context->GetAlignedPointerFromEmbedderData(kModuleEmbedderDataIndex));
     695             : }
     696             : 
     697       52188 : void DisposeModuleEmbedderData(Local<Context> context) {
     698       52188 :   delete GetModuleDataFromContext(context);
     699       52188 :   context->SetAlignedPointerInEmbedderData(kModuleEmbedderDataIndex, nullptr);
     700       52188 : }
     701             : 
     702         993 : MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
     703             :                                          Local<String> specifier,
     704             :                                          Local<Module> referrer) {
     705         993 :   Isolate* isolate = context->GetIsolate();
     706             :   ModuleEmbedderData* d = GetModuleDataFromContext(context);
     707             :   auto specifier_it =
     708         993 :       d->module_to_specifier_map.find(Global<Module>(isolate, referrer));
     709         993 :   CHECK(specifier_it != d->module_to_specifier_map.end());
     710             :   std::string absolute_path = NormalizePath(ToSTLString(isolate, specifier),
     711        2979 :                                             DirName(specifier_it->second));
     712             :   auto module_it = d->specifier_to_module_map.find(absolute_path);
     713         993 :   CHECK(module_it != d->specifier_to_module_map.end());
     714        1986 :   return module_it->second.Get(isolate);
     715             : }
     716             : 
     717             : }  // anonymous namespace
     718             : 
     719        1591 : MaybeLocal<Module> Shell::FetchModuleTree(Local<Context> context,
     720             :                                           const std::string& file_name) {
     721             :   DCHECK(IsAbsolutePath(file_name));
     722        1591 :   Isolate* isolate = context->GetIsolate();
     723        1591 :   Local<String> source_text = ReadFile(isolate, file_name.c_str());
     724        1591 :   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             :       String::NewFromUtf8(isolate, file_name.c_str(), NewStringType::kNormal)
     731             :           .ToLocalChecked(),
     732             :       Local<Integer>(), Local<Integer>(), Local<Boolean>(), Local<Integer>(),
     733        1528 :       Local<Value>(), Local<Boolean>(), Local<Boolean>(), True(isolate));
     734             :   ScriptCompiler::Source source(source_text, origin);
     735             :   Local<Module> module;
     736        3056 :   if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
     737         173 :     return MaybeLocal<Module>();
     738             :   }
     739             : 
     740             :   ModuleEmbedderData* d = GetModuleDataFromContext(context);
     741        2710 :   CHECK(d->specifier_to_module_map
     742             :             .insert(std::make_pair(file_name, Global<Module>(isolate, module)))
     743             :             .second);
     744        2710 :   CHECK(d->module_to_specifier_map
     745             :             .insert(std::make_pair(Global<Module>(isolate, module), file_name))
     746             :             .second);
     747             : 
     748        1355 :   std::string dir_name = DirName(file_name);
     749             : 
     750        2339 :   for (int i = 0, length = module->GetModuleRequestsLength(); i < length; ++i) {
     751         984 :     Local<String> name = module->GetModuleRequest(i);
     752             :     std::string absolute_path =
     753        1968 :         NormalizePath(ToSTLString(isolate, name), dir_name);
     754         984 :     if (!d->specifier_to_module_map.count(absolute_path)) {
     755        1166 :       if (FetchModuleTree(context, absolute_path).IsEmpty()) {
     756           0 :         return MaybeLocal<Module>();
     757             :       }
     758             :     }
     759             :   }
     760             : 
     761        1355 :   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         405 :         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          18 :   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             :       String::NewFromUtf8(isolate, "url", NewStringType::kNormal)
     816          18 :           .ToLocalChecked();
     817             :   Local<String> url = String::NewFromUtf8(isolate, specifier_it->second.c_str(),
     818             :                                           NewStringType::kNormal)
     819          18 :                           .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             :       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         279 :   if (root_module->InstantiateModule(realm, ResolveModuleCallback)
     859         558 :           .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         675 : bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
     877         675 :   HandleScope handle_scope(isolate);
     878             : 
     879             :   PerIsolateData* data = PerIsolateData::Get(isolate);
     880         675 :   Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
     881             :   Context::Scope context_scope(realm);
     882             : 
     883        2025 :   std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory());
     884             : 
     885        1350 :   TryCatch try_catch(isolate);
     886         675 :   try_catch.SetVerbose(true);
     887             : 
     888             :   Local<Module> root_module;
     889             :   MaybeLocal<Value> maybe_exception;
     890             : 
     891        1350 :   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         565 :   if (root_module->InstantiateModule(realm, ResolveModuleCallback)
     899        1130 :           .FromMaybe(false)) {
     900         490 :     maybe_result = root_module->Evaluate(realm);
     901         490 :     EmptyMessageQueues(isolate);
     902             :   }
     903             :   Local<Value> result;
     904         565 :   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         675 :   return true;
     912             : }
     913             : 
     914       30196 : PerIsolateData::PerIsolateData(Isolate* isolate)
     915       90588 :     : isolate_(isolate), realms_(nullptr) {
     916             :   isolate->SetData(0, this);
     917       30196 :   if (i::FLAG_expose_async_hooks) {
     918          50 :     async_hooks_wrapper_ = new AsyncHooks(isolate);
     919             :   }
     920       30196 : }
     921             : 
     922       30196 : PerIsolateData::~PerIsolateData() {
     923       30196 :   isolate_->SetData(0, nullptr);  // Not really needed, just to be sure...
     924       30196 :   if (i::FLAG_expose_async_hooks) {
     925          50 :     delete async_hooks_wrapper_;  // This uses the isolate
     926             :   }
     927       30196 : }
     928             : 
     929        1265 : 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        1265 : }
     934             : 
     935      159240 : MaybeLocal<Function> PerIsolateData::GetTimeoutCallback() {
     936      159240 :   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       51492 : PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
     950       51492 :   data_->realm_count_ = 1;
     951       51492 :   data_->realm_current_ = 0;
     952       51492 :   data_->realm_switch_ = 0;
     953      102984 :   data_->realms_ = new Global<Context>[1];
     954       51492 :   data_->realms_[0].Reset(data_->isolate_,
     955      102984 :                           data_->isolate_->GetEnteredOrMicrotaskContext());
     956       51492 : }
     957             : 
     958             : 
     959       51491 : 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       52178 :   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       51491 :   data_->realm_count_ = 0;
     969      102983 :   delete[] data_->realms_;
     970       51491 : }
     971             : 
     972             : 
     973         316 : int PerIsolateData::RealmFind(Local<Context> context) {
     974        2233 :   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       19827 :     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        9909 :                   ->Int32Value(args.GetIsolate()->GetCurrentContext())
     990       19818 :                   .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           6 : 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         596 : 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         596 :   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          54 : 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             :   int index = data->RealmFind(args[0]
    1032          18 :                                   ->ToObject(isolate->GetCurrentContext())
    1033          18 :                                   .ToLocalChecked()
    1034          18 :                                   ->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        1422 : 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         948 :   if (index == -1) return;
    1046             :   args.GetReturnValue().Set(
    1047         948 :       Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
    1048             : }
    1049             : 
    1050         696 : MaybeLocal<Context> Shell::CreateRealm(
    1051        1392 :     const v8::FunctionCallbackInfo<v8::Value>& args, int index,
    1052             :     v8::MaybeLocal<Value> global_object) {
    1053             :   Isolate* isolate = args.GetIsolate();
    1054         696 :   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        3822 :     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          17 :     const v8::FunctionCallbackInfo<v8::Value>& args) {
    1097             :   Local<Context> context;
    1098          34 :   if (CreateRealm(args, -1, v8::MaybeLocal<Value>()).ToLocal(&context)) {
    1099             :     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          27 : 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       26972 : 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        9120 :   if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
    1162        9120 :            .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       10338 :   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         234 :     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          90 :     const v8::FunctionCallbackInfo<v8::Value>& args) {
    1211             :   Isolate* isolate = args.GetIsolate();
    1212          45 :   HandleScope handle_scope(isolate);
    1213             :   args.GetReturnValue().Set(v8::Number::New(
    1214             :       isolate,
    1215          90 :       PerIsolateData::Get(isolate)->GetAsyncHooks()->GetExecutionAsyncId()));
    1216          45 : }
    1217             : 
    1218          45 : void Shell::AsyncHooksTriggerAsyncId(
    1219          90 :     const v8::FunctionCallbackInfo<v8::Value>& args) {
    1220             :   Isolate* isolate = args.GetIsolate();
    1221          45 :   HandleScope handle_scope(isolate);
    1222             :   args.GetReturnValue().Set(v8::Number::New(
    1223             :       isolate,
    1224          90 :       PerIsolateData::Get(isolate)->GetAsyncHooks()->GetTriggerAsyncId()));
    1225          45 : }
    1226             : 
    1227    13554652 : void WriteToFile(FILE* file, const v8::FunctionCallbackInfo<v8::Value>& args) {
    1228     6870562 :   for (int i = 0; i < args.Length(); i++) {
    1229     2228030 :     HandleScope handle_scope(args.GetIsolate());
    1230     2228030 :     if (i != 0) {
    1231             :       fprintf(file, " ");
    1232             :     }
    1233             : 
    1234             :     // Explicitly catch potential exceptions in toString().
    1235     4456060 :     v8::TryCatch try_catch(args.GetIsolate());
    1236             :     Local<Value> arg = args[i];
    1237             :     Local<String> str_obj;
    1238             : 
    1239     2228030 :     if (arg->IsSymbol()) {
    1240           0 :       arg = Local<Symbol>::Cast(arg)->Name();
    1241             :     }
    1242     4456060 :     if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
    1243     2228030 :              .ToLocal(&str_obj)) {
    1244           0 :       try_catch.ReThrow();
    1245     1207251 :       return;
    1246             :     }
    1247             : 
    1248     4456060 :     v8::String::Utf8Value str(args.GetIsolate(), str_obj);
    1249     2228030 :     int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), file));
    1250     2228030 :     if (n != str.length()) {
    1251             :       printf("Error in fwrite\n");
    1252           0 :       base::OS::ExitProcess(1);
    1253             :     }
    1254     2228030 :   }
    1255             : }
    1256             : 
    1257     1207251 : void WriteAndFlush(FILE* file,
    1258             :                    const v8::FunctionCallbackInfo<v8::Value>& args) {
    1259     1207251 :   WriteToFile(file, args);
    1260             :   fprintf(file, "\n");
    1261     1207251 :   fflush(file);
    1262     1207251 : }
    1263             : 
    1264     1207251 : void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1265     1207251 :   WriteAndFlush(stdout, args);
    1266     1207251 : }
    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         150 : void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1277          30 :   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           0 :     }
    1288             :   }
    1289          60 :   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          30 :   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             :           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             :                          String::NewFromUtf8(isolate, buffer,
    1324             :                                              NewStringType::kNormal, length - 1)
    1325           0 :                              .ToLocalChecked());
    1326             :     } else {
    1327             :       return String::Concat(
    1328             :           isolate, accumulator,
    1329             :           String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
    1330             :                               length - 1)
    1331           0 :               .ToLocalChecked());
    1332             :     }
    1333             :   }
    1334             : }
    1335             : 
    1336             : 
    1337       47680 : void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1338       16456 :   for (int i = 0; i < args.Length(); i++) {
    1339        5961 :     HandleScope handle_scope(args.GetIsolate());
    1340        8228 :     String::Utf8Value file(args.GetIsolate(), args[i]);
    1341        5961 :     if (*file == nullptr) {
    1342           0 :       Throw(args.GetIsolate(), "Error loading file");
    1343           0 :       return;
    1344             :     }
    1345        5961 :     Local<String> source = ReadFile(args.GetIsolate(), *file);
    1346        5961 :     if (source.IsEmpty()) {
    1347           4 :       Throw(args.GetIsolate(), "Error loading file");
    1348           4 :       return;
    1349             :     }
    1350        5957 :     if (!ExecuteString(
    1351             :             args.GetIsolate(), source,
    1352        5957 :             String::NewFromUtf8(args.GetIsolate(), *file,
    1353             :                                 NewStringType::kNormal)
    1354             :                 .ToLocalChecked(),
    1355             :             kNoPrintResult,
    1356             :             options.quiet_load ? kNoReportExceptions : kReportExceptions,
    1357       17871 :             kNoProcessMessageQueue)) {
    1358        3690 :       Throw(args.GetIsolate(), "Error executing file");
    1359        3690 :       return;
    1360             :     }
    1361        2267 :   }
    1362             : }
    1363             : 
    1364        3795 : 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        1265 :   Local<Function> callback = Local<Function>::Cast(args[0]);
    1369        1265 :   Local<Context> context = isolate->GetCurrentContext();
    1370        1265 :   PerIsolateData::Get(isolate)->SetTimeout(callback, context);
    1371             : }
    1372             : 
    1373        3873 : void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1374             :   Isolate* isolate = args.GetIsolate();
    1375         659 :   HandleScope handle_scope(isolate);
    1376        1309 :   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        1273 :   if (args.Length() > 1 && args[1]->IsObject()) {
    1385         614 :     Local<Object> object = args[1].As<Object>();
    1386         614 :     Local<Context> context = isolate->GetCurrentContext();
    1387         614 :     Local<Value> value = GetValue(args.GetIsolate(), context, object, "type");
    1388         614 :     if (value->IsString()) {
    1389         614 :       Local<String> worker_type = value->ToString(context).ToLocalChecked();
    1390         614 :       String::Utf8Value str(isolate, worker_type);
    1391         614 :       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         605 :       }
    1399             :     }
    1400             :   }
    1401             : 
    1402             :   Local<Value> source;
    1403         641 :   if (load_from_file) {
    1404          36 :     String::Utf8Value filename(args.GetIsolate(), args[0]);
    1405          72 :     source = ReadFile(args.GetIsolate(), *filename);
    1406          36 :     if (source.IsEmpty()) {
    1407          27 :       Throw(args.GetIsolate(), "Error loading worker script");
    1408          27 :       return;
    1409           9 :     }
    1410             :   } else {
    1411             :     source = args[0];
    1412             :   }
    1413             : 
    1414         614 :   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        1228 :     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         614 :     args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
    1430             : 
    1431         614 :     if (!allow_new_workers_) return;
    1432             : 
    1433         605 :     Worker* worker = new Worker;
    1434         605 :     args.Holder()->SetAlignedPointerInInternalField(0, worker);
    1435         605 :     workers_.push_back(worker);
    1436             : 
    1437        1210 :     String::Utf8Value script(args.GetIsolate(), source);
    1438         605 :     if (!*script) {
    1439           0 :       Throw(args.GetIsolate(), "Can't get worker script");
    1440           0 :       return;
    1441             :     }
    1442         605 :     worker->StartExecuteInThread(*script);
    1443         605 :   }
    1444             : }
    1445             : 
    1446             : 
    1447        2535 : void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1448             :   Isolate* isolate = args.GetIsolate();
    1449         845 :   HandleScope handle_scope(isolate);
    1450             : 
    1451         845 :   if (args.Length() < 1) {
    1452           0 :     Throw(isolate, "Invalid argument");
    1453           0 :     return;
    1454             :   }
    1455             : 
    1456         845 :   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
    1457         845 :   if (!worker) {
    1458             :     return;
    1459             :   }
    1460             : 
    1461         836 :   Local<Value> message = args[0];
    1462             :   Local<Value> transfer =
    1463        1672 :       args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate));
    1464             :   std::unique_ptr<SerializationData> data =
    1465         836 :       Shell::SerializeValue(isolate, message, transfer);
    1466         836 :   if (data) {
    1467        1294 :     worker->PostMessage(std::move(data));
    1468         836 :   }
    1469             : }
    1470             : 
    1471             : 
    1472        2994 : void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1473             :   Isolate* isolate = args.GetIsolate();
    1474        1007 :   HandleScope handle_scope(isolate);
    1475        1007 :   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
    1476        1007 :   if (!worker) {
    1477           0 :     return;
    1478             :   }
    1479             : 
    1480        1007 :   std::unique_ptr<SerializationData> data = worker->GetMessage();
    1481        1007 :   if (data) {
    1482             :     Local<Value> value;
    1483        1960 :     if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) {
    1484             :       args.GetReturnValue().Set(value);
    1485             :     }
    1486        1007 :   }
    1487             : }
    1488             : 
    1489             : 
    1490         822 : void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1491             :   Isolate* isolate = args.GetIsolate();
    1492         411 :   HandleScope handle_scope(isolate);
    1493         411 :   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
    1494         411 :   if (!worker) {
    1495           0 :     return;
    1496             :   }
    1497             : 
    1498         411 :   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           0 :                       .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        1779 : void Shell::WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1519        1779 :   SetWaitUntilDone(args.GetIsolate(), true);
    1520        1779 : }
    1521             : 
    1522         518 : void Shell::NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1523         518 :   SetWaitUntilDone(args.GetIsolate(), false);
    1524         518 : }
    1525             : 
    1526          81 : void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
    1527             :   args.GetReturnValue().Set(
    1528             :       String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
    1529          54 :                           NewStringType::kNormal).ToLocalChecked());
    1530          27 : }
    1531             : 
    1532             : 
    1533        6290 : void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
    1534        6290 :   HandleScope handle_scope(isolate);
    1535        6290 :   Local<Context> context = isolate->GetCurrentContext();
    1536             :   bool enter_context = context.IsEmpty();
    1537        6290 :   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       21354 :   auto ToCString = [](const v8::String::Utf8Value& value) {
    1543             :     return *value ? *value : "<string conversion failed>";
    1544       21354 :   };
    1545             : 
    1546       12580 :   v8::String::Utf8Value exception(isolate, try_catch->Exception());
    1547             :   const char* exception_string = ToCString(exception);
    1548        6290 :   Local<Message> message = try_catch->Message();
    1549        6290 :   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       12580 :   } 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        6262 :                                    message->GetScriptOrigin().ResourceName());
    1563             :     const char* filename_string = ToCString(filename);
    1564       12524 :     int linenum = message->GetLineNumber(context).FromMaybe(-1);
    1565             :     printf("%s:%i: %s\n", filename_string, linenum, exception_string);
    1566             :     Local<String> sourceline;
    1567       12524 :     if (message->GetSourceLine(context).ToLocal(&sourceline)) {
    1568             :       // Print line of source code.
    1569        6262 :       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       12524 :       int start = message->GetStartColumn(context).FromJust();
    1574       76927 :       for (int i = 0; i < start; i++) {
    1575             :         printf(" ");
    1576             :       }
    1577       12524 :       int end = message->GetEndColumn(context).FromJust();
    1578       21417 :       for (int i = start; i < end; i++) {
    1579             :         printf("^");
    1580             :       }
    1581        6262 :       printf("\n");
    1582        6262 :     }
    1583             :   }
    1584             :   Local<Value> stack_trace_string;
    1585       15129 :   if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
    1586             :       stack_trace_string->IsString()) {
    1587             :     v8::String::Utf8Value stack_trace(isolate,
    1588        2540 :                                       Local<String>::Cast(stack_trace_string));
    1589        2540 :     printf("%s\n", ToCString(stack_trace));
    1590             :   }
    1591             :   printf("\n");
    1592       12580 :   if (enter_context) context->Exit();
    1593        6290 : }
    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       29546 :   magic_number_ = 0xDEADFACE;
    1614       29546 :   max_counters_ = kMaxCounters;
    1615       29546 :   max_name_size_ = Counter::kMaxNameSize;
    1616       29546 :   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             :   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             :         String::NewFromUtf8(isolate, "d8-stringify", NewStringType::kNormal)
    1693           0 :             .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           0 :   return result.ToLocalChecked().As<String>();
    1706             : }
    1707             : 
    1708             : 
    1709       52188 : Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
    1710       52188 :   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
    1711             :   global_template->Set(
    1712             :       String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
    1713             :           .ToLocalChecked(),
    1714      156564 :       FunctionTemplate::New(isolate, Print));
    1715             :   global_template->Set(
    1716             :       String::NewFromUtf8(isolate, "printErr", NewStringType::kNormal)
    1717             :           .ToLocalChecked(),
    1718      156564 :       FunctionTemplate::New(isolate, PrintErr));
    1719             :   global_template->Set(
    1720             :       String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
    1721             :           .ToLocalChecked(),
    1722      156564 :       FunctionTemplate::New(isolate, Write));
    1723             :   global_template->Set(
    1724             :       String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
    1725             :           .ToLocalChecked(),
    1726      156564 :       FunctionTemplate::New(isolate, Read));
    1727             :   global_template->Set(
    1728             :       String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
    1729             :           .ToLocalChecked(),
    1730      156564 :       FunctionTemplate::New(isolate, ReadBuffer));
    1731             :   global_template->Set(
    1732             :       String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
    1733             :           .ToLocalChecked(),
    1734      156564 :       FunctionTemplate::New(isolate, ReadLine));
    1735             :   global_template->Set(
    1736             :       String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
    1737             :           .ToLocalChecked(),
    1738      156564 :       FunctionTemplate::New(isolate, Load));
    1739             :   global_template->Set(
    1740             :       String::NewFromUtf8(isolate, "setTimeout", NewStringType::kNormal)
    1741             :           .ToLocalChecked(),
    1742      156564 :       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       52188 :   if (!options.omit_quit) {
    1747             :     global_template->Set(
    1748             :         String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
    1749             :             .ToLocalChecked(),
    1750      156462 :         FunctionTemplate::New(isolate, Quit));
    1751             :   }
    1752       52188 :   Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
    1753             :   global_template->Set(
    1754             :       String::NewFromUtf8(isolate, "testRunner", NewStringType::kNormal)
    1755             :           .ToLocalChecked(),
    1756      104376 :       test_template);
    1757             :   test_template->Set(
    1758             :       String::NewFromUtf8(isolate, "notifyDone", NewStringType::kNormal)
    1759             :           .ToLocalChecked(),
    1760      156564 :       FunctionTemplate::New(isolate, NotifyDone));
    1761             :   test_template->Set(
    1762             :       String::NewFromUtf8(isolate, "waitUntilDone", NewStringType::kNormal)
    1763             :           .ToLocalChecked(),
    1764      156564 :       FunctionTemplate::New(isolate, WaitUntilDone));
    1765             :   global_template->Set(
    1766             :       String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
    1767             :           .ToLocalChecked(),
    1768      156564 :       FunctionTemplate::New(isolate, Version));
    1769             :   global_template->Set(
    1770             :       Symbol::GetToStringTag(isolate),
    1771             :       String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
    1772      156564 :           .ToLocalChecked());
    1773             : 
    1774             :   // Bind the Realm object.
    1775       52188 :   Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
    1776             :   realm_template->Set(
    1777             :       String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
    1778             :           .ToLocalChecked(),
    1779      156564 :       FunctionTemplate::New(isolate, RealmCurrent));
    1780             :   realm_template->Set(
    1781             :       String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
    1782             :           .ToLocalChecked(),
    1783      156564 :       FunctionTemplate::New(isolate, RealmOwner));
    1784             :   realm_template->Set(
    1785             :       String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
    1786             :           .ToLocalChecked(),
    1787      156564 :       FunctionTemplate::New(isolate, RealmGlobal));
    1788             :   realm_template->Set(
    1789             :       String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
    1790             :           .ToLocalChecked(),
    1791      156564 :       FunctionTemplate::New(isolate, RealmCreate));
    1792             :   realm_template->Set(
    1793             :       String::NewFromUtf8(isolate, "createAllowCrossRealmAccess",
    1794             :                           NewStringType::kNormal)
    1795             :           .ToLocalChecked(),
    1796      156564 :       FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
    1797             :   realm_template->Set(
    1798             :       String::NewFromUtf8(isolate, "navigate", NewStringType::kNormal)
    1799             :           .ToLocalChecked(),
    1800      156564 :       FunctionTemplate::New(isolate, RealmNavigate));
    1801             :   realm_template->Set(
    1802             :       String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
    1803             :           .ToLocalChecked(),
    1804      156564 :       FunctionTemplate::New(isolate, RealmDispose));
    1805             :   realm_template->Set(
    1806             :       String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
    1807             :           .ToLocalChecked(),
    1808      156564 :       FunctionTemplate::New(isolate, RealmSwitch));
    1809             :   realm_template->Set(
    1810             :       String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
    1811             :           .ToLocalChecked(),
    1812      156564 :       FunctionTemplate::New(isolate, RealmEval));
    1813             :   realm_template->SetAccessor(
    1814             :       String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
    1815             :           .ToLocalChecked(),
    1816      104376 :       RealmSharedGet, RealmSharedSet);
    1817             :   global_template->Set(
    1818             :       String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
    1819             :           .ToLocalChecked(),
    1820      104376 :       realm_template);
    1821             : 
    1822       52188 :   Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
    1823             :   performance_template->Set(
    1824             :       String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
    1825             :           .ToLocalChecked(),
    1826      156564 :       FunctionTemplate::New(isolate, PerformanceNow));
    1827             :   global_template->Set(
    1828             :       String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
    1829             :           .ToLocalChecked(),
    1830      104376 :       performance_template);
    1831             : 
    1832             :   Local<FunctionTemplate> worker_fun_template =
    1833       52188 :       FunctionTemplate::New(isolate, WorkerNew);
    1834             :   Local<Signature> worker_signature =
    1835       52188 :       Signature::New(isolate, worker_fun_template);
    1836             :   worker_fun_template->SetClassName(
    1837             :       String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
    1838      104376 :           .ToLocalChecked());
    1839       52188 :   worker_fun_template->ReadOnlyPrototype();
    1840      104376 :   worker_fun_template->PrototypeTemplate()->Set(
    1841             :       String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
    1842             :           .ToLocalChecked(),
    1843             :       FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
    1844      208752 :                             worker_signature));
    1845      104376 :   worker_fun_template->PrototypeTemplate()->Set(
    1846             :       String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
    1847             :           .ToLocalChecked(),
    1848             :       FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
    1849      208752 :                             worker_signature));
    1850      104376 :   worker_fun_template->PrototypeTemplate()->Set(
    1851             :       String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
    1852             :           .ToLocalChecked(),
    1853             :       FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
    1854      208752 :                             worker_signature));
    1855      104376 :   worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
    1856             :   global_template->Set(
    1857             :       String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
    1858             :           .ToLocalChecked(),
    1859      104376 :       worker_fun_template);
    1860             : 
    1861       52188 :   Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
    1862       52188 :   AddOSMethods(isolate, os_templ);
    1863             :   global_template->Set(
    1864             :       String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
    1865             :           .ToLocalChecked(),
    1866      104376 :       os_templ);
    1867             : 
    1868       52188 :   if (i::FLAG_expose_async_hooks) {
    1869          90 :     Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
    1870             :     async_hooks_templ->Set(
    1871             :         String::NewFromUtf8(isolate, "createHook", NewStringType::kNormal)
    1872             :             .ToLocalChecked(),
    1873         270 :         FunctionTemplate::New(isolate, AsyncHooksCreateHook));
    1874             :     async_hooks_templ->Set(
    1875             :         String::NewFromUtf8(isolate, "executionAsyncId", NewStringType::kNormal)
    1876             :             .ToLocalChecked(),
    1877         270 :         FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
    1878             :     async_hooks_templ->Set(
    1879             :         String::NewFromUtf8(isolate, "triggerAsyncId", NewStringType::kNormal)
    1880             :             .ToLocalChecked(),
    1881         270 :         FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
    1882             :     global_template->Set(
    1883             :         String::NewFromUtf8(isolate, "async_hooks", NewStringType::kNormal)
    1884             :             .ToLocalChecked(),
    1885         180 :         async_hooks_templ);
    1886             :   }
    1887             : 
    1888       52188 :   return global_template;
    1889             : }
    1890             : 
    1891        6916 : static void PrintNonErrorsMessageCallback(Local<Message> message,
    1892             :                                           Local<Value> error) {
    1893             :   // Nothing to do here for errors, exceptions thrown up to the shell will be
    1894             :   // reported
    1895             :   // separately by {Shell::ReportException} after they are caught.
    1896             :   // Do print other kinds of messages.
    1897        6916 :   switch (message->ErrorLevel()) {
    1898             :     case v8::Isolate::kMessageWarning:
    1899             :     case v8::Isolate::kMessageLog:
    1900             :     case v8::Isolate::kMessageInfo:
    1901             :     case v8::Isolate::kMessageDebug: {
    1902             :       break;
    1903             :     }
    1904             : 
    1905             :     case v8::Isolate::kMessageError: {
    1906             :       // Ignore errors, printed elsewhere.
    1907        6305 :       return;
    1908             :     }
    1909             : 
    1910             :     default: {
    1911           0 :       UNREACHABLE();
    1912             :       break;
    1913             :     }
    1914             :   }
    1915             :   // Converts a V8 value to a C string.
    1916        1222 :   auto ToCString = [](const v8::String::Utf8Value& value) {
    1917             :     return *value ? *value : "<string conversion failed>";
    1918        1222 :   };
    1919         611 :   Isolate* isolate = Isolate::GetCurrent();
    1920        1222 :   v8::String::Utf8Value msg(isolate, message->Get());
    1921             :   const char* msg_string = ToCString(msg);
    1922             :   // Print (filename):(line number): (message).
    1923             :   v8::String::Utf8Value filename(isolate,
    1924        1222 :                                  message->GetScriptOrigin().ResourceName());
    1925             :   const char* filename_string = ToCString(filename);
    1926         611 :   Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
    1927         611 :   int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
    1928         611 :   printf("%s:%i: %s\n", filename_string, linenum, msg_string);
    1929             : }
    1930             : 
    1931       29591 : void Shell::Initialize(Isolate* isolate) {
    1932             :   // Set up counters
    1933       59182 :   if (i::StrLength(i::FLAG_map_counters) != 0)
    1934           0 :     MapCounters(isolate, i::FLAG_map_counters);
    1935             :   // Disable default message reporting.
    1936             :   isolate->AddMessageListenerWithErrorLevel(
    1937             :       PrintNonErrorsMessageCallback,
    1938             :       v8::Isolate::kMessageError | v8::Isolate::kMessageWarning |
    1939             :           v8::Isolate::kMessageInfo | v8::Isolate::kMessageDebug |
    1940       29591 :           v8::Isolate::kMessageLog);
    1941       29591 : }
    1942             : 
    1943             : 
    1944       51492 : Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
    1945             :   // This needs to be a critical section since this is not thread-safe
    1946             :   base::MutexGuard lock_guard(context_mutex_.Pointer());
    1947             :   // Initialize the global objects
    1948       51492 :   Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
    1949       51492 :   EscapableHandleScope handle_scope(isolate);
    1950       51492 :   Local<Context> context = Context::New(isolate, nullptr, global_template);
    1951             :   DCHECK(!context.IsEmpty());
    1952       51492 :   InitializeModuleEmbedderData(context);
    1953       51492 :   if (options.include_arguments) {
    1954             :     Context::Scope scope(context);
    1955       51519 :     const std::vector<const char*>& args = options.arguments;
    1956       51492 :     int size = static_cast<int>(args.size());
    1957       51492 :     Local<Array> array = Array::New(isolate, size);
    1958       51519 :     for (int i = 0; i < size; i++) {
    1959             :       Local<String> arg =
    1960          54 :           v8::String::NewFromUtf8(isolate, args[i], v8::NewStringType::kNormal)
    1961          27 :               .ToLocalChecked();
    1962          27 :       Local<Number> index = v8::Number::New(isolate, i);
    1963          54 :       array->Set(context, index, arg).FromJust();
    1964             :     }
    1965             :     Local<String> name =
    1966             :         String::NewFromUtf8(isolate, "arguments", NewStringType::kInternalized)
    1967       51492 :             .ToLocalChecked();
    1968      154476 :     context->Global()->Set(context, name, array).FromJust();
    1969             :   }
    1970       51492 :   return handle_scope.Escape(context);
    1971             : }
    1972             : 
    1973             : struct CounterAndKey {
    1974             :   Counter* counter;
    1975             :   const char* key;
    1976             : };
    1977             : 
    1978             : 
    1979             : inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
    1980           0 :   return strcmp(lhs.key, rhs.key) < 0;
    1981             : }
    1982             : 
    1983           0 : void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
    1984           0 :   HandleScope handle_scope(isolate);
    1985           0 :   Local<Context> context = Context::New(isolate);
    1986             :   Context::Scope context_scope(context);
    1987             : 
    1988             :   Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
    1989             :                                         ->interpreter()
    1990           0 :                                         ->GetDispatchCountersObject();
    1991             :   std::ofstream dispatch_counters_stream(
    1992           0 :       i::FLAG_trace_ignition_dispatches_output_file);
    1993             :   dispatch_counters_stream << *String::Utf8Value(
    1994           0 :       isolate, JSON::Stringify(context, dispatch_counters).ToLocalChecked());
    1995           0 : }
    1996             : 
    1997             : namespace {
    1998           0 : int LineFromOffset(Local<debug::Script> script, int offset) {
    1999           0 :   debug::Location location = script->GetSourceLocation(offset);
    2000           0 :   return location.GetLineNumber();
    2001             : }
    2002             : 
    2003           0 : void WriteLcovDataForRange(std::vector<uint32_t>& lines, int start_line,
    2004             :                            int end_line, uint32_t count) {
    2005             :   // Ensure space in the array.
    2006           0 :   lines.resize(std::max(static_cast<size_t>(end_line + 1), lines.size()), 0);
    2007             :   // Boundary lines could be shared between two functions with different
    2008             :   // invocation counts. Take the maximum.
    2009           0 :   lines[start_line] = std::max(lines[start_line], count);
    2010           0 :   lines[end_line] = std::max(lines[end_line], count);
    2011             :   // Invocation counts for non-boundary lines are overwritten.
    2012           0 :   for (int k = start_line + 1; k < end_line; k++) lines[k] = count;
    2013           0 : }
    2014             : 
    2015           0 : void WriteLcovDataForNamedRange(std::ostream& sink,
    2016             :                                 std::vector<uint32_t>& lines,
    2017             :                                 const std::string& name, int start_line,
    2018             :                                 int end_line, uint32_t count) {
    2019           0 :   WriteLcovDataForRange(lines, start_line, end_line, count);
    2020           0 :   sink << "FN:" << start_line + 1 << "," << name << std::endl;
    2021           0 :   sink << "FNDA:" << count << "," << name << std::endl;
    2022           0 : }
    2023             : }  // namespace
    2024             : 
    2025             : // Write coverage data in LCOV format. See man page for geninfo(1).
    2026       50887 : void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) {
    2027      101774 :   if (!file) return;
    2028           0 :   HandleScope handle_scope(isolate);
    2029           0 :   debug::Coverage coverage = debug::Coverage::CollectPrecise(isolate);
    2030           0 :   std::ofstream sink(file, std::ofstream::app);
    2031           0 :   for (size_t i = 0; i < coverage.ScriptCount(); i++) {
    2032           0 :     debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
    2033           0 :     Local<debug::Script> script = script_data.GetScript();
    2034             :     // Skip unnamed scripts.
    2035             :     Local<String> name;
    2036           0 :     if (!script->Name().ToLocal(&name)) continue;
    2037           0 :     std::string file_name = ToSTLString(isolate, name);
    2038             :     // Skip scripts not backed by a file.
    2039           0 :     if (!std::ifstream(file_name).good()) continue;
    2040           0 :     sink << "SF:";
    2041           0 :     sink << NormalizePath(file_name, GetWorkingDirectory()) << std::endl;
    2042             :     std::vector<uint32_t> lines;
    2043           0 :     for (size_t j = 0; j < script_data.FunctionCount(); j++) {
    2044             :       debug::Coverage::FunctionData function_data =
    2045           0 :           script_data.GetFunctionData(j);
    2046             : 
    2047             :       // Write function stats.
    2048             :       {
    2049             :         debug::Location start =
    2050           0 :             script->GetSourceLocation(function_data.StartOffset());
    2051             :         debug::Location end =
    2052           0 :             script->GetSourceLocation(function_data.EndOffset());
    2053           0 :         int start_line = start.GetLineNumber();
    2054           0 :         int end_line = end.GetLineNumber();
    2055           0 :         uint32_t count = function_data.Count();
    2056             : 
    2057             :         Local<String> name;
    2058           0 :         std::stringstream name_stream;
    2059           0 :         if (function_data.Name().ToLocal(&name)) {
    2060           0 :           name_stream << ToSTLString(isolate, name);
    2061             :         } else {
    2062           0 :           name_stream << "<" << start_line + 1 << "-";
    2063           0 :           name_stream << start.GetColumnNumber() << ">";
    2064             :         }
    2065             : 
    2066             :         WriteLcovDataForNamedRange(sink, lines, name_stream.str(), start_line,
    2067           0 :                                    end_line, count);
    2068             :       }
    2069             : 
    2070             :       // Process inner blocks.
    2071           0 :       for (size_t k = 0; k < function_data.BlockCount(); k++) {
    2072           0 :         debug::Coverage::BlockData block_data = function_data.GetBlockData(k);
    2073           0 :         int start_line = LineFromOffset(script, block_data.StartOffset());
    2074           0 :         int end_line = LineFromOffset(script, block_data.EndOffset() - 1);
    2075           0 :         uint32_t count = block_data.Count();
    2076           0 :         WriteLcovDataForRange(lines, start_line, end_line, count);
    2077             :       }
    2078             :     }
    2079             :     // Write per-line coverage. LCOV uses 1-based line numbers.
    2080           0 :     for (size_t i = 0; i < lines.size(); i++) {
    2081           0 :       sink << "DA:" << (i + 1) << "," << lines[i] << std::endl;
    2082             :     }
    2083           0 :     sink << "end_of_record" << std::endl;
    2084           0 :   }
    2085             : }
    2086             : 
    2087       29546 : void Shell::OnExit(v8::Isolate* isolate) {
    2088             :   // Dump basic block profiling data.
    2089       29546 :   if (i::FLAG_turbo_profiling) {
    2090           0 :     i::BasicBlockProfiler* profiler = i::BasicBlockProfiler::Get();
    2091           0 :     i::StdoutStream{} << *profiler;
    2092             :   }
    2093       29546 :   isolate->Dispose();
    2094             : 
    2095       29546 :   if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp) {
    2096           0 :     const int number_of_counters = static_cast<int>(counter_map_->size());
    2097           0 :     CounterAndKey* counters = new CounterAndKey[number_of_counters];
    2098             :     int j = 0;
    2099           0 :     for (auto map_entry : *counter_map_) {
    2100           0 :       counters[j].counter = map_entry.second;
    2101           0 :       counters[j].key = map_entry.first;
    2102           0 :       j++;
    2103             :     }
    2104           0 :     std::sort(counters, counters + number_of_counters);
    2105             : 
    2106           0 :     if (i::FLAG_dump_counters_nvp) {
    2107             :       // Dump counters as name-value pairs.
    2108           0 :       for (j = 0; j < number_of_counters; j++) {
    2109           0 :         Counter* counter = counters[j].counter;
    2110           0 :         const char* key = counters[j].key;
    2111           0 :         if (counter->is_histogram()) {
    2112             :           printf("\"c:%s\"=%i\n", key, counter->count());
    2113             :           printf("\"t:%s\"=%i\n", key, counter->sample_total());
    2114             :         } else {
    2115             :           printf("\"%s\"=%i\n", key, counter->count());
    2116             :         }
    2117             :       }
    2118             :     } else {
    2119             :       // Dump counters in formatted boxes.
    2120             :       printf(
    2121             :           "+----------------------------------------------------------------+"
    2122             :           "-------------+\n");
    2123             :       printf(
    2124             :           "| Name                                                           |"
    2125             :           " Value       |\n");
    2126             :       printf(
    2127             :           "+----------------------------------------------------------------+"
    2128             :           "-------------+\n");
    2129           0 :       for (j = 0; j < number_of_counters; j++) {
    2130           0 :         Counter* counter = counters[j].counter;
    2131           0 :         const char* key = counters[j].key;
    2132           0 :         if (counter->is_histogram()) {
    2133             :           printf("| c:%-60s | %11i |\n", key, counter->count());
    2134             :           printf("| t:%-60s | %11i |\n", key, counter->sample_total());
    2135             :         } else {
    2136             :           printf("| %-62s | %11i |\n", key, counter->count());
    2137             :         }
    2138             :       }
    2139             :       printf(
    2140             :           "+----------------------------------------------------------------+"
    2141             :           "-------------+\n");
    2142             :     }
    2143           0 :     delete [] counters;
    2144             :   }
    2145             : 
    2146       29546 :   delete counters_file_;
    2147       59092 :   delete counter_map_;
    2148       29546 : }
    2149             : 
    2150             : 
    2151          17 : static FILE* FOpen(const char* path, const char* mode) {
    2152             : #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
    2153             :   FILE* result;
    2154             :   if (fopen_s(&result, path, mode) == 0) {
    2155             :     return result;
    2156             :   } else {
    2157             :     return nullptr;
    2158             :   }
    2159             : #else
    2160          17 :   FILE* file = fopen(path, mode);
    2161          17 :   if (file == nullptr) return nullptr;
    2162             :   struct stat file_stat;
    2163          34 :   if (fstat(fileno(file), &file_stat) != 0) return nullptr;
    2164          17 :   bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
    2165          17 :   if (is_regular_file) return file;
    2166           0 :   fclose(file);
    2167           0 :   return nullptr;
    2168             : #endif
    2169             : }
    2170             : 
    2171          17 : static char* ReadChars(const char* name, int* size_out) {
    2172          17 :   if (Shell::options.read_from_tcp_port >= 0) {
    2173           0 :     return Shell::ReadCharsFromTcpPort(name, size_out);
    2174             :   }
    2175             : 
    2176          17 :   FILE* file = FOpen(name, "rb");
    2177          17 :   if (file == nullptr) return nullptr;
    2178             : 
    2179          17 :   fseek(file, 0, SEEK_END);
    2180          17 :   size_t size = ftell(file);
    2181          17 :   rewind(file);
    2182             : 
    2183          17 :   char* chars = new char[size + 1];
    2184          17 :   chars[size] = '\0';
    2185          51 :   for (size_t i = 0; i < size;) {
    2186          34 :     i += fread(&chars[i], 1, size - i, file);
    2187          17 :     if (ferror(file)) {
    2188           0 :       fclose(file);
    2189           0 :       delete[] chars;
    2190             :       return nullptr;
    2191             :     }
    2192             :   }
    2193          17 :   fclose(file);
    2194          17 :   *size_out = static_cast<int>(size);
    2195          17 :   return chars;
    2196             : }
    2197             : 
    2198             : 
    2199             : struct DataAndPersistent {
    2200             :   uint8_t* data;
    2201             :   int byte_length;
    2202             :   Global<ArrayBuffer> handle;
    2203             : };
    2204             : 
    2205             : 
    2206           0 : static void ReadBufferWeakCallback(
    2207           0 :     const v8::WeakCallbackInfo<DataAndPersistent>& data) {
    2208           0 :   int byte_length = data.GetParameter()->byte_length;
    2209             :   data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
    2210           0 :       -static_cast<intptr_t>(byte_length));
    2211             : 
    2212           0 :   delete[] data.GetParameter()->data;
    2213             :   data.GetParameter()->handle.Reset();
    2214           0 :   delete data.GetParameter();
    2215           0 : }
    2216             : 
    2217             : 
    2218          34 : void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
    2219             :   static_assert(sizeof(char) == sizeof(uint8_t),
    2220             :                 "char and uint8_t should both have 1 byte");
    2221             :   Isolate* isolate = args.GetIsolate();
    2222          17 :   String::Utf8Value filename(isolate, args[0]);
    2223             :   int length;
    2224          17 :   if (*filename == nullptr) {
    2225           0 :     Throw(isolate, "Error loading file");
    2226           0 :     return;
    2227             :   }
    2228             : 
    2229          17 :   DataAndPersistent* data = new DataAndPersistent;
    2230          17 :   data->data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
    2231          17 :   if (data->data == nullptr) {
    2232           0 :     delete data;
    2233           0 :     Throw(isolate, "Error reading file");
    2234           0 :     return;
    2235             :   }
    2236          17 :   data->byte_length = length;
    2237          17 :   Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
    2238             :   data->handle.Reset(isolate, buffer);
    2239             :   data->handle.SetWeak(data, ReadBufferWeakCallback,
    2240             :                        v8::WeakCallbackType::kParameter);
    2241          17 :   isolate->AdjustAmountOfExternalAllocatedMemory(length);
    2242             : 
    2243          17 :   args.GetReturnValue().Set(buffer);
    2244             : }
    2245             : 
    2246             : // Reads a file into a v8 string.
    2247      113868 : Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
    2248             :   std::unique_ptr<base::OS::MemoryMappedFile> file(
    2249      113868 :       base::OS::MemoryMappedFile::open(name));
    2250      113868 :   if (!file) return Local<String>();
    2251             : 
    2252      113774 :   int size = static_cast<int>(file->size());
    2253      113774 :   char* chars = static_cast<char*>(file->memory());
    2254             :   Local<String> result;
    2255      113792 :   if (i::FLAG_use_external_strings && i::String::IsAscii(chars, size)) {
    2256             :     String::ExternalOneByteStringResource* resource =
    2257          18 :         new ExternalOwningOneByteStringResource(std::move(file));
    2258          18 :     result = String::NewExternalOneByte(isolate, resource).ToLocalChecked();
    2259             :   } else {
    2260             :     result = String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
    2261      113756 :                  .ToLocalChecked();
    2262             :   }
    2263      113774 :   return result;
    2264             : }
    2265             : 
    2266             : 
    2267           0 : void Shell::RunShell(Isolate* isolate) {
    2268           0 :   HandleScope outer_scope(isolate);
    2269             :   v8::Local<v8::Context> context =
    2270             :       v8::Local<v8::Context>::New(isolate, evaluation_context_);
    2271             :   v8::Context::Scope context_scope(context);
    2272           0 :   PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
    2273             :   Local<String> name =
    2274             :       String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
    2275           0 :           .ToLocalChecked();
    2276           0 :   printf("V8 version %s\n", V8::GetVersion());
    2277             :   while (true) {
    2278           0 :     HandleScope inner_scope(isolate);
    2279             :     printf("d8> ");
    2280           0 :     Local<String> input = Shell::ReadFromStdin(isolate);
    2281           0 :     if (input.IsEmpty()) break;
    2282             :     ExecuteString(isolate, input, name, kPrintResult, kReportExceptions,
    2283           0 :                   kProcessMessageQueue);
    2284           0 :   }
    2285             :   printf("\n");
    2286             :   // We need to explicitly clean up the module embedder data for
    2287             :   // the interative shell context.
    2288           0 :   DisposeModuleEmbedderData(context);
    2289           0 : }
    2290             : 
    2291             : class InspectorFrontend final : public v8_inspector::V8Inspector::Channel {
    2292             :  public:
    2293        5074 :   explicit InspectorFrontend(Local<Context> context) {
    2294        2537 :     isolate_ = context->GetIsolate();
    2295             :     context_.Reset(isolate_, context);
    2296        2537 :   }
    2297        5074 :   ~InspectorFrontend() override = default;
    2298             : 
    2299             :  private:
    2300      128011 :   void sendResponse(
    2301             :       int callId,
    2302             :       std::unique_ptr<v8_inspector::StringBuffer> message) override {
    2303      128011 :     Send(message->string());
    2304      128011 :   }
    2305      143586 :   void sendNotification(
    2306             :       std::unique_ptr<v8_inspector::StringBuffer> message) override {
    2307      143586 :     Send(message->string());
    2308      143586 :   }
    2309           0 :   void flushProtocolNotifications() override {}
    2310             : 
    2311     1086388 :   void Send(const v8_inspector::StringView& string) {
    2312      271597 :     v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate_);
    2313      271597 :     int length = static_cast<int>(string.length());
    2314             :     DCHECK_LT(length, v8::String::kMaxLength);
    2315             :     Local<String> message =
    2316             :         (string.is8Bit()
    2317             :              ? v8::String::NewFromOneByte(
    2318             :                    isolate_,
    2319             :                    reinterpret_cast<const uint8_t*>(string.characters8()),
    2320           0 :                    v8::NewStringType::kNormal, length)
    2321             :              : v8::String::NewFromTwoByte(
    2322             :                    isolate_,
    2323             :                    reinterpret_cast<const uint16_t*>(string.characters16()),
    2324      271597 :                    v8::NewStringType::kNormal, length))
    2325      543194 :             .ToLocalChecked();
    2326             :     Local<String> callback_name =
    2327      271597 :         v8::String::NewFromUtf8(isolate_, "receive", v8::NewStringType::kNormal)
    2328      271597 :             .ToLocalChecked();
    2329      271597 :     Local<Context> context = context_.Get(isolate_);
    2330             :     Local<Value> callback =
    2331      814791 :         context->Global()->Get(context, callback_name).ToLocalChecked();
    2332      271597 :     if (callback->IsFunction()) {
    2333      271597 :       v8::TryCatch try_catch(isolate_);
    2334             :       Local<Value> args[] = {message};
    2335      543194 :       USE(Local<Function>::Cast(callback)->Call(context, Undefined(isolate_), 1,
    2336      271597 :                                                 args));
    2337             : #ifdef DEBUG
    2338             :       if (try_catch.HasCaught()) {
    2339             :         Local<Object> exception = Local<Object>::Cast(try_catch.Exception());
    2340             :         Local<String> key = v8::String::NewFromUtf8(isolate_, "message",
    2341             :                                                     v8::NewStringType::kNormal)
    2342             :                                 .ToLocalChecked();
    2343             :         Local<String> expected =
    2344             :             v8::String::NewFromUtf8(isolate_,
    2345             :                                     "Maximum call stack size exceeded",
    2346             :                                     v8::NewStringType::kNormal)
    2347             :                 .ToLocalChecked();
    2348             :         Local<Value> value = exception->Get(context, key).ToLocalChecked();
    2349             :         DCHECK(value->StrictEquals(expected));
    2350             :       }
    2351             : #endif
    2352      271597 :     }
    2353      271597 :   }
    2354             : 
    2355             :   Isolate* isolate_;
    2356             :   Global<Context> context_;
    2357             : };
    2358             : 
    2359      101774 : class InspectorClient : public v8_inspector::V8InspectorClient {
    2360             :  public:
    2361      101774 :   InspectorClient(Local<Context> context, bool connect) {
    2362       99237 :     if (!connect) return;
    2363        2537 :     isolate_ = context->GetIsolate();
    2364        5074 :     channel_.reset(new InspectorFrontend(context));
    2365        5074 :     inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
    2366        5074 :     session_ =
    2367        2537 :         inspector_->connect(1, channel_.get(), v8_inspector::StringView());
    2368        2537 :     context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
    2369             :     inspector_->contextCreated(v8_inspector::V8ContextInfo(
    2370        5074 :         context, kContextGroupId, v8_inspector::StringView()));
    2371             : 
    2372             :     Local<Value> function =
    2373        5074 :         FunctionTemplate::New(isolate_, SendInspectorMessage)
    2374        5074 :             ->GetFunction(context)
    2375        2537 :             .ToLocalChecked();
    2376             :     Local<String> function_name =
    2377        2537 :         String::NewFromUtf8(isolate_, "send", NewStringType::kNormal)
    2378        2537 :             .ToLocalChecked();
    2379        7611 :     CHECK(context->Global()->Set(context, function_name, function).FromJust());
    2380             : 
    2381        2537 :     context_.Reset(isolate_, context);
    2382             :   }
    2383             : 
    2384             :  private:
    2385             :   static v8_inspector::V8InspectorSession* GetSession(Local<Context> context) {
    2386             :     InspectorClient* inspector_client = static_cast<InspectorClient*>(
    2387             :         context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex));
    2388             :     return inspector_client->session_.get();
    2389             :   }
    2390             : 
    2391         513 :   Local<Context> ensureDefaultContextInGroup(int group_id) override {
    2392             :     DCHECK(isolate_);
    2393             :     DCHECK_EQ(kContextGroupId, group_id);
    2394        1026 :     return context_.Get(isolate_);
    2395             :   }
    2396             : 
    2397      128011 :   static void SendInspectorMessage(
    2398      384033 :       const v8::FunctionCallbackInfo<v8::Value>& args) {
    2399             :     Isolate* isolate = args.GetIsolate();
    2400      128011 :     v8::HandleScope handle_scope(isolate);
    2401      128011 :     Local<Context> context = isolate->GetCurrentContext();
    2402             :     args.GetReturnValue().Set(Undefined(isolate));
    2403      128011 :     Local<String> message = args[0]->ToString(context).ToLocalChecked();
    2404             :     v8_inspector::V8InspectorSession* session =
    2405             :         InspectorClient::GetSession(context);
    2406      128011 :     int length = message->Length();
    2407      128011 :     std::unique_ptr<uint16_t[]> buffer(new uint16_t[length]);
    2408      128011 :     message->Write(isolate, buffer.get(), 0, length);
    2409             :     v8_inspector::StringView message_view(buffer.get(), length);
    2410      128011 :     session->dispatchProtocolMessage(message_view);
    2411      128011 :     args.GetReturnValue().Set(True(isolate));
    2412      128011 :   }
    2413             : 
    2414             :   static const int kContextGroupId = 1;
    2415             : 
    2416             :   std::unique_ptr<v8_inspector::V8Inspector> inspector_;
    2417             :   std::unique_ptr<v8_inspector::V8InspectorSession> session_;
    2418             :   std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
    2419             :   Global<Context> context_;
    2420             :   Isolate* isolate_;
    2421             : };
    2422             : 
    2423       59092 : SourceGroup::~SourceGroup() {
    2424       29546 :   delete thread_;
    2425       29546 :   thread_ = nullptr;
    2426       29546 : }
    2427             : 
    2428      107877 : bool ends_with(const char* input, const char* suffix) {
    2429      107877 :   size_t input_length = strlen(input);
    2430      107877 :   size_t suffix_length = strlen(suffix);
    2431      107877 :   if (suffix_length <= input_length) {
    2432      107877 :     return strcmp(input + input_length - suffix_length, suffix) == 0;
    2433             :   }
    2434             :   return false;
    2435             : }
    2436             : 
    2437       50887 : bool SourceGroup::Execute(Isolate* isolate) {
    2438             :   bool success = true;
    2439      157732 :   for (int i = begin_offset_; i < end_offset_; ++i) {
    2440      109376 :     const char* arg = argv_[i];
    2441      109376 :     if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
    2442             :       // Execute argument given to -e option directly.
    2443        1499 :       HandleScope handle_scope(isolate);
    2444             :       Local<String> file_name =
    2445             :           String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
    2446        1499 :               .ToLocalChecked();
    2447             :       Local<String> source =
    2448        1499 :           String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
    2449        2998 :               .ToLocalChecked();
    2450             :       Shell::set_script_executed();
    2451        1499 :       if (!Shell::ExecuteString(isolate, source, file_name,
    2452             :                                 Shell::kNoPrintResult, Shell::kReportExceptions,
    2453        1499 :                                 Shell::kNoProcessMessageQueue)) {
    2454             :         success = false;
    2455        1341 :         break;
    2456             :       }
    2457             :       ++i;
    2458         158 :       continue;
    2459      107877 :     } else if (ends_with(arg, ".mjs")) {
    2460             :       Shell::set_script_executed();
    2461           0 :       if (!Shell::ExecuteModule(isolate, arg)) {
    2462             :         success = false;
    2463             :         break;
    2464             :       }
    2465             :       continue;
    2466      107877 :     } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
    2467             :       // Treat the next file as a module.
    2468         675 :       arg = argv_[++i];
    2469             :       Shell::set_script_executed();
    2470         675 :       if (!Shell::ExecuteModule(isolate, arg)) {
    2471             :         success = false;
    2472             :         break;
    2473             :       }
    2474             :       continue;
    2475      107202 :     } else if (arg[0] == '-') {
    2476             :       // Ignore other options. They have been parsed already.
    2477             :       continue;
    2478             :     }
    2479             : 
    2480             :     // Use all other arguments as names of files to load and run.
    2481      106250 :     HandleScope handle_scope(isolate);
    2482             :     Local<String> file_name =
    2483             :         String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
    2484      106250 :             .ToLocalChecked();
    2485             :     Local<String> source = ReadFile(isolate, arg);
    2486      106250 :     if (source.IsEmpty()) {
    2487             :       printf("Error reading '%s'\n", arg);
    2488           0 :       base::OS::ExitProcess(1);
    2489             :     }
    2490             :     Shell::set_script_executed();
    2491      106250 :     if (!Shell::ExecuteString(isolate, source, file_name, Shell::kNoPrintResult,
    2492             :                               Shell::kReportExceptions,
    2493      106250 :                               Shell::kProcessMessageQueue)) {
    2494             :       success = false;
    2495        1005 :       break;
    2496             :     }
    2497      105245 :   }
    2498       50887 :   return success;
    2499             : }
    2500             : 
    2501           0 : Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
    2502      106250 :   return Shell::ReadFile(isolate, name);
    2503             : }
    2504             : 
    2505           0 : SourceGroup::IsolateThread::IsolateThread(SourceGroup* group)
    2506           0 :     : base::Thread(GetThreadOptions("IsolateThread")), group_(group) {}
    2507             : 
    2508           0 : void SourceGroup::ExecuteInThread() {
    2509             :   Isolate::CreateParams create_params;
    2510           0 :   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
    2511           0 :   Isolate* isolate = Isolate::New(create_params);
    2512             :   isolate->SetHostImportModuleDynamicallyCallback(
    2513           0 :       Shell::HostImportModuleDynamically);
    2514             :   isolate->SetHostInitializeImportMetaObjectCallback(
    2515           0 :       Shell::HostInitializeImportMetaObject);
    2516           0 :   Shell::SetWaitUntilDone(isolate, false);
    2517           0 :   D8Console console(isolate);
    2518           0 :   debug::SetConsoleDelegate(isolate, &console);
    2519           0 :   for (int i = 0; i < Shell::options.stress_runs; ++i) {
    2520           0 :     next_semaphore_.Wait();
    2521             :     {
    2522             :       Isolate::Scope iscope(isolate);
    2523           0 :       PerIsolateData data(isolate);
    2524             :       {
    2525           0 :         HandleScope scope(isolate);
    2526           0 :         Local<Context> context = Shell::CreateEvaluationContext(isolate);
    2527             :         {
    2528             :           Context::Scope cscope(context);
    2529             :           InspectorClient inspector_client(context,
    2530           0 :                                            Shell::options.enable_inspector);
    2531           0 :           PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
    2532           0 :           Execute(isolate);
    2533           0 :           Shell::CompleteMessageLoop(isolate);
    2534             :         }
    2535           0 :         DisposeModuleEmbedderData(context);
    2536             :       }
    2537           0 :       Shell::CollectGarbage(isolate);
    2538             :     }
    2539           0 :     done_semaphore_.Signal();
    2540             :   }
    2541             : 
    2542           0 :   isolate->Dispose();
    2543           0 : }
    2544             : 
    2545             : 
    2546           0 : void SourceGroup::StartExecuteInThread() {
    2547           0 :   if (thread_ == nullptr) {
    2548           0 :     thread_ = new IsolateThread(this);
    2549           0 :     thread_->Start();
    2550             :   }
    2551           0 :   next_semaphore_.Signal();
    2552           0 : }
    2553             : 
    2554             : 
    2555           0 : void SourceGroup::WaitForThread() {
    2556           0 :   if (thread_ == nullptr) return;
    2557           0 :   done_semaphore_.Wait();
    2558             : }
    2559             : 
    2560             : 
    2561           0 : void SourceGroup::JoinThread() {
    2562           0 :   if (thread_ == nullptr) return;
    2563           0 :   thread_->Join();
    2564             : }
    2565             : 
    2566           0 : ExternalizedContents::~ExternalizedContents() {
    2567         390 :   if (data_ != nullptr) {
    2568         148 :     deleter_(data_, length_, deleter_data_);
    2569             :   }
    2570           0 : }
    2571             : 
    2572        3248 : void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) {
    2573        3248 :   base::MutexGuard lock_guard(&mutex_);
    2574        3248 :   data_.push_back(std::move(data));
    2575        3248 : }
    2576             : 
    2577        2751 : bool SerializationDataQueue::Dequeue(
    2578             :     std::unique_ptr<SerializationData>* out_data) {
    2579             :   out_data->reset();
    2580        2751 :   base::MutexGuard lock_guard(&mutex_);
    2581        2750 :   if (data_.empty()) return false;
    2582             :   *out_data = std::move(data_[0]);
    2583        2115 :   data_.erase(data_.begin());
    2584        2116 :   return true;
    2585             : }
    2586             : 
    2587             : 
    2588           0 : bool SerializationDataQueue::IsEmpty() {
    2589           0 :   base::MutexGuard lock_guard(&mutex_);
    2590           0 :   return data_.empty();
    2591             : }
    2592             : 
    2593             : 
    2594        1210 : void SerializationDataQueue::Clear() {
    2595        1210 :   base::MutexGuard lock_guard(&mutex_);
    2596             :   data_.clear();
    2597        1210 : }
    2598             : 
    2599         605 : Worker::Worker()
    2600             :     : in_semaphore_(0),
    2601             :       out_semaphore_(0),
    2602             :       thread_(nullptr),
    2603             :       script_(nullptr),
    2604        1210 :       running_(false) {}
    2605             : 
    2606        1210 : Worker::~Worker() {
    2607         605 :   delete thread_;
    2608         605 :   thread_ = nullptr;
    2609         605 :   delete[] script_;
    2610         605 :   script_ = nullptr;
    2611         605 :   in_queue_.Clear();
    2612         605 :   out_queue_.Clear();
    2613         605 : }
    2614             : 
    2615             : 
    2616         605 : void Worker::StartExecuteInThread(const char* script) {
    2617         605 :   running_ = true;
    2618         605 :   script_ = i::StrDup(script);
    2619        1210 :   thread_ = new WorkerThread(this);
    2620         605 :   thread_->Start();
    2621         605 : }
    2622             : 
    2623        1663 : void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
    2624        3326 :   in_queue_.Enqueue(std::move(data));
    2625        1663 :   in_semaphore_.Signal();
    2626        1663 : }
    2627             : 
    2628        1007 : std::unique_ptr<SerializationData> Worker::GetMessage() {
    2629        1007 :   std::unique_ptr<SerializationData> result;
    2630        2640 :   while (!out_queue_.Dequeue(&result)) {
    2631             :     // If the worker is no longer running, and there are no messages in the
    2632             :     // queue, don't expect any more messages from it.
    2633        1270 :     if (!base::Relaxed_Load(&running_)) break;
    2634         626 :     out_semaphore_.Wait();
    2635             :   }
    2636        1007 :   return result;
    2637             : }
    2638             : 
    2639             : 
    2640        1016 : void Worker::Terminate() {
    2641        1016 :   base::Relaxed_Store(&running_, false);
    2642             :   // Post nullptr to wake the Worker thread message loop, and tell it to stop
    2643             :   // running.
    2644        2032 :   PostMessage(nullptr);
    2645        1016 : }
    2646             : 
    2647             : 
    2648           0 : void Worker::WaitForThread() {
    2649         605 :   Terminate();
    2650         605 :   thread_->Join();
    2651           0 : }
    2652             : 
    2653             : 
    2654         605 : void Worker::ExecuteInThread() {
    2655             :   Isolate::CreateParams create_params;
    2656         605 :   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
    2657         605 :   Isolate* isolate = Isolate::New(create_params);
    2658             :   isolate->SetHostImportModuleDynamicallyCallback(
    2659         605 :       Shell::HostImportModuleDynamically);
    2660             :   isolate->SetHostInitializeImportMetaObjectCallback(
    2661         605 :       Shell::HostInitializeImportMetaObject);
    2662         605 :   D8Console console(isolate);
    2663         605 :   debug::SetConsoleDelegate(isolate, &console);
    2664             :   {
    2665             :     Isolate::Scope iscope(isolate);
    2666             :     {
    2667         605 :       HandleScope scope(isolate);
    2668        1210 :       PerIsolateData data(isolate);
    2669         605 :       Local<Context> context = Shell::CreateEvaluationContext(isolate);
    2670             :       {
    2671             :         Context::Scope cscope(context);
    2672        1210 :         PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
    2673             : 
    2674         605 :         Local<Object> global = context->Global();
    2675         605 :         Local<Value> this_value = External::New(isolate, this);
    2676             :         Local<FunctionTemplate> postmessage_fun_template =
    2677         605 :             FunctionTemplate::New(isolate, PostMessageOut, this_value);
    2678             : 
    2679             :         Local<Function> postmessage_fun;
    2680         605 :         if (postmessage_fun_template->GetFunction(context)
    2681         605 :                 .ToLocal(&postmessage_fun)) {
    2682             :           global->Set(context, String::NewFromUtf8(isolate, "postMessage",
    2683             :                                                    NewStringType::kNormal)
    2684             :                                    .ToLocalChecked(),
    2685        1815 :                       postmessage_fun).FromJust();
    2686             :         }
    2687             : 
    2688             :         // First run the script
    2689             :         Local<String> file_name =
    2690             :             String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
    2691         605 :                 .ToLocalChecked();
    2692             :         Local<String> source =
    2693         605 :             String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
    2694        1210 :                 .ToLocalChecked();
    2695        1210 :         if (Shell::ExecuteString(
    2696             :                 isolate, source, file_name, Shell::kNoPrintResult,
    2697         605 :                 Shell::kReportExceptions, Shell::kProcessMessageQueue)) {
    2698             :           // Get the message handler
    2699             :           Local<Value> onmessage =
    2700             :               global->Get(context, String::NewFromUtf8(isolate, "onmessage",
    2701             :                                                        NewStringType::kNormal)
    2702        1815 :                                        .ToLocalChecked()).ToLocalChecked();
    2703         605 :           if (onmessage->IsFunction()) {
    2704             :             Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
    2705             :             // Now wait for messages
    2706             :             while (true) {
    2707        1117 :               in_semaphore_.Wait();
    2708        1118 :               std::unique_ptr<SerializationData> data;
    2709        1118 :               if (!in_queue_.Dequeue(&data)) continue;
    2710        1118 :               if (!data) {
    2711             :                 break;
    2712             :               }
    2713        1203 :               v8::TryCatch try_catch(isolate);
    2714             :               Local<Value> value;
    2715         602 :               if (Shell::DeserializeValue(isolate, std::move(data))
    2716         602 :                       .ToLocal(&value)) {
    2717         602 :                 Local<Value> argv[] = {value};
    2718             :                 MaybeLocal<Value> result =
    2719         602 :                     onmessage_fun->Call(context, global, 1, argv);
    2720             :                 USE(result);
    2721             :               }
    2722         600 :               if (try_catch.HasCaught()) {
    2723           9 :                 Shell::ReportException(isolate, &try_catch);
    2724             :               }
    2725             :             }
    2726             :           }
    2727             :         }
    2728             :       }
    2729        1210 :       DisposeModuleEmbedderData(context);
    2730             :     }
    2731         605 :     Shell::CollectGarbage(isolate);
    2732             :   }
    2733         605 :   isolate->Dispose();
    2734             : 
    2735             :   // Post nullptr to wake the thread waiting on GetMessage() if there is one.
    2736        1210 :   out_queue_.Enqueue(nullptr);
    2737         605 :   out_semaphore_.Signal();
    2738         605 : }
    2739             : 
    2740             : 
    2741        2928 : void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
    2742             :   Isolate* isolate = args.GetIsolate();
    2743         973 :   HandleScope handle_scope(isolate);
    2744             : 
    2745         975 :   if (args.Length() < 1) {
    2746           0 :     Throw(isolate, "Invalid argument");
    2747         978 :     return;
    2748             :   }
    2749             : 
    2750         975 :   Local<Value> message = args[0];
    2751             :   Local<Value> transfer = Undefined(isolate);
    2752             :   std::unique_ptr<SerializationData> data =
    2753         975 :       Shell::SerializeValue(isolate, message, transfer);
    2754         980 :   if (data) {
    2755             :     DCHECK(args.Data()->IsExternal());
    2756             :     Local<External> this_value = Local<External>::Cast(args.Data());
    2757         980 :     Worker* worker = static_cast<Worker*>(this_value->Value());
    2758        1960 :     worker->out_queue_.Enqueue(std::move(data));
    2759         980 :     worker->out_semaphore_.Signal();
    2760         979 :   }
    2761             : }
    2762             : 
    2763             : 
    2764       88637 : void SetFlagsFromString(const char* flags) {
    2765       88637 :   v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
    2766       88637 : }
    2767             : 
    2768             : 
    2769       29546 : bool Shell::SetOptions(int argc, char* argv[]) {
    2770             :   bool logfile_per_isolate = false;
    2771      259705 :   for (int i = 0; i < argc; i++) {
    2772      230164 :     if (strcmp(argv[i], "--") == 0) {
    2773           5 :       argv[i] = nullptr;
    2774          20 :       for (int j = i + 1; j < argc; j++) {
    2775          30 :         options.arguments.push_back(argv[j]);
    2776          15 :         argv[j] = nullptr;
    2777             :       }
    2778             :       break;
    2779      230159 :     } else if (strcmp(argv[i], "--no-arguments") == 0) {
    2780           0 :       options.include_arguments = false;
    2781           0 :       argv[i] = nullptr;
    2782      230159 :     } else if (strcmp(argv[i], "--stress-opt") == 0) {
    2783        5733 :       options.stress_opt = true;
    2784        5733 :       argv[i] = nullptr;
    2785      448792 :     } else if (strcmp(argv[i], "--nostress-opt") == 0 ||
    2786      224366 :                strcmp(argv[i], "--no-stress-opt") == 0) {
    2787         364 :       options.stress_opt = false;
    2788         364 :       argv[i] = nullptr;
    2789      224062 :     } else if (strcmp(argv[i], "--stress-deopt") == 0) {
    2790           0 :       options.stress_deopt = true;
    2791           0 :       argv[i] = nullptr;
    2792      224062 :     } else if (strcmp(argv[i], "--stress-background-compile") == 0) {
    2793        5730 :       options.stress_background_compile = true;
    2794        5730 :       argv[i] = nullptr;
    2795      436664 :     } else if (strcmp(argv[i], "--nostress-background-compile") == 0 ||
    2796      218332 :                strcmp(argv[i], "--no-stress-background-compile") == 0) {
    2797           9 :       options.stress_background_compile = false;
    2798           9 :       argv[i] = nullptr;
    2799      436506 :     } else if (strcmp(argv[i], "--noalways-opt") == 0 ||
    2800      218183 :                strcmp(argv[i], "--no-always-opt") == 0) {
    2801             :       // No support for stressing if we can't use --always-opt.
    2802         559 :       options.stress_opt = false;
    2803         559 :       options.stress_deopt = false;
    2804      217764 :     } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
    2805             :       logfile_per_isolate = true;
    2806           0 :       argv[i] = nullptr;
    2807      217764 :     } else if (strcmp(argv[i], "--shell") == 0) {
    2808           0 :       options.interactive_shell = true;
    2809           0 :       argv[i] = nullptr;
    2810      217764 :     } else if (strcmp(argv[i], "--test") == 0) {
    2811       29546 :       options.test_shell = true;
    2812       29546 :       argv[i] = nullptr;
    2813      376436 :     } else if (strcmp(argv[i], "--notest") == 0 ||
    2814      188218 :                strcmp(argv[i], "--no-test") == 0) {
    2815          10 :       options.test_shell = false;
    2816          10 :       argv[i] = nullptr;
    2817      188208 :     } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
    2818           5 :       options.send_idle_notification = true;
    2819           5 :       argv[i] = nullptr;
    2820      188203 :     } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
    2821          32 :       options.invoke_weak_callbacks = true;
    2822             :       // TODO(jochen) See issue 3351
    2823          32 :       options.send_idle_notification = true;
    2824          32 :       argv[i] = nullptr;
    2825      188171 :     } else if (strcmp(argv[i], "--omit-quit") == 0) {
    2826          18 :       options.omit_quit = true;
    2827          18 :       argv[i] = nullptr;
    2828      188153 :     } else if (strcmp(argv[i], "--no-wait-for-wasm") == 0) {
    2829             :       // TODO(herhut) Remove this flag once wasm compilation is fully
    2830             :       // isolate-independent.
    2831           8 :       options.wait_for_wasm = false;
    2832           8 :       argv[i] = nullptr;
    2833      188145 :     } else if (strcmp(argv[i], "-f") == 0) {
    2834             :       // Ignore any -f flags for compatibility with other stand-alone
    2835             :       // JavaScript engines.
    2836             :       continue;
    2837      188145 :     } else if (strcmp(argv[i], "--isolate") == 0) {
    2838           0 :       options.num_isolates++;
    2839      188145 :     } else if (strcmp(argv[i], "--throws") == 0) {
    2840        1350 :       options.expected_to_throw = true;
    2841        1350 :       argv[i] = nullptr;
    2842      186795 :     } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
    2843           0 :       options.icu_data_file = argv[i] + 16;
    2844           0 :       argv[i] = nullptr;
    2845             : #ifdef V8_USE_EXTERNAL_STARTUP_DATA
    2846      186795 :     } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
    2847           0 :       options.natives_blob = argv[i] + 15;
    2848           0 :       argv[i] = nullptr;
    2849      186795 :     } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
    2850           0 :       options.snapshot_blob = argv[i] + 16;
    2851           0 :       argv[i] = nullptr;
    2852             : #endif  // V8_USE_EXTERNAL_STARTUP_DATA
    2853      373590 :     } else if (strcmp(argv[i], "--cache") == 0 ||
    2854      186795 :                strncmp(argv[i], "--cache=", 8) == 0) {
    2855          57 :       const char* value = argv[i] + 7;
    2856          57 :       if (!*value || strncmp(value, "=code", 6) == 0) {
    2857          52 :         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
    2858             :         options.code_cache_options =
    2859          52 :             ShellOptions::CodeCacheOptions::kProduceCache;
    2860           5 :       } else if (strncmp(value, "=none", 6) == 0) {
    2861           0 :         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
    2862             :         options.code_cache_options =
    2863           0 :             ShellOptions::CodeCacheOptions::kNoProduceCache;
    2864           5 :       } else if (strncmp(value, "=after-execute", 15) == 0) {
    2865           5 :         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
    2866             :         options.code_cache_options =
    2867           5 :             ShellOptions::CodeCacheOptions::kProduceCacheAfterExecute;
    2868           0 :       } else if (strncmp(value, "=full-code-cache", 17) == 0) {
    2869           0 :         options.compile_options = v8::ScriptCompiler::kEagerCompile;
    2870             :         options.code_cache_options =
    2871           0 :             ShellOptions::CodeCacheOptions::kProduceCache;
    2872             :       } else {
    2873             :         printf("Unknown option to --cache.\n");
    2874           0 :         return false;
    2875             :       }
    2876          57 :       argv[i] = nullptr;
    2877      186738 :     } else if (strcmp(argv[i], "--enable-tracing") == 0) {
    2878           1 :       options.trace_enabled = true;
    2879           1 :       argv[i] = nullptr;
    2880      186737 :     } else if (strncmp(argv[i], "--trace-path=", 13) == 0) {
    2881           1 :       options.trace_path = argv[i] + 13;
    2882           1 :       argv[i] = nullptr;
    2883      186736 :     } else if (strncmp(argv[i], "--trace-config=", 15) == 0) {
    2884           0 :       options.trace_config = argv[i] + 15;
    2885           0 :       argv[i] = nullptr;
    2886      186736 :     } else if (strcmp(argv[i], "--enable-inspector") == 0) {
    2887        1467 :       options.enable_inspector = true;
    2888        1467 :       argv[i] = nullptr;
    2889      185269 :     } else if (strncmp(argv[i], "--lcov=", 7) == 0) {
    2890           0 :       options.lcov_file = argv[i] + 7;
    2891           0 :       argv[i] = nullptr;
    2892      185269 :     } else if (strcmp(argv[i], "--disable-in-process-stack-traces") == 0) {
    2893          10 :       options.disable_in_process_stack_traces = true;
    2894          10 :       argv[i] = nullptr;
    2895             : #ifdef V8_OS_POSIX
    2896      185259 :     } else if (strncmp(argv[i], "--read-from-tcp-port=", 21) == 0) {
    2897           0 :       options.read_from_tcp_port = atoi(argv[i] + 21);
    2898           0 :       argv[i] = nullptr;
    2899             : #endif  // V8_OS_POSIX
    2900      185259 :     } else if (strcmp(argv[i], "--enable-os-system") == 0) {
    2901           0 :       options.enable_os_system = true;
    2902           0 :       argv[i] = nullptr;
    2903      185259 :     } else if (strcmp(argv[i], "--quiet-load") == 0) {
    2904           0 :       options.quiet_load = true;
    2905           0 :       argv[i] = nullptr;
    2906      185259 :     } else if (strncmp(argv[i], "--thread-pool-size=", 19) == 0) {
    2907           0 :       options.thread_pool_size = atoi(argv[i] + 19);
    2908           0 :       argv[i] = nullptr;
    2909      185259 :     } else if (strcmp(argv[i], "--stress-delay-tasks") == 0) {
    2910             :       // Delay execution of tasks by 0-100ms randomly (based on --random-seed).
    2911           0 :       options.stress_delay_tasks = true;
    2912           0 :       argv[i] = nullptr;
    2913             :     }
    2914             :   }
    2915             : 
    2916       29546 :   v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
    2917       29546 :   options.mock_arraybuffer_allocator = i::FLAG_mock_arraybuffer_allocator;
    2918             :   options.mock_arraybuffer_allocator_limit =
    2919       29546 :       i::FLAG_mock_arraybuffer_allocator_limit;
    2920             : 
    2921             :   // Set up isolated source groups.
    2922       29546 :   options.isolate_sources = new SourceGroup[options.num_isolates];
    2923             :   SourceGroup* current = options.isolate_sources;
    2924             :   current->Begin(argv, 1);
    2925       93671 :   for (int i = 1; i < argc; i++) {
    2926       64125 :     const char* str = argv[i];
    2927       64125 :     if (strcmp(str, "--isolate") == 0) {
    2928             :       current->End(i);
    2929           0 :       current++;
    2930           0 :       current->Begin(argv, i + 1);
    2931       64125 :     } else if (strcmp(str, "--module") == 0) {
    2932             :       // Pass on to SourceGroup, which understands this option.
    2933       63666 :     } else if (strncmp(str, "--", 2) == 0) {
    2934             :       printf("Warning: unknown flag %s.\nTry --help for options\n", str);
    2935       63134 :     } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
    2936             :       set_script_executed();
    2937       61643 :     } else if (strncmp(str, "-", 1) != 0) {
    2938             :       // Not a flag, so it must be a script to execute.
    2939             :       set_script_executed();
    2940             :     }
    2941             :   }
    2942             :   current->End(argc);
    2943             : 
    2944       29546 :   if (!logfile_per_isolate && options.num_isolates) {
    2945       29546 :     SetFlagsFromString("--nologfile_per_isolate");
    2946             :   }
    2947             : 
    2948             :   return true;
    2949             : }
    2950             : 
    2951       50887 : int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
    2952       50887 :   for (int i = 1; i < options.num_isolates; ++i) {
    2953           0 :     options.isolate_sources[i].StartExecuteInThread();
    2954             :   }
    2955             :   bool success = true;
    2956             :   {
    2957       50887 :     SetWaitUntilDone(isolate, false);
    2958       50887 :     if (options.lcov_file) {
    2959           0 :       debug::Coverage::SelectMode(isolate, debug::Coverage::kBlockCount);
    2960             :     }
    2961       50887 :     HandleScope scope(isolate);
    2962       50887 :     Local<Context> context = CreateEvaluationContext(isolate);
    2963       50887 :     bool use_existing_context = last_run && use_interactive_shell();
    2964       50887 :     if (use_existing_context) {
    2965             :       // Keep using the same context in the interactive shell.
    2966             :       evaluation_context_.Reset(isolate, context);
    2967             :     }
    2968             :     {
    2969             :       Context::Scope cscope(context);
    2970      101774 :       InspectorClient inspector_client(context, options.enable_inspector);
    2971      101774 :       PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
    2972       50887 :       if (!options.isolate_sources[0].Execute(isolate)) success = false;
    2973       50887 :       if (!CompleteMessageLoop(isolate)) success = false;
    2974             :     }
    2975       50887 :     if (!use_existing_context) {
    2976       50887 :       DisposeModuleEmbedderData(context);
    2977             :     }
    2978       50887 :     WriteLcovData(isolate, options.lcov_file);
    2979             :   }
    2980       50887 :   CollectGarbage(isolate);
    2981       50887 :   for (int i = 1; i < options.num_isolates; ++i) {
    2982           0 :     if (last_run) {
    2983           0 :       options.isolate_sources[i].JoinThread();
    2984             :     } else {
    2985           0 :       options.isolate_sources[i].WaitForThread();
    2986             :     }
    2987             :   }
    2988       50887 :   CleanupWorkers();
    2989             :   // In order to finish successfully, success must be != expected_to_throw.
    2990       50887 :   return success == Shell::options.expected_to_throw ? 1 : 0;
    2991             : }
    2992             : 
    2993             : 
    2994       81038 : void Shell::CollectGarbage(Isolate* isolate) {
    2995       81038 :   if (options.send_idle_notification) {
    2996             :     const double kLongIdlePauseInSeconds = 1.0;
    2997         142 :     isolate->ContextDisposedNotification();
    2998             :     isolate->IdleNotificationDeadline(
    2999         142 :         g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
    3000             :   }
    3001       81038 :   if (options.invoke_weak_callbacks) {
    3002             :     // By sending a low memory notifications, we will try hard to collect all
    3003             :     // garbage and will therefore also invoke all weak callbacks of actually
    3004             :     // unreachable persistent handles.
    3005          97 :     isolate->LowMemoryNotification();
    3006             :   }
    3007       81038 : }
    3008             : 
    3009       53184 : void Shell::SetWaitUntilDone(Isolate* isolate, bool value) {
    3010             :   base::MutexGuard guard(isolate_status_lock_.Pointer());
    3011       53184 :   if (isolate_status_.count(isolate) == 0) {
    3012       59182 :     isolate_status_.insert(std::make_pair(isolate, value));
    3013             :   } else {
    3014       23593 :     isolate_status_[isolate] = value;
    3015             :   }
    3016       53184 : }
    3017             : 
    3018             : namespace {
    3019      158004 : bool ProcessMessages(
    3020             :     Isolate* isolate,
    3021             :     const std::function<platform::MessageLoopBehavior()>& behavior) {
    3022             :   while (true) {
    3023             :     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
    3024      159240 :     i::SaveAndSwitchContext saved_context(i_isolate, i::Context());
    3025      160476 :     SealHandleScope shs(isolate);
    3026      359483 :     while (v8::platform::PumpMessageLoop(g_default_platform, isolate,
    3027      200243 :                                          behavior())) {
    3028       41003 :       MicrotasksScope::PerformCheckpoint(isolate);
    3029             :     }
    3030      159240 :     if (g_default_platform->IdleTasksEnabled(isolate)) {
    3031             :       v8::platform::RunIdleTasks(g_default_platform, isolate,
    3032      159240 :                                  50.0 / base::Time::kMillisecondsPerSecond);
    3033             :     }
    3034      160476 :     HandleScope handle_scope(isolate);
    3035             :     PerIsolateData* data = PerIsolateData::Get(isolate);
    3036             :     Local<Function> callback;
    3037      318480 :     if (!data->GetTimeoutCallback().ToLocal(&callback)) break;
    3038             :     Local<Context> context;
    3039        2530 :     if (!data->GetTimeoutContext().ToLocal(&context)) break;
    3040        2501 :     TryCatch try_catch(isolate);
    3041        1265 :     try_catch.SetVerbose(true);
    3042             :     Context::Scope context_scope(context);
    3043        2530 :     if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) {
    3044          29 :       Shell::ReportException(isolate, &try_catch);
    3045             :       return false;
    3046             :     }
    3047             :   }
    3048      157975 :   return true;
    3049             : }
    3050             : }  // anonymous namespace
    3051             : 
    3052       50887 : bool Shell::CompleteMessageLoop(Isolate* isolate) {
    3053       54364 :   auto get_waiting_behaviour = [isolate]() {
    3054             :     base::MutexGuard guard(isolate_status_lock_.Pointer());
    3055             :     DCHECK_GT(isolate_status_.count(isolate), 0);
    3056       54364 :     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
    3057             :     i::wasm::WasmEngine* wasm_engine = i_isolate->wasm_engine();
    3058       54345 :     bool should_wait = (options.wait_for_wasm &&
    3059      106621 :                         wasm_engine->HasRunningCompileJob(i_isolate)) ||
    3060       52257 :                        isolate_status_[isolate];
    3061             :     return should_wait ? platform::MessageLoopBehavior::kWaitForWork
    3062      108728 :                        : platform::MessageLoopBehavior::kDoNotWait;
    3063             :   };
    3064      101774 :   return ProcessMessages(isolate, get_waiting_behaviour);
    3065             : }
    3066             : 
    3067      107117 : bool Shell::EmptyMessageQueues(Isolate* isolate) {
    3068             :   return ProcessMessages(
    3069      214234 :       isolate, []() { return platform::MessageLoopBehavior::kDoNotWait; });
    3070             : }
    3071             : 
    3072        5448 : class Serializer : public ValueSerializer::Delegate {
    3073             :  public:
    3074        1810 :   explicit Serializer(Isolate* isolate)
    3075             :       : isolate_(isolate),
    3076             :         serializer_(isolate, this),
    3077        3619 :         current_memory_usage_(0) {}
    3078             : 
    3079        1807 :   Maybe<bool> WriteValue(Local<Context> context, Local<Value> value,
    3080             :                          Local<Value> transfer) {
    3081             :     bool ok;
    3082             :     DCHECK(!data_);
    3083        1807 :     data_.reset(new SerializationData);
    3084        3627 :     if (!PrepareTransfer(context, transfer).To(&ok)) {
    3085             :       return Nothing<bool>();
    3086             :     }
    3087        1650 :     serializer_.WriteHeader();
    3088             : 
    3089        3292 :     if (!serializer_.WriteValue(context, value).To(&ok)) {
    3090             :       data_.reset();
    3091             :       return Nothing<bool>();
    3092             :     }
    3093             : 
    3094        3256 :     if (!FinalizeTransfer().To(&ok)) {
    3095             :       return Nothing<bool>();
    3096             :     }
    3097             : 
    3098        1619 :     std::pair<uint8_t*, size_t> pair = serializer_.Release();
    3099        1622 :     data_->data_.reset(pair.first);
    3100        1622 :     data_->size_ = pair.second;
    3101             :     return Just(true);
    3102             :   }
    3103             : 
    3104             :   std::unique_ptr<SerializationData> Release() { return std::move(data_); }
    3105             : 
    3106        1816 :   void AppendExternalizedContentsTo(std::vector<ExternalizedContents>* to) {
    3107             :     to->insert(to->end(),
    3108             :                std::make_move_iterator(externalized_contents_.begin()),
    3109        1816 :                std::make_move_iterator(externalized_contents_.end()));
    3110             :     externalized_contents_.clear();
    3111        1816 :   }
    3112             : 
    3113             :  protected:
    3114             :   // Implements ValueSerializer::Delegate.
    3115           9 :   void ThrowDataCloneError(Local<String> message) override {
    3116           9 :     isolate_->ThrowException(Exception::Error(message));
    3117           9 :   }
    3118             : 
    3119         369 :   Maybe<uint32_t> GetSharedArrayBufferId(
    3120             :       Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override {
    3121             :     DCHECK_NOT_NULL(data_);
    3122         738 :     for (size_t index = 0; index < shared_array_buffers_.size(); ++index) {
    3123         369 :       if (shared_array_buffers_[index] == shared_array_buffer) {
    3124           0 :         return Just<uint32_t>(static_cast<uint32_t>(index));
    3125             :       }
    3126             :     }
    3127             : 
    3128             :     size_t index = shared_array_buffers_.size();
    3129         369 :     shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
    3130             :     data_->shared_array_buffer_contents_.push_back(
    3131        1107 :         MaybeExternalize(shared_array_buffer));
    3132         369 :     return Just<uint32_t>(static_cast<uint32_t>(index));
    3133             :   }
    3134             : 
    3135          92 :   Maybe<uint32_t> GetWasmModuleTransferId(
    3136             :       Isolate* isolate, Local<WasmModuleObject> module) override {
    3137             :     DCHECK_NOT_NULL(data_);
    3138         184 :     for (size_t index = 0; index < wasm_modules_.size(); ++index) {
    3139          92 :       if (wasm_modules_[index] == module) {
    3140           0 :         return Just<uint32_t>(static_cast<uint32_t>(index));
    3141             :       }
    3142             :     }
    3143             : 
    3144             :     size_t index = wasm_modules_.size();
    3145          92 :     wasm_modules_.emplace_back(isolate_, module);
    3146         276 :     data_->transferrable_modules_.push_back(module->GetTransferrableModule());
    3147          92 :     return Just<uint32_t>(static_cast<uint32_t>(index));
    3148             :   }
    3149             : 
    3150        1691 :   void* ReallocateBufferMemory(void* old_buffer, size_t size,
    3151             :                                size_t* actual_size) override {
    3152             :     // Not accurate, because we don't take into account reallocated buffers,
    3153             :     // but this is fine for testing.
    3154        1691 :     current_memory_usage_ += size;
    3155        1691 :     if (current_memory_usage_ > kMaxSerializerMemoryUsage) return nullptr;
    3156             : 
    3157        1698 :     void* result = realloc(old_buffer, size);
    3158        1698 :     *actual_size = result ? size : 0;
    3159        1698 :     return result;
    3160             :   }
    3161             : 
    3162          27 :   void FreeBufferMemory(void* buffer) override { free(buffer); }
    3163             : 
    3164             :  private:
    3165        1814 :   Maybe<bool> PrepareTransfer(Local<Context> context, Local<Value> transfer) {
    3166        1814 :     if (transfer->IsArray()) {
    3167             :       Local<Array> transfer_array = Local<Array>::Cast(transfer);
    3168         198 :       uint32_t length = transfer_array->Length();
    3169         243 :       for (uint32_t i = 0; i < length; ++i) {
    3170             :         Local<Value> element;
    3171         414 :         if (transfer_array->Get(context, i).ToLocal(&element)) {
    3172         198 :           if (!element->IsArrayBuffer()) {
    3173         144 :             Throw(isolate_, "Transfer array elements must be an ArrayBuffer");
    3174         153 :             return Nothing<bool>();
    3175             :           }
    3176             : 
    3177          54 :           Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(element);
    3178             : 
    3179          54 :           if (std::find(array_buffers_.begin(), array_buffers_.end(),
    3180          45 :                         array_buffer) != array_buffers_.end()) {
    3181             :             Throw(isolate_,
    3182           9 :                   "ArrayBuffer occurs in the transfer array more than once");
    3183             :             return Nothing<bool>();
    3184             :           }
    3185             : 
    3186             :           serializer_.TransferArrayBuffer(
    3187          45 :               static_cast<uint32_t>(array_buffers_.size()), array_buffer);
    3188          45 :           array_buffers_.emplace_back(isolate_, array_buffer);
    3189             :         } else {
    3190             :           return Nothing<bool>();
    3191             :         }
    3192             :       }
    3193             :       return Just(true);
    3194        1614 :     } else if (transfer->IsUndefined()) {
    3195             :       return Just(true);
    3196             :     } else {
    3197           0 :       Throw(isolate_, "Transfer list must be an Array or undefined");
    3198             :       return Nothing<bool>();
    3199             :     }
    3200             :   }
    3201             : 
    3202             :   template <typename T>
    3203         396 :   typename T::Contents MaybeExternalize(Local<T> array_buffer) {
    3204         396 :     if (array_buffer->IsExternal()) {
    3205         230 :       return array_buffer->GetContents();
    3206             :     } else {
    3207         166 :       typename T::Contents contents = array_buffer->Externalize();
    3208         166 :       externalized_contents_.emplace_back(contents);
    3209         166 :       return contents;
    3210             :     }
    3211             :   }
    3212             : 
    3213        1626 :   Maybe<bool> FinalizeTransfer() {
    3214        3279 :     for (const auto& global_array_buffer : array_buffers_) {
    3215             :       Local<ArrayBuffer> array_buffer =
    3216          36 :           Local<ArrayBuffer>::New(isolate_, global_array_buffer);
    3217          36 :       if (!array_buffer->IsDetachable()) {
    3218           9 :         Throw(isolate_, "ArrayBuffer could not be transferred");
    3219           9 :         return Nothing<bool>();
    3220             :       }
    3221             : 
    3222          27 :       ArrayBuffer::Contents contents = MaybeExternalize(array_buffer);
    3223          27 :       array_buffer->Detach();
    3224          27 :       data_->array_buffer_contents_.push_back(contents);
    3225             :     }
    3226             : 
    3227             :     return Just(true);
    3228             :   }
    3229             : 
    3230             :   Isolate* isolate_;
    3231             :   ValueSerializer serializer_;
    3232             :   std::unique_ptr<SerializationData> data_;
    3233             :   std::vector<Global<ArrayBuffer>> array_buffers_;
    3234             :   std::vector<Global<SharedArrayBuffer>> shared_array_buffers_;
    3235             :   std::vector<Global<WasmModuleObject>> wasm_modules_;
    3236             :   std::vector<ExternalizedContents> externalized_contents_;
    3237             :   size_t current_memory_usage_;
    3238             : 
    3239             :   DISALLOW_COPY_AND_ASSIGN(Serializer);
    3240             : };
    3241             : 
    3242        4746 : class Deserializer : public ValueDeserializer::Delegate {
    3243             :  public:
    3244        1582 :   Deserializer(Isolate* isolate, std::unique_ptr<SerializationData> data)
    3245             :       : isolate_(isolate),
    3246             :         deserializer_(isolate, data->data(), data->size(), this),
    3247        4746 :         data_(std::move(data)) {
    3248        1582 :     deserializer_.SetSupportsLegacyWireFormat(true);
    3249        1582 :   }
    3250             : 
    3251        1582 :   MaybeLocal<Value> ReadValue(Local<Context> context) {
    3252             :     bool read_header;
    3253        3164 :     if (!deserializer_.ReadHeader(context).To(&read_header)) {
    3254           0 :       return MaybeLocal<Value>();
    3255             :     }
    3256             : 
    3257             :     uint32_t index = 0;
    3258        3191 :     for (const auto& contents : data_->array_buffer_contents()) {
    3259             :       Local<ArrayBuffer> array_buffer =
    3260          27 :           ArrayBuffer::New(isolate_, contents.Data(), contents.ByteLength());
    3261          27 :       deserializer_.TransferArrayBuffer(index++, array_buffer);
    3262             :     }
    3263             : 
    3264        1582 :     return deserializer_.ReadValue(context);
    3265             :   }
    3266             : 
    3267         369 :   MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
    3268             :       Isolate* isolate, uint32_t clone_id) override {
    3269             :     DCHECK_NOT_NULL(data_);
    3270        1107 :     if (clone_id < data_->shared_array_buffer_contents().size()) {
    3271             :       const SharedArrayBuffer::Contents contents =
    3272         369 :           data_->shared_array_buffer_contents().at(clone_id);
    3273         369 :       return SharedArrayBuffer::New(isolate_, contents);
    3274             :     }
    3275           0 :     return MaybeLocal<SharedArrayBuffer>();
    3276             :   }
    3277             : 
    3278          92 :   MaybeLocal<WasmModuleObject> GetWasmModuleFromId(
    3279             :       Isolate* isolate, uint32_t transfer_id) override {
    3280             :     DCHECK_NOT_NULL(data_);
    3281         276 :     if (transfer_id < data_->transferrable_modules().size()) {
    3282             :       return WasmModuleObject::FromTransferrableModule(
    3283          92 :           isolate_, data_->transferrable_modules().at(transfer_id));
    3284             :     }
    3285           0 :     return MaybeLocal<WasmModuleObject>();
    3286             :   }
    3287             : 
    3288             :  private:
    3289             :   Isolate* isolate_;
    3290             :   ValueDeserializer deserializer_;
    3291             :   std::unique_ptr<SerializationData> data_;
    3292             : 
    3293             :   DISALLOW_COPY_AND_ASSIGN(Deserializer);
    3294             : };
    3295             : 
    3296        1808 : std::unique_ptr<SerializationData> Shell::SerializeValue(
    3297             :     Isolate* isolate, Local<Value> value, Local<Value> transfer) {
    3298             :   bool ok;
    3299        1808 :   Local<Context> context = isolate->GetCurrentContext();
    3300        1810 :   Serializer serializer(isolate);
    3301        1809 :   std::unique_ptr<SerializationData> data;
    3302        3620 :   if (serializer.WriteValue(context, value, transfer).To(&ok)) {
    3303             :     data = serializer.Release();
    3304             :   }
    3305             :   // Append externalized contents even when WriteValue fails.
    3306             :   base::MutexGuard lock_guard(workers_mutex_.Pointer());
    3307        1816 :   serializer.AppendExternalizedContentsTo(&externalized_contents_);
    3308        1816 :   return data;
    3309             : }
    3310             : 
    3311        1582 : MaybeLocal<Value> Shell::DeserializeValue(
    3312             :     Isolate* isolate, std::unique_ptr<SerializationData> data) {
    3313             :   Local<Value> value;
    3314        1582 :   Local<Context> context = isolate->GetCurrentContext();
    3315        3164 :   Deserializer deserializer(isolate, std::move(data));
    3316        1582 :   return deserializer.ReadValue(context);
    3317             : }
    3318             : 
    3319             : 
    3320       50887 : void Shell::CleanupWorkers() {
    3321             :   // Make a copy of workers_, because we don't want to call Worker::Terminate
    3322             :   // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
    3323             :   // create a new Worker, it would deadlock.
    3324             :   std::vector<Worker*> workers_copy;
    3325             :   {
    3326             :     base::MutexGuard lock_guard(workers_mutex_.Pointer());
    3327       50887 :     allow_new_workers_ = false;
    3328             :     workers_copy.swap(workers_);
    3329             :   }
    3330             : 
    3331      102379 :   for (Worker* worker : workers_copy) {
    3332             :     worker->WaitForThread();
    3333         605 :     delete worker;
    3334             :   }
    3335             : 
    3336             :   // Now that all workers are terminated, we can re-enable Worker creation.
    3337             :   base::MutexGuard lock_guard(workers_mutex_.Pointer());
    3338       50887 :   allow_new_workers_ = true;
    3339             :   externalized_contents_.clear();
    3340       50887 : }
    3341             : 
    3342       29546 : int Shell::Main(int argc, char* argv[]) {
    3343       29546 :   std::ofstream trace_file;
    3344             :   v8::base::EnsureConsoleOutput();
    3345       29546 :   if (!SetOptions(argc, argv)) return 1;
    3346       29546 :   v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
    3347             : 
    3348             :   v8::platform::InProcessStackDumping in_process_stack_dumping =
    3349             :       options.disable_in_process_stack_traces
    3350             :           ? v8::platform::InProcessStackDumping::kDisabled
    3351       29546 :           : v8::platform::InProcessStackDumping::kEnabled;
    3352             : 
    3353             :   std::unique_ptr<platform::tracing::TracingController> tracing;
    3354       29546 :   if (options.trace_enabled && !i::FLAG_verify_predictable) {
    3355           2 :     tracing = base::make_unique<platform::tracing::TracingController>();
    3356             : 
    3357           1 :     trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json");
    3358             :     platform::tracing::TraceBuffer* trace_buffer =
    3359             :         platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
    3360             :             platform::tracing::TraceBuffer::kRingBufferChunks,
    3361           1 :             platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
    3362           1 :     tracing->Initialize(trace_buffer);
    3363             :   }
    3364             : 
    3365             :   platform::tracing::TracingController* tracing_controller = tracing.get();
    3366       88638 :   g_platform = v8::platform::NewDefaultPlatform(
    3367             :       options.thread_pool_size, v8::platform::IdleTaskSupport::kEnabled,
    3368             :       in_process_stack_dumping, std::move(tracing));
    3369       29546 :   g_default_platform = g_platform.get();
    3370             :   if (i::FLAG_verify_predictable) {
    3371             :     g_platform = MakePredictablePlatform(std::move(g_platform));
    3372             :   }
    3373       29546 :   if (options.stress_delay_tasks) {
    3374           0 :     int64_t random_seed = i::FLAG_fuzzer_random_seed;
    3375           0 :     if (!random_seed) random_seed = i::FLAG_random_seed;
    3376             :     // If random_seed is still 0 here, the {DelayedTasksPlatform} will choose a
    3377             :     // random seed.
    3378           0 :     g_platform = MakeDelayedTasksPlatform(std::move(g_platform), random_seed);
    3379             :   }
    3380             : 
    3381       29546 :   if (i::FLAG_trace_turbo_cfg_file == nullptr) {
    3382       29545 :     SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
    3383             :   }
    3384       29546 :   if (i::FLAG_redirect_code_traces_to == nullptr) {
    3385       29546 :     SetFlagsFromString("--redirect-code-traces-to=code.asm");
    3386             :   }
    3387       29546 :   v8::V8::InitializePlatform(g_platform.get());
    3388       29546 :   v8::V8::Initialize();
    3389       29546 :   if (options.natives_blob || options.snapshot_blob) {
    3390             :     v8::V8::InitializeExternalStartupData(options.natives_blob,
    3391           0 :                                           options.snapshot_blob);
    3392             :   } else {
    3393       29546 :     v8::V8::InitializeExternalStartupData(argv[0]);
    3394             :   }
    3395             :   int result = 0;
    3396             :   Isolate::CreateParams create_params;
    3397             :   ShellArrayBufferAllocator shell_array_buffer_allocator;
    3398             :   MockArrayBufferAllocator mock_arraybuffer_allocator;
    3399             :   const size_t memory_limit =
    3400       29546 :       options.mock_arraybuffer_allocator_limit * options.num_isolates;
    3401             :   MockArrayBufferAllocatiorWithLimit mock_arraybuffer_allocator_with_limit(
    3402             :       memory_limit >= options.mock_arraybuffer_allocator_limit
    3403             :           ? memory_limit
    3404       29546 :           : std::numeric_limits<size_t>::max());
    3405       29546 :   if (options.mock_arraybuffer_allocator) {
    3406          21 :     if (memory_limit) {
    3407           0 :       Shell::array_buffer_allocator = &mock_arraybuffer_allocator_with_limit;
    3408             :     } else {
    3409          21 :       Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
    3410             :     }
    3411             :   } else {
    3412       29525 :     Shell::array_buffer_allocator = &shell_array_buffer_allocator;
    3413             :   }
    3414       29546 :   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
    3415             : #ifdef ENABLE_VTUNE_JIT_INTERFACE
    3416             :   create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
    3417             : #endif
    3418             :   create_params.constraints.ConfigureDefaults(
    3419       29546 :       base::SysInfo::AmountOfPhysicalMemory(),
    3420       59092 :       base::SysInfo::AmountOfVirtualMemory());
    3421             : 
    3422       59092 :   Shell::counter_map_ = new CounterMap();
    3423       29546 :   if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp || i::FLAG_gc_stats) {
    3424           0 :     create_params.counter_lookup_callback = LookupCounter;
    3425           0 :     create_params.create_histogram_callback = CreateHistogram;
    3426           0 :     create_params.add_histogram_sample_callback = AddHistogramSample;
    3427             :   }
    3428             : 
    3429       29546 :   if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
    3430             :     constexpr bool use_default_trap_handler = true;
    3431       29538 :     if (!v8::V8::EnableWebAssemblyTrapHandler(use_default_trap_handler)) {
    3432           0 :       FATAL("Could not register trap handler");
    3433             :     }
    3434             :   }
    3435             : 
    3436       29546 :   Isolate* isolate = Isolate::New(create_params);
    3437             :   isolate->SetHostImportModuleDynamicallyCallback(
    3438       29546 :       Shell::HostImportModuleDynamically);
    3439             :   isolate->SetHostInitializeImportMetaObjectCallback(
    3440       29546 :       Shell::HostInitializeImportMetaObject);
    3441             : 
    3442       29546 :   D8Console console(isolate);
    3443             :   {
    3444             :     Isolate::Scope scope(isolate);
    3445       29546 :     Initialize(isolate);
    3446       59092 :     PerIsolateData data(isolate);
    3447       29546 :     debug::SetConsoleDelegate(isolate, &console);
    3448             : 
    3449       29546 :     if (options.trace_enabled) {
    3450             :       platform::tracing::TraceConfig* trace_config;
    3451           1 :       if (options.trace_config) {
    3452           0 :         int size = 0;
    3453           0 :         char* trace_config_json_str = ReadChars(options.trace_config, &size);
    3454             :         trace_config =
    3455           0 :             tracing::CreateTraceConfigFromJSON(isolate, trace_config_json_str);
    3456           0 :         delete[] trace_config_json_str;
    3457             :       } else {
    3458             :         trace_config =
    3459           1 :             platform::tracing::TraceConfig::CreateDefaultTraceConfig();
    3460             :       }
    3461           1 :       tracing_controller->StartTracing(trace_config);
    3462             :     }
    3463             : 
    3464       29546 :     if (options.stress_opt || options.stress_deopt) {
    3465             :       Testing::SetStressRunType(options.stress_opt
    3466             :                                 ? Testing::kStressTypeOpt
    3467        5538 :                                 : Testing::kStressTypeDeopt);
    3468        5538 :       options.stress_runs = Testing::GetStressRuns();
    3469       37830 :       for (int i = 0; i < options.stress_runs && result == 0; i++) {
    3470             :         printf("============ Stress %d/%d ============\n", i + 1,
    3471       26754 :                options.stress_runs);
    3472       26754 :         Testing::PrepareStressRun(i);
    3473       26754 :         bool last_run = i == options.stress_runs - 1;
    3474       26754 :         result = RunMain(isolate, argc, argv, last_run);
    3475             :       }
    3476             :       printf("======== Full Deoptimization =======\n");
    3477        5538 :       Testing::DeoptimizeAll(isolate);
    3478       24008 :     } else if (i::FLAG_stress_runs > 0) {
    3479          24 :       options.stress_runs = i::FLAG_stress_runs;
    3480         152 :       for (int i = 0; i < options.stress_runs && result == 0; i++) {
    3481             :         printf("============ Run %d/%d ============\n", i + 1,
    3482         104 :                options.stress_runs);
    3483         104 :         bool last_run = i == options.stress_runs - 1;
    3484         104 :         result = RunMain(isolate, argc, argv, last_run);
    3485             :       }
    3486       23984 :     } else if (options.code_cache_options !=
    3487             :                ShellOptions::CodeCacheOptions::kNoProduceCache) {
    3488             :       printf("============ Run: Produce code cache ============\n");
    3489             :       // First run to produce the cache
    3490             :       Isolate::CreateParams create_params;
    3491          45 :       create_params.array_buffer_allocator = Shell::array_buffer_allocator;
    3492          45 :       i::FLAG_hash_seed ^= 1337;  // Use a different hash seed.
    3493          45 :       Isolate* isolate2 = Isolate::New(create_params);
    3494          45 :       i::FLAG_hash_seed ^= 1337;  // Restore old hash seed.
    3495             :       isolate2->SetHostImportModuleDynamicallyCallback(
    3496          45 :           Shell::HostImportModuleDynamically);
    3497             :       isolate2->SetHostInitializeImportMetaObjectCallback(
    3498          45 :           Shell::HostInitializeImportMetaObject);
    3499             :       {
    3500          45 :         D8Console console(isolate2);
    3501          45 :         Initialize(isolate2);
    3502          45 :         debug::SetConsoleDelegate(isolate2, &console);
    3503          90 :         PerIsolateData data(isolate2);
    3504             :         Isolate::Scope isolate_scope(isolate2);
    3505             : 
    3506          45 :         result = RunMain(isolate2, argc, argv, false);
    3507             :       }
    3508          45 :       isolate2->Dispose();
    3509             : 
    3510             :       // Change the options to consume cache
    3511             :       DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
    3512             :              options.compile_options == v8::ScriptCompiler::kNoCompileOptions);
    3513          45 :       options.compile_options = v8::ScriptCompiler::kConsumeCodeCache;
    3514             :       options.code_cache_options =
    3515          45 :           ShellOptions::CodeCacheOptions::kNoProduceCache;
    3516             : 
    3517             :       printf("============ Run: Consume code cache ============\n");
    3518             :       // Second run to consume the cache in current isolate
    3519          45 :       result = RunMain(isolate, argc, argv, true);
    3520          45 :       options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
    3521             :     } else {
    3522             :       bool last_run = true;
    3523       23939 :       result = RunMain(isolate, argc, argv, last_run);
    3524             :     }
    3525             : 
    3526             :     // Run interactive shell if explicitly requested or if no script has been
    3527             :     // executed, but never on --test
    3528       29546 :     if (use_interactive_shell()) {
    3529           0 :       RunShell(isolate);
    3530             :     }
    3531             : 
    3532       29551 :     if (i::FLAG_trace_ignition_dispatches &&
    3533           5 :         i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
    3534           0 :       WriteIgnitionDispatchCountersFile(isolate);
    3535             :     }
    3536             : 
    3537             :     // Shut down contexts and collect garbage.
    3538             :     cached_code_map_.clear();
    3539             :     evaluation_context_.Reset();
    3540             :     stringify_function_.Reset();
    3541       29546 :     CollectGarbage(isolate);
    3542             :   }
    3543       29546 :   OnExit(isolate);
    3544       29546 :   V8::Dispose();
    3545       29546 :   V8::ShutdownPlatform();
    3546             : 
    3547             :   // Delete the platform explicitly here to write the tracing output to the
    3548             :   // tracing file.
    3549             :   g_platform.reset();
    3550       29546 :   return result;
    3551             : }
    3552             : 
    3553             : }  // namespace v8
    3554             : 
    3555             : 
    3556             : #ifndef GOOGLE3
    3557       29546 : int main(int argc, char* argv[]) {
    3558       29546 :   return v8::Shell::Main(argc, argv);
    3559       88638 : }
    3560             : #endif
    3561             : 
    3562             : #undef CHECK
    3563             : #undef DCHECK

Generated by: LCOV version 1.10