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