LCOV - code coverage report
Current view: top level - src - d8.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 971 1364 71.2 %
Date: 2017-04-26 Functions: 115 165 69.7 %

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

Generated by: LCOV version 1.10