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