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 
      6 // Defined when linking against shared lib on Windows.
      7 #if defined(USING_V8_SHARED) && !defined(V8_SHARED)
      8 #define V8_SHARED
      9 #endif
     10 
     11 #include <errno.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <sys/stat.h>
     15 
     16 #ifdef V8_SHARED
     17 #include <assert.h>
     18 #endif  // V8_SHARED
     19 
     20 #ifndef V8_SHARED
     21 #include <algorithm>
     22 #include <fstream>
     23 #include <vector>
     24 #endif  // !V8_SHARED
     25 
     26 #ifdef V8_SHARED
     27 #include "include/v8-testing.h"
     28 #endif  // V8_SHARED
     29 
     30 #ifdef ENABLE_VTUNE_JIT_INTERFACE
     31 #include "src/third_party/vtune/v8-vtune.h"
     32 #endif
     33 
     34 #include "src/d8.h"
     35 #include "src/ostreams.h"
     36 
     37 #include "include/libplatform/libplatform.h"
     38 #ifndef V8_SHARED
     39 #include "src/api.h"
     40 #include "src/base/cpu.h"
     41 #include "src/base/logging.h"
     42 #include "src/base/platform/platform.h"
     43 #include "src/base/sys-info.h"
     44 #include "src/basic-block-profiler.h"
     45 #include "src/interpreter/interpreter.h"
     46 #include "src/snapshot/natives.h"
     47 #include "src/utils.h"
     48 #include "src/v8.h"
     49 #endif  // !V8_SHARED
     50 
     51 #if !defined(_WIN32) && !defined(_WIN64)
     52 #include <unistd.h>  // NOLINT
     53 #else
     54 #include <windows.h>  // NOLINT
     55 #if defined(_MSC_VER)
     56 #include <crtdbg.h>  // NOLINT
     57 #endif               // defined(_MSC_VER)
     58 #endif               // !defined(_WIN32) && !defined(_WIN64)
     59 
     60 #ifndef DCHECK
     61 #define DCHECK(condition) assert(condition)
     62 #endif
     63 
     64 #ifndef CHECK
     65 #define CHECK(condition) assert(condition)
     66 #endif
     67 
     68 namespace v8 {
     69 
     70 namespace {
     71 
     72 const int MB = 1024 * 1024;
     73 #ifndef V8_SHARED
     74 const int kMaxWorkers = 50;
     75 #endif
     76 
     77 
     78 class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
     79  public:
     80   virtual void* Allocate(size_t length) {
     81     void* data = AllocateUninitialized(length);
     82     return data == NULL ? data : memset(data, 0, length);
     83   }
     84   virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
     85   virtual void Free(void* data, size_t) { free(data); }
     86 };
     87 
     88 
     89 class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
     90  public:
     91   void* Allocate(size_t length) override {
     92     size_t actual_length = length > 10 * MB ? 1 : length;
     93     void* data = AllocateUninitialized(actual_length);
     94     return data == NULL ? data : memset(data, 0, actual_length);
     95   }
     96   void* AllocateUninitialized(size_t length) override {
     97     return length > 10 * MB ? malloc(1) : malloc(length);
     98   }
     99   void Free(void* p, size_t) override { free(p); }
    100 };
    101 
    102 
    103 #ifndef V8_SHARED
    104 // Predictable v8::Platform implementation. All background and foreground
    105 // tasks are run immediately, delayed tasks are not executed at all.
    106 class PredictablePlatform : public Platform {
    107  public:
    108   PredictablePlatform() {}
    109 
    110   void CallOnBackgroundThread(Task* task,
    111                               ExpectedRuntime expected_runtime) override {
    112     task->Run();
    113     delete task;
    114   }
    115 
    116   void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
    117     task->Run();
    118     delete task;
    119   }
    120 
    121   void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
    122                                      double delay_in_seconds) override {
    123     delete task;
    124   }
    125 
    126   void CallIdleOnForegroundThread(v8::Isolate* isolate,
    127                                   IdleTask* task) override {
    128     UNREACHABLE();
    129   }
    130 
    131   bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
    132 
    133   double MonotonicallyIncreasingTime() override {
    134     return synthetic_time_in_sec_ += 0.00001;
    135   }
    136 
    137   uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
    138                          const char* name, const char* scope, uint64_t id,
    139                          uint64_t bind_id, int numArgs, const char** argNames,
    140                          const uint8_t* argTypes, const uint64_t* argValues,
    141                          unsigned int flags) override {
    142     return 0;
    143   }
    144 
    145   void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
    146                                 const char* name, uint64_t handle) override {}
    147 
    148   const uint8_t* GetCategoryGroupEnabled(const char* name) override {
    149     static uint8_t no = 0;
    150     return &no;
    151   }
    152 
    153   const char* GetCategoryGroupName(
    154       const uint8_t* categoryEnabledFlag) override {
    155     static const char* dummy = "dummy";
    156     return dummy;
    157   }
    158 
    159  private:
    160   double synthetic_time_in_sec_ = 0.0;
    161 
    162   DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
    163 };
    164 #endif  // !V8_SHARED
    165 
    166 
    167 v8::Platform* g_platform = NULL;
    168 
    169 
    170 static Local<Value> Throw(Isolate* isolate, const char* message) {
    171   return isolate->ThrowException(
    172       String::NewFromUtf8(isolate, message, NewStringType::kNormal)
    173           .ToLocalChecked());
    174 }
    175 
    176 
    177 #ifndef V8_SHARED
    178 bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
    179   for (int i = 0; i < list.length(); ++i) {
    180     if (list[i]->StrictEquals(object)) {
    181       return true;
    182     }
    183   }
    184   return false;
    185 }
    186 
    187 
    188 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
    189   if (object->InternalFieldCount() != 1) {
    190     Throw(isolate, "this is not a Worker");
    191     return NULL;
    192   }
    193 
    194   Worker* worker =
    195       static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
    196   if (worker == NULL) {
    197     Throw(isolate, "Worker is defunct because main thread is terminating");
    198     return NULL;
    199   }
    200 
    201   return worker;
    202 }
    203 #endif  // !V8_SHARED
    204 
    205 
    206 }  // namespace
    207 
    208 
    209 class PerIsolateData {
    210  public:
    211   explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
    212     HandleScope scope(isolate);
    213     isolate->SetData(0, this);
    214   }
    215 
    216   ~PerIsolateData() {
    217     isolate_->SetData(0, NULL);  // Not really needed, just to be sure...
    218   }
    219 
    220   inline static PerIsolateData* Get(Isolate* isolate) {
    221     return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
    222   }
    223 
    224   class RealmScope {
    225    public:
    226     explicit RealmScope(PerIsolateData* data);
    227     ~RealmScope();
    228    private:
    229     PerIsolateData* data_;
    230   };
    231 
    232  private:
    233   friend class Shell;
    234   friend class RealmScope;
    235   Isolate* isolate_;
    236   int realm_count_;
    237   int realm_current_;
    238   int realm_switch_;
    239   Global<Context>* realms_;
    240   Global<Value> realm_shared_;
    241 
    242   int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
    243                         int arg_offset);
    244   int RealmFind(Local<Context> context);
    245 };
    246 
    247 
    248 #ifndef V8_SHARED
    249 CounterMap* Shell::counter_map_;
    250 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
    251 CounterCollection Shell::local_counters_;
    252 CounterCollection* Shell::counters_ = &local_counters_;
    253 base::LazyMutex Shell::context_mutex_;
    254 const base::TimeTicks Shell::kInitialTicks =
    255     base::TimeTicks::HighResolutionNow();
    256 Global<Function> Shell::stringify_function_;
    257 base::LazyMutex Shell::workers_mutex_;
    258 bool Shell::allow_new_workers_ = true;
    259 i::List<Worker*> Shell::workers_;
    260 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
    261 #endif  // !V8_SHARED
    262 
    263 Global<Context> Shell::evaluation_context_;
    264 ArrayBuffer::Allocator* Shell::array_buffer_allocator;
    265 ShellOptions Shell::options;
    266 base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
    267 
    268 #ifndef V8_SHARED
    269 bool CounterMap::Match(void* key1, void* key2) {
    270   const char* name1 = reinterpret_cast<const char*>(key1);
    271   const char* name2 = reinterpret_cast<const char*>(key2);
    272   return strcmp(name1, name2) == 0;
    273 }
    274 #endif  // !V8_SHARED
    275 
    276 
    277 // Converts a V8 value to a C string.
    278 const char* Shell::ToCString(const v8::String::Utf8Value& value) {
    279   return *value ? *value : "<string conversion failed>";
    280 }
    281 
    282 
    283 ScriptCompiler::CachedData* CompileForCachedData(
    284     Local<String> source, Local<Value> name,
    285     ScriptCompiler::CompileOptions compile_options) {
    286   int source_length = source->Length();
    287   uint16_t* source_buffer = new uint16_t[source_length];
    288   source->Write(source_buffer, 0, source_length);
    289   int name_length = 0;
    290   uint16_t* name_buffer = NULL;
    291   if (name->IsString()) {
    292     Local<String> name_string = Local<String>::Cast(name);
    293     name_length = name_string->Length();
    294     name_buffer = new uint16_t[name_length];
    295     name_string->Write(name_buffer, 0, name_length);
    296   }
    297   Isolate::CreateParams create_params;
    298   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
    299   Isolate* temp_isolate = Isolate::New(create_params);
    300   ScriptCompiler::CachedData* result = NULL;
    301   {
    302     Isolate::Scope isolate_scope(temp_isolate);
    303     HandleScope handle_scope(temp_isolate);
    304     Context::Scope context_scope(Context::New(temp_isolate));
    305     Local<String> source_copy =
    306         v8::String::NewFromTwoByte(temp_isolate, source_buffer,
    307                                    v8::NewStringType::kNormal,
    308                                    source_length).ToLocalChecked();
    309     Local<Value> name_copy;
    310     if (name_buffer) {
    311       name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer,
    312                                              v8::NewStringType::kNormal,
    313                                              name_length).ToLocalChecked();
    314     } else {
    315       name_copy = v8::Undefined(temp_isolate);
    316     }
    317     ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
    318     if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
    319                                               compile_options).IsEmpty() &&
    320         script_source.GetCachedData()) {
    321       int length = script_source.GetCachedData()->length;
    322       uint8_t* cache = new uint8_t[length];
    323       memcpy(cache, script_source.GetCachedData()->data, length);
    324       result = new ScriptCompiler::CachedData(
    325           cache, length, ScriptCompiler::CachedData::BufferOwned);
    326     }
    327   }
    328   temp_isolate->Dispose();
    329   delete[] source_buffer;
    330   delete[] name_buffer;
    331   return result;
    332 }
    333 
    334 
    335 // Compile a string within the current v8 context.
    336 MaybeLocal<Script> Shell::CompileString(
    337     Isolate* isolate, Local<String> source, Local<Value> name,
    338     ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
    339   Local<Context> context(isolate->GetCurrentContext());
    340   ScriptOrigin origin(name);
    341   // TODO(adamk): Make use of compile options for Modules.
    342   if (compile_options == ScriptCompiler::kNoCompileOptions ||
    343       source_type == MODULE) {
    344     ScriptCompiler::Source script_source(source, origin);
    345     return source_type == SCRIPT
    346                ? ScriptCompiler::Compile(context, &script_source,
    347                                          compile_options)
    348                : ScriptCompiler::CompileModule(context, &script_source,
    349                                                compile_options);
    350   }
    351 
    352   ScriptCompiler::CachedData* data =
    353       CompileForCachedData(source, name, compile_options);
    354   ScriptCompiler::Source cached_source(source, origin, data);
    355   if (compile_options == ScriptCompiler::kProduceCodeCache) {
    356     compile_options = ScriptCompiler::kConsumeCodeCache;
    357   } else if (compile_options == ScriptCompiler::kProduceParserCache) {
    358     compile_options = ScriptCompiler::kConsumeParserCache;
    359   } else {
    360     DCHECK(false);  // A new compile option?
    361   }
    362   if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
    363   DCHECK_EQ(SCRIPT, source_type);
    364   MaybeLocal<Script> result =
    365       ScriptCompiler::Compile(context, &cached_source, compile_options);
    366   CHECK(data == NULL || !data->rejected);
    367   return result;
    368 }
    369 
    370 
    371 // Executes a string within the current v8 context.
    372 bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
    373                           Local<Value> name, bool print_result,
    374                           bool report_exceptions, SourceType source_type) {
    375   HandleScope handle_scope(isolate);
    376   TryCatch try_catch(isolate);
    377   try_catch.SetVerbose(true);
    378 
    379   MaybeLocal<Value> maybe_result;
    380   {
    381     PerIsolateData* data = PerIsolateData::Get(isolate);
    382     Local<Context> realm =
    383         Local<Context>::New(isolate, data->realms_[data->realm_current_]);
    384     Context::Scope context_scope(realm);
    385     Local<Script> script;
    386     if (!Shell::CompileString(isolate, source, name, options.compile_options,
    387                               source_type).ToLocal(&script)) {
    388       // Print errors that happened during compilation.
    389       if (report_exceptions) ReportException(isolate, &try_catch);
    390       return false;
    391     }
    392     maybe_result = script->Run(realm);
    393     EmptyMessageQueues(isolate);
    394     data->realm_current_ = data->realm_switch_;
    395   }
    396   Local<Value> result;
    397   if (!maybe_result.ToLocal(&result)) {
    398     DCHECK(try_catch.HasCaught());
    399     // Print errors that happened during execution.
    400     if (report_exceptions) ReportException(isolate, &try_catch);
    401     return false;
    402   }
    403   DCHECK(!try_catch.HasCaught());
    404   if (print_result) {
    405 #if !defined(V8_SHARED)
    406     if (options.test_shell) {
    407 #endif
    408       if (!result->IsUndefined()) {
    409         // If all went well and the result wasn't undefined then print
    410         // the returned value.
    411         v8::String::Utf8Value str(result);
    412         fwrite(*str, sizeof(**str), str.length(), stdout);
    413         printf("\n");
    414       }
    415 #if !defined(V8_SHARED)
    416     } else {
    417       v8::String::Utf8Value str(Stringify(isolate, result));
    418       fwrite(*str, sizeof(**str), str.length(), stdout);
    419       printf("\n");
    420     }
    421 #endif
    422   }
    423   return true;
    424 }
    425 
    426 
    427 PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
    428   data_->realm_count_ = 1;
    429   data_->realm_current_ = 0;
    430   data_->realm_switch_ = 0;
    431   data_->realms_ = new Global<Context>[1];
    432   data_->realms_[0].Reset(data_->isolate_,
    433                           data_->isolate_->GetEnteredContext());
    434 }
    435 
    436 
    437 PerIsolateData::RealmScope::~RealmScope() {
    438   // Drop realms to avoid keeping them alive.
    439   for (int i = 0; i < data_->realm_count_; ++i)
    440     data_->realms_[i].Reset();
    441   delete[] data_->realms_;
    442   if (!data_->realm_shared_.IsEmpty())
    443     data_->realm_shared_.Reset();
    444 }
    445 
    446 
    447 int PerIsolateData::RealmFind(Local<Context> context) {
    448   for (int i = 0; i < realm_count_; ++i) {
    449     if (realms_[i] == context) return i;
    450   }
    451   return -1;
    452 }
    453 
    454 
    455 int PerIsolateData::RealmIndexOrThrow(
    456     const v8::FunctionCallbackInfo<v8::Value>& args,
    457     int arg_offset) {
    458   if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
    459     Throw(args.GetIsolate(), "Invalid argument");
    460     return -1;
    461   }
    462   int index = args[arg_offset]
    463                   ->Int32Value(args.GetIsolate()->GetCurrentContext())
    464                   .FromMaybe(-1);
    465   if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
    466     Throw(args.GetIsolate(), "Invalid realm index");
    467     return -1;
    468   }
    469   return index;
    470 }
    471 
    472 
    473 #ifndef V8_SHARED
    474 // performance.now() returns a time stamp as double, measured in milliseconds.
    475 // When FLAG_verify_predictable mode is enabled it returns result of
    476 // v8::Platform::MonotonicallyIncreasingTime().
    477 void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
    478   if (i::FLAG_verify_predictable) {
    479     args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
    480   } else {
    481     base::TimeDelta delta =
    482         base::TimeTicks::HighResolutionNow() - kInitialTicks;
    483     args.GetReturnValue().Set(delta.InMillisecondsF());
    484   }
    485 }
    486 #endif  // !V8_SHARED
    487 
    488 
    489 // Realm.current() returns the index of the currently active realm.
    490 void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
    491   Isolate* isolate = args.GetIsolate();
    492   PerIsolateData* data = PerIsolateData::Get(isolate);
    493   int index = data->RealmFind(isolate->GetEnteredContext());
    494   if (index == -1) return;
    495   args.GetReturnValue().Set(index);
    496 }
    497 
    498 
    499 // Realm.owner(o) returns the index of the realm that created o.
    500 void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
    501   Isolate* isolate = args.GetIsolate();
    502   PerIsolateData* data = PerIsolateData::Get(isolate);
    503   if (args.Length() < 1 || !args[0]->IsObject()) {
    504     Throw(args.GetIsolate(), "Invalid argument");
    505     return;
    506   }
    507   int index = data->RealmFind(args[0]
    508                                   ->ToObject(isolate->GetCurrentContext())
    509                                   .ToLocalChecked()
    510                                   ->CreationContext());
    511   if (index == -1) return;
    512   args.GetReturnValue().Set(index);
    513 }
    514 
    515 
    516 // Realm.global(i) returns the global object of realm i.
    517 // (Note that properties of global objects cannot be read/written cross-realm.)
    518 void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
    519   PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
    520   int index = data->RealmIndexOrThrow(args, 0);
    521   if (index == -1) return;
    522   args.GetReturnValue().Set(
    523       Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
    524 }
    525 
    526 MaybeLocal<Context> Shell::CreateRealm(
    527     const v8::FunctionCallbackInfo<v8::Value>& args) {
    528   Isolate* isolate = args.GetIsolate();
    529   TryCatch try_catch(isolate);
    530   PerIsolateData* data = PerIsolateData::Get(isolate);
    531   Global<Context>* old_realms = data->realms_;
    532   int index = data->realm_count_;
    533   data->realms_ = new Global<Context>[++data->realm_count_];
    534   for (int i = 0; i < index; ++i) {
    535     data->realms_[i].Reset(isolate, old_realms[i]);
    536     old_realms[i].Reset();
    537   }
    538   delete[] old_realms;
    539   Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
    540   Local<Context> context = Context::New(isolate, NULL, global_template);
    541   if (context.IsEmpty()) {
    542     DCHECK(try_catch.HasCaught());
    543     try_catch.ReThrow();
    544     return MaybeLocal<Context>();
    545   }
    546   data->realms_[index].Reset(isolate, context);
    547   args.GetReturnValue().Set(index);
    548   return context;
    549 }
    550 
    551 // Realm.create() creates a new realm with a distinct security token
    552 // and returns its index.
    553 void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
    554   CreateRealm(args);
    555 }
    556 
    557 // Realm.createAllowCrossRealmAccess() creates a new realm with the same
    558 // security token as the current realm.
    559 void Shell::RealmCreateAllowCrossRealmAccess(
    560     const v8::FunctionCallbackInfo<v8::Value>& args) {
    561   Local<Context> context;
    562   if (CreateRealm(args).ToLocal(&context)) {
    563     context->SetSecurityToken(
    564         args.GetIsolate()->GetEnteredContext()->GetSecurityToken());
    565   }
    566 }
    567 
    568 // Realm.dispose(i) disposes the reference to the realm i.
    569 void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
    570   Isolate* isolate = args.GetIsolate();
    571   PerIsolateData* data = PerIsolateData::Get(isolate);
    572   int index = data->RealmIndexOrThrow(args, 0);
    573   if (index == -1) return;
    574   if (index == 0 ||
    575       index == data->realm_current_ || index == data->realm_switch_) {
    576     Throw(args.GetIsolate(), "Invalid realm index");
    577     return;
    578   }
    579   data->realms_[index].Reset();
    580   isolate->ContextDisposedNotification();
    581   isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
    582 }
    583 
    584 
    585 // Realm.switch(i) switches to the realm i for consecutive interactive inputs.
    586 void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
    587   Isolate* isolate = args.GetIsolate();
    588   PerIsolateData* data = PerIsolateData::Get(isolate);
    589   int index = data->RealmIndexOrThrow(args, 0);
    590   if (index == -1) return;
    591   data->realm_switch_ = index;
    592 }
    593 
    594 
    595 // Realm.eval(i, s) evaluates s in realm i and returns the result.
    596 void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
    597   Isolate* isolate = args.GetIsolate();
    598   PerIsolateData* data = PerIsolateData::Get(isolate);
    599   int index = data->RealmIndexOrThrow(args, 0);
    600   if (index == -1) return;
    601   if (args.Length() < 2 || !args[1]->IsString()) {
    602     Throw(args.GetIsolate(), "Invalid argument");
    603     return;
    604   }
    605   ScriptCompiler::Source script_source(
    606       args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
    607   Local<UnboundScript> script;
    608   if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
    609            .ToLocal(&script)) {
    610     return;
    611   }
    612   Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
    613   realm->Enter();
    614   Local<Value> result;
    615   if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
    616     realm->Exit();
    617     return;
    618   }
    619   realm->Exit();
    620   args.GetReturnValue().Set(result);
    621 }
    622 
    623 
    624 // Realm.shared is an accessor for a single shared value across realms.
    625 void Shell::RealmSharedGet(Local<String> property,
    626                            const PropertyCallbackInfo<Value>& info) {
    627   Isolate* isolate = info.GetIsolate();
    628   PerIsolateData* data = PerIsolateData::Get(isolate);
    629   if (data->realm_shared_.IsEmpty()) return;
    630   info.GetReturnValue().Set(data->realm_shared_);
    631 }
    632 
    633 void Shell::RealmSharedSet(Local<String> property,
    634                            Local<Value> value,
    635                            const PropertyCallbackInfo<void>& info) {
    636   Isolate* isolate = info.GetIsolate();
    637   PerIsolateData* data = PerIsolateData::Get(isolate);
    638   data->realm_shared_.Reset(isolate, value);
    639 }
    640 
    641 
    642 void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
    643   Write(args);
    644   printf("\n");
    645   fflush(stdout);
    646 }
    647 
    648 
    649 void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
    650   for (int i = 0; i < args.Length(); i++) {
    651     HandleScope handle_scope(args.GetIsolate());
    652     if (i != 0) {
    653       printf(" ");
    654     }
    655 
    656     // Explicitly catch potential exceptions in toString().
    657     v8::TryCatch try_catch(args.GetIsolate());
    658     Local<Value> arg = args[i];
    659     Local<String> str_obj;
    660 
    661     if (arg->IsSymbol()) {
    662       arg = Local<Symbol>::Cast(arg)->Name();
    663     }
    664     if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
    665              .ToLocal(&str_obj)) {
    666       try_catch.ReThrow();
    667       return;
    668     }
    669 
    670     v8::String::Utf8Value str(str_obj);
    671     int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
    672     if (n != str.length()) {
    673       printf("Error in fwrite\n");
    674       Exit(1);
    675     }
    676   }
    677 }
    678 
    679 
    680 void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
    681   String::Utf8Value file(args[0]);
    682   if (*file == NULL) {
    683     Throw(args.GetIsolate(), "Error loading file");
    684     return;
    685   }
    686   Local<String> source = ReadFile(args.GetIsolate(), *file);
    687   if (source.IsEmpty()) {
    688     Throw(args.GetIsolate(), "Error loading file");
    689     return;
    690   }
    691   args.GetReturnValue().Set(source);
    692 }
    693 
    694 
    695 Local<String> Shell::ReadFromStdin(Isolate* isolate) {
    696   static const int kBufferSize = 256;
    697   char buffer[kBufferSize];
    698   Local<String> accumulator =
    699       String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
    700   int length;
    701   while (true) {
    702     // Continue reading if the line ends with an escape '\\' or the line has
    703     // not been fully read into the buffer yet (does not end with '\n').
    704     // If fgets gets an error, just give up.
    705     char* input = NULL;
    706     input = fgets(buffer, kBufferSize, stdin);
    707     if (input == NULL) return Local<String>();
    708     length = static_cast<int>(strlen(buffer));
    709     if (length == 0) {
    710       return accumulator;
    711     } else if (buffer[length-1] != '\n') {
    712       accumulator = String::Concat(
    713           accumulator,
    714           String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
    715               .ToLocalChecked());
    716     } else if (length > 1 && buffer[length-2] == '\\') {
    717       buffer[length-2] = '\n';
    718       accumulator = String::Concat(
    719           accumulator,
    720           String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
    721                               length - 1).ToLocalChecked());
    722     } else {
    723       return String::Concat(
    724           accumulator,
    725           String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
    726                               length - 1).ToLocalChecked());
    727     }
    728   }
    729 }
    730 
    731 
    732 void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
    733   for (int i = 0; i < args.Length(); i++) {
    734     HandleScope handle_scope(args.GetIsolate());
    735     String::Utf8Value file(args[i]);
    736     if (*file == NULL) {
    737       Throw(args.GetIsolate(), "Error loading file");
    738       return;
    739     }
    740     Local<String> source = ReadFile(args.GetIsolate(), *file);
    741     if (source.IsEmpty()) {
    742       Throw(args.GetIsolate(), "Error loading file");
    743       return;
    744     }
    745     if (!ExecuteString(
    746             args.GetIsolate(), source,
    747             String::NewFromUtf8(args.GetIsolate(), *file,
    748                                 NewStringType::kNormal).ToLocalChecked(),
    749             false, true)) {
    750       Throw(args.GetIsolate(), "Error executing file");
    751       return;
    752     }
    753   }
    754 }
    755 
    756 
    757 #ifndef V8_SHARED
    758 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
    759   Isolate* isolate = args.GetIsolate();
    760   HandleScope handle_scope(isolate);
    761   if (args.Length() < 1 || !args[0]->IsString()) {
    762     Throw(args.GetIsolate(), "1st argument must be string");
    763     return;
    764   }
    765 
    766   if (!args.IsConstructCall()) {
    767     Throw(args.GetIsolate(), "Worker must be constructed with new");
    768     return;
    769   }
    770 
    771   {
    772     base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
    773     if (workers_.length() >= kMaxWorkers) {
    774       Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
    775       return;
    776     }
    777 
    778     // Initialize the internal field to NULL; if we return early without
    779     // creating a new Worker (because the main thread is terminating) we can
    780     // early-out from the instance calls.
    781     args.Holder()->SetAlignedPointerInInternalField(0, NULL);
    782 
    783     if (!allow_new_workers_) return;
    784 
    785     Worker* worker = new Worker;
    786     args.Holder()->SetAlignedPointerInInternalField(0, worker);
    787     workers_.Add(worker);
    788 
    789     String::Utf8Value script(args[0]);
    790     if (!*script) {
    791       Throw(args.GetIsolate(), "Can't get worker script");
    792       return;
    793     }
    794     worker->StartExecuteInThread(*script);
    795   }
    796 }
    797 
    798 
    799 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
    800   Isolate* isolate = args.GetIsolate();
    801   HandleScope handle_scope(isolate);
    802   Local<Context> context = isolate->GetCurrentContext();
    803 
    804   if (args.Length() < 1) {
    805     Throw(isolate, "Invalid argument");
    806     return;
    807   }
    808 
    809   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
    810   if (!worker) {
    811     return;
    812   }
    813 
    814   Local<Value> message = args[0];
    815   ObjectList to_transfer;
    816   if (args.Length() >= 2) {
    817     if (!args[1]->IsArray()) {
    818       Throw(isolate, "Transfer list must be an Array");
    819       return;
    820     }
    821 
    822     Local<Array> transfer = Local<Array>::Cast(args[1]);
    823     uint32_t length = transfer->Length();
    824     for (uint32_t i = 0; i < length; ++i) {
    825       Local<Value> element;
    826       if (transfer->Get(context, i).ToLocal(&element)) {
    827         if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
    828           Throw(isolate,
    829                 "Transfer array elements must be an ArrayBuffer or "
    830                 "SharedArrayBuffer.");
    831           break;
    832         }
    833 
    834         to_transfer.Add(Local<Object>::Cast(element));
    835       }
    836     }
    837   }
    838 
    839   ObjectList seen_objects;
    840   SerializationData* data = new SerializationData;
    841   if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
    842     worker->PostMessage(data);
    843   } else {
    844     delete data;
    845   }
    846 }
    847 
    848 
    849 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
    850   Isolate* isolate = args.GetIsolate();
    851   HandleScope handle_scope(isolate);
    852   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
    853   if (!worker) {
    854     return;
    855   }
    856 
    857   SerializationData* data = worker->GetMessage();
    858   if (data) {
    859     int offset = 0;
    860     Local<Value> data_value;
    861     if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
    862       args.GetReturnValue().Set(data_value);
    863     }
    864     delete data;
    865   }
    866 }
    867 
    868 
    869 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
    870   Isolate* isolate = args.GetIsolate();
    871   HandleScope handle_scope(isolate);
    872   Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
    873   if (!worker) {
    874     return;
    875   }
    876 
    877   worker->Terminate();
    878 }
    879 #endif  // !V8_SHARED
    880 
    881 
    882 void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
    883   int exit_code = (*args)[0]
    884                       ->Int32Value(args->GetIsolate()->GetCurrentContext())
    885                       .FromMaybe(0);
    886 #ifndef V8_SHARED
    887   CleanupWorkers();
    888 #endif  // !V8_SHARED
    889   OnExit(args->GetIsolate());
    890   Exit(exit_code);
    891 }
    892 
    893 
    894 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
    895   base::CallOnce(&quit_once_, &QuitOnce,
    896                  const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
    897 }
    898 
    899 
    900 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
    901   args.GetReturnValue().Set(
    902       String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
    903                           NewStringType::kNormal).ToLocalChecked());
    904 }
    905 
    906 
    907 void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
    908   HandleScope handle_scope(isolate);
    909 #ifndef V8_SHARED
    910   Local<Context> context;
    911   bool enter_context = !isolate->InContext();
    912   if (enter_context) {
    913     context = Local<Context>::New(isolate, evaluation_context_);
    914     context->Enter();
    915   }
    916 #endif  // !V8_SHARED
    917   v8::String::Utf8Value exception(try_catch->Exception());
    918   const char* exception_string = ToCString(exception);
    919   Local<Message> message = try_catch->Message();
    920   if (message.IsEmpty()) {
    921     // V8 didn't provide any extra information about this error; just
    922     // print the exception.
    923     printf("%s\n", exception_string);
    924   } else {
    925     // Print (filename):(line number): (message).
    926     v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
    927     const char* filename_string = ToCString(filename);
    928     Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
    929     int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
    930     printf("%s:%i: %s\n", filename_string, linenum, exception_string);
    931     Local<String> sourceline;
    932     if (message->GetSourceLine(isolate->GetCurrentContext())
    933             .ToLocal(&sourceline)) {
    934       // Print line of source code.
    935       v8::String::Utf8Value sourcelinevalue(sourceline);
    936       const char* sourceline_string = ToCString(sourcelinevalue);
    937       printf("%s\n", sourceline_string);
    938       // Print wavy underline (GetUnderline is deprecated).
    939       int start =
    940           message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
    941       for (int i = 0; i < start; i++) {
    942         printf(" ");
    943       }
    944       int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
    945       for (int i = start; i < end; i++) {
    946         printf("^");
    947       }
    948       printf("\n");
    949     }
    950     Local<Value> stack_trace_string;
    951     if (try_catch->StackTrace(isolate->GetCurrentContext())
    952             .ToLocal(&stack_trace_string) &&
    953         stack_trace_string->IsString()) {
    954       v8::String::Utf8Value stack_trace(
    955           Local<String>::Cast(stack_trace_string));
    956       printf("%s\n", ToCString(stack_trace));
    957     }
    958   }
    959   printf("\n");
    960 #ifndef V8_SHARED
    961   if (enter_context) context->Exit();
    962 #endif  // !V8_SHARED
    963 }
    964 
    965 
    966 #ifndef V8_SHARED
    967 int32_t* Counter::Bind(const char* name, bool is_histogram) {
    968   int i;
    969   for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
    970     name_[i] = static_cast<char>(name[i]);
    971   name_[i] = '\0';
    972   is_histogram_ = is_histogram;
    973   return ptr();
    974 }
    975 
    976 
    977 void Counter::AddSample(int32_t sample) {
    978   count_++;
    979   sample_total_ += sample;
    980 }
    981 
    982 
    983 CounterCollection::CounterCollection() {
    984   magic_number_ = 0xDEADFACE;
    985   max_counters_ = kMaxCounters;
    986   max_name_size_ = Counter::kMaxNameSize;
    987   counters_in_use_ = 0;
    988 }
    989 
    990 
    991 Counter* CounterCollection::GetNextCounter() {
    992   if (counters_in_use_ == kMaxCounters) return NULL;
    993   return &counters_[counters_in_use_++];
    994 }
    995 
    996 
    997 void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
    998   counters_file_ = base::OS::MemoryMappedFile::create(
    999       name, sizeof(CounterCollection), &local_counters_);
   1000   void* memory = (counters_file_ == NULL) ?
   1001       NULL : counters_file_->memory();
   1002   if (memory == NULL) {
   1003     printf("Could not map counters file %s\n", name);
   1004     Exit(1);
   1005   }
   1006   counters_ = static_cast<CounterCollection*>(memory);
   1007   isolate->SetCounterFunction(LookupCounter);
   1008   isolate->SetCreateHistogramFunction(CreateHistogram);
   1009   isolate->SetAddHistogramSampleFunction(AddHistogramSample);
   1010 }
   1011 
   1012 
   1013 int CounterMap::Hash(const char* name) {
   1014   int h = 0;
   1015   int c;
   1016   while ((c = *name++) != 0) {
   1017     h += h << 5;
   1018     h += c;
   1019   }
   1020   return h;
   1021 }
   1022 
   1023 
   1024 Counter* Shell::GetCounter(const char* name, bool is_histogram) {
   1025   Counter* counter = counter_map_->Lookup(name);
   1026 
   1027   if (counter == NULL) {
   1028     counter = counters_->GetNextCounter();
   1029     if (counter != NULL) {
   1030       counter_map_->Set(name, counter);
   1031       counter->Bind(name, is_histogram);
   1032     }
   1033   } else {
   1034     DCHECK(counter->is_histogram() == is_histogram);
   1035   }
   1036   return counter;
   1037 }
   1038 
   1039 
   1040 int* Shell::LookupCounter(const char* name) {
   1041   Counter* counter = GetCounter(name, false);
   1042 
   1043   if (counter != NULL) {
   1044     return counter->ptr();
   1045   } else {
   1046     return NULL;
   1047   }
   1048 }
   1049 
   1050 
   1051 void* Shell::CreateHistogram(const char* name,
   1052                              int min,
   1053                              int max,
   1054                              size_t buckets) {
   1055   return GetCounter(name, true);
   1056 }
   1057 
   1058 
   1059 void Shell::AddHistogramSample(void* histogram, int sample) {
   1060   Counter* counter = reinterpret_cast<Counter*>(histogram);
   1061   counter->AddSample(sample);
   1062 }
   1063 
   1064 // Turn a value into a human-readable string.
   1065 Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
   1066   v8::Local<v8::Context> context =
   1067       v8::Local<v8::Context>::New(isolate, evaluation_context_);
   1068   if (stringify_function_.IsEmpty()) {
   1069     int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
   1070     i::Vector<const char> source_string =
   1071         i::NativesCollection<i::D8>::GetScriptSource(source_index);
   1072     i::Vector<const char> source_name =
   1073         i::NativesCollection<i::D8>::GetScriptName(source_index);
   1074     Local<String> source =
   1075         String::NewFromUtf8(isolate, source_string.start(),
   1076                             NewStringType::kNormal, source_string.length())
   1077             .ToLocalChecked();
   1078     Local<String> name =
   1079         String::NewFromUtf8(isolate, source_name.start(),
   1080                             NewStringType::kNormal, source_name.length())
   1081             .ToLocalChecked();
   1082     ScriptOrigin origin(name);
   1083     Local<Script> script =
   1084         Script::Compile(context, source, &origin).ToLocalChecked();
   1085     stringify_function_.Reset(
   1086         isolate, script->Run(context).ToLocalChecked().As<Function>());
   1087   }
   1088   Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
   1089   Local<Value> argv[1] = {value};
   1090   v8::TryCatch try_catch(isolate);
   1091   MaybeLocal<Value> result =
   1092       fun->Call(context, Undefined(isolate), 1, argv).ToLocalChecked();
   1093   if (result.IsEmpty()) return String::Empty(isolate);
   1094   return result.ToLocalChecked().As<String>();
   1095 }
   1096 #endif  // !V8_SHARED
   1097 
   1098 
   1099 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   1100   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
   1101   global_template->Set(
   1102       String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
   1103           .ToLocalChecked(),
   1104       FunctionTemplate::New(isolate, Print));
   1105   global_template->Set(
   1106       String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
   1107           .ToLocalChecked(),
   1108       FunctionTemplate::New(isolate, Write));
   1109   global_template->Set(
   1110       String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
   1111           .ToLocalChecked(),
   1112       FunctionTemplate::New(isolate, Read));
   1113   global_template->Set(
   1114       String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
   1115           .ToLocalChecked(),
   1116       FunctionTemplate::New(isolate, ReadBuffer));
   1117   global_template->Set(
   1118       String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
   1119           .ToLocalChecked(),
   1120       FunctionTemplate::New(isolate, ReadLine));
   1121   global_template->Set(
   1122       String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
   1123           .ToLocalChecked(),
   1124       FunctionTemplate::New(isolate, Load));
   1125   // Some Emscripten-generated code tries to call 'quit', which in turn would
   1126   // call C's exit(). This would lead to memory leaks, because there is no way
   1127   // we can terminate cleanly then, so we need a way to hide 'quit'.
   1128   if (!options.omit_quit) {
   1129     global_template->Set(
   1130         String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
   1131             .ToLocalChecked(),
   1132         FunctionTemplate::New(isolate, Quit));
   1133   }
   1134   global_template->Set(
   1135       String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
   1136           .ToLocalChecked(),
   1137       FunctionTemplate::New(isolate, Version));
   1138   global_template->Set(
   1139       Symbol::GetToStringTag(isolate),
   1140       String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
   1141           .ToLocalChecked());
   1142 
   1143   // Bind the Realm object.
   1144   Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
   1145   realm_template->Set(
   1146       String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
   1147           .ToLocalChecked(),
   1148       FunctionTemplate::New(isolate, RealmCurrent));
   1149   realm_template->Set(
   1150       String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
   1151           .ToLocalChecked(),
   1152       FunctionTemplate::New(isolate, RealmOwner));
   1153   realm_template->Set(
   1154       String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
   1155           .ToLocalChecked(),
   1156       FunctionTemplate::New(isolate, RealmGlobal));
   1157   realm_template->Set(
   1158       String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
   1159           .ToLocalChecked(),
   1160       FunctionTemplate::New(isolate, RealmCreate));
   1161   realm_template->Set(
   1162       String::NewFromUtf8(isolate, "createAllowCrossRealmAccess",
   1163                           NewStringType::kNormal)
   1164           .ToLocalChecked(),
   1165       FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
   1166   realm_template->Set(
   1167       String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
   1168           .ToLocalChecked(),
   1169       FunctionTemplate::New(isolate, RealmDispose));
   1170   realm_template->Set(
   1171       String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
   1172           .ToLocalChecked(),
   1173       FunctionTemplate::New(isolate, RealmSwitch));
   1174   realm_template->Set(
   1175       String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
   1176           .ToLocalChecked(),
   1177       FunctionTemplate::New(isolate, RealmEval));
   1178   realm_template->SetAccessor(
   1179       String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
   1180           .ToLocalChecked(),
   1181       RealmSharedGet, RealmSharedSet);
   1182   global_template->Set(
   1183       String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
   1184           .ToLocalChecked(),
   1185       realm_template);
   1186 
   1187 #ifndef V8_SHARED
   1188   Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
   1189   performance_template->Set(
   1190       String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
   1191           .ToLocalChecked(),
   1192       FunctionTemplate::New(isolate, PerformanceNow));
   1193   global_template->Set(
   1194       String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
   1195           .ToLocalChecked(),
   1196       performance_template);
   1197 
   1198   Local<FunctionTemplate> worker_fun_template =
   1199       FunctionTemplate::New(isolate, WorkerNew);
   1200   Local<Signature> worker_signature =
   1201       Signature::New(isolate, worker_fun_template);
   1202   worker_fun_template->SetClassName(
   1203       String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
   1204           .ToLocalChecked());
   1205   worker_fun_template->ReadOnlyPrototype();
   1206   worker_fun_template->PrototypeTemplate()->Set(
   1207       String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
   1208           .ToLocalChecked(),
   1209       FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
   1210                             worker_signature));
   1211   worker_fun_template->PrototypeTemplate()->Set(
   1212       String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
   1213           .ToLocalChecked(),
   1214       FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
   1215                             worker_signature));
   1216   worker_fun_template->PrototypeTemplate()->Set(
   1217       String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
   1218           .ToLocalChecked(),
   1219       FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
   1220                             worker_signature));
   1221   worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
   1222   global_template->Set(
   1223       String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
   1224           .ToLocalChecked(),
   1225       worker_fun_template);
   1226 #endif  // !V8_SHARED
   1227 
   1228   Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
   1229   AddOSMethods(isolate, os_templ);
   1230   global_template->Set(
   1231       String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
   1232           .ToLocalChecked(),
   1233       os_templ);
   1234 
   1235   return global_template;
   1236 }
   1237 
   1238 static void EmptyMessageCallback(Local<Message> message, Local<Value> error) {
   1239   // Nothing to be done here, exceptions thrown up to the shell will be reported
   1240   // separately by {Shell::ReportException} after they are caught.
   1241 }
   1242 
   1243 void Shell::Initialize(Isolate* isolate) {
   1244 #ifndef V8_SHARED
   1245   // Set up counters
   1246   if (i::StrLength(i::FLAG_map_counters) != 0)
   1247     MapCounters(isolate, i::FLAG_map_counters);
   1248 #endif  // !V8_SHARED
   1249   // Disable default message reporting.
   1250   isolate->AddMessageListener(EmptyMessageCallback);
   1251 }
   1252 
   1253 
   1254 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
   1255 #ifndef V8_SHARED
   1256   // This needs to be a critical section since this is not thread-safe
   1257   base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
   1258 #endif  // !V8_SHARED
   1259   // Initialize the global objects
   1260   Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
   1261   EscapableHandleScope handle_scope(isolate);
   1262   Local<Context> context = Context::New(isolate, NULL, global_template);
   1263   DCHECK(!context.IsEmpty());
   1264   Context::Scope scope(context);
   1265 
   1266 #ifndef V8_SHARED
   1267   i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
   1268   i::JSArguments js_args = i::FLAG_js_arguments;
   1269   i::Handle<i::FixedArray> arguments_array =
   1270       factory->NewFixedArray(js_args.argc);
   1271   for (int j = 0; j < js_args.argc; j++) {
   1272     i::Handle<i::String> arg =
   1273         factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
   1274     arguments_array->set(j, *arg);
   1275   }
   1276   i::Handle<i::JSArray> arguments_jsarray =
   1277       factory->NewJSArrayWithElements(arguments_array);
   1278   context->Global()
   1279       ->Set(context,
   1280             String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
   1281                 .ToLocalChecked(),
   1282             Utils::ToLocal(arguments_jsarray))
   1283       .FromJust();
   1284 #endif  // !V8_SHARED
   1285   return handle_scope.Escape(context);
   1286 }
   1287 
   1288 
   1289 void Shell::Exit(int exit_code) {
   1290   // Use _exit instead of exit to avoid races between isolate
   1291   // threads and static destructors.
   1292   fflush(stdout);
   1293   fflush(stderr);
   1294   _exit(exit_code);
   1295 }
   1296 
   1297 
   1298 #ifndef V8_SHARED
   1299 struct CounterAndKey {
   1300   Counter* counter;
   1301   const char* key;
   1302 };
   1303 
   1304 
   1305 inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
   1306   return strcmp(lhs.key, rhs.key) < 0;
   1307 }
   1308 
   1309 void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
   1310   HandleScope handle_scope(isolate);
   1311   Local<Context> context = Context::New(isolate);
   1312   Context::Scope context_scope(context);
   1313 
   1314   Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
   1315                                         ->interpreter()
   1316                                         ->GetDispatchCountersObject();
   1317   std::ofstream dispatch_counters_stream(
   1318       i::FLAG_trace_ignition_dispatches_output_file);
   1319   dispatch_counters_stream << *String::Utf8Value(
   1320       JSON::Stringify(context, dispatch_counters).ToLocalChecked());
   1321 }
   1322 
   1323 #endif  // !V8_SHARED
   1324 
   1325 
   1326 void Shell::OnExit(v8::Isolate* isolate) {
   1327 #ifndef V8_SHARED
   1328   if (i::FLAG_dump_counters) {
   1329     int number_of_counters = 0;
   1330     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
   1331       number_of_counters++;
   1332     }
   1333     CounterAndKey* counters = new CounterAndKey[number_of_counters];
   1334     int j = 0;
   1335     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
   1336       counters[j].counter = i.CurrentValue();
   1337       counters[j].key = i.CurrentKey();
   1338     }
   1339     std::sort(counters, counters + number_of_counters);
   1340     printf("+----------------------------------------------------------------+"
   1341            "-------------+\n");
   1342     printf("| Name                                                           |"
   1343            " Value       |\n");
   1344     printf("+----------------------------------------------------------------+"
   1345            "-------------+\n");
   1346     for (j = 0; j < number_of_counters; j++) {
   1347       Counter* counter = counters[j].counter;
   1348       const char* key = counters[j].key;
   1349       if (counter->is_histogram()) {
   1350         printf("| c:%-60s | %11i |\n", key, counter->count());
   1351         printf("| t:%-60s | %11i |\n", key, counter->sample_total());
   1352       } else {
   1353         printf("| %-62s | %11i |\n", key, counter->count());
   1354       }
   1355     }
   1356     printf("+----------------------------------------------------------------+"
   1357            "-------------+\n");
   1358     delete [] counters;
   1359   }
   1360 
   1361   delete counters_file_;
   1362   delete counter_map_;
   1363 #endif  // !V8_SHARED
   1364 }
   1365 
   1366 
   1367 
   1368 static FILE* FOpen(const char* path, const char* mode) {
   1369 #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
   1370   FILE* result;
   1371   if (fopen_s(&result, path, mode) == 0) {
   1372     return result;
   1373   } else {
   1374     return NULL;
   1375   }
   1376 #else
   1377   FILE* file = fopen(path, mode);
   1378   if (file == NULL) return NULL;
   1379   struct stat file_stat;
   1380   if (fstat(fileno(file), &file_stat) != 0) return NULL;
   1381   bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
   1382   if (is_regular_file) return file;
   1383   fclose(file);
   1384   return NULL;
   1385 #endif
   1386 }
   1387 
   1388 
   1389 static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
   1390   FILE* file = FOpen(name, "rb");
   1391   if (file == NULL) return NULL;
   1392 
   1393   fseek(file, 0, SEEK_END);
   1394   size_t size = ftell(file);
   1395   rewind(file);
   1396 
   1397   char* chars = new char[size + 1];
   1398   chars[size] = '\0';
   1399   for (size_t i = 0; i < size;) {
   1400     i += fread(&chars[i], 1, size - i, file);
   1401     if (ferror(file)) {
   1402       fclose(file);
   1403       delete[] chars;
   1404       return nullptr;
   1405     }
   1406   }
   1407   fclose(file);
   1408   *size_out = static_cast<int>(size);
   1409   return chars;
   1410 }
   1411 
   1412 
   1413 struct DataAndPersistent {
   1414   uint8_t* data;
   1415   int byte_length;
   1416   Global<ArrayBuffer> handle;
   1417 };
   1418 
   1419 
   1420 static void ReadBufferWeakCallback(
   1421     const v8::WeakCallbackInfo<DataAndPersistent>& data) {
   1422   int byte_length = data.GetParameter()->byte_length;
   1423   data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
   1424       -static_cast<intptr_t>(byte_length));
   1425 
   1426   delete[] data.GetParameter()->data;
   1427   data.GetParameter()->handle.Reset();
   1428   delete data.GetParameter();
   1429 }
   1430 
   1431 
   1432 void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1433   DCHECK(sizeof(char) == sizeof(uint8_t));  // NOLINT
   1434   String::Utf8Value filename(args[0]);
   1435   int length;
   1436   if (*filename == NULL) {
   1437     Throw(args.GetIsolate(), "Error loading file");
   1438     return;
   1439   }
   1440 
   1441   Isolate* isolate = args.GetIsolate();
   1442   DataAndPersistent* data = new DataAndPersistent;
   1443   data->data = reinterpret_cast<uint8_t*>(
   1444       ReadChars(args.GetIsolate(), *filename, &length));
   1445   if (data->data == NULL) {
   1446     delete data;
   1447     Throw(args.GetIsolate(), "Error reading file");
   1448     return;
   1449   }
   1450   data->byte_length = length;
   1451   Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
   1452   data->handle.Reset(isolate, buffer);
   1453   data->handle.SetWeak(data, ReadBufferWeakCallback,
   1454                        v8::WeakCallbackType::kParameter);
   1455   data->handle.MarkIndependent();
   1456   isolate->AdjustAmountOfExternalAllocatedMemory(length);
   1457 
   1458   args.GetReturnValue().Set(buffer);
   1459 }
   1460 
   1461 
   1462 // Reads a file into a v8 string.
   1463 Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
   1464   int size = 0;
   1465   char* chars = ReadChars(isolate, name, &size);
   1466   if (chars == NULL) return Local<String>();
   1467   Local<String> result =
   1468       String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
   1469           .ToLocalChecked();
   1470   delete[] chars;
   1471   return result;
   1472 }
   1473 
   1474 
   1475 void Shell::RunShell(Isolate* isolate) {
   1476   HandleScope outer_scope(isolate);
   1477   v8::Local<v8::Context> context =
   1478       v8::Local<v8::Context>::New(isolate, evaluation_context_);
   1479   v8::Context::Scope context_scope(context);
   1480   PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   1481   Local<String> name =
   1482       String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
   1483           .ToLocalChecked();
   1484   printf("V8 version %s\n", V8::GetVersion());
   1485   while (true) {
   1486     HandleScope inner_scope(isolate);
   1487     printf("d8> ");
   1488 #if defined(__native_client__)
   1489     // Native Client libc is used to being embedded in Chrome and
   1490     // has trouble recognizing when to flush.
   1491     fflush(stdout);
   1492 #endif
   1493     Local<String> input = Shell::ReadFromStdin(isolate);
   1494     if (input.IsEmpty()) break;
   1495     ExecuteString(isolate, input, name, true, true);
   1496   }
   1497   printf("\n");
   1498 }
   1499 
   1500 
   1501 SourceGroup::~SourceGroup() {
   1502 #ifndef V8_SHARED
   1503   delete thread_;
   1504   thread_ = NULL;
   1505 #endif  // !V8_SHARED
   1506 }
   1507 
   1508 
   1509 void SourceGroup::Execute(Isolate* isolate) {
   1510   bool exception_was_thrown = false;
   1511   for (int i = begin_offset_; i < end_offset_; ++i) {
   1512     const char* arg = argv_[i];
   1513     Shell::SourceType source_type = Shell::SCRIPT;
   1514     if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
   1515       // Execute argument given to -e option directly.
   1516       HandleScope handle_scope(isolate);
   1517       Local<String> file_name =
   1518           String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
   1519               .ToLocalChecked();
   1520       Local<String> source =
   1521           String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
   1522               .ToLocalChecked();
   1523       Shell::options.script_executed = true;
   1524       if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
   1525         exception_was_thrown = true;
   1526         break;
   1527       }
   1528       ++i;
   1529       continue;
   1530     } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
   1531       // Treat the next file as a module.
   1532       source_type = Shell::MODULE;
   1533       arg = argv_[++i];
   1534     } else if (arg[0] == '-') {
   1535       // Ignore other options. They have been parsed already.
   1536       continue;
   1537     }
   1538 
   1539     // Use all other arguments as names of files to load and run.
   1540     HandleScope handle_scope(isolate);
   1541     Local<String> file_name =
   1542         String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
   1543             .ToLocalChecked();
   1544     Local<String> source = ReadFile(isolate, arg);
   1545     if (source.IsEmpty()) {
   1546       printf("Error reading '%s'\n", arg);
   1547       Shell::Exit(1);
   1548     }
   1549     Shell::options.script_executed = true;
   1550     if (!Shell::ExecuteString(isolate, source, file_name, false, true,
   1551                               source_type)) {
   1552       exception_was_thrown = true;
   1553       break;
   1554     }
   1555   }
   1556   if (exception_was_thrown != Shell::options.expected_to_throw) {
   1557     Shell::Exit(1);
   1558   }
   1559 }
   1560 
   1561 
   1562 Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
   1563   int size;
   1564   char* chars = ReadChars(isolate, name, &size);
   1565   if (chars == NULL) return Local<String>();
   1566   Local<String> result =
   1567       String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
   1568           .ToLocalChecked();
   1569   delete[] chars;
   1570   return result;
   1571 }
   1572 
   1573 
   1574 #ifndef V8_SHARED
   1575 base::Thread::Options SourceGroup::GetThreadOptions() {
   1576   // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
   1577   // which is not enough to parse the big literal expressions used in tests.
   1578   // The stack size should be at least StackGuard::kLimitSize + some
   1579   // OS-specific padding for thread startup code.  2Mbytes seems to be enough.
   1580   return base::Thread::Options("IsolateThread", 2 * MB);
   1581 }
   1582 
   1583 
   1584 void SourceGroup::ExecuteInThread() {
   1585   Isolate::CreateParams create_params;
   1586   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   1587   Isolate* isolate = Isolate::New(create_params);
   1588   for (int i = 0; i < Shell::options.stress_runs; ++i) {
   1589     next_semaphore_.Wait();
   1590     {
   1591       Isolate::Scope iscope(isolate);
   1592       {
   1593         HandleScope scope(isolate);
   1594         PerIsolateData data(isolate);
   1595         Local<Context> context = Shell::CreateEvaluationContext(isolate);
   1596         {
   1597           Context::Scope cscope(context);
   1598           PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   1599           Execute(isolate);
   1600         }
   1601       }
   1602       Shell::CollectGarbage(isolate);
   1603     }
   1604     done_semaphore_.Signal();
   1605   }
   1606 
   1607   isolate->Dispose();
   1608 }
   1609 
   1610 
   1611 void SourceGroup::StartExecuteInThread() {
   1612   if (thread_ == NULL) {
   1613     thread_ = new IsolateThread(this);
   1614     thread_->Start();
   1615   }
   1616   next_semaphore_.Signal();
   1617 }
   1618 
   1619 
   1620 void SourceGroup::WaitForThread() {
   1621   if (thread_ == NULL) return;
   1622   done_semaphore_.Wait();
   1623 }
   1624 
   1625 
   1626 void SourceGroup::JoinThread() {
   1627   if (thread_ == NULL) return;
   1628   thread_->Join();
   1629 }
   1630 
   1631 
   1632 SerializationData::~SerializationData() {
   1633   // Any ArrayBuffer::Contents are owned by this SerializationData object if
   1634   // ownership hasn't been transferred out via ReadArrayBufferContents.
   1635   // SharedArrayBuffer::Contents may be used by multiple threads, so must be
   1636   // cleaned up by the main thread in Shell::CleanupWorkers().
   1637   for (int i = 0; i < array_buffer_contents_.length(); ++i) {
   1638     ArrayBuffer::Contents& contents = array_buffer_contents_[i];
   1639     if (contents.Data()) {
   1640       Shell::array_buffer_allocator->Free(contents.Data(),
   1641                                           contents.ByteLength());
   1642     }
   1643   }
   1644 }
   1645 
   1646 
   1647 void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
   1648 
   1649 
   1650 void SerializationData::WriteMemory(const void* p, int length) {
   1651   if (length > 0) {
   1652     i::Vector<uint8_t> block = data_.AddBlock(0, length);
   1653     memcpy(&block[0], p, length);
   1654   }
   1655 }
   1656 
   1657 
   1658 void SerializationData::WriteArrayBufferContents(
   1659     const ArrayBuffer::Contents& contents) {
   1660   array_buffer_contents_.Add(contents);
   1661   WriteTag(kSerializationTagTransferredArrayBuffer);
   1662   int index = array_buffer_contents_.length() - 1;
   1663   Write(index);
   1664 }
   1665 
   1666 
   1667 void SerializationData::WriteSharedArrayBufferContents(
   1668     const SharedArrayBuffer::Contents& contents) {
   1669   shared_array_buffer_contents_.Add(contents);
   1670   WriteTag(kSerializationTagTransferredSharedArrayBuffer);
   1671   int index = shared_array_buffer_contents_.length() - 1;
   1672   Write(index);
   1673 }
   1674 
   1675 
   1676 SerializationTag SerializationData::ReadTag(int* offset) const {
   1677   return static_cast<SerializationTag>(Read<uint8_t>(offset));
   1678 }
   1679 
   1680 
   1681 void SerializationData::ReadMemory(void* p, int length, int* offset) const {
   1682   if (length > 0) {
   1683     memcpy(p, &data_[*offset], length);
   1684     (*offset) += length;
   1685   }
   1686 }
   1687 
   1688 
   1689 void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
   1690                                                 int* offset) const {
   1691   int index = Read<int>(offset);
   1692   DCHECK(index < array_buffer_contents_.length());
   1693   *contents = array_buffer_contents_[index];
   1694   // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
   1695   // our copy so it won't be double-free'd when this SerializationData is
   1696   // destroyed.
   1697   array_buffer_contents_[index] = ArrayBuffer::Contents();
   1698 }
   1699 
   1700 
   1701 void SerializationData::ReadSharedArrayBufferContents(
   1702     SharedArrayBuffer::Contents* contents, int* offset) const {
   1703   int index = Read<int>(offset);
   1704   DCHECK(index < shared_array_buffer_contents_.length());
   1705   *contents = shared_array_buffer_contents_[index];
   1706 }
   1707 
   1708 
   1709 void SerializationDataQueue::Enqueue(SerializationData* data) {
   1710   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   1711   data_.Add(data);
   1712 }
   1713 
   1714 
   1715 bool SerializationDataQueue::Dequeue(SerializationData** data) {
   1716   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   1717   *data = NULL;
   1718   if (data_.is_empty()) return false;
   1719   *data = data_.Remove(0);
   1720   return true;
   1721 }
   1722 
   1723 
   1724 bool SerializationDataQueue::IsEmpty() {
   1725   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   1726   return data_.is_empty();
   1727 }
   1728 
   1729 
   1730 void SerializationDataQueue::Clear() {
   1731   base::LockGuard<base::Mutex> lock_guard(&mutex_);
   1732   for (int i = 0; i < data_.length(); ++i) {
   1733     delete data_[i];
   1734   }
   1735   data_.Clear();
   1736 }
   1737 
   1738 
   1739 Worker::Worker()
   1740     : in_semaphore_(0),
   1741       out_semaphore_(0),
   1742       thread_(NULL),
   1743       script_(NULL),
   1744       running_(false) {}
   1745 
   1746 
   1747 Worker::~Worker() {
   1748   delete thread_;
   1749   thread_ = NULL;
   1750   delete[] script_;
   1751   script_ = NULL;
   1752   in_queue_.Clear();
   1753   out_queue_.Clear();
   1754 }
   1755 
   1756 
   1757 void Worker::StartExecuteInThread(const char* script) {
   1758   running_ = true;
   1759   script_ = i::StrDup(script);
   1760   thread_ = new WorkerThread(this);
   1761   thread_->Start();
   1762 }
   1763 
   1764 
   1765 void Worker::PostMessage(SerializationData* data) {
   1766   in_queue_.Enqueue(data);
   1767   in_semaphore_.Signal();
   1768 }
   1769 
   1770 
   1771 SerializationData* Worker::GetMessage() {
   1772   SerializationData* data = NULL;
   1773   while (!out_queue_.Dequeue(&data)) {
   1774     // If the worker is no longer running, and there are no messages in the
   1775     // queue, don't expect any more messages from it.
   1776     if (!base::NoBarrier_Load(&running_)) break;
   1777     out_semaphore_.Wait();
   1778   }
   1779   return data;
   1780 }
   1781 
   1782 
   1783 void Worker::Terminate() {
   1784   base::NoBarrier_Store(&running_, false);
   1785   // Post NULL to wake the Worker thread message loop, and tell it to stop
   1786   // running.
   1787   PostMessage(NULL);
   1788 }
   1789 
   1790 
   1791 void Worker::WaitForThread() {
   1792   Terminate();
   1793   thread_->Join();
   1794 }
   1795 
   1796 
   1797 void Worker::ExecuteInThread() {
   1798   Isolate::CreateParams create_params;
   1799   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   1800   Isolate* isolate = Isolate::New(create_params);
   1801   {
   1802     Isolate::Scope iscope(isolate);
   1803     {
   1804       HandleScope scope(isolate);
   1805       PerIsolateData data(isolate);
   1806       Local<Context> context = Shell::CreateEvaluationContext(isolate);
   1807       {
   1808         Context::Scope cscope(context);
   1809         PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   1810 
   1811         Local<Object> global = context->Global();
   1812         Local<Value> this_value = External::New(isolate, this);
   1813         Local<FunctionTemplate> postmessage_fun_template =
   1814             FunctionTemplate::New(isolate, PostMessageOut, this_value);
   1815 
   1816         Local<Function> postmessage_fun;
   1817         if (postmessage_fun_template->GetFunction(context)
   1818                 .ToLocal(&postmessage_fun)) {
   1819           global->Set(context, String::NewFromUtf8(isolate, "postMessage",
   1820                                                    NewStringType::kNormal)
   1821                                    .ToLocalChecked(),
   1822                       postmessage_fun).FromJust();
   1823         }
   1824 
   1825         // First run the script
   1826         Local<String> file_name =
   1827             String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
   1828                 .ToLocalChecked();
   1829         Local<String> source =
   1830             String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
   1831                 .ToLocalChecked();
   1832         if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
   1833           // Get the message handler
   1834           Local<Value> onmessage =
   1835               global->Get(context, String::NewFromUtf8(isolate, "onmessage",
   1836                                                        NewStringType::kNormal)
   1837                                        .ToLocalChecked()).ToLocalChecked();
   1838           if (onmessage->IsFunction()) {
   1839             Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
   1840             // Now wait for messages
   1841             while (true) {
   1842               in_semaphore_.Wait();
   1843               SerializationData* data;
   1844               if (!in_queue_.Dequeue(&data)) continue;
   1845               if (data == NULL) {
   1846                 break;
   1847               }
   1848               int offset = 0;
   1849               Local<Value> data_value;
   1850               if (Shell::DeserializeValue(isolate, *data, &offset)
   1851                       .ToLocal(&data_value)) {
   1852                 Local<Value> argv[] = {data_value};
   1853                 (void)onmessage_fun->Call(context, global, 1, argv);
   1854               }
   1855               delete data;
   1856             }
   1857           }
   1858         }
   1859       }
   1860     }
   1861     Shell::CollectGarbage(isolate);
   1862   }
   1863   isolate->Dispose();
   1864 
   1865   // Post NULL to wake the thread waiting on GetMessage() if there is one.
   1866   out_queue_.Enqueue(NULL);
   1867   out_semaphore_.Signal();
   1868 }
   1869 
   1870 
   1871 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1872   Isolate* isolate = args.GetIsolate();
   1873   HandleScope handle_scope(isolate);
   1874 
   1875   if (args.Length() < 1) {
   1876     Throw(isolate, "Invalid argument");
   1877     return;
   1878   }
   1879 
   1880   Local<Value> message = args[0];
   1881 
   1882   // TODO(binji): Allow transferring from worker to main thread?
   1883   Shell::ObjectList to_transfer;
   1884 
   1885   Shell::ObjectList seen_objects;
   1886   SerializationData* data = new SerializationData;
   1887   if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
   1888                             data)) {
   1889     DCHECK(args.Data()->IsExternal());
   1890     Local<External> this_value = Local<External>::Cast(args.Data());
   1891     Worker* worker = static_cast<Worker*>(this_value->Value());
   1892     worker->out_queue_.Enqueue(data);
   1893     worker->out_semaphore_.Signal();
   1894   } else {
   1895     delete data;
   1896   }
   1897 }
   1898 #endif  // !V8_SHARED
   1899 
   1900 
   1901 void SetFlagsFromString(const char* flags) {
   1902   v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
   1903 }
   1904 
   1905 
   1906 bool Shell::SetOptions(int argc, char* argv[]) {
   1907   bool logfile_per_isolate = false;
   1908   for (int i = 0; i < argc; i++) {
   1909     if (strcmp(argv[i], "--stress-opt") == 0) {
   1910       options.stress_opt = true;
   1911       argv[i] = NULL;
   1912     } else if (strcmp(argv[i], "--nostress-opt") == 0) {
   1913       options.stress_opt = false;
   1914       argv[i] = NULL;
   1915     } else if (strcmp(argv[i], "--stress-deopt") == 0) {
   1916       options.stress_deopt = true;
   1917       argv[i] = NULL;
   1918     } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
   1919       options.mock_arraybuffer_allocator = true;
   1920       argv[i] = NULL;
   1921     } else if (strcmp(argv[i], "--noalways-opt") == 0) {
   1922       // No support for stressing if we can't use --always-opt.
   1923       options.stress_opt = false;
   1924       options.stress_deopt = false;
   1925     } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
   1926       logfile_per_isolate = true;
   1927       argv[i] = NULL;
   1928     } else if (strcmp(argv[i], "--shell") == 0) {
   1929       options.interactive_shell = true;
   1930       argv[i] = NULL;
   1931     } else if (strcmp(argv[i], "--test") == 0) {
   1932       options.test_shell = true;
   1933       argv[i] = NULL;
   1934     } else if (strcmp(argv[i], "--notest") == 0 ||
   1935                strcmp(argv[i], "--no-test") == 0) {
   1936       options.test_shell = false;
   1937       argv[i] = NULL;
   1938     } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
   1939       options.send_idle_notification = true;
   1940       argv[i] = NULL;
   1941     } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
   1942       options.invoke_weak_callbacks = true;
   1943       // TODO(jochen) See issue 3351
   1944       options.send_idle_notification = true;
   1945       argv[i] = NULL;
   1946     } else if (strcmp(argv[i], "--omit-quit") == 0) {
   1947       options.omit_quit = true;
   1948       argv[i] = NULL;
   1949     } else if (strcmp(argv[i], "-f") == 0) {
   1950       // Ignore any -f flags for compatibility with other stand-alone
   1951       // JavaScript engines.
   1952       continue;
   1953     } else if (strcmp(argv[i], "--isolate") == 0) {
   1954 #ifdef V8_SHARED
   1955       printf("D8 with shared library does not support multi-threading\n");
   1956       return false;
   1957 #endif  // V8_SHARED
   1958       options.num_isolates++;
   1959     } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
   1960 #ifdef V8_SHARED
   1961       printf("D8 with shared library does not support constant dumping\n");
   1962       return false;
   1963 #else
   1964       options.dump_heap_constants = true;
   1965       argv[i] = NULL;
   1966 #endif  // V8_SHARED
   1967     } else if (strcmp(argv[i], "--throws") == 0) {
   1968       options.expected_to_throw = true;
   1969       argv[i] = NULL;
   1970     } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
   1971       options.icu_data_file = argv[i] + 16;
   1972       argv[i] = NULL;
   1973 #ifdef V8_SHARED
   1974     } else if (strcmp(argv[i], "--dump-counters") == 0) {
   1975       printf("D8 with shared library does not include counters\n");
   1976       return false;
   1977 #endif  // V8_SHARED
   1978 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   1979     } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
   1980       options.natives_blob = argv[i] + 15;
   1981       argv[i] = NULL;
   1982     } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
   1983       options.snapshot_blob = argv[i] + 16;
   1984       argv[i] = NULL;
   1985 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
   1986     } else if (strcmp(argv[i], "--cache") == 0 ||
   1987                strncmp(argv[i], "--cache=", 8) == 0) {
   1988       const char* value = argv[i] + 7;
   1989       if (!*value || strncmp(value, "=code", 6) == 0) {
   1990         options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
   1991       } else if (strncmp(value, "=parse", 7) == 0) {
   1992         options.compile_options = v8::ScriptCompiler::kProduceParserCache;
   1993       } else if (strncmp(value, "=none", 6) == 0) {
   1994         options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
   1995       } else {
   1996         printf("Unknown option to --cache.\n");
   1997         return false;
   1998       }
   1999       argv[i] = NULL;
   2000     }
   2001   }
   2002 
   2003   v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
   2004 
   2005   // Set up isolated source groups.
   2006   options.isolate_sources = new SourceGroup[options.num_isolates];
   2007   SourceGroup* current = options.isolate_sources;
   2008   current->Begin(argv, 1);
   2009   for (int i = 1; i < argc; i++) {
   2010     const char* str = argv[i];
   2011     if (strcmp(str, "--isolate") == 0) {
   2012       current->End(i);
   2013       current++;
   2014       current->Begin(argv, i + 1);
   2015     } else if (strcmp(str, "--module") == 0) {
   2016       // Pass on to SourceGroup, which understands this option.
   2017     } else if (strncmp(argv[i], "--", 2) == 0) {
   2018       printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
   2019     } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
   2020       options.script_executed = true;
   2021     } else if (strncmp(str, "-", 1) != 0) {
   2022       // Not a flag, so it must be a script to execute.
   2023       options.script_executed = true;
   2024     }
   2025   }
   2026   current->End(argc);
   2027 
   2028   if (!logfile_per_isolate && options.num_isolates) {
   2029     SetFlagsFromString("--nologfile_per_isolate");
   2030   }
   2031 
   2032   return true;
   2033 }
   2034 
   2035 
   2036 int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
   2037 #ifndef V8_SHARED
   2038   for (int i = 1; i < options.num_isolates; ++i) {
   2039     options.isolate_sources[i].StartExecuteInThread();
   2040   }
   2041 #endif  // !V8_SHARED
   2042   {
   2043     HandleScope scope(isolate);
   2044     Local<Context> context = CreateEvaluationContext(isolate);
   2045     if (last_run && options.use_interactive_shell()) {
   2046       // Keep using the same context in the interactive shell.
   2047       evaluation_context_.Reset(isolate, context);
   2048     }
   2049     {
   2050       Context::Scope cscope(context);
   2051       PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
   2052       options.isolate_sources[0].Execute(isolate);
   2053     }
   2054   }
   2055   CollectGarbage(isolate);
   2056 #ifndef V8_SHARED
   2057   for (int i = 1; i < options.num_isolates; ++i) {
   2058     if (last_run) {
   2059       options.isolate_sources[i].JoinThread();
   2060     } else {
   2061       options.isolate_sources[i].WaitForThread();
   2062     }
   2063   }
   2064   CleanupWorkers();
   2065 #endif  // !V8_SHARED
   2066   return 0;
   2067 }
   2068 
   2069 
   2070 void Shell::CollectGarbage(Isolate* isolate) {
   2071   if (options.send_idle_notification) {
   2072     const double kLongIdlePauseInSeconds = 1.0;
   2073     isolate->ContextDisposedNotification();
   2074     isolate->IdleNotificationDeadline(
   2075         g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
   2076   }
   2077   if (options.invoke_weak_callbacks) {
   2078     // By sending a low memory notifications, we will try hard to collect all
   2079     // garbage and will therefore also invoke all weak callbacks of actually
   2080     // unreachable persistent handles.
   2081     isolate->LowMemoryNotification();
   2082   }
   2083 }
   2084 
   2085 
   2086 void Shell::EmptyMessageQueues(Isolate* isolate) {
   2087 #ifndef V8_SHARED
   2088   if (!i::FLAG_verify_predictable) {
   2089 #endif
   2090     while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
   2091 #ifndef V8_SHARED
   2092   }
   2093 #endif
   2094 }
   2095 
   2096 
   2097 #ifndef V8_SHARED
   2098 bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
   2099                            const ObjectList& to_transfer,
   2100                            ObjectList* seen_objects,
   2101                            SerializationData* out_data) {
   2102   DCHECK(out_data);
   2103   Local<Context> context = isolate->GetCurrentContext();
   2104 
   2105   if (value->IsUndefined()) {
   2106     out_data->WriteTag(kSerializationTagUndefined);
   2107   } else if (value->IsNull()) {
   2108     out_data->WriteTag(kSerializationTagNull);
   2109   } else if (value->IsTrue()) {
   2110     out_data->WriteTag(kSerializationTagTrue);
   2111   } else if (value->IsFalse()) {
   2112     out_data->WriteTag(kSerializationTagFalse);
   2113   } else if (value->IsNumber()) {
   2114     Local<Number> num = Local<Number>::Cast(value);
   2115     double value = num->Value();
   2116     out_data->WriteTag(kSerializationTagNumber);
   2117     out_data->Write(value);
   2118   } else if (value->IsString()) {
   2119     v8::String::Utf8Value str(value);
   2120     out_data->WriteTag(kSerializationTagString);
   2121     out_data->Write(str.length());
   2122     out_data->WriteMemory(*str, str.length());
   2123   } else if (value->IsArray()) {
   2124     Local<Array> array = Local<Array>::Cast(value);
   2125     if (FindInObjectList(array, *seen_objects)) {
   2126       Throw(isolate, "Duplicated arrays not supported");
   2127       return false;
   2128     }
   2129     seen_objects->Add(array);
   2130     out_data->WriteTag(kSerializationTagArray);
   2131     uint32_t length = array->Length();
   2132     out_data->Write(length);
   2133     for (uint32_t i = 0; i < length; ++i) {
   2134       Local<Value> element_value;
   2135       if (array->Get(context, i).ToLocal(&element_value)) {
   2136         if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
   2137                             out_data))
   2138           return false;
   2139       } else {
   2140         Throw(isolate, "Failed to serialize array element.");
   2141         return false;
   2142       }
   2143     }
   2144   } else if (value->IsArrayBuffer()) {
   2145     Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
   2146     if (FindInObjectList(array_buffer, *seen_objects)) {
   2147       Throw(isolate, "Duplicated array buffers not supported");
   2148       return false;
   2149     }
   2150     seen_objects->Add(array_buffer);
   2151     if (FindInObjectList(array_buffer, to_transfer)) {
   2152       // Transfer ArrayBuffer
   2153       if (!array_buffer->IsNeuterable()) {
   2154         Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
   2155         return false;
   2156       }
   2157 
   2158       ArrayBuffer::Contents contents = array_buffer->IsExternal()
   2159                                            ? array_buffer->GetContents()
   2160                                            : array_buffer->Externalize();
   2161       array_buffer->Neuter();
   2162       out_data->WriteArrayBufferContents(contents);
   2163     } else {
   2164       ArrayBuffer::Contents contents = array_buffer->GetContents();
   2165       // Clone ArrayBuffer
   2166       if (contents.ByteLength() > i::kMaxInt) {
   2167         Throw(isolate, "ArrayBuffer is too big to clone");
   2168         return false;
   2169       }
   2170 
   2171       int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
   2172       out_data->WriteTag(kSerializationTagArrayBuffer);
   2173       out_data->Write(byte_length);
   2174       out_data->WriteMemory(contents.Data(), byte_length);
   2175     }
   2176   } else if (value->IsSharedArrayBuffer()) {
   2177     Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
   2178     if (FindInObjectList(sab, *seen_objects)) {
   2179       Throw(isolate, "Duplicated shared array buffers not supported");
   2180       return false;
   2181     }
   2182     seen_objects->Add(sab);
   2183     if (!FindInObjectList(sab, to_transfer)) {
   2184       Throw(isolate, "SharedArrayBuffer must be transferred");
   2185       return false;
   2186     }
   2187 
   2188     SharedArrayBuffer::Contents contents;
   2189     if (sab->IsExternal()) {
   2190       contents = sab->GetContents();
   2191     } else {
   2192       contents = sab->Externalize();
   2193       base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   2194       externalized_shared_contents_.Add(contents);
   2195     }
   2196     out_data->WriteSharedArrayBufferContents(contents);
   2197   } else if (value->IsObject()) {
   2198     Local<Object> object = Local<Object>::Cast(value);
   2199     if (FindInObjectList(object, *seen_objects)) {
   2200       Throw(isolate, "Duplicated objects not supported");
   2201       return false;
   2202     }
   2203     seen_objects->Add(object);
   2204     Local<Array> property_names;
   2205     if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
   2206       Throw(isolate, "Unable to get property names");
   2207       return false;
   2208     }
   2209 
   2210     uint32_t length = property_names->Length();
   2211     out_data->WriteTag(kSerializationTagObject);
   2212     out_data->Write(length);
   2213     for (uint32_t i = 0; i < length; ++i) {
   2214       Local<Value> name;
   2215       Local<Value> property_value;
   2216       if (property_names->Get(context, i).ToLocal(&name) &&
   2217           object->Get(context, name).ToLocal(&property_value)) {
   2218         if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
   2219           return false;
   2220         if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
   2221                             out_data))
   2222           return false;
   2223       } else {
   2224         Throw(isolate, "Failed to serialize property.");
   2225         return false;
   2226       }
   2227     }
   2228   } else {
   2229     Throw(isolate, "Don't know how to serialize object");
   2230     return false;
   2231   }
   2232 
   2233   return true;
   2234 }
   2235 
   2236 
   2237 MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
   2238                                           const SerializationData& data,
   2239                                           int* offset) {
   2240   DCHECK(offset);
   2241   EscapableHandleScope scope(isolate);
   2242   Local<Value> result;
   2243   SerializationTag tag = data.ReadTag(offset);
   2244 
   2245   switch (tag) {
   2246     case kSerializationTagUndefined:
   2247       result = Undefined(isolate);
   2248       break;
   2249     case kSerializationTagNull:
   2250       result = Null(isolate);
   2251       break;
   2252     case kSerializationTagTrue:
   2253       result = True(isolate);
   2254       break;
   2255     case kSerializationTagFalse:
   2256       result = False(isolate);
   2257       break;
   2258     case kSerializationTagNumber:
   2259       result = Number::New(isolate, data.Read<double>(offset));
   2260       break;
   2261     case kSerializationTagString: {
   2262       int length = data.Read<int>(offset);
   2263       CHECK(length >= 0);
   2264       std::vector<char> buffer(length + 1);  // + 1 so it is never empty.
   2265       data.ReadMemory(&buffer[0], length, offset);
   2266       MaybeLocal<String> str =
   2267           String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
   2268                               length).ToLocalChecked();
   2269       if (!str.IsEmpty()) result = str.ToLocalChecked();
   2270       break;
   2271     }
   2272     case kSerializationTagArray: {
   2273       uint32_t length = data.Read<uint32_t>(offset);
   2274       Local<Array> array = Array::New(isolate, length);
   2275       for (uint32_t i = 0; i < length; ++i) {
   2276         Local<Value> element_value;
   2277         CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
   2278         array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
   2279       }
   2280       result = array;
   2281       break;
   2282     }
   2283     case kSerializationTagObject: {
   2284       int length = data.Read<int>(offset);
   2285       Local<Object> object = Object::New(isolate);
   2286       for (int i = 0; i < length; ++i) {
   2287         Local<Value> property_name;
   2288         CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
   2289         Local<Value> property_value;
   2290         CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
   2291         object->Set(isolate->GetCurrentContext(), property_name, property_value)
   2292             .FromJust();
   2293       }
   2294       result = object;
   2295       break;
   2296     }
   2297     case kSerializationTagArrayBuffer: {
   2298       int32_t byte_length = data.Read<int32_t>(offset);
   2299       Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
   2300       ArrayBuffer::Contents contents = array_buffer->GetContents();
   2301       DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
   2302       data.ReadMemory(contents.Data(), byte_length, offset);
   2303       result = array_buffer;
   2304       break;
   2305     }
   2306     case kSerializationTagTransferredArrayBuffer: {
   2307       ArrayBuffer::Contents contents;
   2308       data.ReadArrayBufferContents(&contents, offset);
   2309       result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
   2310                                 ArrayBufferCreationMode::kInternalized);
   2311       break;
   2312     }
   2313     case kSerializationTagTransferredSharedArrayBuffer: {
   2314       SharedArrayBuffer::Contents contents;
   2315       data.ReadSharedArrayBufferContents(&contents, offset);
   2316       result = SharedArrayBuffer::New(isolate, contents.Data(),
   2317                                       contents.ByteLength());
   2318       break;
   2319     }
   2320     default:
   2321       UNREACHABLE();
   2322   }
   2323 
   2324   return scope.Escape(result);
   2325 }
   2326 
   2327 
   2328 void Shell::CleanupWorkers() {
   2329   // Make a copy of workers_, because we don't want to call Worker::Terminate
   2330   // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
   2331   // create a new Worker, it would deadlock.
   2332   i::List<Worker*> workers_copy;
   2333   {
   2334     base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   2335     allow_new_workers_ = false;
   2336     workers_copy.AddAll(workers_);
   2337     workers_.Clear();
   2338   }
   2339 
   2340   for (int i = 0; i < workers_copy.length(); ++i) {
   2341     Worker* worker = workers_copy[i];
   2342     worker->WaitForThread();
   2343     delete worker;
   2344   }
   2345 
   2346   // Now that all workers are terminated, we can re-enable Worker creation.
   2347   base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
   2348   allow_new_workers_ = true;
   2349 
   2350   for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
   2351     const SharedArrayBuffer::Contents& contents =
   2352         externalized_shared_contents_[i];
   2353     Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
   2354   }
   2355   externalized_shared_contents_.Clear();
   2356 }
   2357 
   2358 
   2359 static void DumpHeapConstants(i::Isolate* isolate) {
   2360   i::Heap* heap = isolate->heap();
   2361 
   2362   // Dump the INSTANCE_TYPES table to the console.
   2363   printf("# List of known V8 instance types.\n");
   2364 #define DUMP_TYPE(T) printf("  %d: \"%s\",\n", i::T, #T);
   2365   printf("INSTANCE_TYPES = {\n");
   2366   INSTANCE_TYPE_LIST(DUMP_TYPE)
   2367   printf("}\n");
   2368 #undef DUMP_TYPE
   2369 
   2370   // Dump the KNOWN_MAP table to the console.
   2371   printf("\n# List of known V8 maps.\n");
   2372 #define ROOT_LIST_CASE(type, name, camel_name) \
   2373   if (n == NULL && o == heap->name()) n = #camel_name;
   2374 #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
   2375   if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
   2376   i::HeapObjectIterator it(heap->map_space());
   2377   printf("KNOWN_MAPS = {\n");
   2378   for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
   2379     i::Map* m = i::Map::cast(o);
   2380     const char* n = NULL;
   2381     intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
   2382     int t = m->instance_type();
   2383     ROOT_LIST(ROOT_LIST_CASE)
   2384     STRUCT_LIST(STRUCT_LIST_CASE)
   2385     if (n == NULL) continue;
   2386     printf("  0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
   2387   }
   2388   printf("}\n");
   2389 #undef STRUCT_LIST_CASE
   2390 #undef ROOT_LIST_CASE
   2391 
   2392   // Dump the KNOWN_OBJECTS table to the console.
   2393   printf("\n# List of known V8 objects.\n");
   2394 #define ROOT_LIST_CASE(type, name, camel_name) \
   2395   if (n == NULL && o == heap->name()) n = #camel_name;
   2396   i::OldSpaces spit(heap);
   2397   printf("KNOWN_OBJECTS = {\n");
   2398   for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
   2399     i::HeapObjectIterator it(s);
   2400     const char* sname = AllocationSpaceName(s->identity());
   2401     for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
   2402       const char* n = NULL;
   2403       intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
   2404       ROOT_LIST(ROOT_LIST_CASE)
   2405       if (n == NULL) continue;
   2406       printf("  (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
   2407     }
   2408   }
   2409   printf("}\n");
   2410 #undef ROOT_LIST_CASE
   2411 }
   2412 #endif  // !V8_SHARED
   2413 
   2414 
   2415 int Shell::Main(int argc, char* argv[]) {
   2416 #if (defined(_WIN32) || defined(_WIN64))
   2417   UINT new_flags =
   2418       SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
   2419   UINT existing_flags = SetErrorMode(new_flags);
   2420   SetErrorMode(existing_flags | new_flags);
   2421 #if defined(_MSC_VER)
   2422   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   2423   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
   2424   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   2425   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
   2426   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   2427   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
   2428   _set_error_mode(_OUT_TO_STDERR);
   2429 #endif  // defined(_MSC_VER)
   2430 #endif  // defined(_WIN32) || defined(_WIN64)
   2431   if (!SetOptions(argc, argv)) return 1;
   2432   v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
   2433 #ifndef V8_SHARED
   2434   g_platform = i::FLAG_verify_predictable
   2435                    ? new PredictablePlatform()
   2436                    : v8::platform::CreateDefaultPlatform();
   2437 #else
   2438   g_platform = v8::platform::CreateDefaultPlatform();
   2439 #endif  // !V8_SHARED
   2440 
   2441   v8::V8::InitializePlatform(g_platform);
   2442   v8::V8::Initialize();
   2443   if (options.natives_blob || options.snapshot_blob) {
   2444     v8::V8::InitializeExternalStartupData(options.natives_blob,
   2445                                           options.snapshot_blob);
   2446   } else {
   2447     v8::V8::InitializeExternalStartupData(argv[0]);
   2448   }
   2449   SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
   2450   SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
   2451   SetFlagsFromString("--redirect-code-traces-to=code.asm");
   2452   int result = 0;
   2453   Isolate::CreateParams create_params;
   2454   ShellArrayBufferAllocator shell_array_buffer_allocator;
   2455   MockArrayBufferAllocator mock_arraybuffer_allocator;
   2456   if (options.mock_arraybuffer_allocator) {
   2457     Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
   2458   } else {
   2459     Shell::array_buffer_allocator = &shell_array_buffer_allocator;
   2460   }
   2461   create_params.array_buffer_allocator = Shell::array_buffer_allocator;
   2462 #ifdef ENABLE_VTUNE_JIT_INTERFACE
   2463   create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
   2464 #endif
   2465 #ifndef V8_SHARED
   2466   create_params.constraints.ConfigureDefaults(
   2467       base::SysInfo::AmountOfPhysicalMemory(),
   2468       base::SysInfo::AmountOfVirtualMemory());
   2469 
   2470   Shell::counter_map_ = new CounterMap();
   2471   if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
   2472     create_params.counter_lookup_callback = LookupCounter;
   2473     create_params.create_histogram_callback = CreateHistogram;
   2474     create_params.add_histogram_sample_callback = AddHistogramSample;
   2475   }
   2476 #endif
   2477   Isolate* isolate = Isolate::New(create_params);
   2478   {
   2479     Isolate::Scope scope(isolate);
   2480     Initialize(isolate);
   2481     PerIsolateData data(isolate);
   2482 
   2483 #ifndef V8_SHARED
   2484     if (options.dump_heap_constants) {
   2485       DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
   2486       return 0;
   2487     }
   2488 #endif
   2489 
   2490     if (options.stress_opt || options.stress_deopt) {
   2491       Testing::SetStressRunType(options.stress_opt
   2492                                 ? Testing::kStressTypeOpt
   2493                                 : Testing::kStressTypeDeopt);
   2494       options.stress_runs = Testing::GetStressRuns();
   2495       for (int i = 0; i < options.stress_runs && result == 0; i++) {
   2496         printf("============ Stress %d/%d ============\n", i + 1,
   2497                options.stress_runs);
   2498         Testing::PrepareStressRun(i);
   2499         bool last_run = i == options.stress_runs - 1;
   2500         result = RunMain(isolate, argc, argv, last_run);
   2501       }
   2502       printf("======== Full Deoptimization =======\n");
   2503       Testing::DeoptimizeAll(isolate);
   2504 #if !defined(V8_SHARED)
   2505     } else if (i::FLAG_stress_runs > 0) {
   2506       options.stress_runs = i::FLAG_stress_runs;
   2507       for (int i = 0; i < options.stress_runs && result == 0; i++) {
   2508         printf("============ Run %d/%d ============\n", i + 1,
   2509                options.stress_runs);
   2510         bool last_run = i == options.stress_runs - 1;
   2511         result = RunMain(isolate, argc, argv, last_run);
   2512       }
   2513 #endif
   2514     } else {
   2515       bool last_run = true;
   2516       result = RunMain(isolate, argc, argv, last_run);
   2517     }
   2518 
   2519     // Run interactive shell if explicitly requested or if no script has been
   2520     // executed, but never on --test
   2521     if (options.use_interactive_shell()) {
   2522       RunShell(isolate);
   2523     }
   2524 
   2525 #ifndef V8_SHARED
   2526     if (i::FLAG_ignition && i::FLAG_trace_ignition_dispatches &&
   2527         i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
   2528       WriteIgnitionDispatchCountersFile(isolate);
   2529     }
   2530 #endif
   2531 
   2532     // Shut down contexts and collect garbage.
   2533     evaluation_context_.Reset();
   2534 #ifndef V8_SHARED
   2535     stringify_function_.Reset();
   2536 #endif  // !V8_SHARED
   2537     CollectGarbage(isolate);
   2538   }
   2539   OnExit(isolate);
   2540 #ifndef V8_SHARED
   2541   // Dump basic block profiling data.
   2542   if (i::BasicBlockProfiler* profiler =
   2543           reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
   2544     i::OFStream os(stdout);
   2545     os << *profiler;
   2546   }
   2547 #endif  // !V8_SHARED
   2548   isolate->Dispose();
   2549   V8::Dispose();
   2550   V8::ShutdownPlatform();
   2551   delete g_platform;
   2552 
   2553   return result;
   2554 }
   2555 
   2556 }  // namespace v8
   2557 
   2558 
   2559 #ifndef GOOGLE3
   2560 int main(int argc, char* argv[]) {
   2561   return v8::Shell::Main(argc, argv);
   2562 }
   2563 #endif
   2564