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