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:
Allocate(size_t length)81   virtual void* Allocate(size_t length) {
82     void* data = AllocateUninitialized(length);
83     return data == NULL ? data : memset(data, 0, length);
84   }
AllocateUninitialized(size_t length)85   virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
Free(void * data,size_t)86   virtual void Free(void* data, size_t) { free(data); }
87 };
88 
89 
90 class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
91  public:
Allocate(size_t length)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   }
AllocateUninitialized(size_t length)97   void* AllocateUninitialized(size_t length) override {
98     return length > 10 * MB ? malloc(1) : malloc(length);
99   }
Free(void * p,size_t)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:
PredictablePlatform()109   PredictablePlatform() {}
110 
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)111   void CallOnBackgroundThread(Task* task,
112                               ExpectedRuntime expected_runtime) override {
113     task->Run();
114     delete task;
115   }
116 
CallOnForegroundThread(v8::Isolate * isolate,Task * task)117   void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
118     task->Run();
119     delete task;
120   }
121 
CallDelayedOnForegroundThread(v8::Isolate * isolate,Task * task,double delay_in_seconds)122   void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
123                                      double delay_in_seconds) override {
124     delete task;
125   }
126 
CallIdleOnForegroundThread(v8::Isolate * isolate,IdleTask * task)127   void CallIdleOnForegroundThread(v8::Isolate* isolate,
128                                   IdleTask* task) override {
129     UNREACHABLE();
130   }
131 
IdleTasksEnabled(v8::Isolate * isolate)132   bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
133 
MonotonicallyIncreasingTime()134   double MonotonicallyIncreasingTime() override {
135     return synthetic_time_in_sec_ += 0.00001;
136   }
137 
AddTraceEvent(char phase,const uint8_t * categoryEnabledFlag,const char * name,uint64_t id,uint64_t bind_id,int numArgs,const char ** argNames,const uint8_t * argTypes,const uint64_t * argValues,unsigned int flags)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 
UpdateTraceEventDuration(const uint8_t * categoryEnabledFlag,const char * name,uint64_t handle)146   void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
147                                 const char* name, uint64_t handle) override {}
148 
GetCategoryGroupEnabled(const char * name)149   const uint8_t* GetCategoryGroupEnabled(const char* name) override {
150     static uint8_t no = 0;
151     return &no;
152   }
153 
GetCategoryGroupName(const uint8_t * categoryEnabledFlag)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 
Throw(Isolate * isolate,const char * message)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
FindInObjectList(Local<Object> object,const Shell::ObjectList & list)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 
GetWorkerFromInternalField(Isolate * isolate,Local<Object> object)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:
PerIsolateData(Isolate * isolate)212   explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
213     HandleScope scope(isolate);
214     isolate->SetData(0, this);
215   }
216 
~PerIsolateData()217   ~PerIsolateData() {
218     isolate_->SetData(0, NULL);  // Not really needed, just to be sure...
219   }
220 
Get(Isolate * isolate)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
Match(void * key1,void * key2)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.
ToCString(const v8::String::Utf8Value & value)279 const char* Shell::ToCString(const v8::String::Utf8Value& value) {
280   return *value ? *value : "<string conversion failed>";
281 }
282 
283 
CompileForCachedData(Local<String> source,Local<Value> name,ScriptCompiler::CompileOptions compile_options)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.
CompileString(Isolate * isolate,Local<String> source,Local<Value> name,ScriptCompiler::CompileOptions compile_options,SourceType source_type)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.
ExecuteString(Isolate * isolate,Local<String> source,Local<Value> name,bool print_result,bool report_exceptions,SourceType source_type)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 
RealmScope(PerIsolateData * data)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 
~RealmScope()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 
RealmFind(Local<Context> context)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 
RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value> & args,int arg_offset)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().
PerformanceNow(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmCurrent(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmOwner(const v8::FunctionCallbackInfo<v8::Value> & args)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.)
RealmGlobal(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmCreate(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmDispose(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmSwitch(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmEval(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RealmSharedGet(Local<String> property,const PropertyCallbackInfo<Value> & info)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 
RealmSharedSet(Local<String> property,Local<Value> value,const PropertyCallbackInfo<void> & info)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 
Print(const v8::FunctionCallbackInfo<v8::Value> & args)643 void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
644   Write(args);
645   printf("\n");
646   fflush(stdout);
647 }
648 
649 
Write(const v8::FunctionCallbackInfo<v8::Value> & args)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 
Read(const v8::FunctionCallbackInfo<v8::Value> & args)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 
ReadFromStdin(Isolate * isolate)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 
Load(const v8::FunctionCallbackInfo<v8::Value> & args)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
WorkerNew(const v8::FunctionCallbackInfo<v8::Value> & args)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 
WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value> & args)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 
WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value> & args)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 
WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value> & args)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 
QuitOnce(v8::FunctionCallbackInfo<v8::Value> * args)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 
Quit(const v8::FunctionCallbackInfo<v8::Value> & args)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 
Version(const v8::FunctionCallbackInfo<v8::Value> & args)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 
ReportException(Isolate * isolate,v8::TryCatch * try_catch)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
Bind(const char * name,bool is_histogram)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 
AddSample(int32_t sample)975 void Counter::AddSample(int32_t sample) {
976   count_++;
977   sample_total_ += sample;
978 }
979 
980 
CounterCollection()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 
GetNextCounter()989 Counter* CounterCollection::GetNextCounter() {
990   if (counters_in_use_ == kMaxCounters) return NULL;
991   return &counters_[counters_in_use_++];
992 }
993 
994 
MapCounters(v8::Isolate * isolate,const char * name)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 
Hash(const char * name)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 
GetCounter(const char * name,bool is_histogram)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 
LookupCounter(const char * name)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 
CreateHistogram(const char * name,int min,int max,size_t buckets)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 
AddHistogramSample(void * histogram,int sample)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:
NoUseStrongForUtilityScriptScope()1065   NoUseStrongForUtilityScriptScope() : flag_(i::FLAG_use_strong) {
1066     i::FLAG_use_strong = false;
1067   }
~NoUseStrongForUtilityScriptScope()1068   ~NoUseStrongForUtilityScriptScope() { i::FLAG_use_strong = flag_; }
1069 
1070  private:
1071   bool flag_;
1072 };
1073 
1074 
InstallUtilityScript(Isolate * isolate)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 
CreateGlobalTemplate(Isolate * isolate)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 
Initialize(Isolate * isolate)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 
CreateEvaluationContext(Isolate * isolate)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 
Exit(int exit_code)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 
operator <(const CounterAndKey & lhs,const CounterAndKey & rhs)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 
OnExit(v8::Isolate * isolate)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 
FOpen(const char * path,const char * mode)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 
ReadChars(Isolate * isolate,const char * name,int * size_out)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 
ReadBufferWeakCallback(const v8::WeakCallbackInfo<DataAndPersistent> & data)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 
ReadBuffer(const v8::FunctionCallbackInfo<v8::Value> & args)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.
ReadFile(Isolate * isolate,const char * name)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 
RunShell(Isolate * isolate)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 
~SourceGroup()1492 SourceGroup::~SourceGroup() {
1493 #ifndef V8_SHARED
1494   delete thread_;
1495   thread_ = NULL;
1496 #endif  // !V8_SHARED
1497 }
1498 
1499 
Execute(Isolate * isolate)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 
ReadFile(Isolate * isolate,const char * name)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
GetThreadOptions()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 
ExecuteInThread()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 
StartExecuteInThread()1602 void SourceGroup::StartExecuteInThread() {
1603   if (thread_ == NULL) {
1604     thread_ = new IsolateThread(this);
1605     thread_->Start();
1606   }
1607   next_semaphore_.Signal();
1608 }
1609 
1610 
WaitForThread()1611 void SourceGroup::WaitForThread() {
1612   if (thread_ == NULL) return;
1613   done_semaphore_.Wait();
1614 }
1615 
1616 
JoinThread()1617 void SourceGroup::JoinThread() {
1618   if (thread_ == NULL) return;
1619   thread_->Join();
1620 }
1621 
1622 
~SerializationData()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 
WriteTag(SerializationTag tag)1638 void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1639 
1640 
WriteMemory(const void * p,int length)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 
WriteArrayBufferContents(const ArrayBuffer::Contents & contents)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 
WriteSharedArrayBufferContents(const SharedArrayBuffer::Contents & contents)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 
ReadTag(int * offset) const1667 SerializationTag SerializationData::ReadTag(int* offset) const {
1668   return static_cast<SerializationTag>(Read<uint8_t>(offset));
1669 }
1670 
1671 
ReadMemory(void * p,int length,int * offset) const1672 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 
ReadArrayBufferContents(ArrayBuffer::Contents * contents,int * offset) const1680 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 
ReadSharedArrayBufferContents(SharedArrayBuffer::Contents * contents,int * offset) const1692 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 
Enqueue(SerializationData * data)1700 void SerializationDataQueue::Enqueue(SerializationData* data) {
1701   base::LockGuard<base::Mutex> lock_guard(&mutex_);
1702   data_.Add(data);
1703 }
1704 
1705 
Dequeue(SerializationData ** data)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 
IsEmpty()1715 bool SerializationDataQueue::IsEmpty() {
1716   base::LockGuard<base::Mutex> lock_guard(&mutex_);
1717   return data_.is_empty();
1718 }
1719 
1720 
Clear()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 
Worker()1730 Worker::Worker()
1731     : in_semaphore_(0),
1732       out_semaphore_(0),
1733       thread_(NULL),
1734       script_(NULL),
1735       running_(false) {}
1736 
1737 
~Worker()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 
StartExecuteInThread(const char * script)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 
PostMessage(SerializationData * data)1756 void Worker::PostMessage(SerializationData* data) {
1757   in_queue_.Enqueue(data);
1758   in_semaphore_.Signal();
1759 }
1760 
1761 
GetMessage()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 
Terminate()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 
WaitForThread()1782 void Worker::WaitForThread() {
1783   Terminate();
1784   thread_->Join();
1785 }
1786 
1787 
ExecuteInThread()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 
PostMessageOut(const v8::FunctionCallbackInfo<v8::Value> & args)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 
SetFlagsFromString(const char * flags)1892 void SetFlagsFromString(const char* flags) {
1893   v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1894 }
1895 
1896 
SetOptions(int argc,char * argv[])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 
RunMain(Isolate * isolate,int argc,char * argv[],bool last_run)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 
CollectGarbage(Isolate * isolate)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 
EmptyMessageQueues(Isolate * isolate)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
SerializeValue(Isolate * isolate,Local<Value> value,const ObjectList & to_transfer,ObjectList * seen_objects,SerializationData * out_data)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 
DeserializeValue(Isolate * isolate,const SerializationData & data,int * offset)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 
CleanupWorkers()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 
DumpHeapConstants(i::Isolate * isolate)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 
Main(int argc,char * argv[])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
main(int argc,char * argv[])2561 int main(int argc, char* argv[]) {
2562   return v8::Shell::Main(argc, argv);
2563 }
2564 #endif
2565