V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
d8.cc
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 "include/libplatform/libplatform.h"
21 #include "include/libplatform/v8-tracing.h"
22 #include "include/v8-inspector.h"
23 #include "src/api-inl.h"
24 #include "src/base/cpu.h"
25 #include "src/base/logging.h"
26 #include "src/base/platform/platform.h"
27 #include "src/base/platform/time.h"
28 #include "src/base/sys-info.h"
29 #include "src/basic-block-profiler.h"
30 #include "src/d8-console.h"
31 #include "src/d8-platforms.h"
32 #include "src/d8.h"
33 #include "src/debug/debug-interface.h"
34 #include "src/interpreter/interpreter.h"
35 #include "src/msan.h"
36 #include "src/objects-inl.h"
37 #include "src/objects.h"
38 #include "src/ostreams.h"
39 #include "src/snapshot/natives.h"
40 #include "src/trap-handler/trap-handler.h"
41 #include "src/utils.h"
42 #include "src/v8.h"
43 #include "src/wasm/wasm-engine.h"
44 
45 #if !defined(_WIN32) && !defined(_WIN64)
46 #include <unistd.h> // NOLINT
47 #else
48 #include <windows.h> // NOLINT
49 #endif // !defined(_WIN32) && !defined(_WIN64)
50 
51 #ifndef DCHECK
52 #define DCHECK(condition) assert(condition)
53 #endif
54 
55 #ifndef CHECK
56 #define CHECK(condition) assert(condition)
57 #endif
58 
59 namespace v8 {
60 
61 namespace {
62 
63 const int kMB = 1024 * 1024;
64 
65 const int kMaxWorkers = 100;
66 const int kMaxSerializerMemoryUsage =
67  1 * kMB; // Arbitrary maximum for testing.
68 
69 // Base class for shell ArrayBuffer allocators. It forwards all opertions to
70 // the default v8 allocator.
71 class ArrayBufferAllocatorBase : public v8::ArrayBuffer::Allocator {
72  public:
73  void* Allocate(size_t length) override {
74  return allocator_->Allocate(length);
75  }
76 
77  void* AllocateUninitialized(size_t length) override {
78  return allocator_->AllocateUninitialized(length);
79  }
80 
81  void Free(void* data, size_t length) override {
82  allocator_->Free(data, length);
83  }
84 
85  private:
86  std::unique_ptr<Allocator> allocator_ =
87  std::unique_ptr<Allocator>(NewDefaultAllocator());
88 };
89 
90 // ArrayBuffer allocator that can use virtual memory to improve performance.
91 class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
92  public:
93  void* Allocate(size_t length) override {
94  if (length >= kVMThreshold) return AllocateVM(length);
95  return ArrayBufferAllocatorBase::Allocate(length);
96  }
97 
98  void* AllocateUninitialized(size_t length) override {
99  if (length >= kVMThreshold) return AllocateVM(length);
100  return ArrayBufferAllocatorBase::AllocateUninitialized(length);
101  }
102 
103  void Free(void* data, size_t length) override {
104  if (length >= kVMThreshold) {
105  FreeVM(data, length);
106  } else {
107  ArrayBufferAllocatorBase::Free(data, length);
108  }
109  }
110 
111  private:
112  static constexpr size_t kVMThreshold = 65536;
113  static constexpr size_t kTwoGB = 2u * 1024u * 1024u * 1024u;
114 
115  void* AllocateVM(size_t length) {
116  DCHECK_LE(kVMThreshold, length);
117  // TODO(titzer): allocations should fail if >= 2gb because array buffers
118  // store their lengths as a SMI internally.
119  if (length >= kTwoGB) return nullptr;
120 
121  v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator();
122  size_t page_size = page_allocator->AllocatePageSize();
123  size_t allocated = RoundUp(length, page_size);
124  // Rounding up could go over the limit.
125  if (allocated >= kTwoGB) return nullptr;
126  return i::AllocatePages(page_allocator, nullptr, allocated, page_size,
127  PageAllocator::kReadWrite);
128  }
129 
130  void FreeVM(void* data, size_t length) {
131  v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator();
132  size_t page_size = page_allocator->AllocatePageSize();
133  size_t allocated = RoundUp(length, page_size);
134  CHECK(i::FreePages(page_allocator, data, allocated));
135  }
136 };
137 
138 // ArrayBuffer allocator that never allocates over 10MB.
139 class MockArrayBufferAllocator : public ArrayBufferAllocatorBase {
140  protected:
141  void* Allocate(size_t length) override {
142  return ArrayBufferAllocatorBase::Allocate(Adjust(length));
143  }
144 
145  void* AllocateUninitialized(size_t length) override {
146  return ArrayBufferAllocatorBase::AllocateUninitialized(Adjust(length));
147  }
148 
149  void Free(void* data, size_t length) override {
150  return ArrayBufferAllocatorBase::Free(data, Adjust(length));
151  }
152 
153  private:
154  size_t Adjust(size_t length) {
155  const size_t kAllocationLimit = 10 * kMB;
156  return length > kAllocationLimit ? i::AllocatePageSize() : length;
157  }
158 };
159 
160 // ArrayBuffer allocator that can be equipped with a limit to simulate system
161 // OOM.
162 class MockArrayBufferAllocatiorWithLimit : public MockArrayBufferAllocator {
163  public:
164  explicit MockArrayBufferAllocatiorWithLimit(size_t allocation_limit)
165  : space_left_(allocation_limit) {}
166 
167  protected:
168  void* Allocate(size_t length) override {
169  if (length > space_left_) {
170  return nullptr;
171  }
172  space_left_ -= length;
173  return MockArrayBufferAllocator::Allocate(length);
174  }
175 
176  void* AllocateUninitialized(size_t length) override {
177  if (length > space_left_) {
178  return nullptr;
179  }
180  space_left_ -= length;
181  return MockArrayBufferAllocator::AllocateUninitialized(length);
182  }
183 
184  void Free(void* data, size_t length) override {
185  space_left_ += length;
186  return MockArrayBufferAllocator::Free(data, length);
187  }
188 
189  private:
190  std::atomic<size_t> space_left_;
191 };
192 
193 v8::Platform* g_default_platform;
194 std::unique_ptr<v8::Platform> g_platform;
195 
196 static Local<Value> Throw(Isolate* isolate, const char* message) {
197  return isolate->ThrowException(
199  .ToLocalChecked());
200 }
201 
202 static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
203  Local<v8::Object> object, const char* property) {
204  Local<String> v8_str =
205  String::NewFromUtf8(isolate, property, NewStringType::kNormal)
206  .ToLocalChecked();
207  return object->Get(context, v8_str).ToLocalChecked();
208 }
209 
210 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
211  if (object->InternalFieldCount() != 1) {
212  Throw(isolate, "this is not a Worker");
213  return nullptr;
214  }
215 
216  Worker* worker =
217  static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
218  if (worker == nullptr) {
219  Throw(isolate, "Worker is defunct because main thread is terminating");
220  return nullptr;
221  }
222 
223  return worker;
224 }
225 
226 base::Thread::Options GetThreadOptions(const char* name) {
227  // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
228  // which is not enough to parse the big literal expressions used in tests.
229  // The stack size should be at least StackGuard::kLimitSize + some
230  // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
231  return base::Thread::Options(name, 2 * kMB);
232 }
233 
234 } // namespace
235 
236 namespace tracing {
237 
238 namespace {
239 
240 // String options that can be used to initialize TraceOptions.
241 const char kRecordUntilFull[] = "record-until-full";
242 const char kRecordContinuously[] = "record-continuously";
243 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
244 
245 const char kRecordModeParam[] = "record_mode";
246 const char kEnableSystraceParam[] = "enable_systrace";
247 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
248 const char kIncludedCategoriesParam[] = "included_categories";
249 
250 class TraceConfigParser {
251  public:
252  static void FillTraceConfig(v8::Isolate* isolate,
253  platform::tracing::TraceConfig* trace_config,
254  const char* json_str) {
255  HandleScope outer_scope(isolate);
256  Local<Context> context = Context::New(isolate);
257  Context::Scope context_scope(context);
258  HandleScope inner_scope(isolate);
259 
260  Local<String> source =
261  String::NewFromUtf8(isolate, json_str, NewStringType::kNormal)
262  .ToLocalChecked();
263  Local<Value> result = JSON::Parse(context, source).ToLocalChecked();
264  Local<v8::Object> trace_config_object = Local<v8::Object>::Cast(result);
265 
266  trace_config->SetTraceRecordMode(
267  GetTraceRecordMode(isolate, context, trace_config_object));
268  if (GetBoolean(isolate, context, trace_config_object,
269  kEnableSystraceParam)) {
270  trace_config->EnableSystrace();
271  }
272  if (GetBoolean(isolate, context, trace_config_object,
273  kEnableArgumentFilterParam)) {
274  trace_config->EnableArgumentFilter();
275  }
276  UpdateIncludedCategoriesList(isolate, context, trace_config_object,
277  trace_config);
278  }
279 
280  private:
281  static bool GetBoolean(v8::Isolate* isolate, Local<Context> context,
282  Local<v8::Object> object, const char* property) {
283  Local<Value> value = GetValue(isolate, context, object, property);
284  if (value->IsNumber()) {
285  return value->BooleanValue(isolate);
286  }
287  return false;
288  }
289 
290  static int UpdateIncludedCategoriesList(
291  v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object,
292  platform::tracing::TraceConfig* trace_config) {
293  Local<Value> value =
294  GetValue(isolate, context, object, kIncludedCategoriesParam);
295  if (value->IsArray()) {
296  Local<Array> v8_array = Local<Array>::Cast(value);
297  for (int i = 0, length = v8_array->Length(); i < length; ++i) {
298  Local<Value> v = v8_array->Get(context, i)
299  .ToLocalChecked()
300  ->ToString(context)
301  .ToLocalChecked();
302  String::Utf8Value str(isolate, v->ToString(context).ToLocalChecked());
303  trace_config->AddIncludedCategory(*str);
304  }
305  return v8_array->Length();
306  }
307  return 0;
308  }
309 
310  static platform::tracing::TraceRecordMode GetTraceRecordMode(
311  v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object) {
312  Local<Value> value = GetValue(isolate, context, object, kRecordModeParam);
313  if (value->IsString()) {
314  Local<String> v8_string = value->ToString(context).ToLocalChecked();
315  String::Utf8Value str(isolate, v8_string);
316  if (strcmp(kRecordUntilFull, *str) == 0) {
317  return platform::tracing::TraceRecordMode::RECORD_UNTIL_FULL;
318  } else if (strcmp(kRecordContinuously, *str) == 0) {
319  return platform::tracing::TraceRecordMode::RECORD_CONTINUOUSLY;
320  } else if (strcmp(kRecordAsMuchAsPossible, *str) == 0) {
321  return platform::tracing::TraceRecordMode::RECORD_AS_MUCH_AS_POSSIBLE;
322  }
323  }
324  return platform::tracing::TraceRecordMode::RECORD_UNTIL_FULL;
325  }
326 };
327 
328 } // namespace
329 
330 static platform::tracing::TraceConfig* CreateTraceConfigFromJSON(
331  v8::Isolate* isolate, const char* json_str) {
332  platform::tracing::TraceConfig* trace_config =
333  new platform::tracing::TraceConfig();
334  TraceConfigParser::FillTraceConfig(isolate, trace_config, json_str);
335  return trace_config;
336 }
337 
338 } // namespace tracing
339 
340 
343  public:
346  std::unique_ptr<base::OS::MemoryMappedFile> file)
347  : file_(std::move(file)) {}
348  const char* data() const override {
349  return static_cast<char*>(file_->memory());
350  }
351  size_t length() const override { return file_->size(); }
352 
353  private:
354  std::unique_ptr<base::OS::MemoryMappedFile> file_;
355 };
356 
357 CounterMap* Shell::counter_map_;
358 base::OS::MemoryMappedFile* Shell::counters_file_ = nullptr;
359 CounterCollection Shell::local_counters_;
360 CounterCollection* Shell::counters_ = &local_counters_;
361 base::LazyMutex Shell::context_mutex_;
362 const base::TimeTicks Shell::kInitialTicks =
363  base::TimeTicks::HighResolutionNow();
364 Global<Function> Shell::stringify_function_;
365 base::LazyMutex Shell::workers_mutex_;
366 bool Shell::allow_new_workers_ = true;
367 std::vector<Worker*> Shell::workers_;
368 std::vector<ExternalizedContents> Shell::externalized_contents_;
369 std::atomic<bool> Shell::script_executed_{false};
370 base::LazyMutex Shell::isolate_status_lock_;
371 std::map<v8::Isolate*, bool> Shell::isolate_status_;
372 base::LazyMutex Shell::cached_code_mutex_;
373 std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
374  Shell::cached_code_map_;
375 
376 Global<Context> Shell::evaluation_context_;
377 ArrayBuffer::Allocator* Shell::array_buffer_allocator;
378 ShellOptions Shell::options;
379 base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
380 
381 // Dummy external source stream which returns the whole source in one go.
383  public:
384  DummySourceStream(Local<String> source, Isolate* isolate) : done_(false) {
385  source_length_ = source->Utf8Length(isolate);
386  source_buffer_.reset(new uint8_t[source_length_]);
387  source->WriteUtf8(isolate, reinterpret_cast<char*>(source_buffer_.get()),
388  source_length_);
389  }
390 
391  size_t GetMoreData(const uint8_t** src) override {
392  if (done_) {
393  return 0;
394  }
395  *src = source_buffer_.release();
396  done_ = true;
397 
398  return source_length_;
399  }
400 
401  private:
402  int source_length_;
403  std::unique_ptr<uint8_t[]> source_buffer_;
404  bool done_;
405 };
406 
408  public:
409  BackgroundCompileThread(Isolate* isolate, Local<String> source)
410  : base::Thread(GetThreadOptions("BackgroundCompileThread")),
411  source_(source),
412  streamed_source_(new DummySourceStream(source, isolate),
413  v8::ScriptCompiler::StreamedSource::UTF8),
415  &streamed_source_)) {}
416 
417  void Run() override { task_->Run(); }
418 
419  v8::ScriptCompiler::StreamedSource* streamed_source() {
420  return &streamed_source_;
421  }
422 
423  private:
424  Local<String> source_;
425  v8::ScriptCompiler::StreamedSource streamed_source_;
426  std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task_;
427 };
428 
429 ScriptCompiler::CachedData* Shell::LookupCodeCache(Isolate* isolate,
430  Local<Value> source) {
431  base::MutexGuard lock_guard(cached_code_mutex_.Pointer());
432  CHECK(source->IsString());
433  v8::String::Utf8Value key(isolate, source);
434  DCHECK(*key);
435  auto entry = cached_code_map_.find(*key);
436  if (entry != cached_code_map_.end() && entry->second) {
437  int length = entry->second->length;
438  uint8_t* cache = new uint8_t[length];
439  memcpy(cache, entry->second->data, length);
441  cache, length, ScriptCompiler::CachedData::BufferOwned);
442  return cached_data;
443  }
444  return nullptr;
445 }
446 
447 void Shell::StoreInCodeCache(Isolate* isolate, Local<Value> source,
448  const ScriptCompiler::CachedData* cache_data) {
449  base::MutexGuard lock_guard(cached_code_mutex_.Pointer());
450  CHECK(source->IsString());
451  if (cache_data == nullptr) return;
452  v8::String::Utf8Value key(isolate, source);
453  DCHECK(*key);
454  int length = cache_data->length;
455  uint8_t* cache = new uint8_t[length];
456  memcpy(cache, cache_data->data, length);
457  cached_code_map_[*key] = std::unique_ptr<ScriptCompiler::CachedData>(
458  new ScriptCompiler::CachedData(cache, length,
459  ScriptCompiler::CachedData::BufferOwned));
460 }
461 
462 // Executes a string within the current v8 context.
463 bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
464  Local<Value> name, PrintResult print_result,
465  ReportExceptions report_exceptions,
466  ProcessMessageQueue process_message_queue) {
467  HandleScope handle_scope(isolate);
468  TryCatch try_catch(isolate);
469  try_catch.SetVerbose(true);
470 
471  MaybeLocal<Value> maybe_result;
472  bool success = true;
473  {
474  PerIsolateData* data = PerIsolateData::Get(isolate);
475  Local<Context> realm =
476  Local<Context>::New(isolate, data->realms_[data->realm_current_]);
477  Context::Scope context_scope(realm);
478  MaybeLocal<Script> maybe_script;
479  Local<Context> context(isolate->GetCurrentContext());
480  ScriptOrigin origin(name);
481 
482  if (options.compile_options == ScriptCompiler::kConsumeCodeCache) {
483  ScriptCompiler::CachedData* cached_code =
484  LookupCodeCache(isolate, source);
485  if (cached_code != nullptr) {
486  ScriptCompiler::Source script_source(source, origin, cached_code);
487  maybe_script = ScriptCompiler::Compile(context, &script_source,
488  options.compile_options);
489  CHECK(!cached_code->rejected);
490  } else {
491  ScriptCompiler::Source script_source(source, origin);
492  maybe_script = ScriptCompiler::Compile(
493  context, &script_source, ScriptCompiler::kNoCompileOptions);
494  }
495  } else if (options.stress_background_compile) {
496  // Start a background thread compiling the script.
497  BackgroundCompileThread background_compile_thread(isolate, source);
498  background_compile_thread.Start();
499 
500  // In parallel, compile on the main thread to flush out any data races.
501  {
502  TryCatch ignore_try_catch(isolate);
503  ScriptCompiler::Source script_source(source, origin);
504  USE(ScriptCompiler::Compile(context, &script_source,
505  ScriptCompiler::kNoCompileOptions));
506  }
507 
508  // Join with background thread and finalize compilation.
509  background_compile_thread.Join();
510  maybe_script = v8::ScriptCompiler::Compile(
511  context, background_compile_thread.streamed_source(), source, origin);
512  } else {
513  ScriptCompiler::Source script_source(source, origin);
514  maybe_script = ScriptCompiler::Compile(context, &script_source,
515  options.compile_options);
516  }
517 
518  Local<Script> script;
519  if (!maybe_script.ToLocal(&script)) {
520  // Print errors that happened during compilation.
521  if (report_exceptions) ReportException(isolate, &try_catch);
522  return false;
523  }
524 
525  if (options.code_cache_options ==
526  ShellOptions::CodeCacheOptions::kProduceCache) {
527  // Serialize and store it in memory for the next execution.
528  ScriptCompiler::CachedData* cached_data =
529  ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
530  StoreInCodeCache(isolate, source, cached_data);
531  delete cached_data;
532  }
533  maybe_result = script->Run(realm);
534  if (options.code_cache_options ==
535  ShellOptions::CodeCacheOptions::kProduceCacheAfterExecute) {
536  // Serialize and store it in memory for the next execution.
537  ScriptCompiler::CachedData* cached_data =
538  ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
539  StoreInCodeCache(isolate, source, cached_data);
540  delete cached_data;
541  }
542  if (process_message_queue && !EmptyMessageQueues(isolate)) success = false;
543  data->realm_current_ = data->realm_switch_;
544  }
545  Local<Value> result;
546  if (!maybe_result.ToLocal(&result)) {
547  DCHECK(try_catch.HasCaught());
548  // Print errors that happened during execution.
549  if (report_exceptions) ReportException(isolate, &try_catch);
550  return false;
551  }
552  DCHECK(!try_catch.HasCaught());
553  if (print_result) {
554  if (options.test_shell) {
555  if (!result->IsUndefined()) {
556  // If all went well and the result wasn't undefined then print
557  // the returned value.
558  v8::String::Utf8Value str(isolate, result);
559  fwrite(*str, sizeof(**str), str.length(), stdout);
560  printf("\n");
561  }
562  } else {
563  v8::String::Utf8Value str(isolate, Stringify(isolate, result));
564  fwrite(*str, sizeof(**str), str.length(), stdout);
565  printf("\n");
566  }
567  }
568  return success;
569 }
570 
571 namespace {
572 
573 std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
574  String::Utf8Value utf8(isolate, v8_str);
575  // Should not be able to fail since the input is a String.
576  CHECK(*utf8);
577  return *utf8;
578 }
579 
580 bool IsAbsolutePath(const std::string& path) {
581 #if defined(_WIN32) || defined(_WIN64)
582  // TODO(adamk): This is an incorrect approximation, but should
583  // work for all our test-running cases.
584  return path.find(':') != std::string::npos;
585 #else
586  return path[0] == '/';
587 #endif
588 }
589 
590 std::string GetWorkingDirectory() {
591 #if defined(_WIN32) || defined(_WIN64)
592  char system_buffer[MAX_PATH];
593  // TODO(adamk): Support Unicode paths.
594  DWORD len = GetCurrentDirectoryA(MAX_PATH, system_buffer);
595  CHECK_GT(len, 0);
596  return system_buffer;
597 #else
598  char curdir[PATH_MAX];
599  CHECK_NOT_NULL(getcwd(curdir, PATH_MAX));
600  return curdir;
601 #endif
602 }
603 
604 // Returns the directory part of path, without the trailing '/'.
605 std::string DirName(const std::string& path) {
606  DCHECK(IsAbsolutePath(path));
607  size_t last_slash = path.find_last_of('/');
608  DCHECK(last_slash != std::string::npos);
609  return path.substr(0, last_slash);
610 }
611 
612 // Resolves path to an absolute path if necessary, and does some
613 // normalization (eliding references to the current directory
614 // and replacing backslashes with slashes).
615 std::string NormalizePath(const std::string& path,
616  const std::string& dir_name) {
617  std::string result;
618  if (IsAbsolutePath(path)) {
619  result = path;
620  } else {
621  result = dir_name + '/' + path;
622  }
623  std::replace(result.begin(), result.end(), '\\', '/');
624  size_t i;
625  while ((i = result.find("/./")) != std::string::npos) {
626  result.erase(i, 2);
627  }
628  return result;
629 }
630 
631 // Per-context Module data, allowing sharing of module maps
632 // across top-level module loads.
633 class ModuleEmbedderData {
634  private:
635  class ModuleGlobalHash {
636  public:
637  explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
638  size_t operator()(const Global<Module>& module) const {
639  return module.Get(isolate_)->GetIdentityHash();
640  }
641 
642  private:
643  Isolate* isolate_;
644  };
645 
646  public:
647  explicit ModuleEmbedderData(Isolate* isolate)
648  : module_to_specifier_map(10, ModuleGlobalHash(isolate)) {}
649 
650  // Map from normalized module specifier to Module.
651  std::unordered_map<std::string, Global<Module>> specifier_to_module_map;
652  // Map from Module to its URL as defined in the ScriptOrigin
653  std::unordered_map<Global<Module>, std::string, ModuleGlobalHash>
654  module_to_specifier_map;
655 };
656 
657 enum {
658  kModuleEmbedderDataIndex,
659  kInspectorClientIndex
660 };
661 
662 void InitializeModuleEmbedderData(Local<Context> context) {
663  context->SetAlignedPointerInEmbedderData(
664  kModuleEmbedderDataIndex, new ModuleEmbedderData(context->GetIsolate()));
665 }
666 
667 ModuleEmbedderData* GetModuleDataFromContext(Local<Context> context) {
668  return static_cast<ModuleEmbedderData*>(
669  context->GetAlignedPointerFromEmbedderData(kModuleEmbedderDataIndex));
670 }
671 
672 void DisposeModuleEmbedderData(Local<Context> context) {
673  delete GetModuleDataFromContext(context);
674  context->SetAlignedPointerInEmbedderData(kModuleEmbedderDataIndex, nullptr);
675 }
676 
677 MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
678  Local<String> specifier,
679  Local<Module> referrer) {
680  Isolate* isolate = context->GetIsolate();
681  ModuleEmbedderData* d = GetModuleDataFromContext(context);
682  auto specifier_it =
683  d->module_to_specifier_map.find(Global<Module>(isolate, referrer));
684  CHECK(specifier_it != d->module_to_specifier_map.end());
685  std::string absolute_path = NormalizePath(ToSTLString(isolate, specifier),
686  DirName(specifier_it->second));
687  auto module_it = d->specifier_to_module_map.find(absolute_path);
688  CHECK(module_it != d->specifier_to_module_map.end());
689  return module_it->second.Get(isolate);
690 }
691 
692 } // anonymous namespace
693 
694 MaybeLocal<Module> Shell::FetchModuleTree(Local<Context> context,
695  const std::string& file_name) {
696  DCHECK(IsAbsolutePath(file_name));
697  Isolate* isolate = context->GetIsolate();
698  Local<String> source_text = ReadFile(isolate, file_name.c_str());
699  if (source_text.IsEmpty()) {
700  std::string msg = "Error reading: " + file_name;
701  Throw(isolate, msg.c_str());
702  return MaybeLocal<Module>();
703  }
704  ScriptOrigin origin(
705  String::NewFromUtf8(isolate, file_name.c_str(), NewStringType::kNormal)
706  .ToLocalChecked(),
707  Local<Integer>(), Local<Integer>(), Local<Boolean>(), Local<Integer>(),
708  Local<Value>(), Local<Boolean>(), Local<Boolean>(), True(isolate));
709  ScriptCompiler::Source source(source_text, origin);
710  Local<Module> module;
711  if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
712  return MaybeLocal<Module>();
713  }
714 
715  ModuleEmbedderData* d = GetModuleDataFromContext(context);
716  CHECK(d->specifier_to_module_map
717  .insert(std::make_pair(file_name, Global<Module>(isolate, module)))
718  .second);
719  CHECK(d->module_to_specifier_map
720  .insert(std::make_pair(Global<Module>(isolate, module), file_name))
721  .second);
722 
723  std::string dir_name = DirName(file_name);
724 
725  for (int i = 0, length = module->GetModuleRequestsLength(); i < length; ++i) {
726  Local<String> name = module->GetModuleRequest(i);
727  std::string absolute_path =
728  NormalizePath(ToSTLString(isolate, name), dir_name);
729  if (!d->specifier_to_module_map.count(absolute_path)) {
730  if (FetchModuleTree(context, absolute_path).IsEmpty()) {
731  return MaybeLocal<Module>();
732  }
733  }
734  }
735 
736  return module;
737 }
738 
739 namespace {
740 
741 struct DynamicImportData {
742  DynamicImportData(Isolate* isolate_, Local<String> referrer_,
743  Local<String> specifier_,
744  Local<Promise::Resolver> resolver_)
745  : isolate(isolate_) {
746  referrer.Reset(isolate, referrer_);
747  specifier.Reset(isolate, specifier_);
748  resolver.Reset(isolate, resolver_);
749  }
750 
751  Isolate* isolate;
752  Global<String> referrer;
753  Global<String> specifier;
754  Global<Promise::Resolver> resolver;
755 };
756 
757 } // namespace
758 
759 MaybeLocal<Promise> Shell::HostImportModuleDynamically(
760  Local<Context> context, Local<ScriptOrModule> referrer,
761  Local<String> specifier) {
762  Isolate* isolate = context->GetIsolate();
763 
764  MaybeLocal<Promise::Resolver> maybe_resolver =
765  Promise::Resolver::New(context);
766  Local<Promise::Resolver> resolver;
767  if (maybe_resolver.ToLocal(&resolver)) {
768  DynamicImportData* data = new DynamicImportData(
769  isolate, Local<String>::Cast(referrer->GetResourceName()), specifier,
770  resolver);
771  isolate->EnqueueMicrotask(Shell::DoHostImportModuleDynamically, data);
772  return resolver->GetPromise();
773  }
774 
775  return MaybeLocal<Promise>();
776 }
777 
778 void Shell::HostInitializeImportMetaObject(Local<Context> context,
779  Local<Module> module,
780  Local<Object> meta) {
781  Isolate* isolate = context->GetIsolate();
782  HandleScope handle_scope(isolate);
783 
784  ModuleEmbedderData* d = GetModuleDataFromContext(context);
785  auto specifier_it =
786  d->module_to_specifier_map.find(Global<Module>(isolate, module));
787  CHECK(specifier_it != d->module_to_specifier_map.end());
788 
789  Local<String> url_key =
791  .ToLocalChecked();
792  Local<String> url = String::NewFromUtf8(isolate, specifier_it->second.c_str(),
794  .ToLocalChecked();
795  meta->CreateDataProperty(context, url_key, url).ToChecked();
796 }
797 
798 void Shell::DoHostImportModuleDynamically(void* import_data) {
799  std::unique_ptr<DynamicImportData> import_data_(
800  static_cast<DynamicImportData*>(import_data));
801  Isolate* isolate(import_data_->isolate);
802  HandleScope handle_scope(isolate);
803 
804  Local<String> referrer(import_data_->referrer.Get(isolate));
805  Local<String> specifier(import_data_->specifier.Get(isolate));
806  Local<Promise::Resolver> resolver(import_data_->resolver.Get(isolate));
807 
808  PerIsolateData* data = PerIsolateData::Get(isolate);
809  Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
810  Context::Scope context_scope(realm);
811 
812  std::string source_url = ToSTLString(isolate, referrer);
813  std::string dir_name =
814  DirName(NormalizePath(source_url, GetWorkingDirectory()));
815  std::string file_name = ToSTLString(isolate, specifier);
816  std::string absolute_path = NormalizePath(file_name, dir_name);
817 
818  TryCatch try_catch(isolate);
819  try_catch.SetVerbose(true);
820 
821  ModuleEmbedderData* d = GetModuleDataFromContext(realm);
822  Local<Module> root_module;
823  auto module_it = d->specifier_to_module_map.find(absolute_path);
824  if (module_it != d->specifier_to_module_map.end()) {
825  root_module = module_it->second.Get(isolate);
826  } else if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) {
827  CHECK(try_catch.HasCaught());
828  resolver->Reject(realm, try_catch.Exception()).ToChecked();
829  return;
830  }
831 
832  MaybeLocal<Value> maybe_result;
833  if (root_module->InstantiateModule(realm, ResolveModuleCallback)
834  .FromMaybe(false)) {
835  maybe_result = root_module->Evaluate(realm);
836  EmptyMessageQueues(isolate);
837  }
838 
839  Local<Value> module;
840  if (!maybe_result.ToLocal(&module)) {
841  DCHECK(try_catch.HasCaught());
842  resolver->Reject(realm, try_catch.Exception()).ToChecked();
843  return;
844  }
845 
846  DCHECK(!try_catch.HasCaught());
847  Local<Value> module_namespace = root_module->GetModuleNamespace();
848  resolver->Resolve(realm, module_namespace).ToChecked();
849 }
850 
851 bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
852  HandleScope handle_scope(isolate);
853 
854  PerIsolateData* data = PerIsolateData::Get(isolate);
855  Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
856  Context::Scope context_scope(realm);
857 
858  std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory());
859 
860  TryCatch try_catch(isolate);
861  try_catch.SetVerbose(true);
862 
863  Local<Module> root_module;
864  MaybeLocal<Value> maybe_exception;
865 
866  if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) {
867  CHECK(try_catch.HasCaught());
868  ReportException(isolate, &try_catch);
869  return false;
870  }
871 
872  MaybeLocal<Value> maybe_result;
873  if (root_module->InstantiateModule(realm, ResolveModuleCallback)
874  .FromMaybe(false)) {
875  maybe_result = root_module->Evaluate(realm);
876  EmptyMessageQueues(isolate);
877  }
878  Local<Value> result;
879  if (!maybe_result.ToLocal(&result)) {
880  DCHECK(try_catch.HasCaught());
881  // Print errors that happened during execution.
882  ReportException(isolate, &try_catch);
883  return false;
884  }
885  DCHECK(!try_catch.HasCaught());
886  return true;
887 }
888 
889 PerIsolateData::PerIsolateData(Isolate* isolate)
890  : isolate_(isolate), realms_(nullptr) {
891  isolate->SetData(0, this);
892  if (i::FLAG_expose_async_hooks) {
893  async_hooks_wrapper_ = new AsyncHooks(isolate);
894  }
895 }
896 
897 PerIsolateData::~PerIsolateData() {
898  isolate_->SetData(0, nullptr); // Not really needed, just to be sure...
899  if (i::FLAG_expose_async_hooks) {
900  delete async_hooks_wrapper_; // This uses the isolate
901  }
902 }
903 
904 void PerIsolateData::SetTimeout(Local<Function> callback,
905  Local<Context> context) {
906  set_timeout_callbacks_.emplace(isolate_, callback);
907  set_timeout_contexts_.emplace(isolate_, context);
908 }
909 
910 MaybeLocal<Function> PerIsolateData::GetTimeoutCallback() {
911  if (set_timeout_callbacks_.empty()) return MaybeLocal<Function>();
912  Local<Function> result = set_timeout_callbacks_.front().Get(isolate_);
913  set_timeout_callbacks_.pop();
914  return result;
915 }
916 
917 MaybeLocal<Context> PerIsolateData::GetTimeoutContext() {
918  if (set_timeout_contexts_.empty()) return MaybeLocal<Context>();
919  Local<Context> result = set_timeout_contexts_.front().Get(isolate_);
920  set_timeout_contexts_.pop();
921  return result;
922 }
923 
924 PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
925  data_->realm_count_ = 1;
926  data_->realm_current_ = 0;
927  data_->realm_switch_ = 0;
928  data_->realms_ = new Global<Context>[1];
929  data_->realms_[0].Reset(data_->isolate_,
930  data_->isolate_->GetEnteredOrMicrotaskContext());
931 }
932 
933 
934 PerIsolateData::RealmScope::~RealmScope() {
935  // Drop realms to avoid keeping them alive. We don't dispose the
936  // module embedder data for the first realm here, but instead do
937  // it in RunShell or in RunMain, if not running in interactive mode
938  for (int i = 1; i < data_->realm_count_; ++i) {
939  Global<Context>& realm = data_->realms_[i];
940  if (realm.IsEmpty()) continue;
941  DisposeModuleEmbedderData(realm.Get(data_->isolate_));
942  // TODO(adamk): No need to reset manually, Globals reset when destructed.
943  realm.Reset();
944  }
945  data_->realm_count_ = 0;
946  delete[] data_->realms_;
947  // TODO(adamk): No need to reset manually, Globals reset when destructed.
948  if (!data_->realm_shared_.IsEmpty())
949  data_->realm_shared_.Reset();
950 }
951 
952 
953 int PerIsolateData::RealmFind(Local<Context> context) {
954  for (int i = 0; i < realm_count_; ++i) {
955  if (realms_[i] == context) return i;
956  }
957  return -1;
958 }
959 
960 
961 int PerIsolateData::RealmIndexOrThrow(
963  int arg_offset) {
964  if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
965  Throw(args.GetIsolate(), "Invalid argument");
966  return -1;
967  }
968  int index = args[arg_offset]
969  ->Int32Value(args.GetIsolate()->GetCurrentContext())
970  .FromMaybe(-1);
971  if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
972  Throw(args.GetIsolate(), "Invalid realm index");
973  return -1;
974  }
975  return index;
976 }
977 
978 
979 // performance.now() returns a time stamp as double, measured in milliseconds.
980 // When FLAG_verify_predictable mode is enabled it returns result of
981 // v8::Platform::MonotonicallyIncreasingTime().
982 void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
983  if (i::FLAG_verify_predictable) {
984  args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
985  } else {
986  base::TimeDelta delta =
987  base::TimeTicks::HighResolutionNow() - kInitialTicks;
988  args.GetReturnValue().Set(delta.InMillisecondsF());
989  }
990 }
991 
992 
993 // Realm.current() returns the index of the currently active realm.
994 void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
995  Isolate* isolate = args.GetIsolate();
996  PerIsolateData* data = PerIsolateData::Get(isolate);
997  int index = data->RealmFind(isolate->GetEnteredOrMicrotaskContext());
998  if (index == -1) return;
999  args.GetReturnValue().Set(index);
1000 }
1001 
1002 
1003 // Realm.owner(o) returns the index of the realm that created o.
1004 void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
1005  Isolate* isolate = args.GetIsolate();
1006  PerIsolateData* data = PerIsolateData::Get(isolate);
1007  if (args.Length() < 1 || !args[0]->IsObject()) {
1008  Throw(args.GetIsolate(), "Invalid argument");
1009  return;
1010  }
1011  int index = data->RealmFind(args[0]
1012  ->ToObject(isolate->GetCurrentContext())
1013  .ToLocalChecked()
1014  ->CreationContext());
1015  if (index == -1) return;
1016  args.GetReturnValue().Set(index);
1017 }
1018 
1019 
1020 // Realm.global(i) returns the global object of realm i.
1021 // (Note that properties of global objects cannot be read/written cross-realm.)
1022 void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
1023  PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
1024  int index = data->RealmIndexOrThrow(args, 0);
1025  if (index == -1) return;
1026  args.GetReturnValue().Set(
1027  Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
1028 }
1029 
1030 MaybeLocal<Context> Shell::CreateRealm(
1031  const v8::FunctionCallbackInfo<v8::Value>& args, int index,
1032  v8::MaybeLocal<Value> global_object) {
1033  Isolate* isolate = args.GetIsolate();
1034  TryCatch try_catch(isolate);
1035  PerIsolateData* data = PerIsolateData::Get(isolate);
1036  if (index < 0) {
1037  Global<Context>* old_realms = data->realms_;
1038  index = data->realm_count_;
1039  data->realms_ = new Global<Context>[++data->realm_count_];
1040  for (int i = 0; i < index; ++i) {
1041  data->realms_[i].Reset(isolate, old_realms[i]);
1042  old_realms[i].Reset();
1043  }
1044  delete[] old_realms;
1045  }
1046  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1047  Local<Context> context =
1048  Context::New(isolate, nullptr, global_template, global_object);
1049  DCHECK(!try_catch.HasCaught());
1050  if (context.IsEmpty()) return MaybeLocal<Context>();
1051  InitializeModuleEmbedderData(context);
1052  data->realms_[index].Reset(isolate, context);
1053  args.GetReturnValue().Set(index);
1054  return context;
1055 }
1056 
1057 void Shell::DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
1058  int index) {
1059  Isolate* isolate = args.GetIsolate();
1060  PerIsolateData* data = PerIsolateData::Get(isolate);
1061  DisposeModuleEmbedderData(data->realms_[index].Get(isolate));
1062  data->realms_[index].Reset();
1063  isolate->ContextDisposedNotification();
1064  isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
1065 }
1066 
1067 // Realm.create() creates a new realm with a distinct security token
1068 // and returns its index.
1069 void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1070  CreateRealm(args, -1, v8::MaybeLocal<Value>());
1071 }
1072 
1073 // Realm.createAllowCrossRealmAccess() creates a new realm with the same
1074 // security token as the current realm.
1075 void Shell::RealmCreateAllowCrossRealmAccess(
1077  Local<Context> context;
1078  if (CreateRealm(args, -1, v8::MaybeLocal<Value>()).ToLocal(&context)) {
1079  context->SetSecurityToken(
1080  args.GetIsolate()->GetEnteredOrMicrotaskContext()->GetSecurityToken());
1081  }
1082 }
1083 
1084 // Realm.navigate(i) creates a new realm with a distinct security token
1085 // in place of realm i.
1086 void Shell::RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1087  Isolate* isolate = args.GetIsolate();
1088  PerIsolateData* data = PerIsolateData::Get(isolate);
1089  int index = data->RealmIndexOrThrow(args, 0);
1090  if (index == -1) return;
1091  if (index == 0 || index == data->realm_current_ ||
1092  index == data->realm_switch_) {
1093  Throw(args.GetIsolate(), "Invalid realm index");
1094  return;
1095  }
1096 
1097  Local<Context> context = Local<Context>::New(isolate, data->realms_[index]);
1098  v8::MaybeLocal<Value> global_object = context->Global();
1099  DisposeRealm(args, index);
1100  CreateRealm(args, index, global_object);
1101 }
1102 
1103 // Realm.dispose(i) disposes the reference to the realm i.
1104 void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
1105  Isolate* isolate = args.GetIsolate();
1106  PerIsolateData* data = PerIsolateData::Get(isolate);
1107  int index = data->RealmIndexOrThrow(args, 0);
1108  if (index == -1) return;
1109  if (index == 0 ||
1110  index == data->realm_current_ || index == data->realm_switch_) {
1111  Throw(args.GetIsolate(), "Invalid realm index");
1112  return;
1113  }
1114  DisposeRealm(args, index);
1115 }
1116 
1117 
1118 // Realm.switch(i) switches to the realm i for consecutive interactive inputs.
1119 void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
1120  Isolate* isolate = args.GetIsolate();
1121  PerIsolateData* data = PerIsolateData::Get(isolate);
1122  int index = data->RealmIndexOrThrow(args, 0);
1123  if (index == -1) return;
1124  data->realm_switch_ = index;
1125 }
1126 
1127 
1128 // Realm.eval(i, s) evaluates s in realm i and returns the result.
1129 void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
1130  Isolate* isolate = args.GetIsolate();
1131  PerIsolateData* data = PerIsolateData::Get(isolate);
1132  int index = data->RealmIndexOrThrow(args, 0);
1133  if (index == -1) return;
1134  if (args.Length() < 2 || !args[1]->IsString()) {
1135  Throw(args.GetIsolate(), "Invalid argument");
1136  return;
1137  }
1138  ScriptCompiler::Source script_source(
1139  args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
1140  Local<UnboundScript> script;
1141  if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
1142  .ToLocal(&script)) {
1143  return;
1144  }
1145  Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
1146  realm->Enter();
1147  int previous_index = data->realm_current_;
1148  data->realm_current_ = data->realm_switch_ = index;
1149  Local<Value> result;
1150  if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
1151  realm->Exit();
1152  data->realm_current_ = data->realm_switch_ = previous_index;
1153  return;
1154  }
1155  realm->Exit();
1156  data->realm_current_ = data->realm_switch_ = previous_index;
1157  args.GetReturnValue().Set(result);
1158 }
1159 
1160 
1161 // Realm.shared is an accessor for a single shared value across realms.
1162 void Shell::RealmSharedGet(Local<String> property,
1163  const PropertyCallbackInfo<Value>& info) {
1164  Isolate* isolate = info.GetIsolate();
1165  PerIsolateData* data = PerIsolateData::Get(isolate);
1166  if (data->realm_shared_.IsEmpty()) return;
1167  info.GetReturnValue().Set(data->realm_shared_);
1168 }
1169 
1170 void Shell::RealmSharedSet(Local<String> property,
1171  Local<Value> value,
1172  const PropertyCallbackInfo<void>& info) {
1173  Isolate* isolate = info.GetIsolate();
1174  PerIsolateData* data = PerIsolateData::Get(isolate);
1175  data->realm_shared_.Reset(isolate, value);
1176 }
1177 
1178 // async_hooks.createHook() registers functions to be called for different
1179 // lifetime events of each async operation.
1180 void Shell::AsyncHooksCreateHook(
1182  Local<Object> wrap =
1183  PerIsolateData::Get(args.GetIsolate())->GetAsyncHooks()->CreateHook(args);
1184  args.GetReturnValue().Set(wrap);
1185 }
1186 
1187 // async_hooks.executionAsyncId() returns the asyncId of the current execution
1188 // context.
1189 void Shell::AsyncHooksExecutionAsyncId(
1191  Isolate* isolate = args.GetIsolate();
1192  HandleScope handle_scope(isolate);
1193  args.GetReturnValue().Set(v8::Number::New(
1194  isolate,
1195  PerIsolateData::Get(isolate)->GetAsyncHooks()->GetExecutionAsyncId()));
1196 }
1197 
1198 void Shell::AsyncHooksTriggerAsyncId(
1200  Isolate* isolate = args.GetIsolate();
1201  HandleScope handle_scope(isolate);
1202  args.GetReturnValue().Set(v8::Number::New(
1203  isolate,
1204  PerIsolateData::Get(isolate)->GetAsyncHooks()->GetTriggerAsyncId()));
1205 }
1206 
1207 void WriteToFile(FILE* file, const v8::FunctionCallbackInfo<v8::Value>& args) {
1208  for (int i = 0; i < args.Length(); i++) {
1209  HandleScope handle_scope(args.GetIsolate());
1210  if (i != 0) {
1211  fprintf(file, " ");
1212  }
1213 
1214  // Explicitly catch potential exceptions in toString().
1215  v8::TryCatch try_catch(args.GetIsolate());
1216  Local<Value> arg = args[i];
1217  Local<String> str_obj;
1218 
1219  if (arg->IsSymbol()) {
1220  arg = Local<Symbol>::Cast(arg)->Name();
1221  }
1222  if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
1223  .ToLocal(&str_obj)) {
1224  try_catch.ReThrow();
1225  return;
1226  }
1227 
1228  v8::String::Utf8Value str(args.GetIsolate(), str_obj);
1229  int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), file));
1230  if (n != str.length()) {
1231  printf("Error in fwrite\n");
1232  base::OS::ExitProcess(1);
1233  }
1234  }
1235 }
1236 
1237 void WriteAndFlush(FILE* file,
1239  WriteToFile(file, args);
1240  fprintf(file, "\n");
1241  fflush(file);
1242 }
1243 
1244 void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
1245  WriteAndFlush(stdout, args);
1246 }
1247 
1248 void Shell::PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args) {
1249  WriteAndFlush(stderr, args);
1250 }
1251 
1252 void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
1253  WriteToFile(stdout, args);
1254 }
1255 
1256 void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
1257  String::Utf8Value file(args.GetIsolate(), args[0]);
1258  if (*file == nullptr) {
1259  Throw(args.GetIsolate(), "Error loading file");
1260  return;
1261  }
1262  if (args.Length() == 2) {
1263  String::Utf8Value format(args.GetIsolate(), args[1]);
1264  if (*format && std::strcmp(*format, "binary") == 0) {
1265  ReadBuffer(args);
1266  return;
1267  }
1268  }
1269  Local<String> source = ReadFile(args.GetIsolate(), *file);
1270  if (source.IsEmpty()) {
1271  Throw(args.GetIsolate(), "Error loading file");
1272  return;
1273  }
1274  args.GetReturnValue().Set(source);
1275 }
1276 
1277 
1278 Local<String> Shell::ReadFromStdin(Isolate* isolate) {
1279  static const int kBufferSize = 256;
1280  char buffer[kBufferSize];
1281  Local<String> accumulator =
1282  String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
1283  int length;
1284  while (true) {
1285  // Continue reading if the line ends with an escape '\\' or the line has
1286  // not been fully read into the buffer yet (does not end with '\n').
1287  // If fgets gets an error, just give up.
1288  char* input = nullptr;
1289  input = fgets(buffer, kBufferSize, stdin);
1290  if (input == nullptr) return Local<String>();
1291  length = static_cast<int>(strlen(buffer));
1292  if (length == 0) {
1293  return accumulator;
1294  } else if (buffer[length-1] != '\n') {
1295  accumulator = String::Concat(
1296  isolate, accumulator,
1297  String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
1298  .ToLocalChecked());
1299  } else if (length > 1 && buffer[length-2] == '\\') {
1300  buffer[length-2] = '\n';
1301  accumulator =
1302  String::Concat(isolate, accumulator,
1303  String::NewFromUtf8(isolate, buffer,
1304  NewStringType::kNormal, length - 1)
1305  .ToLocalChecked());
1306  } else {
1307  return String::Concat(
1308  isolate, accumulator,
1310  length - 1)
1311  .ToLocalChecked());
1312  }
1313  }
1314 }
1315 
1316 
1317 void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
1318  for (int i = 0; i < args.Length(); i++) {
1319  HandleScope handle_scope(args.GetIsolate());
1320  String::Utf8Value file(args.GetIsolate(), args[i]);
1321  if (*file == nullptr) {
1322  Throw(args.GetIsolate(), "Error loading file");
1323  return;
1324  }
1325  Local<String> source = ReadFile(args.GetIsolate(), *file);
1326  if (source.IsEmpty()) {
1327  Throw(args.GetIsolate(), "Error loading file");
1328  return;
1329  }
1330  if (!ExecuteString(
1331  args.GetIsolate(), source,
1332  String::NewFromUtf8(args.GetIsolate(), *file,
1334  .ToLocalChecked(),
1335  kNoPrintResult,
1336  options.quiet_load ? kNoReportExceptions : kReportExceptions,
1337  kNoProcessMessageQueue)) {
1338  Throw(args.GetIsolate(), "Error executing file");
1339  return;
1340  }
1341  }
1342 }
1343 
1344 void Shell::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) {
1345  Isolate* isolate = args.GetIsolate();
1346  args.GetReturnValue().Set(v8::Number::New(isolate, 0));
1347  if (args.Length() == 0 || !args[0]->IsFunction()) return;
1348  Local<Function> callback = Local<Function>::Cast(args[0]);
1349  Local<Context> context = isolate->GetCurrentContext();
1350  PerIsolateData::Get(isolate)->SetTimeout(callback, context);
1351 }
1352 
1353 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
1354  Isolate* isolate = args.GetIsolate();
1355  HandleScope handle_scope(isolate);
1356  if (args.Length() < 1 || !args[0]->IsString()) {
1357  Throw(args.GetIsolate(), "1st argument must be string");
1358  return;
1359  }
1360 
1361  // d8 honors `options={type: string}`, which means the first argument is
1362  // not a filename but string of script to be run.
1363  bool load_from_file = true;
1364  if (args.Length() > 1 && args[1]->IsObject()) {
1365  Local<Object> object = args[1].As<Object>();
1366  Local<Context> context = isolate->GetCurrentContext();
1367  Local<Value> value = GetValue(args.GetIsolate(), context, object, "type");
1368  if (value->IsString()) {
1369  Local<String> worker_type = value->ToString(context).ToLocalChecked();
1370  String::Utf8Value str(isolate, worker_type);
1371  if (strcmp("string", *str) == 0) {
1372  load_from_file = false;
1373  } else if (strcmp("classic", *str) == 0) {
1374  load_from_file = true;
1375  } else {
1376  Throw(args.GetIsolate(), "Unsupported worker type");
1377  return;
1378  }
1379  }
1380  }
1381 
1382  Local<Value> source;
1383  if (load_from_file) {
1384  String::Utf8Value filename(args.GetIsolate(), args[0]);
1385  source = ReadFile(args.GetIsolate(), *filename);
1386  if (source.IsEmpty()) {
1387  Throw(args.GetIsolate(), "Error loading worker script");
1388  return;
1389  }
1390  } else {
1391  source = args[0];
1392  }
1393 
1394  if (!args.IsConstructCall()) {
1395  Throw(args.GetIsolate(), "Worker must be constructed with new");
1396  return;
1397  }
1398 
1399  {
1400  base::MutexGuard lock_guard(workers_mutex_.Pointer());
1401  if (workers_.size() >= kMaxWorkers) {
1402  Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
1403  return;
1404  }
1405 
1406  // Initialize the embedder field to nullptr; if we return early without
1407  // creating a new Worker (because the main thread is terminating) we can
1408  // early-out from the instance calls.
1409  args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
1410 
1411  if (!allow_new_workers_) return;
1412 
1413  Worker* worker = new Worker;
1414  args.Holder()->SetAlignedPointerInInternalField(0, worker);
1415  workers_.push_back(worker);
1416 
1417  String::Utf8Value script(args.GetIsolate(), source);
1418  if (!*script) {
1419  Throw(args.GetIsolate(), "Can't get worker script");
1420  return;
1421  }
1422  worker->StartExecuteInThread(*script);
1423  }
1424 }
1425 
1426 
1427 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
1428  Isolate* isolate = args.GetIsolate();
1429  HandleScope handle_scope(isolate);
1430 
1431  if (args.Length() < 1) {
1432  Throw(isolate, "Invalid argument");
1433  return;
1434  }
1435 
1436  Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1437  if (!worker) {
1438  return;
1439  }
1440 
1441  Local<Value> message = args[0];
1442  Local<Value> transfer =
1443  args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate));
1444  std::unique_ptr<SerializationData> data =
1445  Shell::SerializeValue(isolate, message, transfer);
1446  if (data) {
1447  worker->PostMessage(std::move(data));
1448  }
1449 }
1450 
1451 
1452 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
1453  Isolate* isolate = args.GetIsolate();
1454  HandleScope handle_scope(isolate);
1455  Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1456  if (!worker) {
1457  return;
1458  }
1459 
1460  std::unique_ptr<SerializationData> data = worker->GetMessage();
1461  if (data) {
1462  Local<Value> value;
1463  if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) {
1464  args.GetReturnValue().Set(value);
1465  }
1466  }
1467 }
1468 
1469 
1470 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1471  Isolate* isolate = args.GetIsolate();
1472  HandleScope handle_scope(isolate);
1473  Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1474  if (!worker) {
1475  return;
1476  }
1477 
1478  worker->Terminate();
1479 }
1480 
1481 
1482 void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
1483  int exit_code = (*args)[0]
1484  ->Int32Value(args->GetIsolate()->GetCurrentContext())
1485  .FromMaybe(0);
1486  CleanupWorkers();
1487  args->GetIsolate()->Exit();
1488  OnExit(args->GetIsolate());
1489  base::OS::ExitProcess(exit_code);
1490 }
1491 
1492 
1493 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
1494  base::CallOnce(&quit_once_, &QuitOnce,
1495  const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
1496 }
1497 
1498 void Shell::WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
1499  SetWaitUntilDone(args.GetIsolate(), true);
1500 }
1501 
1502 void Shell::NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
1503  SetWaitUntilDone(args.GetIsolate(), false);
1504 }
1505 
1506 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
1507  args.GetReturnValue().Set(
1508  String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
1509  NewStringType::kNormal).ToLocalChecked());
1510 }
1511 
1512 
1513 void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
1514  HandleScope handle_scope(isolate);
1515  Local<Context> context = isolate->GetCurrentContext();
1516  bool enter_context = context.IsEmpty();
1517  if (enter_context) {
1518  context = Local<Context>::New(isolate, evaluation_context_);
1519  context->Enter();
1520  }
1521  // Converts a V8 value to a C string.
1522  auto ToCString = [](const v8::String::Utf8Value& value) {
1523  return *value ? *value : "<string conversion failed>";
1524  };
1525 
1526  v8::String::Utf8Value exception(isolate, try_catch->Exception());
1527  const char* exception_string = ToCString(exception);
1528  Local<Message> message = try_catch->Message();
1529  if (message.IsEmpty()) {
1530  // V8 didn't provide any extra information about this error; just
1531  // print the exception.
1532  printf("%s\n", exception_string);
1533  } else if (message->GetScriptOrigin().Options().IsWasm()) {
1534  // Print wasm-function[(function index)]:(offset): (message).
1535  int function_index = message->GetLineNumber(context).FromJust() - 1;
1536  int offset = message->GetStartColumn(context).FromJust();
1537  printf("wasm-function[%d]:%d: %s\n", function_index, offset,
1538  exception_string);
1539  } else {
1540  // Print (filename):(line number): (message).
1541  v8::String::Utf8Value filename(isolate,
1542  message->GetScriptOrigin().ResourceName());
1543  const char* filename_string = ToCString(filename);
1544  int linenum = message->GetLineNumber(context).FromMaybe(-1);
1545  printf("%s:%i: %s\n", filename_string, linenum, exception_string);
1546  Local<String> sourceline;
1547  if (message->GetSourceLine(context).ToLocal(&sourceline)) {
1548  // Print line of source code.
1549  v8::String::Utf8Value sourcelinevalue(isolate, sourceline);
1550  const char* sourceline_string = ToCString(sourcelinevalue);
1551  printf("%s\n", sourceline_string);
1552  // Print wavy underline (GetUnderline is deprecated).
1553  int start = message->GetStartColumn(context).FromJust();
1554  for (int i = 0; i < start; i++) {
1555  printf(" ");
1556  }
1557  int end = message->GetEndColumn(context).FromJust();
1558  for (int i = start; i < end; i++) {
1559  printf("^");
1560  }
1561  printf("\n");
1562  }
1563  }
1564  Local<Value> stack_trace_string;
1565  if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
1566  stack_trace_string->IsString()) {
1567  v8::String::Utf8Value stack_trace(isolate,
1568  Local<String>::Cast(stack_trace_string));
1569  printf("%s\n", ToCString(stack_trace));
1570  }
1571  printf("\n");
1572  if (enter_context) context->Exit();
1573 }
1574 
1575 
1576 int32_t* Counter::Bind(const char* name, bool is_histogram) {
1577  int i;
1578  for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
1579  name_[i] = static_cast<char>(name[i]);
1580  name_[i] = '\0';
1581  is_histogram_ = is_histogram;
1582  return ptr();
1583 }
1584 
1585 
1586 void Counter::AddSample(int32_t sample) {
1587  count_++;
1588  sample_total_ += sample;
1589 }
1590 
1591 
1592 CounterCollection::CounterCollection() {
1593  magic_number_ = 0xDEADFACE;
1594  max_counters_ = kMaxCounters;
1595  max_name_size_ = Counter::kMaxNameSize;
1596  counters_in_use_ = 0;
1597 }
1598 
1599 
1600 Counter* CounterCollection::GetNextCounter() {
1601  if (counters_in_use_ == kMaxCounters) return nullptr;
1602  return &counters_[counters_in_use_++];
1603 }
1604 
1605 
1606 void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
1607  counters_file_ = base::OS::MemoryMappedFile::create(
1608  name, sizeof(CounterCollection), &local_counters_);
1609  void* memory =
1610  (counters_file_ == nullptr) ? nullptr : counters_file_->memory();
1611  if (memory == nullptr) {
1612  printf("Could not map counters file %s\n", name);
1613  base::OS::ExitProcess(1);
1614  }
1615  counters_ = static_cast<CounterCollection*>(memory);
1616  isolate->SetCounterFunction(LookupCounter);
1617  isolate->SetCreateHistogramFunction(CreateHistogram);
1618  isolate->SetAddHistogramSampleFunction(AddHistogramSample);
1619 }
1620 
1621 Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1622  auto map_entry = counter_map_->find(name);
1623  Counter* counter =
1624  map_entry != counter_map_->end() ? map_entry->second : nullptr;
1625 
1626  if (counter == nullptr) {
1627  counter = counters_->GetNextCounter();
1628  if (counter != nullptr) {
1629  (*counter_map_)[name] = counter;
1630  counter->Bind(name, is_histogram);
1631  }
1632  } else {
1633  DCHECK(counter->is_histogram() == is_histogram);
1634  }
1635  return counter;
1636 }
1637 
1638 
1639 int* Shell::LookupCounter(const char* name) {
1640  Counter* counter = GetCounter(name, false);
1641 
1642  if (counter != nullptr) {
1643  return counter->ptr();
1644  } else {
1645  return nullptr;
1646  }
1647 }
1648 
1649 
1650 void* Shell::CreateHistogram(const char* name,
1651  int min,
1652  int max,
1653  size_t buckets) {
1654  return GetCounter(name, true);
1655 }
1656 
1657 
1658 void Shell::AddHistogramSample(void* histogram, int sample) {
1659  Counter* counter = reinterpret_cast<Counter*>(histogram);
1660  counter->AddSample(sample);
1661 }
1662 
1663 // Turn a value into a human-readable string.
1664 Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
1665  v8::Local<v8::Context> context =
1666  v8::Local<v8::Context>::New(isolate, evaluation_context_);
1667  if (stringify_function_.IsEmpty()) {
1668  int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1669  i::Vector<const char> source_string =
1671  i::Vector<const char> source_name =
1673  Local<String> source =
1674  String::NewFromUtf8(isolate, source_string.start(),
1675  NewStringType::kNormal, source_string.length())
1676  .ToLocalChecked();
1677  Local<String> name =
1678  String::NewFromUtf8(isolate, source_name.start(),
1679  NewStringType::kNormal, source_name.length())
1680  .ToLocalChecked();
1681  ScriptOrigin origin(name);
1682  Local<Script> script =
1683  Script::Compile(context, source, &origin).ToLocalChecked();
1684  stringify_function_.Reset(
1685  isolate, script->Run(context).ToLocalChecked().As<Function>());
1686  }
1687  Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
1688  Local<Value> argv[1] = {value};
1689  v8::TryCatch try_catch(isolate);
1690  MaybeLocal<Value> result = fun->Call(context, Undefined(isolate), 1, argv);
1691  if (result.IsEmpty()) return String::Empty(isolate);
1692  return result.ToLocalChecked().As<String>();
1693 }
1694 
1695 
1696 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1697  Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1698  global_template->Set(
1699  String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1700  .ToLocalChecked(),
1701  FunctionTemplate::New(isolate, Print));
1702  global_template->Set(
1703  String::NewFromUtf8(isolate, "printErr", NewStringType::kNormal)
1704  .ToLocalChecked(),
1705  FunctionTemplate::New(isolate, PrintErr));
1706  global_template->Set(
1707  String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1708  .ToLocalChecked(),
1709  FunctionTemplate::New(isolate, Write));
1710  global_template->Set(
1712  .ToLocalChecked(),
1713  FunctionTemplate::New(isolate, Read));
1714  global_template->Set(
1715  String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1716  .ToLocalChecked(),
1717  FunctionTemplate::New(isolate, ReadBuffer));
1718  global_template->Set(
1719  String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1720  .ToLocalChecked(),
1721  FunctionTemplate::New(isolate, ReadLine));
1722  global_template->Set(
1724  .ToLocalChecked(),
1725  FunctionTemplate::New(isolate, Load));
1726  global_template->Set(
1727  String::NewFromUtf8(isolate, "setTimeout", NewStringType::kNormal)
1728  .ToLocalChecked(),
1729  FunctionTemplate::New(isolate, SetTimeout));
1730  // Some Emscripten-generated code tries to call 'quit', which in turn would
1731  // call C's exit(). This would lead to memory leaks, because there is no way
1732  // we can terminate cleanly then, so we need a way to hide 'quit'.
1733  if (!options.omit_quit) {
1734  global_template->Set(
1736  .ToLocalChecked(),
1737  FunctionTemplate::New(isolate, Quit));
1738  }
1739  Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
1740  global_template->Set(
1741  String::NewFromUtf8(isolate, "testRunner", NewStringType::kNormal)
1742  .ToLocalChecked(),
1743  test_template);
1744  test_template->Set(
1745  String::NewFromUtf8(isolate, "notifyDone", NewStringType::kNormal)
1746  .ToLocalChecked(),
1747  FunctionTemplate::New(isolate, NotifyDone));
1748  test_template->Set(
1749  String::NewFromUtf8(isolate, "waitUntilDone", NewStringType::kNormal)
1750  .ToLocalChecked(),
1751  FunctionTemplate::New(isolate, WaitUntilDone));
1752  global_template->Set(
1753  String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1754  .ToLocalChecked(),
1755  FunctionTemplate::New(isolate, Version));
1756  global_template->Set(
1757  Symbol::GetToStringTag(isolate),
1758  String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1759  .ToLocalChecked());
1760 
1761  // Bind the Realm object.
1762  Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1763  realm_template->Set(
1764  String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1765  .ToLocalChecked(),
1766  FunctionTemplate::New(isolate, RealmCurrent));
1767  realm_template->Set(
1768  String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1769  .ToLocalChecked(),
1770  FunctionTemplate::New(isolate, RealmOwner));
1771  realm_template->Set(
1772  String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1773  .ToLocalChecked(),
1774  FunctionTemplate::New(isolate, RealmGlobal));
1775  realm_template->Set(
1776  String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1777  .ToLocalChecked(),
1778  FunctionTemplate::New(isolate, RealmCreate));
1779  realm_template->Set(
1780  String::NewFromUtf8(isolate, "createAllowCrossRealmAccess",
1782  .ToLocalChecked(),
1783  FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
1784  realm_template->Set(
1785  String::NewFromUtf8(isolate, "navigate", NewStringType::kNormal)
1786  .ToLocalChecked(),
1787  FunctionTemplate::New(isolate, RealmNavigate));
1788  realm_template->Set(
1789  String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1790  .ToLocalChecked(),
1791  FunctionTemplate::New(isolate, RealmDispose));
1792  realm_template->Set(
1793  String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1794  .ToLocalChecked(),
1795  FunctionTemplate::New(isolate, RealmSwitch));
1796  realm_template->Set(
1798  .ToLocalChecked(),
1799  FunctionTemplate::New(isolate, RealmEval));
1800  realm_template->SetAccessor(
1801  String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1802  .ToLocalChecked(),
1803  RealmSharedGet, RealmSharedSet);
1804  global_template->Set(
1805  String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1806  .ToLocalChecked(),
1807  realm_template);
1808 
1809  Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1810  performance_template->Set(
1812  .ToLocalChecked(),
1813  FunctionTemplate::New(isolate, PerformanceNow));
1814  global_template->Set(
1815  String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1816  .ToLocalChecked(),
1817  performance_template);
1818 
1819  Local<FunctionTemplate> worker_fun_template =
1820  FunctionTemplate::New(isolate, WorkerNew);
1821  Local<Signature> worker_signature =
1822  Signature::New(isolate, worker_fun_template);
1823  worker_fun_template->SetClassName(
1824  String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1825  .ToLocalChecked());
1826  worker_fun_template->ReadOnlyPrototype();
1827  worker_fun_template->PrototypeTemplate()->Set(
1828  String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1829  .ToLocalChecked(),
1830  FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1831  worker_signature));
1832  worker_fun_template->PrototypeTemplate()->Set(
1833  String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1834  .ToLocalChecked(),
1835  FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1836  worker_signature));
1837  worker_fun_template->PrototypeTemplate()->Set(
1838  String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1839  .ToLocalChecked(),
1840  FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1841  worker_signature));
1842  worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1843  global_template->Set(
1844  String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1845  .ToLocalChecked(),
1846  worker_fun_template);
1847 
1848  Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
1849  AddOSMethods(isolate, os_templ);
1850  global_template->Set(
1852  .ToLocalChecked(),
1853  os_templ);
1854 
1855  if (i::FLAG_expose_async_hooks) {
1856  Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
1857  async_hooks_templ->Set(
1858  String::NewFromUtf8(isolate, "createHook", NewStringType::kNormal)
1859  .ToLocalChecked(),
1860  FunctionTemplate::New(isolate, AsyncHooksCreateHook));
1861  async_hooks_templ->Set(
1862  String::NewFromUtf8(isolate, "executionAsyncId", NewStringType::kNormal)
1863  .ToLocalChecked(),
1864  FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
1865  async_hooks_templ->Set(
1866  String::NewFromUtf8(isolate, "triggerAsyncId", NewStringType::kNormal)
1867  .ToLocalChecked(),
1868  FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
1869  global_template->Set(
1870  String::NewFromUtf8(isolate, "async_hooks", NewStringType::kNormal)
1871  .ToLocalChecked(),
1872  async_hooks_templ);
1873  }
1874 
1875  return global_template;
1876 }
1877 
1878 static void PrintNonErrorsMessageCallback(Local<Message> message,
1879  Local<Value> error) {
1880  // Nothing to do here for errors, exceptions thrown up to the shell will be
1881  // reported
1882  // separately by {Shell::ReportException} after they are caught.
1883  // Do print other kinds of messages.
1884  switch (message->ErrorLevel()) {
1885  case v8::Isolate::kMessageWarning:
1886  case v8::Isolate::kMessageLog:
1887  case v8::Isolate::kMessageInfo:
1888  case v8::Isolate::kMessageDebug: {
1889  break;
1890  }
1891 
1892  case v8::Isolate::kMessageError: {
1893  // Ignore errors, printed elsewhere.
1894  return;
1895  }
1896 
1897  default: {
1898  UNREACHABLE();
1899  break;
1900  }
1901  }
1902  // Converts a V8 value to a C string.
1903  auto ToCString = [](const v8::String::Utf8Value& value) {
1904  return *value ? *value : "<string conversion failed>";
1905  };
1906  Isolate* isolate = Isolate::GetCurrent();
1907  v8::String::Utf8Value msg(isolate, message->Get());
1908  const char* msg_string = ToCString(msg);
1909  // Print (filename):(line number): (message).
1910  v8::String::Utf8Value filename(isolate,
1911  message->GetScriptOrigin().ResourceName());
1912  const char* filename_string = ToCString(filename);
1913  Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
1914  int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
1915  printf("%s:%i: %s\n", filename_string, linenum, msg_string);
1916 }
1917 
1918 void Shell::Initialize(Isolate* isolate) {
1919  // Set up counters
1920  if (i::StrLength(i::FLAG_map_counters) != 0)
1921  MapCounters(isolate, i::FLAG_map_counters);
1922  // Disable default message reporting.
1923  isolate->AddMessageListenerWithErrorLevel(
1924  PrintNonErrorsMessageCallback,
1925  v8::Isolate::kMessageError | v8::Isolate::kMessageWarning |
1926  v8::Isolate::kMessageInfo | v8::Isolate::kMessageDebug |
1927  v8::Isolate::kMessageLog);
1928 }
1929 
1930 
1931 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
1932  // This needs to be a critical section since this is not thread-safe
1933  base::MutexGuard lock_guard(context_mutex_.Pointer());
1934  // Initialize the global objects
1935  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1936  EscapableHandleScope handle_scope(isolate);
1937  Local<Context> context = Context::New(isolate, nullptr, global_template);
1938  DCHECK(!context.IsEmpty());
1939  InitializeModuleEmbedderData(context);
1940  if (options.include_arguments) {
1941  Context::Scope scope(context);
1942  const std::vector<const char*>& args = options.arguments;
1943  int size = static_cast<int>(args.size());
1944  Local<Array> array = Array::New(isolate, size);
1945  for (int i = 0; i < size; i++) {
1946  Local<String> arg =
1948  .ToLocalChecked();
1949  Local<Number> index = v8::Number::New(isolate, i);
1950  array->Set(context, index, arg).FromJust();
1951  }
1952  Local<String> name =
1953  String::NewFromUtf8(isolate, "arguments", NewStringType::kInternalized)
1954  .ToLocalChecked();
1955  context->Global()->Set(context, name, array).FromJust();
1956  }
1957  return handle_scope.Escape(context);
1958 }
1959 
1961  Counter* counter;
1962  const char* key;
1963 };
1964 
1965 
1966 inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1967  return strcmp(lhs.key, rhs.key) < 0;
1968 }
1969 
1970 void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
1971  HandleScope handle_scope(isolate);
1972  Local<Context> context = Context::New(isolate);
1973  Context::Scope context_scope(context);
1974 
1975  Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
1976  ->interpreter()
1977  ->GetDispatchCountersObject();
1978  std::ofstream dispatch_counters_stream(
1979  i::FLAG_trace_ignition_dispatches_output_file);
1980  dispatch_counters_stream << *String::Utf8Value(
1981  isolate, JSON::Stringify(context, dispatch_counters).ToLocalChecked());
1982 }
1983 
1984 namespace {
1985 int LineFromOffset(Local<debug::Script> script, int offset) {
1986  debug::Location location = script->GetSourceLocation(offset);
1987  return location.GetLineNumber();
1988 }
1989 
1990 void WriteLcovDataForRange(std::vector<uint32_t>& lines, int start_line,
1991  int end_line, uint32_t count) {
1992  // Ensure space in the array.
1993  lines.resize(std::max(static_cast<size_t>(end_line + 1), lines.size()), 0);
1994  // Boundary lines could be shared between two functions with different
1995  // invocation counts. Take the maximum.
1996  lines[start_line] = std::max(lines[start_line], count);
1997  lines[end_line] = std::max(lines[end_line], count);
1998  // Invocation counts for non-boundary lines are overwritten.
1999  for (int k = start_line + 1; k < end_line; k++) lines[k] = count;
2000 }
2001 
2002 void WriteLcovDataForNamedRange(std::ostream& sink,
2003  std::vector<uint32_t>& lines,
2004  const std::string& name, int start_line,
2005  int end_line, uint32_t count) {
2006  WriteLcovDataForRange(lines, start_line, end_line, count);
2007  sink << "FN:" << start_line + 1 << "," << name << std::endl;
2008  sink << "FNDA:" << count << "," << name << std::endl;
2009 }
2010 } // namespace
2011 
2012 // Write coverage data in LCOV format. See man page for geninfo(1).
2013 void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) {
2014  if (!file) return;
2015  HandleScope handle_scope(isolate);
2016  debug::Coverage coverage = debug::Coverage::CollectPrecise(isolate);
2017  std::ofstream sink(file, std::ofstream::app);
2018  for (size_t i = 0; i < coverage.ScriptCount(); i++) {
2019  debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
2020  Local<debug::Script> script = script_data.GetScript();
2021  // Skip unnamed scripts.
2022  Local<String> name;
2023  if (!script->Name().ToLocal(&name)) continue;
2024  std::string file_name = ToSTLString(isolate, name);
2025  // Skip scripts not backed by a file.
2026  if (!std::ifstream(file_name).good()) continue;
2027  sink << "SF:";
2028  sink << NormalizePath(file_name, GetWorkingDirectory()) << std::endl;
2029  std::vector<uint32_t> lines;
2030  for (size_t j = 0; j < script_data.FunctionCount(); j++) {
2031  debug::Coverage::FunctionData function_data =
2032  script_data.GetFunctionData(j);
2033 
2034  // Write function stats.
2035  {
2036  debug::Location start =
2037  script->GetSourceLocation(function_data.StartOffset());
2038  debug::Location end =
2039  script->GetSourceLocation(function_data.EndOffset());
2040  int start_line = start.GetLineNumber();
2041  int end_line = end.GetLineNumber();
2042  uint32_t count = function_data.Count();
2043 
2044  Local<String> name;
2045  std::stringstream name_stream;
2046  if (function_data.Name().ToLocal(&name)) {
2047  name_stream << ToSTLString(isolate, name);
2048  } else {
2049  name_stream << "<" << start_line + 1 << "-";
2050  name_stream << start.GetColumnNumber() << ">";
2051  }
2052 
2053  WriteLcovDataForNamedRange(sink, lines, name_stream.str(), start_line,
2054  end_line, count);
2055  }
2056 
2057  // Process inner blocks.
2058  for (size_t k = 0; k < function_data.BlockCount(); k++) {
2059  debug::Coverage::BlockData block_data = function_data.GetBlockData(k);
2060  int start_line = LineFromOffset(script, block_data.StartOffset());
2061  int end_line = LineFromOffset(script, block_data.EndOffset() - 1);
2062  uint32_t count = block_data.Count();
2063  WriteLcovDataForRange(lines, start_line, end_line, count);
2064  }
2065  }
2066  // Write per-line coverage. LCOV uses 1-based line numbers.
2067  for (size_t i = 0; i < lines.size(); i++) {
2068  sink << "DA:" << (i + 1) << "," << lines[i] << std::endl;
2069  }
2070  sink << "end_of_record" << std::endl;
2071  }
2072 }
2073 
2074 void Shell::OnExit(v8::Isolate* isolate) {
2075  // Dump basic block profiling data.
2076  if (i::FLAG_turbo_profiling) {
2077  i::BasicBlockProfiler* profiler = i::BasicBlockProfiler::Get();
2078  i::StdoutStream{} << *profiler;
2079  }
2080  isolate->Dispose();
2081 
2082  if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp) {
2083  const int number_of_counters = static_cast<int>(counter_map_->size());
2084  CounterAndKey* counters = new CounterAndKey[number_of_counters];
2085  int j = 0;
2086  for (auto map_entry : *counter_map_) {
2087  counters[j].counter = map_entry.second;
2088  counters[j].key = map_entry.first;
2089  j++;
2090  }
2091  std::sort(counters, counters + number_of_counters);
2092 
2093  if (i::FLAG_dump_counters_nvp) {
2094  // Dump counters as name-value pairs.
2095  for (j = 0; j < number_of_counters; j++) {
2096  Counter* counter = counters[j].counter;
2097  const char* key = counters[j].key;
2098  if (counter->is_histogram()) {
2099  printf("\"c:%s\"=%i\n", key, counter->count());
2100  printf("\"t:%s\"=%i\n", key, counter->sample_total());
2101  } else {
2102  printf("\"%s\"=%i\n", key, counter->count());
2103  }
2104  }
2105  } else {
2106  // Dump counters in formatted boxes.
2107  printf(
2108  "+----------------------------------------------------------------+"
2109  "-------------+\n");
2110  printf(
2111  "| Name |"
2112  " Value |\n");
2113  printf(
2114  "+----------------------------------------------------------------+"
2115  "-------------+\n");
2116  for (j = 0; j < number_of_counters; j++) {
2117  Counter* counter = counters[j].counter;
2118  const char* key = counters[j].key;
2119  if (counter->is_histogram()) {
2120  printf("| c:%-60s | %11i |\n", key, counter->count());
2121  printf("| t:%-60s | %11i |\n", key, counter->sample_total());
2122  } else {
2123  printf("| %-62s | %11i |\n", key, counter->count());
2124  }
2125  }
2126  printf(
2127  "+----------------------------------------------------------------+"
2128  "-------------+\n");
2129  }
2130  delete [] counters;
2131  }
2132 
2133  delete counters_file_;
2134  delete counter_map_;
2135 }
2136 
2137 
2138 static FILE* FOpen(const char* path, const char* mode) {
2139 #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
2140  FILE* result;
2141  if (fopen_s(&result, path, mode) == 0) {
2142  return result;
2143  } else {
2144  return nullptr;
2145  }
2146 #else
2147  FILE* file = fopen(path, mode);
2148  if (file == nullptr) return nullptr;
2149  struct stat file_stat;
2150  if (fstat(fileno(file), &file_stat) != 0) return nullptr;
2151  bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
2152  if (is_regular_file) return file;
2153  fclose(file);
2154  return nullptr;
2155 #endif
2156 }
2157 
2158 static char* ReadChars(const char* name, int* size_out) {
2159  if (Shell::options.read_from_tcp_port >= 0) {
2160  return Shell::ReadCharsFromTcpPort(name, size_out);
2161  }
2162 
2163  FILE* file = FOpen(name, "rb");
2164  if (file == nullptr) return nullptr;
2165 
2166  fseek(file, 0, SEEK_END);
2167  size_t size = ftell(file);
2168  rewind(file);
2169 
2170  char* chars = new char[size + 1];
2171  chars[size] = '\0';
2172  for (size_t i = 0; i < size;) {
2173  i += fread(&chars[i], 1, size - i, file);
2174  if (ferror(file)) {
2175  fclose(file);
2176  delete[] chars;
2177  return nullptr;
2178  }
2179  }
2180  fclose(file);
2181  *size_out = static_cast<int>(size);
2182  return chars;
2183 }
2184 
2185 
2187  uint8_t* data;
2188  int byte_length;
2189  Global<ArrayBuffer> handle;
2190 };
2191 
2192 
2193 static void ReadBufferWeakCallback(
2195  int byte_length = data.GetParameter()->byte_length;
2196  data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
2197  -static_cast<intptr_t>(byte_length));
2198 
2199  delete[] data.GetParameter()->data;
2200  data.GetParameter()->handle.Reset();
2201  delete data.GetParameter();
2202 }
2203 
2204 
2205 void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
2206  static_assert(sizeof(char) == sizeof(uint8_t),
2207  "char and uint8_t should both have 1 byte");
2208  Isolate* isolate = args.GetIsolate();
2209  String::Utf8Value filename(isolate, args[0]);
2210  int length;
2211  if (*filename == nullptr) {
2212  Throw(isolate, "Error loading file");
2213  return;
2214  }
2215 
2216  DataAndPersistent* data = new DataAndPersistent;
2217  data->data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
2218  if (data->data == nullptr) {
2219  delete data;
2220  Throw(isolate, "Error reading file");
2221  return;
2222  }
2223  data->byte_length = length;
2224  Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
2225  data->handle.Reset(isolate, buffer);
2226  data->handle.SetWeak(data, ReadBufferWeakCallback,
2227  v8::WeakCallbackType::kParameter);
2228  isolate->AdjustAmountOfExternalAllocatedMemory(length);
2229 
2230  args.GetReturnValue().Set(buffer);
2231 }
2232 
2233 // Reads a file into a v8 string.
2234 Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
2235  std::unique_ptr<base::OS::MemoryMappedFile> file(
2236  base::OS::MemoryMappedFile::open(name));
2237  if (!file) return Local<String>();
2238 
2239  int size = static_cast<int>(file->size());
2240  char* chars = static_cast<char*>(file->memory());
2241  Local<String> result;
2242  if (i::FLAG_use_external_strings && i::String::IsAscii(chars, size)) {
2243  String::ExternalOneByteStringResource* resource =
2244  new ExternalOwningOneByteStringResource(std::move(file));
2245  result = String::NewExternalOneByte(isolate, resource).ToLocalChecked();
2246  } else {
2247  result = String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
2248  .ToLocalChecked();
2249  }
2250  return result;
2251 }
2252 
2253 
2254 void Shell::RunShell(Isolate* isolate) {
2255  HandleScope outer_scope(isolate);
2256  v8::Local<v8::Context> context =
2257  v8::Local<v8::Context>::New(isolate, evaluation_context_);
2258  v8::Context::Scope context_scope(context);
2259  PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2260  Local<String> name =
2262  .ToLocalChecked();
2263  printf("V8 version %s\n", V8::GetVersion());
2264  while (true) {
2265  HandleScope inner_scope(isolate);
2266  printf("d8> ");
2267  Local<String> input = Shell::ReadFromStdin(isolate);
2268  if (input.IsEmpty()) break;
2269  ExecuteString(isolate, input, name, kPrintResult, kReportExceptions,
2270  kProcessMessageQueue);
2271  }
2272  printf("\n");
2273  // We need to explicitly clean up the module embedder data for
2274  // the interative shell context.
2275  DisposeModuleEmbedderData(context);
2276 }
2277 
2279  public:
2280  explicit InspectorFrontend(Local<Context> context) {
2281  isolate_ = context->GetIsolate();
2282  context_.Reset(isolate_, context);
2283  }
2284  ~InspectorFrontend() override = default;
2285 
2286  private:
2287  void sendResponse(
2288  int callId,
2289  std::unique_ptr<v8_inspector::StringBuffer> message) override {
2290  Send(message->string());
2291  }
2292  void sendNotification(
2293  std::unique_ptr<v8_inspector::StringBuffer> message) override {
2294  Send(message->string());
2295  }
2296  void flushProtocolNotifications() override {}
2297 
2298  void Send(const v8_inspector::StringView& string) {
2299  v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate_);
2300  int length = static_cast<int>(string.length());
2301  DCHECK_LT(length, v8::String::kMaxLength);
2302  Local<String> message =
2303  (string.is8Bit()
2305  isolate_,
2306  reinterpret_cast<const uint8_t*>(string.characters8()),
2309  isolate_,
2310  reinterpret_cast<const uint16_t*>(string.characters16()),
2311  v8::NewStringType::kNormal, length))
2312  .ToLocalChecked();
2313  Local<String> callback_name =
2315  .ToLocalChecked();
2316  Local<Context> context = context_.Get(isolate_);
2317  Local<Value> callback =
2318  context->Global()->Get(context, callback_name).ToLocalChecked();
2319  if (callback->IsFunction()) {
2320  v8::TryCatch try_catch(isolate_);
2321  Local<Value> args[] = {message};
2322  USE(Local<Function>::Cast(callback)->Call(context, Undefined(isolate_), 1,
2323  args));
2324 #ifdef DEBUG
2325  if (try_catch.HasCaught()) {
2326  Local<Object> exception = Local<Object>::Cast(try_catch.Exception());
2327  Local<String> key = v8::String::NewFromUtf8(isolate_, "message",
2329  .ToLocalChecked();
2330  Local<String> expected =
2331  v8::String::NewFromUtf8(isolate_,
2332  "Maximum call stack size exceeded",
2334  .ToLocalChecked();
2335  Local<Value> value = exception->Get(context, key).ToLocalChecked();
2336  DCHECK(value->StrictEquals(expected));
2337  }
2338 #endif
2339  }
2340  }
2341 
2342  Isolate* isolate_;
2343  Global<Context> context_;
2344 };
2345 
2347  public:
2348  InspectorClient(Local<Context> context, bool connect) {
2349  if (!connect) return;
2350  isolate_ = context->GetIsolate();
2351  channel_.reset(new InspectorFrontend(context));
2352  inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
2353  session_ =
2354  inspector_->connect(1, channel_.get(), v8_inspector::StringView());
2355  context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
2356  inspector_->contextCreated(v8_inspector::V8ContextInfo(
2357  context, kContextGroupId, v8_inspector::StringView()));
2358 
2359  Local<Value> function =
2360  FunctionTemplate::New(isolate_, SendInspectorMessage)
2361  ->GetFunction(context)
2362  .ToLocalChecked();
2363  Local<String> function_name =
2364  String::NewFromUtf8(isolate_, "send", NewStringType::kNormal)
2365  .ToLocalChecked();
2366  CHECK(context->Global()->Set(context, function_name, function).FromJust());
2367 
2368  context_.Reset(isolate_, context);
2369  }
2370 
2371  private:
2372  static v8_inspector::V8InspectorSession* GetSession(Local<Context> context) {
2373  InspectorClient* inspector_client = static_cast<InspectorClient*>(
2374  context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex));
2375  return inspector_client->session_.get();
2376  }
2377 
2378  Local<Context> ensureDefaultContextInGroup(int group_id) override {
2379  DCHECK(isolate_);
2380  DCHECK_EQ(kContextGroupId, group_id);
2381  return context_.Get(isolate_);
2382  }
2383 
2384  static void SendInspectorMessage(
2386  Isolate* isolate = args.GetIsolate();
2387  v8::HandleScope handle_scope(isolate);
2388  Local<Context> context = isolate->GetCurrentContext();
2389  args.GetReturnValue().Set(Undefined(isolate));
2390  Local<String> message = args[0]->ToString(context).ToLocalChecked();
2392  InspectorClient::GetSession(context);
2393  int length = message->Length();
2394  std::unique_ptr<uint16_t[]> buffer(new uint16_t[length]);
2395  message->Write(isolate, buffer.get(), 0, length);
2396  v8_inspector::StringView message_view(buffer.get(), length);
2397  session->dispatchProtocolMessage(message_view);
2398  args.GetReturnValue().Set(True(isolate));
2399  }
2400 
2401  static const int kContextGroupId = 1;
2402 
2403  std::unique_ptr<v8_inspector::V8Inspector> inspector_;
2404  std::unique_ptr<v8_inspector::V8InspectorSession> session_;
2405  std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
2406  Global<Context> context_;
2407  Isolate* isolate_;
2408 };
2409 
2410 SourceGroup::~SourceGroup() {
2411  delete thread_;
2412  thread_ = nullptr;
2413 }
2414 
2415 bool ends_with(const char* input, const char* suffix) {
2416  size_t input_length = strlen(input);
2417  size_t suffix_length = strlen(suffix);
2418  if (suffix_length <= input_length) {
2419  return strcmp(input + input_length - suffix_length, suffix) == 0;
2420  }
2421  return false;
2422 }
2423 
2424 void SourceGroup::Execute(Isolate* isolate) {
2425  bool exception_was_thrown = false;
2426  for (int i = begin_offset_; i < end_offset_; ++i) {
2427  const char* arg = argv_[i];
2428  if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
2429  // Execute argument given to -e option directly.
2430  HandleScope handle_scope(isolate);
2431  Local<String> file_name =
2432  String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
2433  .ToLocalChecked();
2434  Local<String> source =
2435  String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
2436  .ToLocalChecked();
2437  Shell::set_script_executed();
2438  if (!Shell::ExecuteString(isolate, source, file_name,
2439  Shell::kNoPrintResult, Shell::kReportExceptions,
2440  Shell::kNoProcessMessageQueue)) {
2441  exception_was_thrown = true;
2442  break;
2443  }
2444  ++i;
2445  continue;
2446  } else if (ends_with(arg, ".mjs")) {
2447  Shell::set_script_executed();
2448  if (!Shell::ExecuteModule(isolate, arg)) {
2449  exception_was_thrown = true;
2450  break;
2451  }
2452  continue;
2453  } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
2454  // Treat the next file as a module.
2455  arg = argv_[++i];
2456  Shell::set_script_executed();
2457  if (!Shell::ExecuteModule(isolate, arg)) {
2458  exception_was_thrown = true;
2459  break;
2460  }
2461  continue;
2462  } else if (arg[0] == '-') {
2463  // Ignore other options. They have been parsed already.
2464  continue;
2465  }
2466 
2467  // Use all other arguments as names of files to load and run.
2468  HandleScope handle_scope(isolate);
2469  Local<String> file_name =
2471  .ToLocalChecked();
2472  Local<String> source = ReadFile(isolate, arg);
2473  if (source.IsEmpty()) {
2474  printf("Error reading '%s'\n", arg);
2475  base::OS::ExitProcess(1);
2476  }
2477  Shell::set_script_executed();
2478  if (!Shell::ExecuteString(isolate, source, file_name, Shell::kNoPrintResult,
2479  Shell::kReportExceptions,
2480  Shell::kProcessMessageQueue)) {
2481  exception_was_thrown = true;
2482  break;
2483  }
2484  }
2485  if (exception_was_thrown != Shell::options.expected_to_throw) {
2486  base::OS::ExitProcess(1);
2487  }
2488 }
2489 
2490 Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
2491  return Shell::ReadFile(isolate, name);
2492 }
2493 
2494 SourceGroup::IsolateThread::IsolateThread(SourceGroup* group)
2495  : base::Thread(GetThreadOptions("IsolateThread")), group_(group) {}
2496 
2497 void SourceGroup::ExecuteInThread() {
2498  Isolate::CreateParams create_params;
2499  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
2500  Isolate* isolate = Isolate::New(create_params);
2501  isolate->SetHostImportModuleDynamicallyCallback(
2502  Shell::HostImportModuleDynamically);
2503  isolate->SetHostInitializeImportMetaObjectCallback(
2504  Shell::HostInitializeImportMetaObject);
2505  Shell::SetWaitUntilDone(isolate, false);
2506  D8Console console(isolate);
2507  debug::SetConsoleDelegate(isolate, &console);
2508  for (int i = 0; i < Shell::options.stress_runs; ++i) {
2509  next_semaphore_.Wait();
2510  {
2511  Isolate::Scope iscope(isolate);
2512  PerIsolateData data(isolate);
2513  {
2514  HandleScope scope(isolate);
2515  Local<Context> context = Shell::CreateEvaluationContext(isolate);
2516  {
2517  Context::Scope cscope(context);
2518  InspectorClient inspector_client(context,
2519  Shell::options.enable_inspector);
2520  PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2521  Execute(isolate);
2522  Shell::CompleteMessageLoop(isolate);
2523  }
2524  DisposeModuleEmbedderData(context);
2525  }
2526  Shell::CollectGarbage(isolate);
2527  }
2528  done_semaphore_.Signal();
2529  }
2530 
2531  isolate->Dispose();
2532 }
2533 
2534 
2535 void SourceGroup::StartExecuteInThread() {
2536  if (thread_ == nullptr) {
2537  thread_ = new IsolateThread(this);
2538  thread_->Start();
2539  }
2540  next_semaphore_.Signal();
2541 }
2542 
2543 
2544 void SourceGroup::WaitForThread() {
2545  if (thread_ == nullptr) return;
2546  done_semaphore_.Wait();
2547 }
2548 
2549 
2550 void SourceGroup::JoinThread() {
2551  if (thread_ == nullptr) return;
2552  thread_->Join();
2553 }
2554 
2555 ExternalizedContents::~ExternalizedContents() {
2556  if (data_ != nullptr) {
2557  deleter_(data_, length_, deleter_data_);
2558  }
2559 }
2560 
2561 void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) {
2562  base::MutexGuard lock_guard(&mutex_);
2563  data_.push_back(std::move(data));
2564 }
2565 
2566 bool SerializationDataQueue::Dequeue(
2567  std::unique_ptr<SerializationData>* out_data) {
2568  out_data->reset();
2569  base::MutexGuard lock_guard(&mutex_);
2570  if (data_.empty()) return false;
2571  *out_data = std::move(data_[0]);
2572  data_.erase(data_.begin());
2573  return true;
2574 }
2575 
2576 
2577 bool SerializationDataQueue::IsEmpty() {
2578  base::MutexGuard lock_guard(&mutex_);
2579  return data_.empty();
2580 }
2581 
2582 
2583 void SerializationDataQueue::Clear() {
2584  base::MutexGuard lock_guard(&mutex_);
2585  data_.clear();
2586 }
2587 
2588 Worker::Worker()
2589  : in_semaphore_(0),
2590  out_semaphore_(0),
2591  thread_(nullptr),
2592  script_(nullptr),
2593  running_(false) {}
2594 
2595 Worker::~Worker() {
2596  delete thread_;
2597  thread_ = nullptr;
2598  delete[] script_;
2599  script_ = nullptr;
2600  in_queue_.Clear();
2601  out_queue_.Clear();
2602 }
2603 
2604 
2605 void Worker::StartExecuteInThread(const char* script) {
2606  running_ = true;
2607  script_ = i::StrDup(script);
2608  thread_ = new WorkerThread(this);
2609  thread_->Start();
2610 }
2611 
2612 void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
2613  in_queue_.Enqueue(std::move(data));
2614  in_semaphore_.Signal();
2615 }
2616 
2617 std::unique_ptr<SerializationData> Worker::GetMessage() {
2618  std::unique_ptr<SerializationData> result;
2619  while (!out_queue_.Dequeue(&result)) {
2620  // If the worker is no longer running, and there are no messages in the
2621  // queue, don't expect any more messages from it.
2622  if (!base::Relaxed_Load(&running_)) break;
2623  out_semaphore_.Wait();
2624  }
2625  return result;
2626 }
2627 
2628 
2629 void Worker::Terminate() {
2630  base::Relaxed_Store(&running_, false);
2631  // Post nullptr to wake the Worker thread message loop, and tell it to stop
2632  // running.
2633  PostMessage(nullptr);
2634 }
2635 
2636 
2637 void Worker::WaitForThread() {
2638  Terminate();
2639  thread_->Join();
2640 }
2641 
2642 
2643 void Worker::ExecuteInThread() {
2644  Isolate::CreateParams create_params;
2645  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
2646  Isolate* isolate = Isolate::New(create_params);
2647  isolate->SetHostImportModuleDynamicallyCallback(
2648  Shell::HostImportModuleDynamically);
2649  isolate->SetHostInitializeImportMetaObjectCallback(
2650  Shell::HostInitializeImportMetaObject);
2651  D8Console console(isolate);
2652  debug::SetConsoleDelegate(isolate, &console);
2653  {
2654  Isolate::Scope iscope(isolate);
2655  {
2656  HandleScope scope(isolate);
2657  PerIsolateData data(isolate);
2658  Local<Context> context = Shell::CreateEvaluationContext(isolate);
2659  {
2660  Context::Scope cscope(context);
2661  PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2662 
2663  Local<Object> global = context->Global();
2664  Local<Value> this_value = External::New(isolate, this);
2665  Local<FunctionTemplate> postmessage_fun_template =
2666  FunctionTemplate::New(isolate, PostMessageOut, this_value);
2667 
2668  Local<Function> postmessage_fun;
2669  if (postmessage_fun_template->GetFunction(context)
2670  .ToLocal(&postmessage_fun)) {
2671  global->Set(context, String::NewFromUtf8(isolate, "postMessage",
2673  .ToLocalChecked(),
2674  postmessage_fun).FromJust();
2675  }
2676 
2677  // First run the script
2678  Local<String> file_name =
2679  String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
2680  .ToLocalChecked();
2681  Local<String> source =
2682  String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
2683  .ToLocalChecked();
2684  if (Shell::ExecuteString(
2685  isolate, source, file_name, Shell::kNoPrintResult,
2686  Shell::kReportExceptions, Shell::kProcessMessageQueue)) {
2687  // Get the message handler
2688  Local<Value> onmessage =
2689  global->Get(context, String::NewFromUtf8(isolate, "onmessage",
2691  .ToLocalChecked()).ToLocalChecked();
2692  if (onmessage->IsFunction()) {
2693  Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
2694  // Now wait for messages
2695  while (true) {
2696  in_semaphore_.Wait();
2697  std::unique_ptr<SerializationData> data;
2698  if (!in_queue_.Dequeue(&data)) continue;
2699  if (!data) {
2700  break;
2701  }
2702  v8::TryCatch try_catch(isolate);
2703  Local<Value> value;
2704  if (Shell::DeserializeValue(isolate, std::move(data))
2705  .ToLocal(&value)) {
2706  Local<Value> argv[] = {value};
2707  MaybeLocal<Value> result =
2708  onmessage_fun->Call(context, global, 1, argv);
2709  USE(result);
2710  }
2711  if (try_catch.HasCaught()) {
2712  Shell::ReportException(isolate, &try_catch);
2713  }
2714  }
2715  }
2716  }
2717  }
2718  DisposeModuleEmbedderData(context);
2719  }
2720  Shell::CollectGarbage(isolate);
2721  }
2722  isolate->Dispose();
2723 
2724  // Post nullptr to wake the thread waiting on GetMessage() if there is one.
2725  out_queue_.Enqueue(nullptr);
2726  out_semaphore_.Signal();
2727 }
2728 
2729 
2730 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
2731  Isolate* isolate = args.GetIsolate();
2732  HandleScope handle_scope(isolate);
2733 
2734  if (args.Length() < 1) {
2735  Throw(isolate, "Invalid argument");
2736  return;
2737  }
2738 
2739  Local<Value> message = args[0];
2740  Local<Value> transfer = Undefined(isolate);
2741  std::unique_ptr<SerializationData> data =
2742  Shell::SerializeValue(isolate, message, transfer);
2743  if (data) {
2744  DCHECK(args.Data()->IsExternal());
2745  Local<External> this_value = Local<External>::Cast(args.Data());
2746  Worker* worker = static_cast<Worker*>(this_value->Value());
2747  worker->out_queue_.Enqueue(std::move(data));
2748  worker->out_semaphore_.Signal();
2749  }
2750 }
2751 
2752 
2753 void SetFlagsFromString(const char* flags) {
2754  v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
2755 }
2756 
2757 
2758 bool Shell::SetOptions(int argc, char* argv[]) {
2759  bool logfile_per_isolate = false;
2760  for (int i = 0; i < argc; i++) {
2761  if (strcmp(argv[i], "--") == 0) {
2762  argv[i] = nullptr;
2763  for (int j = i + 1; j < argc; j++) {
2764  options.arguments.push_back(argv[j]);
2765  argv[j] = nullptr;
2766  }
2767  break;
2768  } else if (strcmp(argv[i], "--no-arguments") == 0) {
2769  options.include_arguments = false;
2770  argv[i] = nullptr;
2771  } else if (strcmp(argv[i], "--stress-opt") == 0) {
2772  options.stress_opt = true;
2773  argv[i] = nullptr;
2774  } else if (strcmp(argv[i], "--nostress-opt") == 0 ||
2775  strcmp(argv[i], "--no-stress-opt") == 0) {
2776  options.stress_opt = false;
2777  argv[i] = nullptr;
2778  } else if (strcmp(argv[i], "--stress-deopt") == 0) {
2779  options.stress_deopt = true;
2780  argv[i] = nullptr;
2781  } else if (strcmp(argv[i], "--stress-background-compile") == 0) {
2782  options.stress_background_compile = true;
2783  argv[i] = nullptr;
2784  } else if (strcmp(argv[i], "--nostress-background-compile") == 0 ||
2785  strcmp(argv[i], "--no-stress-background-compile") == 0) {
2786  options.stress_background_compile = false;
2787  argv[i] = nullptr;
2788  } else if (strcmp(argv[i], "--noalways-opt") == 0 ||
2789  strcmp(argv[i], "--no-always-opt") == 0) {
2790  // No support for stressing if we can't use --always-opt.
2791  options.stress_opt = false;
2792  options.stress_deopt = false;
2793  } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
2794  logfile_per_isolate = true;
2795  argv[i] = nullptr;
2796  } else if (strcmp(argv[i], "--shell") == 0) {
2797  options.interactive_shell = true;
2798  argv[i] = nullptr;
2799  } else if (strcmp(argv[i], "--test") == 0) {
2800  options.test_shell = true;
2801  argv[i] = nullptr;
2802  } else if (strcmp(argv[i], "--notest") == 0 ||
2803  strcmp(argv[i], "--no-test") == 0) {
2804  options.test_shell = false;
2805  argv[i] = nullptr;
2806  } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
2807  options.send_idle_notification = true;
2808  argv[i] = nullptr;
2809  } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
2810  options.invoke_weak_callbacks = true;
2811  // TODO(jochen) See issue 3351
2812  options.send_idle_notification = true;
2813  argv[i] = nullptr;
2814  } else if (strcmp(argv[i], "--omit-quit") == 0) {
2815  options.omit_quit = true;
2816  argv[i] = nullptr;
2817  } else if (strcmp(argv[i], "--no-wait-for-wasm") == 0) {
2818  // TODO(herhut) Remove this flag once wasm compilation is fully
2819  // isolate-independent.
2820  options.wait_for_wasm = false;
2821  argv[i] = nullptr;
2822  } else if (strcmp(argv[i], "-f") == 0) {
2823  // Ignore any -f flags for compatibility with other stand-alone
2824  // JavaScript engines.
2825  continue;
2826  } else if (strcmp(argv[i], "--isolate") == 0) {
2827  options.num_isolates++;
2828  } else if (strcmp(argv[i], "--throws") == 0) {
2829  options.expected_to_throw = true;
2830  argv[i] = nullptr;
2831  } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
2832  options.icu_data_file = argv[i] + 16;
2833  argv[i] = nullptr;
2834 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
2835  } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
2836  options.natives_blob = argv[i] + 15;
2837  argv[i] = nullptr;
2838  } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
2839  options.snapshot_blob = argv[i] + 16;
2840  argv[i] = nullptr;
2841 #endif // V8_USE_EXTERNAL_STARTUP_DATA
2842  } else if (strcmp(argv[i], "--cache") == 0 ||
2843  strncmp(argv[i], "--cache=", 8) == 0) {
2844  const char* value = argv[i] + 7;
2845  if (!*value || strncmp(value, "=code", 6) == 0) {
2846  options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
2847  options.code_cache_options =
2848  ShellOptions::CodeCacheOptions::kProduceCache;
2849  } else if (strncmp(value, "=none", 6) == 0) {
2850  options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
2851  options.code_cache_options =
2852  ShellOptions::CodeCacheOptions::kNoProduceCache;
2853  } else if (strncmp(value, "=after-execute", 15) == 0) {
2854  options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
2855  options.code_cache_options =
2856  ShellOptions::CodeCacheOptions::kProduceCacheAfterExecute;
2857  } else if (strncmp(value, "=full-code-cache", 17) == 0) {
2858  options.compile_options = v8::ScriptCompiler::kEagerCompile;
2859  options.code_cache_options =
2860  ShellOptions::CodeCacheOptions::kProduceCache;
2861  } else {
2862  printf("Unknown option to --cache.\n");
2863  return false;
2864  }
2865  argv[i] = nullptr;
2866  } else if (strcmp(argv[i], "--enable-tracing") == 0) {
2867  options.trace_enabled = true;
2868  argv[i] = nullptr;
2869  } else if (strncmp(argv[i], "--trace-path=", 13) == 0) {
2870  options.trace_path = argv[i] + 13;
2871  argv[i] = nullptr;
2872  } else if (strncmp(argv[i], "--trace-config=", 15) == 0) {
2873  options.trace_config = argv[i] + 15;
2874  argv[i] = nullptr;
2875  } else if (strcmp(argv[i], "--enable-inspector") == 0) {
2876  options.enable_inspector = true;
2877  argv[i] = nullptr;
2878  } else if (strncmp(argv[i], "--lcov=", 7) == 0) {
2879  options.lcov_file = argv[i] + 7;
2880  argv[i] = nullptr;
2881  } else if (strcmp(argv[i], "--disable-in-process-stack-traces") == 0) {
2882  options.disable_in_process_stack_traces = true;
2883  argv[i] = nullptr;
2884 #ifdef V8_OS_POSIX
2885  } else if (strncmp(argv[i], "--read-from-tcp-port=", 21) == 0) {
2886  options.read_from_tcp_port = atoi(argv[i] + 21);
2887  argv[i] = nullptr;
2888 #endif // V8_OS_POSIX
2889  } else if (strcmp(argv[i], "--enable-os-system") == 0) {
2890  options.enable_os_system = true;
2891  argv[i] = nullptr;
2892  } else if (strcmp(argv[i], "--quiet-load") == 0) {
2893  options.quiet_load = true;
2894  argv[i] = nullptr;
2895  } else if (strncmp(argv[i], "--thread-pool-size=", 19) == 0) {
2896  options.thread_pool_size = atoi(argv[i] + 19);
2897  argv[i] = nullptr;
2898  } else if (strcmp(argv[i], "--stress-delay-tasks") == 0) {
2899  // Delay execution of tasks by 0-100ms randomly (based on --random-seed).
2900  options.stress_delay_tasks = true;
2901  argv[i] = nullptr;
2902  }
2903  }
2904 
2905  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
2906  options.mock_arraybuffer_allocator = i::FLAG_mock_arraybuffer_allocator;
2907  options.mock_arraybuffer_allocator_limit =
2908  i::FLAG_mock_arraybuffer_allocator_limit;
2909 
2910  // Set up isolated source groups.
2911  options.isolate_sources = new SourceGroup[options.num_isolates];
2912  SourceGroup* current = options.isolate_sources;
2913  current->Begin(argv, 1);
2914  for (int i = 1; i < argc; i++) {
2915  const char* str = argv[i];
2916  if (strcmp(str, "--isolate") == 0) {
2917  current->End(i);
2918  current++;
2919  current->Begin(argv, i + 1);
2920  } else if (strcmp(str, "--module") == 0) {
2921  // Pass on to SourceGroup, which understands this option.
2922  } else if (strncmp(str, "--", 2) == 0) {
2923  printf("Warning: unknown flag %s.\nTry --help for options\n", str);
2924  } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
2925  set_script_executed();
2926  } else if (strncmp(str, "-", 1) != 0) {
2927  // Not a flag, so it must be a script to execute.
2928  set_script_executed();
2929  }
2930  }
2931  current->End(argc);
2932 
2933  if (!logfile_per_isolate && options.num_isolates) {
2934  SetFlagsFromString("--nologfile_per_isolate");
2935  }
2936 
2937  return true;
2938 }
2939 
2940 int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
2941  for (int i = 1; i < options.num_isolates; ++i) {
2942  options.isolate_sources[i].StartExecuteInThread();
2943  }
2944  {
2945  SetWaitUntilDone(isolate, false);
2946  if (options.lcov_file) {
2947  debug::Coverage::SelectMode(isolate, debug::Coverage::kBlockCount);
2948  }
2949  HandleScope scope(isolate);
2950  Local<Context> context = CreateEvaluationContext(isolate);
2951  bool use_existing_context = last_run && use_interactive_shell();
2952  if (use_existing_context) {
2953  // Keep using the same context in the interactive shell.
2954  evaluation_context_.Reset(isolate, context);
2955  }
2956  {
2957  Context::Scope cscope(context);
2958  InspectorClient inspector_client(context, options.enable_inspector);
2959  PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2960  options.isolate_sources[0].Execute(isolate);
2961  CompleteMessageLoop(isolate);
2962  }
2963  if (!use_existing_context) {
2964  DisposeModuleEmbedderData(context);
2965  }
2966  WriteLcovData(isolate, options.lcov_file);
2967  }
2968  CollectGarbage(isolate);
2969  for (int i = 1; i < options.num_isolates; ++i) {
2970  if (last_run) {
2971  options.isolate_sources[i].JoinThread();
2972  } else {
2973  options.isolate_sources[i].WaitForThread();
2974  }
2975  }
2976  CleanupWorkers();
2977  return 0;
2978 }
2979 
2980 
2981 void Shell::CollectGarbage(Isolate* isolate) {
2982  if (options.send_idle_notification) {
2983  const double kLongIdlePauseInSeconds = 1.0;
2984  isolate->ContextDisposedNotification();
2985  isolate->IdleNotificationDeadline(
2986  g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
2987  }
2988  if (options.invoke_weak_callbacks) {
2989  // By sending a low memory notifications, we will try hard to collect all
2990  // garbage and will therefore also invoke all weak callbacks of actually
2991  // unreachable persistent handles.
2992  isolate->LowMemoryNotification();
2993  }
2994 }
2995 
2996 void Shell::SetWaitUntilDone(Isolate* isolate, bool value) {
2997  base::MutexGuard guard(isolate_status_lock_.Pointer());
2998  if (isolate_status_.count(isolate) == 0) {
2999  isolate_status_.insert(std::make_pair(isolate, value));
3000  } else {
3001  isolate_status_[isolate] = value;
3002  }
3003 }
3004 
3005 namespace {
3006 bool ProcessMessages(
3007  Isolate* isolate,
3008  const std::function<platform::MessageLoopBehavior()>& behavior) {
3009  while (true) {
3010  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3011  i::SaveContext saved_context(i_isolate);
3012  i_isolate->set_context(i::Context());
3013  SealHandleScope shs(isolate);
3014  while (v8::platform::PumpMessageLoop(g_default_platform, isolate,
3015  behavior())) {
3016  isolate->RunMicrotasks();
3017  }
3018  if (g_default_platform->IdleTasksEnabled(isolate)) {
3019  v8::platform::RunIdleTasks(g_default_platform, isolate,
3020  50.0 / base::Time::kMillisecondsPerSecond);
3021  }
3022  HandleScope handle_scope(isolate);
3023  PerIsolateData* data = PerIsolateData::Get(isolate);
3024  Local<Function> callback;
3025  if (!data->GetTimeoutCallback().ToLocal(&callback)) break;
3026  Local<Context> context;
3027  if (!data->GetTimeoutContext().ToLocal(&context)) break;
3028  TryCatch try_catch(isolate);
3029  try_catch.SetVerbose(true);
3030  Context::Scope context_scope(context);
3031  if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) {
3032  Shell::ReportException(isolate, &try_catch);
3033  return false;
3034  }
3035  }
3036  return true;
3037 }
3038 } // anonymous namespace
3039 
3040 void Shell::CompleteMessageLoop(Isolate* isolate) {
3041  auto get_waiting_behaviour = [isolate]() {
3042  base::MutexGuard guard(isolate_status_lock_.Pointer());
3043  DCHECK_GT(isolate_status_.count(isolate), 0);
3044  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3045  i::wasm::WasmEngine* wasm_engine = i_isolate->wasm_engine();
3046  bool should_wait = (options.wait_for_wasm &&
3047  wasm_engine->HasRunningCompileJob(i_isolate)) ||
3048  isolate_status_[isolate];
3049  return should_wait ? platform::MessageLoopBehavior::kWaitForWork
3050  : platform::MessageLoopBehavior::kDoNotWait;
3051  };
3052  ProcessMessages(isolate, get_waiting_behaviour);
3053 }
3054 
3055 bool Shell::EmptyMessageQueues(Isolate* isolate) {
3056  return ProcessMessages(
3057  isolate, []() { return platform::MessageLoopBehavior::kDoNotWait; });
3058 }
3059 
3061  public:
3062  explicit Serializer(Isolate* isolate)
3063  : isolate_(isolate),
3064  serializer_(isolate, this),
3065  current_memory_usage_(0) {}
3066 
3067  Maybe<bool> WriteValue(Local<Context> context, Local<Value> value,
3068  Local<Value> transfer) {
3069  bool ok;
3070  DCHECK(!data_);
3071  data_.reset(new SerializationData);
3072  if (!PrepareTransfer(context, transfer).To(&ok)) {
3073  return Nothing<bool>();
3074  }
3075  serializer_.WriteHeader();
3076 
3077  if (!serializer_.WriteValue(context, value).To(&ok)) {
3078  data_.reset();
3079  return Nothing<bool>();
3080  }
3081 
3082  if (!FinalizeTransfer().To(&ok)) {
3083  return Nothing<bool>();
3084  }
3085 
3086  std::pair<uint8_t*, size_t> pair = serializer_.Release();
3087  data_->data_.reset(pair.first);
3088  data_->size_ = pair.second;
3089  return Just(true);
3090  }
3091 
3092  std::unique_ptr<SerializationData> Release() { return std::move(data_); }
3093 
3094  void AppendExternalizedContentsTo(std::vector<ExternalizedContents>* to) {
3095  to->insert(to->end(),
3096  std::make_move_iterator(externalized_contents_.begin()),
3097  std::make_move_iterator(externalized_contents_.end()));
3098  externalized_contents_.clear();
3099  }
3100 
3101  protected:
3102  // Implements ValueSerializer::Delegate.
3103  void ThrowDataCloneError(Local<String> message) override {
3104  isolate_->ThrowException(Exception::Error(message));
3105  }
3106 
3108  Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override {
3109  DCHECK_NOT_NULL(data_);
3110  for (size_t index = 0; index < shared_array_buffers_.size(); ++index) {
3111  if (shared_array_buffers_[index] == shared_array_buffer) {
3112  return Just<uint32_t>(static_cast<uint32_t>(index));
3113  }
3114  }
3115 
3116  size_t index = shared_array_buffers_.size();
3117  shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
3118  data_->shared_array_buffer_contents_.push_back(
3119  MaybeExternalize(shared_array_buffer));
3120  return Just<uint32_t>(static_cast<uint32_t>(index));
3121  }
3122 
3123  Maybe<uint32_t> GetWasmModuleTransferId(
3124  Isolate* isolate, Local<WasmCompiledModule> module) override {
3125  DCHECK_NOT_NULL(data_);
3126  for (size_t index = 0; index < wasm_modules_.size(); ++index) {
3127  if (wasm_modules_[index] == module) {
3128  return Just<uint32_t>(static_cast<uint32_t>(index));
3129  }
3130  }
3131 
3132  size_t index = wasm_modules_.size();
3133  wasm_modules_.emplace_back(isolate_, module);
3134  data_->transferrable_modules_.push_back(module->GetTransferrableModule());
3135  return Just<uint32_t>(static_cast<uint32_t>(index));
3136  }
3137 
3138  void* ReallocateBufferMemory(void* old_buffer, size_t size,
3139  size_t* actual_size) override {
3140  // Not accurate, because we don't take into account reallocated buffers,
3141  // but this is fine for testing.
3142  current_memory_usage_ += size;
3143  if (current_memory_usage_ > kMaxSerializerMemoryUsage) return nullptr;
3144 
3145  void* result = realloc(old_buffer, size);
3146  *actual_size = result ? size : 0;
3147  return result;
3148  }
3149 
3150  void FreeBufferMemory(void* buffer) override { free(buffer); }
3151 
3152  private:
3153  Maybe<bool> PrepareTransfer(Local<Context> context, Local<Value> transfer) {
3154  if (transfer->IsArray()) {
3155  Local<Array> transfer_array = Local<Array>::Cast(transfer);
3156  uint32_t length = transfer_array->Length();
3157  for (uint32_t i = 0; i < length; ++i) {
3158  Local<Value> element;
3159  if (transfer_array->Get(context, i).ToLocal(&element)) {
3160  if (!element->IsArrayBuffer()) {
3161  Throw(isolate_, "Transfer array elements must be an ArrayBuffer");
3162  return Nothing<bool>();
3163  }
3164 
3165  Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(element);
3166 
3167  if (std::find(array_buffers_.begin(), array_buffers_.end(),
3168  array_buffer) != array_buffers_.end()) {
3169  Throw(isolate_,
3170  "ArrayBuffer occurs in the transfer array more than once");
3171  return Nothing<bool>();
3172  }
3173 
3174  serializer_.TransferArrayBuffer(
3175  static_cast<uint32_t>(array_buffers_.size()), array_buffer);
3176  array_buffers_.emplace_back(isolate_, array_buffer);
3177  } else {
3178  return Nothing<bool>();
3179  }
3180  }
3181  return Just(true);
3182  } else if (transfer->IsUndefined()) {
3183  return Just(true);
3184  } else {
3185  Throw(isolate_, "Transfer list must be an Array or undefined");
3186  return Nothing<bool>();
3187  }
3188  }
3189 
3190  template <typename T>
3191  typename T::Contents MaybeExternalize(Local<T> array_buffer) {
3192  if (array_buffer->IsExternal()) {
3193  return array_buffer->GetContents();
3194  } else {
3195  typename T::Contents contents = array_buffer->Externalize();
3196  externalized_contents_.emplace_back(contents);
3197  return contents;
3198  }
3199  }
3200 
3201  Maybe<bool> FinalizeTransfer() {
3202  for (const auto& global_array_buffer : array_buffers_) {
3203  Local<ArrayBuffer> array_buffer =
3204  Local<ArrayBuffer>::New(isolate_, global_array_buffer);
3205  if (!array_buffer->IsNeuterable()) {
3206  Throw(isolate_, "ArrayBuffer could not be transferred");
3207  return Nothing<bool>();
3208  }
3209 
3210  ArrayBuffer::Contents contents = MaybeExternalize(array_buffer);
3211  array_buffer->Neuter();
3212  data_->array_buffer_contents_.push_back(contents);
3213  }
3214 
3215  return Just(true);
3216  }
3217 
3218  Isolate* isolate_;
3219  ValueSerializer serializer_;
3220  std::unique_ptr<SerializationData> data_;
3221  std::vector<Global<ArrayBuffer>> array_buffers_;
3222  std::vector<Global<SharedArrayBuffer>> shared_array_buffers_;
3223  std::vector<Global<WasmCompiledModule>> wasm_modules_;
3224  std::vector<ExternalizedContents> externalized_contents_;
3225  size_t current_memory_usage_;
3226 
3227  DISALLOW_COPY_AND_ASSIGN(Serializer);
3228 };
3229 
3231  public:
3232  Deserializer(Isolate* isolate, std::unique_ptr<SerializationData> data)
3233  : isolate_(isolate),
3234  deserializer_(isolate, data->data(), data->size(), this),
3235  data_(std::move(data)) {
3236  deserializer_.SetSupportsLegacyWireFormat(true);
3237  }
3238 
3239  MaybeLocal<Value> ReadValue(Local<Context> context) {
3240  bool read_header;
3241  if (!deserializer_.ReadHeader(context).To(&read_header)) {
3242  return MaybeLocal<Value>();
3243  }
3244 
3245  uint32_t index = 0;
3246  for (const auto& contents : data_->array_buffer_contents()) {
3247  Local<ArrayBuffer> array_buffer =
3248  ArrayBuffer::New(isolate_, contents.Data(), contents.ByteLength());
3249  deserializer_.TransferArrayBuffer(index++, array_buffer);
3250  }
3251 
3252  return deserializer_.ReadValue(context);
3253  }
3254 
3256  Isolate* isolate, uint32_t clone_id) override {
3257  DCHECK_NOT_NULL(data_);
3258  if (clone_id < data_->shared_array_buffer_contents().size()) {
3259  SharedArrayBuffer::Contents contents =
3260  data_->shared_array_buffer_contents().at(clone_id);
3261  return SharedArrayBuffer::New(isolate_, contents.Data(),
3262  contents.ByteLength());
3263  }
3265  }
3266 
3268  Isolate* isolate, uint32_t transfer_id) override {
3269  DCHECK_NOT_NULL(data_);
3270  if (transfer_id < data_->transferrable_modules().size()) {
3272  isolate_, data_->transferrable_modules().at(transfer_id));
3273  }
3275  }
3276 
3277  private:
3278  Isolate* isolate_;
3279  ValueDeserializer deserializer_;
3280  std::unique_ptr<SerializationData> data_;
3281 
3282  DISALLOW_COPY_AND_ASSIGN(Deserializer);
3283 };
3284 
3285 std::unique_ptr<SerializationData> Shell::SerializeValue(
3286  Isolate* isolate, Local<Value> value, Local<Value> transfer) {
3287  bool ok;
3288  Local<Context> context = isolate->GetCurrentContext();
3289  Serializer serializer(isolate);
3290  std::unique_ptr<SerializationData> data;
3291  if (serializer.WriteValue(context, value, transfer).To(&ok)) {
3292  data = serializer.Release();
3293  }
3294  // Append externalized contents even when WriteValue fails.
3295  base::MutexGuard lock_guard(workers_mutex_.Pointer());
3296  serializer.AppendExternalizedContentsTo(&externalized_contents_);
3297  return data;
3298 }
3299 
3300 MaybeLocal<Value> Shell::DeserializeValue(
3301  Isolate* isolate, std::unique_ptr<SerializationData> data) {
3302  Local<Value> value;
3303  Local<Context> context = isolate->GetCurrentContext();
3304  Deserializer deserializer(isolate, std::move(data));
3305  return deserializer.ReadValue(context);
3306 }
3307 
3308 
3309 void Shell::CleanupWorkers() {
3310  // Make a copy of workers_, because we don't want to call Worker::Terminate
3311  // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
3312  // create a new Worker, it would deadlock.
3313  std::vector<Worker*> workers_copy;
3314  {
3315  base::MutexGuard lock_guard(workers_mutex_.Pointer());
3316  allow_new_workers_ = false;
3317  workers_copy.swap(workers_);
3318  }
3319 
3320  for (Worker* worker : workers_copy) {
3321  worker->WaitForThread();
3322  delete worker;
3323  }
3324 
3325  // Now that all workers are terminated, we can re-enable Worker creation.
3326  base::MutexGuard lock_guard(workers_mutex_.Pointer());
3327  allow_new_workers_ = true;
3328  externalized_contents_.clear();
3329 }
3330 
3331 int Shell::Main(int argc, char* argv[]) {
3332  std::ofstream trace_file;
3333  v8::base::EnsureConsoleOutput();
3334  if (!SetOptions(argc, argv)) return 1;
3335  v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
3336 
3337  v8::platform::InProcessStackDumping in_process_stack_dumping =
3338  options.disable_in_process_stack_traces
3339  ? v8::platform::InProcessStackDumping::kDisabled
3340  : v8::platform::InProcessStackDumping::kEnabled;
3341 
3342  std::unique_ptr<platform::tracing::TracingController> tracing;
3343  if (options.trace_enabled && !i::FLAG_verify_predictable) {
3344  tracing = base::make_unique<platform::tracing::TracingController>();
3345 
3346  trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json");
3347  platform::tracing::TraceBuffer* trace_buffer =
3348  platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
3349  platform::tracing::TraceBuffer::kRingBufferChunks,
3350  platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
3351  tracing->Initialize(trace_buffer);
3352  }
3353 
3354  platform::tracing::TracingController* tracing_controller = tracing.get();
3355  g_platform = v8::platform::NewDefaultPlatform(
3356  options.thread_pool_size, v8::platform::IdleTaskSupport::kEnabled,
3357  in_process_stack_dumping, std::move(tracing));
3358  g_default_platform = g_platform.get();
3359  if (i::FLAG_verify_predictable) {
3360  g_platform = MakePredictablePlatform(std::move(g_platform));
3361  }
3362  if (options.stress_delay_tasks) {
3363  int64_t random_seed = i::FLAG_fuzzer_random_seed;
3364  if (!random_seed) random_seed = i::FLAG_random_seed;
3365  // If random_seed is still 0 here, the {DelayedTasksPlatform} will choose a
3366  // random seed.
3367  g_platform = MakeDelayedTasksPlatform(std::move(g_platform), random_seed);
3368  }
3369 
3370  if (i::FLAG_trace_turbo_cfg_file == nullptr) {
3371  SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
3372  }
3373  if (i::FLAG_redirect_code_traces_to == nullptr) {
3374  SetFlagsFromString("--redirect-code-traces-to=code.asm");
3375  }
3376  v8::V8::InitializePlatform(g_platform.get());
3377  v8::V8::Initialize();
3378  if (options.natives_blob || options.snapshot_blob) {
3379  v8::V8::InitializeExternalStartupData(options.natives_blob,
3380  options.snapshot_blob);
3381  } else {
3382  v8::V8::InitializeExternalStartupData(argv[0]);
3383  }
3384  int result = 0;
3385  Isolate::CreateParams create_params;
3386  ShellArrayBufferAllocator shell_array_buffer_allocator;
3387  MockArrayBufferAllocator mock_arraybuffer_allocator;
3388  const size_t memory_limit =
3389  options.mock_arraybuffer_allocator_limit * options.num_isolates;
3390  MockArrayBufferAllocatiorWithLimit mock_arraybuffer_allocator_with_limit(
3391  memory_limit >= options.mock_arraybuffer_allocator_limit
3392  ? memory_limit
3393  : std::numeric_limits<size_t>::max());
3394  if (options.mock_arraybuffer_allocator) {
3395  if (memory_limit) {
3396  Shell::array_buffer_allocator = &mock_arraybuffer_allocator_with_limit;
3397  } else {
3398  Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
3399  }
3400  } else {
3401  Shell::array_buffer_allocator = &shell_array_buffer_allocator;
3402  }
3403  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
3404 #ifdef ENABLE_VTUNE_JIT_INTERFACE
3405  create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
3406 #endif
3407  create_params.constraints.ConfigureDefaults(
3408  base::SysInfo::AmountOfPhysicalMemory(),
3409  base::SysInfo::AmountOfVirtualMemory());
3410 
3411  Shell::counter_map_ = new CounterMap();
3412  if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp || i::FLAG_gc_stats) {
3413  create_params.counter_lookup_callback = LookupCounter;
3414  create_params.create_histogram_callback = CreateHistogram;
3415  create_params.add_histogram_sample_callback = AddHistogramSample;
3416  }
3417 
3418  if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
3419  constexpr bool use_default_trap_handler = true;
3420  if (!v8::V8::EnableWebAssemblyTrapHandler(use_default_trap_handler)) {
3421  FATAL("Could not register trap handler");
3422  }
3423  }
3424 
3425  Isolate* isolate = Isolate::New(create_params);
3426  isolate->SetHostImportModuleDynamicallyCallback(
3427  Shell::HostImportModuleDynamically);
3428  isolate->SetHostInitializeImportMetaObjectCallback(
3429  Shell::HostInitializeImportMetaObject);
3430 
3431  D8Console console(isolate);
3432  {
3433  Isolate::Scope scope(isolate);
3434  Initialize(isolate);
3435  PerIsolateData data(isolate);
3436  debug::SetConsoleDelegate(isolate, &console);
3437 
3438  if (options.trace_enabled) {
3439  platform::tracing::TraceConfig* trace_config;
3440  if (options.trace_config) {
3441  int size = 0;
3442  char* trace_config_json_str = ReadChars(options.trace_config, &size);
3443  trace_config =
3444  tracing::CreateTraceConfigFromJSON(isolate, trace_config_json_str);
3445  delete[] trace_config_json_str;
3446  } else {
3447  trace_config =
3448  platform::tracing::TraceConfig::CreateDefaultTraceConfig();
3449  }
3450  tracing_controller->StartTracing(trace_config);
3451  }
3452 
3453  if (options.stress_opt || options.stress_deopt) {
3454  Testing::SetStressRunType(options.stress_opt
3455  ? Testing::kStressTypeOpt
3456  : Testing::kStressTypeDeopt);
3457  options.stress_runs = Testing::GetStressRuns();
3458  for (int i = 0; i < options.stress_runs && result == 0; i++) {
3459  printf("============ Stress %d/%d ============\n", i + 1,
3460  options.stress_runs);
3462  bool last_run = i == options.stress_runs - 1;
3463  result = RunMain(isolate, argc, argv, last_run);
3464  }
3465  printf("======== Full Deoptimization =======\n");
3466  Testing::DeoptimizeAll(isolate);
3467  } else if (i::FLAG_stress_runs > 0) {
3468  options.stress_runs = i::FLAG_stress_runs;
3469  for (int i = 0; i < options.stress_runs && result == 0; i++) {
3470  printf("============ Run %d/%d ============\n", i + 1,
3471  options.stress_runs);
3472  bool last_run = i == options.stress_runs - 1;
3473  result = RunMain(isolate, argc, argv, last_run);
3474  }
3475  } else if (options.code_cache_options !=
3476  ShellOptions::CodeCacheOptions::kNoProduceCache) {
3477  printf("============ Run: Produce code cache ============\n");
3478  // First run to produce the cache
3479  Isolate::CreateParams create_params;
3480  create_params.array_buffer_allocator = Shell::array_buffer_allocator;
3481  i::FLAG_hash_seed ^= 1337; // Use a different hash seed.
3482  Isolate* isolate2 = Isolate::New(create_params);
3483  i::FLAG_hash_seed ^= 1337; // Restore old hash seed.
3484  isolate2->SetHostImportModuleDynamicallyCallback(
3485  Shell::HostImportModuleDynamically);
3486  isolate2->SetHostInitializeImportMetaObjectCallback(
3487  Shell::HostInitializeImportMetaObject);
3488  {
3489  D8Console console(isolate2);
3490  Initialize(isolate2);
3491  debug::SetConsoleDelegate(isolate2, &console);
3492  PerIsolateData data(isolate2);
3493  Isolate::Scope isolate_scope(isolate2);
3494 
3495  result = RunMain(isolate2, argc, argv, false);
3496  }
3497  isolate2->Dispose();
3498 
3499  // Change the options to consume cache
3500  DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
3501  options.compile_options == v8::ScriptCompiler::kNoCompileOptions);
3502  options.compile_options = v8::ScriptCompiler::kConsumeCodeCache;
3503  options.code_cache_options =
3504  ShellOptions::CodeCacheOptions::kNoProduceCache;
3505 
3506  printf("============ Run: Consume code cache ============\n");
3507  // Second run to consume the cache in current isolate
3508  result = RunMain(isolate, argc, argv, true);
3509  options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
3510  } else {
3511  bool last_run = true;
3512  result = RunMain(isolate, argc, argv, last_run);
3513  }
3514 
3515  // Run interactive shell if explicitly requested or if no script has been
3516  // executed, but never on --test
3517  if (use_interactive_shell()) {
3518  RunShell(isolate);
3519  }
3520 
3521  if (i::FLAG_trace_ignition_dispatches &&
3522  i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
3523  WriteIgnitionDispatchCountersFile(isolate);
3524  }
3525 
3526  // Shut down contexts and collect garbage.
3527  cached_code_map_.clear();
3528  evaluation_context_.Reset();
3529  stringify_function_.Reset();
3530  CollectGarbage(isolate);
3531  }
3532  OnExit(isolate);
3533  V8::Dispose();
3534  V8::ShutdownPlatform();
3535 
3536  // Delete the platform explicitly here to write the tracing output to the
3537  // tracing file.
3538  g_platform.reset();
3539  return result;
3540 }
3541 
3542 } // namespace v8
3543 
3544 
3545 #ifndef GOOGLE3
3546 int main(int argc, char* argv[]) {
3547  return v8::Shell::Main(argc, argv);
3548 }
3549 #endif
3550 
3551 #undef CHECK
3552 #undef DCHECK
static V8_WARN_UNUSED_RESULT MaybeLocal< Module > CompileModule(Isolate *isolate, Source *source, CompileOptions options=kNoCompileOptions, NoCacheReason no_cache_reason=kNoCacheNoReason)
Definition: api.cc:2394
static V8_WARN_UNUSED_RESULT MaybeLocal< Resolver > New(Local< Context > context)
Definition: api.cc:7240
static CachedData * CreateCodeCache(Local< UnboundScript > unbound_script)
Definition: api.cc:2579
static V8_WARN_UNUSED_RESULT MaybeLocal< String > Stringify(Local< Context > context, Local< Value > json_object, Local< String > gap=Local< String >())
Definition: api.cc:3018
Definition: v8.h:94
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromOneByte(Isolate *isolate, const uint8_t *data, v8::NewStringType type, int length=-1)
Definition: api.cc:6528
static V8_WARN_UNUSED_RESULT MaybeLocal< Script > Compile(Local< Context > context, Source *source, CompileOptions options=kNoCompileOptions, NoCacheReason no_cache_reason=kNoCacheNoReason)
Definition: api.cc:2378
static V8_INLINE Local< T > Cast(Local< S > that)
Definition: v8.h:251
static int GetStressRuns()
Definition: api.cc:10502
static Local< SharedArrayBuffer > New(Isolate *isolate, size_t byte_length)
Definition: api.cc:7858
MaybeLocal< WasmCompiledModule > GetWasmModuleFromId(Isolate *isolate, uint32_t transfer_id) override
Definition: d8.cc:3267
Maybe< uint32_t > GetSharedArrayBufferId(Isolate *isolate, Local< SharedArrayBuffer > shared_array_buffer) override
Definition: d8.cc:3107
void FreeBufferMemory(void *buffer) override
Definition: d8.cc:3150
Definition: v8.h:56
MaybeLocal< SharedArrayBuffer > GetSharedArrayBufferFromId(Isolate *isolate, uint32_t clone_id) override
Definition: d8.cc:3255
size_t GetMoreData(const uint8_t **src) override
Definition: d8.cc:391
static Local< Array > New(Isolate *isolate, int length=0)
Definition: api.cc:6966
void SetSupportsLegacyWireFormat(bool supports_legacy_wire_format)
Definition: api.cc:3231
Definition: v8.h:85
const char * data() const override
Definition: d8.cc:348
size_t length() const override
Definition: d8.cc:351
void TransferArrayBuffer(uint32_t transfer_id, Local< ArrayBuffer > array_buffer)
Definition: api.cc:3261
Definition: libplatform.h:13
static V8_WARN_UNUSED_RESULT MaybeLocal< Script > Compile(Local< Context > context, Local< String > source, ScriptOrigin *origin=nullptr)
Definition: api.cc:2608
static Local< ObjectTemplate > New(Isolate *isolate, Local< FunctionTemplate > constructor=Local< FunctionTemplate >())
Definition: api.cc:1616
static Local< ArrayBuffer > New(Isolate *isolate, size_t byte_length)
Definition: api.cc:7634
V8_WARN_UNUSED_RESULT Maybe< bool > ReadHeader(Local< Context > context)
Definition: api.cc:3200
void WriteHeader()
Definition: api.cc:3090
V8_WARN_UNUSED_RESULT Maybe< bool > WriteValue(Local< Context > context, Local< Value > value)
Definition: api.cc:3096
V8_WARN_UNUSED_RESULT MaybeLocal< Value > ReadValue(Local< Context > context)
Definition: api.cc:3245
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromTwoByte(Isolate *isolate, const uint16_t *data, v8::NewStringType type, int length=-1)
Definition: api.cc:6535
void ThrowDataCloneError(Local< String > message) override
Definition: d8.cc:3103
static V8_WARN_UNUSED_RESULT MaybeLocal< UnboundScript > CompileUnboundScript(Isolate *isolate, Source *source, CompileOptions options=kNoCompileOptions, NoCacheReason no_cache_reason=kNoCacheNoReason)
Definition: api.cc:2368
virtual bool IdleTasksEnabled(Isolate *isolate)
Definition: v8-platform.h:380
static V8_INLINE Local< T > New(Isolate *isolate, Local< T > that)
Definition: v8.h:9365
Definition: d8.h:29
virtual size_t AllocatePageSize()=0
static void SetStressRunType(StressType type)
Definition: api.cc:10497
static V8_INLINE Local< String > Empty(Isolate *isolate)
Definition: v8.h:9913
static MaybeLocal< WasmCompiledModule > FromTransferrableModule(Isolate *isolate, const TransferrableModule &)
Definition: api.cc:7420
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromUtf8(Isolate *isolate, const char *data, v8::NewStringType type, int length=-1)
Definition: api.cc:6511
static Local< FunctionTemplate > New(Isolate *isolate, FunctionCallback callback=nullptr, Local< Value > data=Local< Value >(), Local< Signature > signature=Local< Signature >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect)
Definition: api.cc:1417
virtual double MonotonicallyIncreasingTime()=0
V8_WARN_UNUSED_RESULT std::pair< uint8_t *, size_t > Release()
Definition: api.cc:3112
V8_INLINE void Reset()
Definition: v8.h:9469
void * ReallocateBufferMemory(void *old_buffer, size_t size, size_t *actual_size) override
Definition: d8.cc:3138
static Local< String > Concat(Isolate *isolate, Local< String > left, Local< String > right)
Definition: api.cc:6552
static void DeoptimizeAll(Isolate *isolate)
Definition: api.cc:10553
static void PrepareStressRun(int run)
Definition: api.cc:10519
static ScriptStreamingTask * StartStreamingScript(Isolate *isolate, StreamedSource *source, CompileOptions options=kNoCompileOptions)
Definition: api.cc:2524
void TransferArrayBuffer(uint32_t transfer_id, Local< ArrayBuffer > array_buffer)
Definition: api.cc:3116