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