LCOV - code coverage report
Current view: top level - src - d8.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1072 1490 71.9 %
Date: 2017-10-20 Functions: 133 188 70.7 %

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

Generated by: LCOV version 1.10