v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
d8.cc
Go to the documentation of this file.
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 <fcntl.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/stat.h>
10
11#include <algorithm>
12#include <fstream>
13#include <iomanip>
14#include <iterator>
15#include <string>
16#include <tuple>
17#include <type_traits>
18#include <unordered_map>
19#include <utility>
20#include <vector>
21
22#ifdef ENABLE_VTUNE_JIT_INTERFACE
23#include "third_party/vtune/v8-vtune.h"
24#endif
25
28#include "include/v8-function.h"
31#include "include/v8-isolate.h"
32#include "include/v8-json.h"
33#include "include/v8-locker.h"
34#include "include/v8-profiler.h"
35#include "include/v8-wasm.h"
36#include "src/api/api-inl.h"
37#include "src/base/cpu.h"
38#include "src/base/fpu.h"
39#include "src/base/logging.h"
45#include "src/base/sys-info.h"
48#include "src/d8/d8-console.h"
49#include "src/d8/d8-platforms.h"
50#include "src/d8/d8.h"
57#include "src/flags/flags.h"
60#include "src/init/v8.h"
67#include "src/objects/objects.h"
69#include "src/parsing/parsing.h"
74#include "src/utils/ostreams.h"
75#include "src/utils/utils.h"
76
77#ifdef V8_OS_DARWIN
78#include <mach/mach.h>
79#include <mach/task_policy.h>
80#endif
81
82#ifdef V8_ENABLE_MAGLEV
84#endif // V8_ENABLE_MAGLEV
85
86#ifdef V8_ENABLE_PARTITION_ALLOC
87#include <partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h>
88#endif // V8_ENABLE_PARTITION_ALLOC
89
90#if V8_OS_POSIX
91#include <signal.h>
92#endif // V8_OS_POSIX
93
94#ifdef V8_FUZZILLI
95#include "src/fuzzilli/cov.h"
97#endif // V8_FUZZILLI
98
99#ifdef V8_USE_PERFETTO
100#include "perfetto/tracing/track_event.h"
101#include "perfetto/tracing/track_event_legacy.h"
102#endif // V8_USE_PERFETTO
103
104#ifdef V8_INTL_SUPPORT
105#include "unicode/locid.h"
106#endif // V8_INTL_SUPPORT
107
108#ifdef V8_OS_LINUX
109#include <sys/mman.h> // For MultiMappedAllocator.
110#endif
111
112#if defined(V8_OS_WIN)
113#include <windows.h>
114#else
115#include <unistd.h>
116#endif // defined(V8_OS_WIN)
117
118#if V8_ENABLE_WEBASSEMBLY
120#endif // V8_ENABLE_WEBASSEMBLY
121
122#ifndef DCHECK
123#define DCHECK(condition) assert(condition)
124#endif
125
126#ifndef CHECK
127#define CHECK(condition) assert(condition)
128#endif
129
130namespace v8 {
131
132namespace {
133
134// Set on worker threads to the current Worker instance.
135thread_local Worker* current_worker_ = nullptr;
136
137#ifdef V8_FUZZILLI
138bool fuzzilli_reprl = true;
139#else
140bool fuzzilli_reprl = false;
141#endif // V8_FUZZILLI
142
143// Base class for shell ArrayBuffer allocators. It forwards all operations to
144// the default v8 allocator.
145class ArrayBufferAllocatorBase : public v8::ArrayBuffer::Allocator {
146 public:
147 void* Allocate(size_t length) override {
148 return allocator_->Allocate(length);
149 }
150
151 void* AllocateUninitialized(size_t length) override {
152 return allocator_->AllocateUninitialized(length);
153 }
154
155 void Free(void* data, size_t length) override {
156 allocator_->Free(data, length);
157 }
158
159 PageAllocator* GetPageAllocator() override {
160 return allocator_->GetPageAllocator();
161 }
162
163 private:
164 std::unique_ptr<Allocator> allocator_ =
165 std::unique_ptr<Allocator>(NewDefaultAllocator());
166};
167
168// ArrayBuffer allocator that can use virtual memory to improve performance.
169class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
170 public:
171 void* Allocate(size_t length) override {
172 if (length >= kVMThreshold) return AllocateVM(length);
173 return ArrayBufferAllocatorBase::Allocate(length);
174 }
175
176 void* AllocateUninitialized(size_t length) override {
177 if (length >= kVMThreshold) return AllocateVM(length);
178 return ArrayBufferAllocatorBase::AllocateUninitialized(length);
179 }
180
181 void Free(void* data, size_t length) override {
182 if (length >= kVMThreshold) {
183 FreeVM(data, length);
184 } else {
185 ArrayBufferAllocatorBase::Free(data, length);
186 }
187 }
188
189 private:
190 static constexpr size_t kVMThreshold = 65536;
191
192 void* AllocateVM(size_t length) {
193 DCHECK_LE(kVMThreshold, length);
194 v8::PageAllocator* page_allocator = GetPageAllocator();
195 size_t page_size = page_allocator->AllocatePageSize();
196 size_t allocated = RoundUp(length, page_size);
197 return i::AllocatePages(page_allocator, nullptr, allocated, page_size,
199 }
200
201 void FreeVM(void* data, size_t length) {
202 v8::PageAllocator* page_allocator = GetPageAllocator();
203 size_t page_size = page_allocator->AllocatePageSize();
204 size_t allocated = RoundUp(length, page_size);
205 i::FreePages(page_allocator, data, allocated);
206 }
207};
208
209// ArrayBuffer allocator that never allocates over 10MB.
210class MockArrayBufferAllocator : public ArrayBufferAllocatorBase {
211 protected:
212 void* Allocate(size_t length) override {
213 return ArrayBufferAllocatorBase::Allocate(Adjust(length));
214 }
215
216 void* AllocateUninitialized(size_t length) override {
217 return ArrayBufferAllocatorBase::AllocateUninitialized(Adjust(length));
218 }
219
220 void Free(void* data, size_t length) override {
221 return ArrayBufferAllocatorBase::Free(data, Adjust(length));
222 }
223
224 private:
225 size_t Adjust(size_t length) {
226 const size_t kAllocationLimit = 10 * i::MB;
227 return length > kAllocationLimit ? i::AllocatePageSize() : length;
228 }
229};
230
231// ArrayBuffer allocator that can be equipped with a limit to simulate system
232// OOM.
233class MockArrayBufferAllocatiorWithLimit : public MockArrayBufferAllocator {
234 public:
235 explicit MockArrayBufferAllocatiorWithLimit(size_t allocation_limit)
236 : limit_(allocation_limit), space_left_(allocation_limit) {}
237
238 protected:
239 void* Allocate(size_t length) override {
240 if (length > space_left_) {
241 return nullptr;
242 }
243 space_left_ -= length;
244 return MockArrayBufferAllocator::Allocate(length);
245 }
246
247 void* AllocateUninitialized(size_t length) override {
248 if (length > space_left_) {
249 return nullptr;
250 }
251 space_left_ -= length;
252 return MockArrayBufferAllocator::AllocateUninitialized(length);
253 }
254
255 void Free(void* data, size_t length) override {
256 space_left_ += length;
257 return MockArrayBufferAllocator::Free(data, length);
258 }
259
260 size_t MaxAllocationSize() const override { return limit_; }
261
262 private:
263 size_t limit_;
264 std::atomic<size_t> space_left_;
265};
266
267#ifdef V8_OS_LINUX
268
269// This is a mock allocator variant that provides a huge virtual allocation
270// backed by a small real allocation that is repeatedly mapped. If you create an
271// array on memory allocated by this allocator, you will observe that elements
272// will alias each other as if their indices were modulo-divided by the real
273// allocation length.
274// The purpose is to allow stability-testing of huge (typed) arrays without
275// actually consuming huge amounts of physical memory.
276// This is currently only available on Linux because it relies on {mremap}.
277class MultiMappedAllocator : public ArrayBufferAllocatorBase {
278 protected:
279 void* Allocate(size_t length) override {
280 if (length < kChunkSize) {
281 return ArrayBufferAllocatorBase::Allocate(length);
282 }
283 // We use mmap, which initializes pages to zero anyway.
284 return AllocateUninitialized(length);
285 }
286
287 void* AllocateUninitialized(size_t length) override {
288 if (length < kChunkSize) {
289 return ArrayBufferAllocatorBase::AllocateUninitialized(length);
290 }
291 size_t rounded_length = RoundUp(length, kChunkSize);
292 int prot = PROT_READ | PROT_WRITE;
293 // We have to specify MAP_SHARED to make {mremap} below do what we want.
294 int flags = MAP_SHARED | MAP_ANONYMOUS;
295 void* real_alloc = mmap(nullptr, kChunkSize, prot, flags, -1, 0);
296 if (reinterpret_cast<intptr_t>(real_alloc) == -1) {
297 // If we ran into some limit (physical or virtual memory, or number
298 // of mappings, etc), return {nullptr}, which callers can handle.
299 if (errno == ENOMEM) {
300 return nullptr;
301 }
302 // Other errors may be bugs which we want to learn about.
303 FATAL("mmap (real) failed with error %d: %s", errno, strerror(errno));
304 }
305#ifdef V8_ENABLE_SANDBOX
306 // The backing memory must be allocated inside the sandbox as it will be
307 // used for array buffer contents.
308 // Here we go into somewhat less-well-defined territory by using the
309 // sandbox's virtual address space to essentially just reserve a number of
310 // OS pages inside the sandbox, but then using mremap to replace these
311 // pages directly afterwards. In practice, this works fine however.
312 VirtualAddressSpace* vas = i::Sandbox::current()->address_space();
313 i::Address in_sandbox_page_reservation = vas->AllocatePages(
314 VirtualAddressSpace::kNoHint, rounded_length,
315 vas->allocation_granularity(), PagePermissions::kNoAccess);
316 void* virtual_alloc =
317 in_sandbox_page_reservation != 0
318 ? reinterpret_cast<void*>(in_sandbox_page_reservation)
319 : reinterpret_cast<void*>(-1);
320#else
321 void* virtual_alloc =
322 mmap(nullptr, rounded_length, prot, flags | MAP_NORESERVE, -1, 0);
323#endif
324 if (reinterpret_cast<intptr_t>(virtual_alloc) == -1) {
325 if (errno == ENOMEM) {
326 // Undo earlier, successful mappings.
327 munmap(real_alloc, kChunkSize);
328 return nullptr;
329 }
330 FATAL("mmap (virtual) failed with error %d: %s", errno, strerror(errno));
331 }
332 i::Address virtual_base = reinterpret_cast<i::Address>(virtual_alloc);
333 i::Address virtual_end = virtual_base + rounded_length;
334 for (i::Address to_map = virtual_base; to_map < virtual_end;
335 to_map += kChunkSize) {
336 // Specifying 0 as the "old size" causes the existing map entry to not
337 // get deleted, which is important so that we can remap it again in the
338 // next iteration of this loop.
339 void* result =
340 mremap(real_alloc, 0, kChunkSize, MREMAP_MAYMOVE | MREMAP_FIXED,
341 reinterpret_cast<void*>(to_map));
342 if (reinterpret_cast<intptr_t>(result) == -1) {
343 if (errno == ENOMEM) {
344 // Undo earlier, successful mappings.
345 munmap(real_alloc, kChunkSize);
346#ifdef V8_ENABLE_SANDBOX
347 vas->FreePages(in_sandbox_page_reservation, rounded_length);
348#else
349 munmap(virtual_alloc, rounded_length);
350#endif
351 return nullptr;
352 }
353 FATAL("mremap failed with error %d: %s", errno, strerror(errno));
354 }
355 }
356 base::MutexGuard lock_guard(&regions_mutex_);
357 regions_[virtual_alloc] = real_alloc;
358 return virtual_alloc;
359 }
360
361 void Free(void* data, size_t length) override {
362 if (length < kChunkSize) {
363 return ArrayBufferAllocatorBase::Free(data, length);
364 }
365 base::MutexGuard lock_guard(&regions_mutex_);
366 void* real_alloc = regions_[data];
367 munmap(real_alloc, kChunkSize);
368 size_t rounded_length = RoundUp(length, kChunkSize);
369#ifdef V8_ENABLE_SANDBOX
370 VirtualAddressSpace* vas = i::Sandbox::current()->address_space();
371 vas->FreePages(reinterpret_cast<i::Address>(data), rounded_length);
372#else
373 munmap(data, rounded_length);
374#endif
375 regions_.erase(data);
376 }
377
378 private:
379 // Aiming for a "Huge Page" (2M on Linux x64) to go easy on the TLB.
380 static constexpr size_t kChunkSize = 2 * 1024 * 1024;
381
382 std::unordered_map<void*, void*> regions_;
383 base::Mutex regions_mutex_;
384};
385
386#endif // V8_OS_LINUX
387
388v8::Platform* g_default_platform;
389std::unique_ptr<v8::Platform> g_platform;
390
391template <int N>
392void ThrowError(Isolate* isolate, const char (&message)[N]) {
393 if (isolate->IsExecutionTerminating()) return;
394 isolate->ThrowError(message);
395}
396
397void ThrowError(Isolate* isolate, Local<String> message) {
398 if (isolate->IsExecutionTerminating()) return;
399 isolate->ThrowError(message);
400}
401
402void ThrowException(Isolate* isolate, Local<Value> exception) {
403 if (isolate->IsExecutionTerminating()) return;
404 isolate->ThrowException(exception);
405}
406
407static MaybeLocal<Value> TryGetValue(v8::Isolate* isolate,
408 Local<Context> context,
409 Local<v8::Object> object,
410 const char* property) {
411 MaybeLocal<String> v8_str = String::NewFromUtf8(isolate, property);
412 if (v8_str.IsEmpty()) return {};
413 return object->Get(context, v8_str.ToLocalChecked());
414}
415
416static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
417 Local<v8::Object> object, const char* property) {
418 return TryGetValue(isolate, context, object, property).ToLocalChecked();
419}
420
421std::shared_ptr<Worker> GetWorkerFromInternalField(Isolate* isolate,
422 Local<Object> object) {
423 if (object->InternalFieldCount() != 1) {
424 ThrowError(isolate, "this is not a Worker");
425 return nullptr;
426 }
427
429 Utils::OpenDirectHandle(*object->GetInternalField(0));
430 if (IsSmi(*handle)) {
431 ThrowError(isolate, "Worker is defunct because main thread is terminating");
432 return nullptr;
433 }
434 auto managed = i::Cast<i::Managed<Worker>>(handle);
435 return managed->get();
436}
437
438base::Thread::Options GetThreadOptions(const char* name) {
439 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
440 // which is not enough to parse the big literal expressions used in tests.
441 // The stack size should be at least StackGuard::kLimitSize + some
442 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
443 return base::Thread::Options(name, 2 * i::MB);
444}
445
446} // namespace
447
448namespace tracing {
449
450namespace {
451
452static constexpr char kIncludedCategoriesParam[] = "included_categories";
453static constexpr char kTraceConfigParam[] = "trace_config";
454
455class TraceConfigParser {
456 public:
457 static void FillTraceConfig(v8::Isolate* isolate,
458 platform::tracing::TraceConfig* trace_config,
459 const char* json_str) {
460 HandleScope outer_scope(isolate);
461 Local<Context> context = Context::New(isolate);
462 Context::Scope context_scope(context);
463 HandleScope inner_scope(isolate);
464
465 Local<String> source =
466 String::NewFromUtf8(isolate, json_str).ToLocalChecked();
467 Local<Value> result = JSON::Parse(context, source).ToLocalChecked();
468 Local<v8::Object> trace_config_object = result.As<v8::Object>();
469 // Try reading 'trace_config' property from a full chrome trace config.
470 // https://chromium.googlesource.com/chromium/src/+/master/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way
471 Local<Value> maybe_trace_config_object =
472 GetValue(isolate, context, trace_config_object, kTraceConfigParam);
473 if (maybe_trace_config_object->IsObject()) {
474 trace_config_object = maybe_trace_config_object.As<Object>();
475 }
476
477 UpdateIncludedCategoriesList(isolate, context, trace_config_object,
478 trace_config);
479 }
480
481 private:
482 static int UpdateIncludedCategoriesList(
483 v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object,
484 platform::tracing::TraceConfig* trace_config) {
485 Local<Value> value =
486 GetValue(isolate, context, object, kIncludedCategoriesParam);
487 if (value->IsArray()) {
488 Local<Array> v8_array = value.As<Array>();
489 for (int i = 0, length = v8_array->Length(); i < length; ++i) {
490 Local<Value> v = v8_array->Get(context, i)
491 .ToLocalChecked()
492 ->ToString(context)
493 .ToLocalChecked();
494 String::Utf8Value str(isolate, v->ToString(context).ToLocalChecked());
495 trace_config->AddIncludedCategory(*str);
496 }
497 return v8_array->Length();
498 }
499 return 0;
500 }
501};
502
503} // namespace
504
506 v8::Isolate* isolate, const char* json_str) {
507 platform::tracing::TraceConfig* trace_config =
509 TraceConfigParser::FillTraceConfig(isolate, trace_config, json_str);
510 return trace_config;
511}
512
513} // namespace tracing
514
517 public:
520 std::unique_ptr<base::OS::MemoryMappedFile> file)
521 : file_(std::move(file)) {}
522 const char* data() const override {
523 return static_cast<char*>(file_->memory());
524 }
525 size_t length() const override { return file_->size(); }
526
527 private:
528 std::unique_ptr<base::OS::MemoryMappedFile> file_;
529};
530
531// static variables:
536CounterCollection* Shell::counters_ = &local_counters_;
541std::map<Isolate*, std::pair<Global<Function>, Global<Context>>>
544bool Shell::allow_new_workers_ = true;
545
546std::unordered_set<std::shared_ptr<Worker>> Shell::running_workers_;
547std::atomic<bool> Shell::script_executed_{false};
548std::atomic<bool> Shell::valid_fuzz_script_{false};
550std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
552std::atomic<int> Shell::unhandled_promise_rejections_{0};
553
554Global<Context> Shell::evaluation_context_;
555ArrayBuffer::Allocator* Shell::array_buffer_allocator;
559
561 Local<Value> source) {
562 i::ParkedMutexGuard lock_guard(
563 reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(),
565 CHECK(source->IsString());
566 v8::String::Utf8Value key(isolate, source);
567 DCHECK(*key);
568 auto entry = cached_code_map_.find(*key);
569 if (entry != cached_code_map_.end() && entry->second) {
570 int length = entry->second->length;
571 uint8_t* cache = new uint8_t[length];
572 memcpy(cache, entry->second->data, length);
575 return cached_data;
576 }
577 return nullptr;
578}
579
581 const ScriptCompiler::CachedData* cache_data) {
582 i::ParkedMutexGuard lock_guard(
583 reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(),
585 CHECK(source->IsString());
586 if (cache_data == nullptr) return;
587 v8::String::Utf8Value key(isolate, source);
588 DCHECK(*key);
589 int length = cache_data->length;
590 uint8_t* cache = new uint8_t[length];
591 memcpy(cache, cache_data->data, length);
592 cached_code_map_[*key] = std::unique_ptr<ScriptCompiler::CachedData>(
593 new ScriptCompiler::CachedData(cache, length,
595}
596
597// Dummy external source stream which returns the whole source in one go.
598// TODO(leszeks): Also test chunking the data.
600 public:
601 DummySourceStream(Isolate* isolate, Local<String> source) : done_(false) {
602 source_length_ = source->Length();
603 source_buffer_ = std::make_unique<uint16_t[]>(source_length_);
604 source->WriteV2(isolate, 0, source_length_, source_buffer_.get());
605 }
606
607 size_t GetMoreData(const uint8_t** src) override {
608 if (done_) {
609 return 0;
610 }
611 *src = reinterpret_cast<uint8_t*>(source_buffer_.release());
612 done_ = true;
613
614 return source_length_ * 2;
615 }
616
617 private:
619 std::unique_ptr<uint16_t[]> source_buffer_;
620 bool done_;
621};
622
623// Run a ScriptStreamingTask in a separate thread.
625 public:
628 StreamerThread thread(task);
629 CHECK(thread.Start());
630 thread.Join();
631 }
632
635
636 void Run() override { task_->Run(); }
637
638 private:
640};
641
642namespace {
643template <class T>
644MaybeLocal<T> CompileStreamed(Local<Context> context,
646 Local<String> full_source_string,
647 const ScriptOrigin& origin) {}
648
649template <>
650MaybeLocal<Script> CompileStreamed(Local<Context> context,
651 ScriptCompiler::StreamedSource* v8_source,
652 Local<String> full_source_string,
653 const ScriptOrigin& origin) {
654 return ScriptCompiler::Compile(context, v8_source, full_source_string,
655 origin);
656}
657
658template <>
659MaybeLocal<Module> CompileStreamed(Local<Context> context,
660 ScriptCompiler::StreamedSource* v8_source,
661 Local<String> full_source_string,
662 const ScriptOrigin& origin) {
663 return ScriptCompiler::CompileModule(context, v8_source, full_source_string,
664 origin);
665}
666
667template <class T>
668MaybeLocal<T> Compile(Local<Context> context, ScriptCompiler::Source* source,
670template <>
671MaybeLocal<Script> Compile(Local<Context> context,
672 ScriptCompiler::Source* source,
674 return ScriptCompiler::Compile(context, source, options);
675}
676
677template <>
678MaybeLocal<Module> Compile(Local<Context> context,
679 ScriptCompiler::Source* source,
681 return ScriptCompiler::CompileModule(context->GetIsolate(), source, options);
682}
683
684} // namespace
685
686template <class T>
688 Local<String> source,
689 const ScriptOrigin& origin) {
690 if (options.streaming_compile) {
692 std::make_unique<DummySourceStream>(isolate, source),
694 std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> streaming_task(
695 v8::ScriptCompiler::StartStreaming(isolate, &streamed_source,
696 std::is_same_v<T, Module>
699 StreamerThread::StartThreadForTaskAndJoin(streaming_task.get());
700 return CompileStreamed<T>(context, &streamed_source, source, origin);
701 }
702
703 ScriptCompiler::CachedData* cached_code = nullptr;
704 if (options.compile_options & ScriptCompiler::kConsumeCodeCache) {
705 cached_code = LookupCodeCache(isolate, source);
706 }
707 ScriptCompiler::Source script_source(source, origin, cached_code);
709 Compile<T>(context, &script_source,
712 if (cached_code) CHECK(!cached_code->rejected);
713 return result;
714}
715
716namespace {
717// For testing.
718const int kHostDefinedOptionsLength = 2;
719const uint32_t kHostDefinedOptionsMagicConstant = 0xF1F2F3F0;
720
721const char kDataURLPrefix[] = "data:text/javascript,";
722
723std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
724 String::Utf8Value utf8(isolate, v8_str);
725 // Should not be able to fail since the input is a String.
726 CHECK(*utf8);
727 return *utf8;
728}
729
730// Per-context Module data, allowing sharing of module maps
731// across top-level module loads.
732class ModuleEmbedderData {
733 private:
734 class ModuleGlobalHash {
735 public:
736 explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
737 size_t operator()(const Global<Module>& module) const {
738 return module.Get(isolate_)->GetIdentityHash();
739 }
740
741 private:
742 Isolate* isolate_;
743 };
744
745 public:
746 static constexpr i::ExternalPointerTag kManagedTag =
748
749 explicit ModuleEmbedderData(Isolate* isolate)
750 : isolate_(isolate),
751 module_to_specifier_map(10, ModuleGlobalHash(isolate)),
752 json_module_to_parsed_json_map(
753 10, module_to_specifier_map.hash_function()) {}
754
755 std::string GetModuleSpecifier(Local<Module> module) {
756 Global<Module> global_module(isolate_, module);
757 auto specifier_it = module_to_specifier_map.find(global_module);
758 CHECK(specifier_it != module_to_specifier_map.end());
759 return specifier_it->second;
760 }
761
762 Local<Module> GetModule(
763 std::pair<std::string, ModuleType> module_specifier_and_type) {
764 auto module_it = module_map.find(module_specifier_and_type);
765 CHECK(module_it != module_map.end());
766 return module_it->second.Get(isolate_);
767 }
768
769 Local<Object> GetModuleSource(
770 std::pair<std::string, ModuleType> module_specifier_and_type) {
771 auto module_source_it = module_source_map.find(module_specifier_and_type);
772 CHECK(module_source_it != module_source_map.end());
773 return module_source_it->second.Get(isolate_);
774 }
775
776 Local<Value> GetJsonModuleValue(Local<Module> module) {
777 auto json_value_it =
778 json_module_to_parsed_json_map.find(Global<Module>(isolate_, module));
779 CHECK(json_value_it != json_module_to_parsed_json_map.end());
780 return json_value_it->second.Get(isolate_);
781 }
782
783 static ModuleType ModuleTypeFromImportSpecifierAndAttributes(
784 Local<Context> context, const std::string& specifier,
785 Local<FixedArray> import_attributes, bool hasPositions) {
786 Isolate* isolate = context->GetIsolate();
787 const int kV8AssertionEntrySize = hasPositions ? 3 : 2;
788 for (int i = 0; i < import_attributes->Length();
789 i += kV8AssertionEntrySize) {
790 Local<String> v8_assertion_key =
791 import_attributes->Get(context, i).As<v8::String>();
792 std::string assertion_key = ToSTLString(isolate, v8_assertion_key);
793
794 if (assertion_key == "type") {
795 Local<String> v8_assertion_value =
796 import_attributes->Get(context, i + 1).As<String>();
797 std::string assertion_value = ToSTLString(isolate, v8_assertion_value);
798 if (assertion_value == "json") {
799 return ModuleType::kJSON;
800 } else {
801 // JSON and WebAssembly are currently the only supported non-JS types
803 }
804 }
805 }
806
807 // If no type is asserted, check for the extension. Otherwise default to JS.
808 if (specifier.ends_with(".wasm")) {
810 }
812 }
813
814 Isolate* isolate_;
815 // Map from (normalized module specifier, module type) pair to Module.
816 std::map<std::pair<std::string, ModuleType>, Global<Module>> module_map;
817 // Map from (normalized module specifier, module type) pair to ModuleSource.
818 std::map<std::pair<std::string, ModuleType>, Global<Object>>
819 module_source_map;
820 // Map from Module to its URL as defined in the ScriptOrigin
821 std::unordered_map<Global<Module>, std::string, ModuleGlobalHash>
822 module_to_specifier_map;
823 // Map from JSON Module to its parsed content, for use in module
824 // JSONModuleEvaluationSteps
825 std::unordered_map<Global<Module>, Global<Value>, ModuleGlobalHash>
826 json_module_to_parsed_json_map;
827
828 // Origin location used for resolving modules when referrer is null.
829 std::string origin;
830};
831
832enum { kModuleEmbedderDataIndex, kInspectorClientIndex };
833
834std::shared_ptr<ModuleEmbedderData> InitializeModuleEmbedderData(
835 Local<Context> context) {
836 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
837 const size_t kModuleEmbedderDataEstimate = 4 * 1024; // module map.
840 i_isolate, kModuleEmbedderDataEstimate,
841 std::make_shared<ModuleEmbedderData>(context->GetIsolate()));
842 v8::Local<v8::Value> module_data = Utils::ToLocal(module_data_managed);
843 context->SetEmbedderData(kModuleEmbedderDataIndex, module_data);
844 return module_data_managed->get();
845}
846
847std::shared_ptr<ModuleEmbedderData> GetModuleDataFromContext(
848 Local<Context> context) {
849 v8::Local<v8::Value> module_data =
850 context->GetEmbedderData(kModuleEmbedderDataIndex);
854 return module_data_managed->get();
855}
856
857ScriptOrigin CreateScriptOrigin(Isolate* isolate, Local<String> resource_name,
858 v8::ScriptType type) {
859 Local<PrimitiveArray> options =
860 PrimitiveArray::New(isolate, kHostDefinedOptionsLength);
861 options->Set(isolate, 0,
862 v8::Uint32::New(isolate, kHostDefinedOptionsMagicConstant));
863 options->Set(isolate, 1, resource_name);
864 return ScriptOrigin(resource_name, 0, 0, false, -1, Local<Value>(), false,
865 false, type == v8::ScriptType::kModule, options);
866}
867
868bool IsValidHostDefinedOptions(Local<Context> context, Local<Data> options,
869 Local<Value> resource_name) {
870 if (!options->IsFixedArray()) return false;
871 Local<FixedArray> array = options.As<FixedArray>();
872 if (array->Length() != kHostDefinedOptionsLength) return false;
873 uint32_t magic = 0;
874 if (!array->Get(context, 0).As<Value>()->Uint32Value(context).To(&magic)) {
875 return false;
876 }
877 if (magic != kHostDefinedOptionsMagicConstant) return false;
878 return array->Get(context, 1).As<String>()->StrictEquals(resource_name);
879}
880
881class D8WasmAsyncResolvePromiseTask : public v8::Task {
882 public:
883 D8WasmAsyncResolvePromiseTask(v8::Isolate* isolate,
887 WasmAsyncSuccess success)
888 : isolate_(isolate),
889 context_(isolate, context),
890 resolver_(isolate, resolver),
891 result_(isolate, result),
892 success_(success) {}
893
894 void Run() override {
895 v8::HandleScope scope(isolate_);
896 v8::Local<v8::Context> context = context_.Get(isolate_);
897 v8::Context::Scope context_scope(context);
898 MicrotasksScope microtasks_scope(context,
901 v8::Local<v8::Value> result = result_.Get(isolate_);
902
903 Maybe<bool> ret = success_ == WasmAsyncSuccess::kSuccess
904 ? resolver->Resolve(context, result)
905 : resolver->Reject(context, result);
906 // It's guaranteed that no exceptions will be thrown by these
907 // operations, but execution might be terminating.
908 CHECK(ret.IsJust() ? ret.FromJust() : isolate_->IsExecutionTerminating());
909 }
910
911 private:
916 WasmAsyncSuccess success_;
917};
918
919void D8WasmAsyncResolvePromiseCallback(
920 v8::Isolate* isolate, v8::Local<v8::Context> context,
922 WasmAsyncSuccess success) {
923 // We have to resolve the promise in a separate task which is not a cancelable
924 // task, to avoid a deadlock when {quit()} is called in the then-handler of
925 // the result promise.
926 g_platform->GetForegroundTaskRunner(isolate)->PostTask(
927 std::make_unique<D8WasmAsyncResolvePromiseTask>(
928 isolate, context, resolver, result, success));
929}
930
931} // namespace
932
933// Executes a string within the current v8 context.
935 Local<String> name,
936 ReportExceptions report_exceptions,
937 Global<Value>* out_result) {
938 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
939 if (i_isolate->is_execution_terminating()) return true;
940 if (i::v8_flags.parse_only) {
941 i::VMState<PARSER> state(i_isolate);
943
944 // Set up ParseInfo.
945 i::UnoptimizedCompileState compile_state;
946 i::ReusableUnoptimizedCompileState reusable_state(i_isolate);
947
949 i::UnoptimizedCompileFlags::ForToplevelCompile(
950 i_isolate, true, i::construct_language_mode(i::v8_flags.use_strict),
951 i::REPLMode::kNo, ScriptType::kClassic, i::v8_flags.lazy);
952
953 if (options.compile_options & v8::ScriptCompiler::kEagerCompile) {
954 flags.set_is_eager(true);
955 }
956
957 i::ParseInfo parse_info(i_isolate, flags, &compile_state, &reusable_state);
958
959 i::Handle<i::Script> script = parse_info.CreateScript(
960 i_isolate, str, i::kNullMaybeHandle, ScriptOriginOptions());
961 if (!i::parsing::ParseProgram(&parse_info, script, i_isolate,
962 i::parsing::ReportStatisticsMode::kYes)) {
964 i_isolate, parse_info.ast_value_factory());
965 parse_info.pending_error_handler()->ReportErrors(i_isolate, script);
966
967 fprintf(stderr, "Failed parsing\n");
968 return false;
969 }
970 return true;
971 }
972
973 HandleScope handle_scope(isolate);
974 TryCatch try_catch(isolate);
975 try_catch.SetVerbose(report_exceptions == kReportExceptions);
976
977 // Explicitly check for stack overflows. This method can be called
978 // recursively, and since we consume quite some stack space for the C++
979 // frames, the stack check in the called frame might be too late.
980 if (i::StackLimitCheck{i_isolate}.HasOverflowed()) {
981 i_isolate->StackOverflow();
982 return false;
983 }
984
985 PerIsolateData* data = PerIsolateData::Get(isolate);
986 Local<Context> realm =
987 Local<Context>::New(isolate, data->realms_[data->realm_current_]);
988 Context::Scope context_scope(realm);
989 Local<Context> context(isolate->GetCurrentContext());
990 ScriptOrigin origin = CreateScriptOrigin(isolate, name, ScriptType::kClassic);
991
992 std::shared_ptr<ModuleEmbedderData> module_data =
993 GetModuleDataFromContext(realm);
994 module_data->origin = ToSTLString(isolate, name);
995
996 for (int i = 1; i < options.repeat_compile; ++i) {
997 HandleScope handle_scope_for_compiling(isolate);
998 if (CompileString<Script>(isolate, context, source, origin).IsEmpty()) {
999 return false;
1000 }
1001 }
1002 Local<Script> script;
1003 if (!CompileString<Script>(isolate, context, source, origin)
1004 .ToLocal(&script)) {
1005 return false;
1006 }
1007
1008 if (options.code_cache_options ==
1010 // Serialize and store it in memory for the next execution.
1011 ScriptCompiler::CachedData* cached_data =
1012 ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
1013 StoreInCodeCache(isolate, source, cached_data);
1014 delete cached_data;
1015 }
1016 if (options.compile_only) return true;
1017 if (options.compile_options & ScriptCompiler::kConsumeCodeCache) {
1020 Utils::OpenDirectHandle(*script)->shared()->script()),
1021 i_isolate);
1022 // TODO(cbruni, chromium:1244145): remove once context-allocated.
1023 i_script->set_host_defined_options(i::Cast<i::FixedArray>(
1025 }
1026
1027 MaybeLocal<Value> maybe_result = script->Run(realm);
1028
1029 if (options.code_cache_options ==
1031 !isolate->IsExecutionTerminating()) {
1032 // Serialize and store it in memory for the next execution.
1033 ScriptCompiler::CachedData* cached_data =
1034 ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
1035 StoreInCodeCache(isolate, source, cached_data);
1036 delete cached_data;
1037 }
1038 data->realm_current_ = data->realm_switch_;
1039
1041 if (!maybe_result.ToLocal(&result)) {
1042 if (try_catch.HasTerminated()) {
1043 // Re-request terminate execution as it's been cleared, so
1044 // Shell::FinishExecution doesn't waste time draining all enqueued tasks
1045 // and microtasks.
1046 isolate->TerminateExecution();
1047 return true;
1048 }
1049 DCHECK(try_catch.HasCaught());
1050 return false;
1051 } else if (out_result != nullptr) {
1052 out_result->Reset(isolate, result);
1053 }
1054
1055 // It's possible that a FinalizationRegistry cleanup task threw an error.
1056 return !try_catch.HasCaught();
1057}
1058
1059namespace {
1060
1061bool IsAbsolutePath(const std::string& path) {
1062#if defined(V8_OS_WIN)
1063 // This is an incorrect approximation, but should
1064 // work for all our test-running cases.
1065 return path.find(':') != std::string::npos;
1066#else
1067 return path[0] == '/';
1068#endif
1069}
1070
1071std::string GetWorkingDirectory() {
1072#if defined(V8_OS_WIN)
1073 char system_buffer[MAX_PATH];
1074 // Unicode paths are unsupported, which is fine as long as
1075 // the test directory doesn't include any such paths.
1076 DWORD len = GetCurrentDirectoryA(MAX_PATH, system_buffer);
1077 CHECK_GT(len, 0);
1078 return system_buffer;
1079#else
1080 char curdir[PATH_MAX];
1081 CHECK_NOT_NULL(getcwd(curdir, PATH_MAX));
1082 return curdir;
1083#endif
1084}
1085
1086// Returns the directory part of path, without the trailing '/'.
1087std::string DirName(const std::string& path) {
1088 DCHECK(IsAbsolutePath(path));
1089 size_t last_slash = path.find_last_of('/');
1090 DCHECK(last_slash != std::string::npos);
1091 return path.substr(0, last_slash);
1092}
1093
1094// Resolves path to an absolute path if necessary, and does some
1095// normalization (eliding references to the current directory
1096// and replacing backslashes with slashes).
1097std::string NormalizePath(const std::string& path,
1098 const std::string& dir_name) {
1099 std::string absolute_path;
1100 if (IsAbsolutePath(path)) {
1101 absolute_path = path;
1102 } else {
1103 absolute_path = dir_name + '/' + path;
1104 }
1105 std::replace(absolute_path.begin(), absolute_path.end(), '\\', '/');
1106 std::vector<std::string> segments;
1107 std::istringstream segment_stream(absolute_path);
1108 std::string segment;
1109 while (std::getline(segment_stream, segment, '/')) {
1110 if (segment == "..") {
1111 if (!segments.empty()) segments.pop_back();
1112 } else if (segment != ".") {
1113 segments.push_back(segment);
1114 }
1115 }
1116 // Join path segments.
1117 std::ostringstream os;
1118 if (segments.size() > 1) {
1119 std::copy(segments.begin(), segments.end() - 1,
1120 std::ostream_iterator<std::string>(os, "/"));
1121 os << *segments.rbegin();
1122 } else {
1123 os << "/";
1124 if (!segments.empty()) os << segments[0];
1125 }
1126 return os.str();
1127}
1128
1129// Resolves specifier to an absolute path if necessary, and does some
1130// normalization (eliding references to the current directory
1131// and replacing backslashes with slashes).
1132//
1133// If specifier is a data url, returns it unchanged.
1134std::string NormalizeModuleSpecifier(const std::string& specifier,
1135 const std::string& dir_name) {
1136 if (specifier.starts_with(kDataURLPrefix)) return specifier;
1137 return NormalizePath(specifier, dir_name);
1138}
1139
1140MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
1141 Local<String> specifier,
1142 Local<FixedArray> import_attributes,
1143 Local<Module> referrer) {
1144 Isolate* isolate = context->GetIsolate();
1145 std::shared_ptr<ModuleEmbedderData> module_data =
1146 GetModuleDataFromContext(context);
1147 std::string referrer_specifier = module_data->GetModuleSpecifier(referrer);
1148
1149 std::string stl_specifier = ToSTLString(isolate, specifier);
1150 std::string absolute_path =
1151 NormalizeModuleSpecifier(stl_specifier, DirName(referrer_specifier));
1152 ModuleType module_type =
1153 ModuleEmbedderData::ModuleTypeFromImportSpecifierAndAttributes(
1154 context, stl_specifier, import_attributes, true);
1155 return module_data->GetModule(std::make_pair(absolute_path, module_type));
1156}
1157
1158MaybeLocal<Object> ResolveModuleSourceCallback(
1159 Local<Context> context, Local<String> specifier,
1160 Local<FixedArray> import_attributes, Local<Module> referrer) {
1161 Isolate* isolate = context->GetIsolate();
1162 std::shared_ptr<ModuleEmbedderData> module_data =
1163 GetModuleDataFromContext(context);
1164 std::string referrer_specifier = module_data->GetModuleSpecifier(referrer);
1165
1166 std::string stl_specifier = ToSTLString(isolate, specifier);
1167 std::string absolute_path =
1168 NormalizeModuleSpecifier(stl_specifier, DirName(referrer_specifier));
1169 ModuleType module_type =
1170 ModuleEmbedderData::ModuleTypeFromImportSpecifierAndAttributes(
1171 context, stl_specifier, import_attributes, true);
1172
1173 return module_data->GetModuleSource(
1174 std::make_pair(absolute_path, module_type));
1175}
1176
1177} // anonymous namespace
1178
1180 Local<Context> context,
1181 const std::string& module_specifier,
1182 ModuleType module_type) {
1183 Isolate* isolate = context->GetIsolate();
1184 DCHECK(IsAbsolutePath(module_specifier));
1185 auto file = ReadFileData(isolate, module_specifier.c_str());
1186
1187 std::shared_ptr<ModuleEmbedderData> module_data =
1188 GetModuleDataFromContext(context);
1189 if (!file) {
1190 std::string msg = "d8: Error reading module from " + module_specifier;
1191 if (!referrer.IsEmpty()) {
1192 std::string referrer_specifier =
1193 module_data->GetModuleSpecifier(referrer);
1194 msg += "\n imported by " + referrer_specifier;
1195 }
1196 ThrowError(isolate,
1197 v8::String::NewFromUtf8(isolate, msg.c_str()).ToLocalChecked());
1198 return MaybeLocal<Object>();
1199 }
1200
1201 Local<Object> module_source;
1202 switch (module_type) {
1205 isolate,
1206 MemorySpan<const uint8_t>(static_cast<uint8_t*>(file->memory()),
1207 file->size()))
1208 .ToLocal(&module_source)) {
1209 return MaybeLocal<Object>();
1210 }
1211 break;
1212 }
1213 default:
1214 // https://tc39.es/proposal-source-phase-imports/#table-abstract-methods-of-module-records
1215 // For Module Records that do not have a source representation,
1216 // GetModuleSource() must always return a throw completion whose [[Value]]
1217 // is a ReferenceError.
1218 ThrowException(
1220 isolate, "Module source can not be imported for type")));
1221 return MaybeLocal<Object>();
1222 }
1223
1224 CHECK(
1225 module_data->module_source_map
1226 .insert(std::make_pair(std::make_pair(module_specifier, module_type),
1227 Global<Object>(isolate, module_source)))
1228 .second);
1229 return module_source;
1230}
1231
1232// file_name must be either an absolute path to the filesystem or a data URL.
1234 Local<Context> context,
1235 const std::string& module_specifier,
1236 ModuleType module_type) {
1237 Isolate* isolate = context->GetIsolate();
1238 const bool is_data_url = module_specifier.starts_with(kDataURLPrefix);
1239 MaybeLocal<String> source_text;
1240 if (is_data_url) {
1241 source_text = String::NewFromUtf8(
1242 isolate, module_specifier.c_str() + strlen(kDataURLPrefix));
1243 } else {
1244 DCHECK(IsAbsolutePath(module_specifier));
1245 source_text = ReadFile(isolate, module_specifier.c_str(), false);
1246 if (source_text.IsEmpty() && options.fuzzy_module_file_extensions) {
1247 std::string fallback_file_name = module_specifier + ".js";
1248 source_text = ReadFile(isolate, fallback_file_name.c_str(), false);
1249 if (source_text.IsEmpty()) {
1250 fallback_file_name = module_specifier + ".mjs";
1251 source_text = ReadFile(isolate, fallback_file_name.c_str());
1252 }
1253 }
1254 }
1255
1256 std::shared_ptr<ModuleEmbedderData> module_data =
1257 GetModuleDataFromContext(context);
1258 if (source_text.IsEmpty()) {
1259 std::string msg = "d8: Error reading module from " + module_specifier;
1260 if (!referrer.IsEmpty()) {
1261 std::string referrer_specifier =
1262 module_data->GetModuleSpecifier(referrer);
1263 msg += "\n imported by " + referrer_specifier;
1264 }
1265 ThrowError(isolate,
1266 v8::String::NewFromUtf8(isolate, msg.c_str()).ToLocalChecked());
1267 return MaybeLocal<Module>();
1268 }
1269
1270 Local<String> resource_name =
1271 String::NewFromUtf8(isolate, module_specifier.c_str()).ToLocalChecked();
1272 ScriptOrigin origin =
1273 CreateScriptOrigin(isolate, resource_name, ScriptType::kModule);
1274
1275 Local<Module> module;
1276 if (module_type == ModuleType::kJavaScript) {
1277 ScriptCompiler::Source source(source_text.ToLocalChecked(), origin);
1278 if (!CompileString<Module>(isolate, context, source_text.ToLocalChecked(),
1279 origin)
1280 .ToLocal(&module)) {
1281 return MaybeLocal<Module>();
1282 }
1283 } else if (module_type == ModuleType::kJSON) {
1284 Local<Value> parsed_json;
1285 if (!v8::JSON::Parse(context, source_text.ToLocalChecked())
1286 .ToLocal(&parsed_json)) {
1287 return MaybeLocal<Module>();
1288 }
1289
1290 auto export_names = v8::to_array<Local<String>>(
1291 {String::NewFromUtf8(isolate, "default").ToLocalChecked()});
1292
1294 isolate,
1295 String::NewFromUtf8(isolate, module_specifier.c_str()).ToLocalChecked(),
1296 export_names, Shell::JSONModuleEvaluationSteps);
1297
1298 CHECK(module_data->json_module_to_parsed_json_map
1299 .insert(std::make_pair(Global<Module>(isolate, module),
1300 Global<Value>(isolate, parsed_json)))
1301 .second);
1302 } else {
1303 UNREACHABLE();
1304 }
1305
1306 CHECK(
1307 module_data->module_map
1308 .insert(std::make_pair(std::make_pair(module_specifier, module_type),
1309 Global<Module>(isolate, module)))
1310 .second);
1311 CHECK(module_data->module_to_specifier_map
1312 .insert(std::make_pair(Global<Module>(isolate, module),
1313 module_specifier))
1314 .second);
1315
1316 // data URLs don't support further imports, so we're done.
1317 if (is_data_url) return module;
1318
1319 std::string dir_name = DirName(module_specifier);
1320
1321 Local<FixedArray> module_requests = module->GetModuleRequests();
1322 for (int i = 0, length = module_requests->Length(); i < length; ++i) {
1323 Local<ModuleRequest> module_request =
1324 module_requests->Get(context, i).As<ModuleRequest>();
1325 std::string specifier =
1326 ToSTLString(isolate, module_request->GetSpecifier());
1327 std::string normalized_specifier =
1328 NormalizeModuleSpecifier(specifier, dir_name);
1329 Local<FixedArray> import_attributes = module_request->GetImportAttributes();
1330 ModuleType request_module_type =
1331 ModuleEmbedderData::ModuleTypeFromImportSpecifierAndAttributes(
1332 context, normalized_specifier, import_attributes, true);
1333
1334 if (request_module_type == ModuleType::kInvalid) {
1335 ThrowError(isolate, "Invalid module type was asserted");
1336 return MaybeLocal<Module>();
1337 }
1338
1339 if (module_request->GetPhase() == ModuleImportPhase::kSource) {
1340 if (module_data->module_source_map.count(
1341 std::make_pair(normalized_specifier, request_module_type))) {
1342 continue;
1343 }
1344
1345 if (FetchModuleSource(module, context, normalized_specifier,
1346 request_module_type)
1347 .IsEmpty()) {
1348 return MaybeLocal<Module>();
1349 }
1350 } else {
1351 if (module_data->module_map.count(
1352 std::make_pair(normalized_specifier, request_module_type))) {
1353 continue;
1354 }
1355
1356 if (FetchModuleTree(module, context, normalized_specifier,
1357 request_module_type)
1358 .IsEmpty()) {
1359 return MaybeLocal<Module>();
1360 }
1361 }
1362 }
1363
1364 return module;
1365}
1366
1368 Local<Module> module) {
1369 Isolate* isolate = context->GetIsolate();
1370
1371 std::shared_ptr<ModuleEmbedderData> module_data =
1372 GetModuleDataFromContext(context);
1373 Local<Value> json_value = module_data->GetJsonModuleValue(module);
1374
1375 TryCatch try_catch(isolate);
1376 Maybe<bool> result = module->SetSyntheticModuleExport(
1377 isolate,
1378 String::NewFromUtf8Literal(isolate, "default",
1379 NewStringType::kInternalized),
1380 json_value);
1381
1382 // Setting the default export should never fail.
1383 CHECK(!try_catch.HasCaught());
1384 CHECK(!result.IsNothing() && result.FromJust());
1385
1386 Local<Promise::Resolver> resolver =
1387 Promise::Resolver::New(context).ToLocalChecked();
1388 resolver->Resolve(context, Undefined(isolate)).ToChecked();
1389 return resolver->GetPromise();
1390}
1391
1394 Local<Value> referrer_, Local<String> specifier_,
1395 ModuleImportPhase phase_,
1396 Local<FixedArray> import_attributes_,
1398 : isolate(isolate_), phase(phase_) {
1399 context.Reset(isolate, context_);
1400 referrer.Reset(isolate, referrer_);
1401 specifier.Reset(isolate, specifier_);
1402 import_attributes.Reset(isolate, import_attributes_);
1403 resolver.Reset(isolate, resolver_);
1404 }
1405
1407 // The initiating context. It can be the Realm created by d8, or the context
1408 // created by ShadowRealm built-in.
1415};
1416
1417namespace {
1418
1419enum ModuleResolutionDataIndex : uint32_t {
1420 kResolver = 0,
1421 kNamespaceOrSource = 1,
1422};
1423
1424} // namespace
1425
1427 const FunctionCallbackInfo<Value>& info) {
1429 Isolate* isolate(info.GetIsolate());
1430 HandleScope handle_scope(isolate);
1431 Local<Array> module_resolution_data(info.Data().As<Array>());
1432 Local<Context> context(isolate->GetCurrentContext());
1433
1434 Local<Promise::Resolver> resolver(
1435 module_resolution_data->Get(context, ModuleResolutionDataIndex::kResolver)
1436 .ToLocalChecked()
1437 .As<Promise::Resolver>());
1438 Local<Value> namespace_or_source(
1439 module_resolution_data
1440 ->Get(context, ModuleResolutionDataIndex::kNamespaceOrSource)
1441 .ToLocalChecked());
1442
1443 PerIsolateData* data = PerIsolateData::Get(isolate);
1444 Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
1445 Context::Scope context_scope(realm);
1446
1447 resolver->Resolve(realm, namespace_or_source).ToChecked();
1448}
1449
1451 const FunctionCallbackInfo<Value>& info) {
1453 Isolate* isolate(info.GetIsolate());
1454 HandleScope handle_scope(isolate);
1455 Local<Array> module_resolution_data(info.Data().As<Array>());
1456 Local<Context> context(isolate->GetCurrentContext());
1457
1458 Local<Promise::Resolver> resolver(
1459 module_resolution_data->Get(context, ModuleResolutionDataIndex::kResolver)
1460 .ToLocalChecked()
1461 .As<Promise::Resolver>());
1462
1463 PerIsolateData* data = PerIsolateData::Get(isolate);
1464 Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
1465 Context::Scope context_scope(realm);
1466
1467 DCHECK_EQ(info.Length(), 1);
1468 resolver->Reject(realm, info[0]).ToChecked();
1469}
1470
1472 Local<Context> context, Local<Data> host_defined_options,
1473 Local<Value> resource_name, Local<String> specifier,
1474 Local<FixedArray> import_attributes) {
1476 context, host_defined_options, resource_name, specifier,
1477 ModuleImportPhase::kEvaluation, import_attributes);
1478}
1479
1481 Local<Context> context, Local<Data> host_defined_options,
1482 Local<Value> resource_name, Local<String> specifier,
1483 ModuleImportPhase phase, Local<FixedArray> import_attributes) {
1484 Isolate* isolate = context->GetIsolate();
1485
1486 MaybeLocal<Promise::Resolver> maybe_resolver =
1487 Promise::Resolver::New(context);
1488 Local<Promise::Resolver> resolver;
1489 if (!maybe_resolver.ToLocal(&resolver)) return MaybeLocal<Promise>();
1490
1491 if (!resource_name->IsNull() &&
1492 !IsValidHostDefinedOptions(context, host_defined_options,
1493 resource_name)) {
1494 resolver
1496 isolate, "Invalid host defined options")))
1497 .ToChecked();
1498 } else {
1499 DynamicImportData* data =
1500 new DynamicImportData(isolate, context, resource_name, specifier, phase,
1501 import_attributes, resolver);
1503 isolate->EnqueueMicrotask(Shell::DoHostImportModuleDynamically, data);
1504 }
1505 return resolver->GetPromise();
1506}
1507
1509 Local<Module> module,
1510 Local<Object> meta) {
1511 Isolate* isolate = context->GetIsolate();
1512 HandleScope handle_scope(isolate);
1513
1514 std::shared_ptr<ModuleEmbedderData> module_data =
1515 GetModuleDataFromContext(context);
1516 std::string specifier = module_data->GetModuleSpecifier(module);
1517
1518 Local<String> url_key =
1520 Local<String> url =
1521 String::NewFromUtf8(isolate, specifier.c_str()).ToLocalChecked();
1522 meta->CreateDataProperty(context, url_key, url).ToChecked();
1523}
1524
1526 Local<Context> initiator_context) {
1527 Local<Context> context = v8::Context::New(initiator_context->GetIsolate());
1528 std::shared_ptr<ModuleEmbedderData> shadow_realm_data =
1529 InitializeModuleEmbedderData(context);
1530 std::shared_ptr<ModuleEmbedderData> initiator_data =
1531 GetModuleDataFromContext(initiator_context);
1532
1533 // ShadowRealms are synchronously accessible and are always in the same origin
1534 // as the initiator context.
1535 context->SetSecurityToken(initiator_context->GetSecurityToken());
1536 shadow_realm_data->origin = initiator_data->origin;
1537
1538 return context;
1539}
1540
1541namespace {
1542void RejectPromiseIfExecutionIsNotTerminating(Isolate* isolate,
1543 Local<Context> realm,
1544 Local<Promise::Resolver> resolver,
1545 const TryCatch& try_catch) {
1546 CHECK(try_catch.HasCaught());
1547 if (isolate->IsExecutionTerminating()) {
1548 Shell::ReportException(isolate, try_catch);
1549 } else {
1550 resolver->Reject(realm, try_catch.Exception()).ToChecked();
1551 }
1552}
1553
1554Maybe<bool> ChainDynamicImportPromise(Isolate* isolate, Local<Context> realm,
1556 Local<Promise> result_promise,
1557 Local<Value> namespace_or_source) {
1558 Local<Array> module_resolution_data = v8::Array::New(isolate);
1559 if (module_resolution_data->SetPrototypeV2(realm, v8::Null(isolate))
1560 .IsNothing()) {
1561 return Nothing<bool>();
1562 }
1563 if (module_resolution_data
1564 ->Set(realm, ModuleResolutionDataIndex::kResolver, resolver)
1565 .IsNothing()) {
1566 return Nothing<bool>();
1567 }
1568 if (module_resolution_data
1569 ->Set(realm, ModuleResolutionDataIndex::kNamespaceOrSource,
1570 namespace_or_source)
1571 .IsNothing()) {
1572 return Nothing<bool>();
1573 }
1574 Local<Function> callback_success;
1576 module_resolution_data)
1577 .ToLocal(&callback_success)) {
1578 return Nothing<bool>();
1579 }
1580
1581 Local<Function> callback_failure;
1583 module_resolution_data)
1584 .ToLocal(&callback_failure)) {
1585 return Nothing<bool>();
1586 }
1587 if (result_promise->Then(realm, callback_success, callback_failure)
1588 .IsEmpty()) {
1589 return Nothing<bool>();
1590 }
1591 return Just(true);
1592}
1593} // namespace
1594
1596 DynamicImportData* import_data_ =
1597 static_cast<DynamicImportData*>(import_data);
1598
1599 Isolate* isolate(import_data_->isolate);
1600 Global<Context> global_realm;
1601 Global<Promise::Resolver> global_resolver;
1602 Global<Promise> global_result_promise;
1603 Global<Value> global_namespace_or_source;
1604
1605 TryCatch try_catch(isolate);
1606 try_catch.SetVerbose(true);
1607
1608 {
1609 HandleScope handle_scope(isolate);
1610 Local<Context> realm = import_data_->context.Get(isolate);
1611 Local<Value> referrer = import_data_->referrer.Get(isolate);
1612 Local<String> v8_specifier = import_data_->specifier.Get(isolate);
1613 ModuleImportPhase phase = import_data_->phase;
1614 Local<FixedArray> import_attributes =
1615 import_data_->import_attributes.Get(isolate);
1616 Local<Promise::Resolver> resolver = import_data_->resolver.Get(isolate);
1617
1618 global_realm.Reset(isolate, realm);
1619 global_resolver.Reset(isolate, resolver);
1620
1621 PerIsolateData* data = PerIsolateData::Get(isolate);
1622 data->DeleteDynamicImportData(import_data_);
1623
1624 Context::Scope context_scope(realm);
1625 std::string specifier = ToSTLString(isolate, v8_specifier);
1626
1627 ModuleType module_type =
1628 ModuleEmbedderData::ModuleTypeFromImportSpecifierAndAttributes(
1629 realm, specifier, import_attributes, false);
1630
1631 if (module_type == ModuleType::kInvalid) {
1632 ThrowError(isolate, "Invalid module type was asserted");
1633 RejectPromiseIfExecutionIsNotTerminating(isolate, realm, resolver,
1634 try_catch);
1635 return;
1636 }
1637
1638 std::shared_ptr<ModuleEmbedderData> module_data =
1639 GetModuleDataFromContext(realm);
1640
1641 std::string source_url = referrer->IsNull()
1642 ? module_data->origin
1643 : ToSTLString(isolate, referrer.As<String>());
1644 std::string dir_name =
1645 DirName(NormalizePath(source_url, GetWorkingDirectory()));
1646 std::string absolute_path = NormalizeModuleSpecifier(specifier, dir_name);
1647
1648 switch (phase) {
1650 Local<Object> module_source;
1651 auto module_it = module_data->module_source_map.find(
1652 std::make_pair(absolute_path, module_type));
1653 if (module_it != module_data->module_source_map.end()) {
1654 module_source = module_it->second.Get(isolate);
1655 } else if (!FetchModuleSource(Local<Module>(), realm, absolute_path,
1656 module_type)
1657 .ToLocal(&module_source)) {
1658 break;
1659 }
1660 Local<Promise::Resolver> module_resolver =
1661 Promise::Resolver::New(realm).ToLocalChecked();
1662 module_resolver->Resolve(realm, module_source).ToChecked();
1663
1664 global_namespace_or_source.Reset(isolate, module_source);
1665 global_result_promise.Reset(isolate, module_resolver->GetPromise());
1666 break;
1667 }
1669 Local<Module> root_module;
1670 auto module_it = module_data->module_map.find(
1671 std::make_pair(absolute_path, module_type));
1672 if (module_it != module_data->module_map.end()) {
1673 root_module = module_it->second.Get(isolate);
1674 } else if (!FetchModuleTree(Local<Module>(), realm, absolute_path,
1675 module_type)
1676 .ToLocal(&root_module)) {
1677 break;
1678 }
1679 if (root_module
1680 ->InstantiateModule(realm, ResolveModuleCallback,
1681 ResolveModuleSourceCallback)
1682 .FromMaybe(false)) {
1683 MaybeLocal<Value> maybe_result = root_module->Evaluate(realm);
1684 if (maybe_result.IsEmpty()) break;
1685 global_result_promise.Reset(
1686 isolate, maybe_result.ToLocalChecked().As<Promise>());
1687 global_namespace_or_source.Reset(isolate,
1688 root_module->GetModuleNamespace());
1689 }
1690 break;
1691 }
1692 default: {
1693 UNREACHABLE();
1694 }
1695 }
1696 }
1697
1698 if (global_result_promise.IsEmpty()) {
1699 HandleScope handle_scope(isolate);
1700 Local<Context> realm = global_realm.Get(isolate);
1701 Local<Promise::Resolver> resolver = global_resolver.Get(isolate);
1702 RejectPromiseIfExecutionIsNotTerminating(isolate, realm, resolver,
1703 try_catch);
1704 return;
1705 }
1706
1707 {
1708 // This method is invoked from a microtask, where in general we may have
1709 // an non-trivial stack. Emptying the message queue below may trigger the
1710 // execution of a stackless GC. We need to override the embedder stack
1711 // state, to force scanning the stack, if this happens.
1712 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
1714 heap, i::EmbedderStackStateOrigin::kExplicitInvocation,
1715 StackState::kMayContainHeapPointers);
1716 EmptyMessageQueues(isolate);
1717 }
1718
1719 // Setup callbacks, and then chain them to the result promise.
1720 HandleScope handle_scope(isolate);
1721 Local<Context> realm = global_realm.Get(isolate);
1722 Local<Promise::Resolver> resolver = global_resolver.Get(isolate);
1723 Local<Promise> result_promise = global_result_promise.Get(isolate);
1724 Local<Value> namespace_or_source = global_namespace_or_source.Get(isolate);
1725
1726 Context::Scope context_scope(realm);
1727
1728 // Chaining the promise generally does not throw, but execution may be
1729 // terminating (e.g. when within a worker being terminated). Check the return
1730 // value to display a helpful message.
1731 if (ChainDynamicImportPromise(isolate, realm, resolver, result_promise,
1732 namespace_or_source)
1733 .IsNothing()) {
1734 RejectPromiseIfExecutionIsNotTerminating(isolate, realm, resolver,
1735 try_catch);
1736 }
1737}
1738
1739bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
1740 HandleScope handle_scope(isolate);
1741 Global<Module> global_root_module;
1742 Global<Promise> global_result_promise;
1743
1744 // Use a non-verbose TryCatch and report exceptions manually using
1745 // Shell::ReportException, because some errors (such as file errors) are
1746 // thrown without entering JS and thus do not trigger
1747 // isolate->ReportPendingMessages().
1748 TryCatch try_catch(isolate);
1749
1750 {
1751 PerIsolateData* data = PerIsolateData::Get(isolate);
1752 Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
1753 Context::Scope context_scope(realm);
1754
1755 std::string absolute_path =
1756 NormalizeModuleSpecifier(file_name, GetWorkingDirectory());
1757
1758 std::shared_ptr<ModuleEmbedderData> module_data =
1759 GetModuleDataFromContext(realm);
1760 Local<Module> root_module;
1761 auto module_it = module_data->module_map.find(
1762 std::make_pair(absolute_path, ModuleType::kJavaScript));
1763 if (module_it != module_data->module_map.end()) {
1764 root_module = module_it->second.Get(isolate);
1765 } else if (!FetchModuleTree(Local<Module>(), realm, absolute_path,
1767 .ToLocal(&root_module)) {
1768 CHECK(try_catch.HasCaught());
1769 ReportException(isolate, try_catch);
1770 return false;
1771 }
1772 global_root_module.Reset(isolate, root_module);
1773
1774 module_data->origin = absolute_path;
1775
1776 MaybeLocal<Value> maybe_result;
1777 if (root_module
1778 ->InstantiateModule(realm, ResolveModuleCallback,
1779 ResolveModuleSourceCallback)
1780 .FromMaybe(false)) {
1781 maybe_result = root_module->Evaluate(realm);
1782 CHECK(!maybe_result.IsEmpty());
1783 global_result_promise.Reset(isolate,
1784 maybe_result.ToLocalChecked().As<Promise>());
1785 }
1786 }
1787
1788 if (!global_result_promise.IsEmpty()) {
1789 EmptyMessageQueues(isolate);
1790 } else {
1791 DCHECK(try_catch.HasCaught());
1792 ReportException(isolate, try_catch);
1793 return false;
1794 }
1795
1796 // Loop until module execution finishes
1797 while (isolate->HasPendingBackgroundTasks() ||
1798 (i::ValueHelper::HandleAsValue(global_result_promise)->State() ==
1800 reinterpret_cast<i::Isolate*>(isolate)
1801 ->default_microtask_queue()
1802 ->size() > 0)) {
1804 }
1805
1806 {
1807 Local<Promise> result_promise = global_result_promise.Get(isolate);
1808 Local<Module> root_module = global_root_module.Get(isolate);
1809
1810 if (result_promise->State() == Promise::kRejected) {
1811 // If the exception has been caught by the promise pipeline, we rethrow
1812 // here in order to ReportException.
1813 // TODO(cbruni): Clean this up after we create a new API for the case
1814 // where TLA is enabled.
1815 if (!try_catch.HasCaught()) {
1816 isolate->ThrowException(result_promise->Result());
1817 } else {
1818 DCHECK_EQ(try_catch.Exception(), result_promise->Result());
1819 }
1820 ReportException(isolate, try_catch);
1821 return false;
1822 }
1823
1824 auto [stalled_modules, stalled_messages] =
1825 root_module->GetStalledTopLevelAwaitMessages(isolate);
1826 DCHECK_EQ(stalled_modules.size(), stalled_messages.size());
1827 if (stalled_messages.size() > 0) {
1828 Local<Message> message = stalled_messages[0];
1829 ReportException(isolate, message, v8::Exception::Error(message->Get()));
1830 return false;
1831 }
1832 }
1833
1834 DCHECK(!try_catch.HasCaught());
1835 return true;
1836}
1837
1838// Treat every line as a JSON value and parse it.
1839bool Shell::LoadJSON(Isolate* isolate, const char* file_name) {
1840 HandleScope handle_scope(isolate);
1841 PerIsolateData* isolate_data = PerIsolateData::Get(isolate);
1842 Local<Context> realm =
1843 isolate_data->realms_[isolate_data->realm_current_].Get(isolate);
1844 Context::Scope context_scope(realm);
1845 TryCatch try_catch(isolate);
1846
1847 std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory());
1848 int length = 0;
1849 std::unique_ptr<char[]> data(ReadChars(absolute_path.c_str(), &length));
1850 if (length == 0) {
1851 printf("Error reading '%s'\n", file_name);
1853 }
1854 std::stringstream stream(data.get());
1855 std::string line;
1856 while (std::getline(stream, line, '\n')) {
1857 for (int r = 0; r < DeserializationRunCount(); ++r) {
1858 Local<String> source =
1859 String::NewFromUtf8(isolate, line.c_str()).ToLocalChecked();
1860 MaybeLocal<Value> maybe_value = JSON::Parse(realm, source);
1861
1863 if (!maybe_value.ToLocal(&value)) {
1864 DCHECK(try_catch.HasCaught());
1865 ReportException(isolate, try_catch);
1866 return false;
1867 }
1868 }
1869 }
1870 return true;
1871}
1872
1874 : isolate_(isolate), realms_(nullptr) {
1875 isolate->SetData(0, this);
1876 if (i::v8_flags.expose_async_hooks) {
1877 async_hooks_wrapper_ = new AsyncHooks(isolate);
1878 }
1880}
1881
1883 isolate_->SetData(0, nullptr); // Not really needed, just to be sure...
1884 if (i::v8_flags.expose_async_hooks) {
1885 delete async_hooks_wrapper_; // This uses the isolate
1886 }
1887#if defined(LEAK_SANITIZER)
1888 for (DynamicImportData* data : import_data_) {
1889 delete data;
1890 }
1891#endif
1892}
1893
1895 if (ignore_unhandled_promises_) return;
1896 // Remove handled promises from the list
1897 DCHECK_EQ(promise->GetIsolate(), isolate_);
1898 for (auto it = unhandled_promises_.begin(); it != unhandled_promises_.end();
1899 ++it) {
1900 v8::Local<v8::Promise> unhandled_promise = std::get<0>(*it).Get(isolate_);
1901 if (unhandled_promise == promise) {
1902 unhandled_promises_.erase(it--);
1903 }
1904 }
1905}
1906
1908 Local<Message> message,
1909 Local<Value> exception) {
1910 if (ignore_unhandled_promises_) return;
1911 DCHECK_EQ(promise->GetIsolate(), isolate_);
1914 v8::Global<v8::Value>(isolate_, exception));
1915}
1916
1918 // Avoid recursive calls to HandleUnhandledPromiseRejections.
1919 if (ignore_unhandled_promises_) return 0;
1920 if (isolate_->IsExecutionTerminating()) return 0;
1923 // Ignore promises that get added during error reporting.
1924 size_t i = 0;
1925 for (; i < unhandled_promises_.size(); i++) {
1926 const auto& tuple = unhandled_promises_[i];
1927 Local<v8::Message> message = std::get<1>(tuple).Get(isolate_);
1928 Local<v8::Value> value = std::get<2>(tuple).Get(isolate_);
1929 Shell::ReportException(isolate_, message, value);
1930 }
1933 return static_cast<int>(i);
1934}
1935
1937#if defined(LEAK_SANITIZER)
1938 import_data_.insert(data);
1939#endif
1940}
1942#if defined(LEAK_SANITIZER)
1943 import_data_.erase(data);
1944#endif
1945 delete data;
1946}
1947
1951
1955
1959
1963
1965 // Only consider subscribed workers, so that code that spawns a worker and
1966 // never subscribes to message events will quit.
1967 return !worker_message_callbacks_.empty();
1968}
1969
1970void PerIsolateData::RegisterWorker(std::shared_ptr<Worker> worker) {
1971 registered_workers_.insert(std::move(worker));
1972}
1973
1975 const std::shared_ptr<Worker>& worker, Local<Context> context,
1977 if (!registered_workers_.contains(worker)) {
1978 // The worker has already terminated, so it won't be posting any more
1979 // messages. Don't try to subscribe to its events.
1980 fprintf(
1981 stderr,
1982 "Trying to subscribe to message events from a terminated worker -- "
1983 "consider registering the event handler before the event loop runs.\n");
1984 return;
1985 }
1987 worker, std::make_pair(Global<Context>(isolate_, context),
1989}
1990
1992 const std::shared_ptr<Worker>& worker) const {
1993 auto it = worker_message_callbacks_.find(worker);
1994 if (it == worker_message_callbacks_.end()) {
1995 return {};
1996 }
1997 return {it->second.first.Get(isolate_), it->second.second.Get(isolate_)};
1998}
1999
2000void PerIsolateData::UnregisterWorker(const std::shared_ptr<Worker>& worker) {
2001 registered_workers_.erase(worker);
2002 worker_message_callbacks_.erase(worker);
2003}
2004
2006 const Global<Context>& context)
2007 : data_(PerIsolateData::Get(isolate)) {
2008 data_->realm_count_ = 1;
2009 data_->realm_current_ = 0;
2010 data_->realm_switch_ = 0;
2011 data_->realms_ = new Global<Context>[1];
2012 data_->realms_[0].Reset(data_->isolate_, context);
2013}
2014
2016 // Drop realms to avoid keeping them alive.
2017 data_->realm_count_ = 0;
2018 delete[] data_->realms_;
2019}
2020
2022 int index)
2023 : data_(data), index_(index) {
2024 realm_ = Local<Context>::New(data->isolate_, data->realms_[index_]);
2025 realm_->Enter();
2026 previous_index_ = data->realm_current_;
2027 data->realm_current_ = data->realm_switch_ = index_;
2028}
2029
2031 realm_->Exit();
2032 data_->realm_current_ = data_->realm_switch_ = previous_index_;
2033}
2034
2038
2040 for (int i = 0; i < realm_count_; ++i) {
2041 if (realms_[i] == context) return i;
2042 }
2043 return -1;
2044}
2045
2047 const v8::FunctionCallbackInfo<v8::Value>& info, int arg_offset) {
2048 if (info.Length() < arg_offset || !info[arg_offset]->IsNumber()) {
2049 ThrowError(info.GetIsolate(), "Invalid argument");
2050 return -1;
2051 }
2052 int index = info[arg_offset]
2053 ->Int32Value(info.GetIsolate()->GetCurrentContext())
2054 .FromMaybe(-1);
2055 if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
2056 ThrowError(info.GetIsolate(), "Invalid realm index");
2057 return -1;
2058 }
2059 return index;
2060}
2061
2062// GetTimestamp() returns a time stamp as double, measured in milliseconds.
2063// When v8_flags.verify_predictable mode is enabled it returns result of
2064// v8::Platform::MonotonicallyIncreasingTime().
2066 if (i::v8_flags.verify_predictable) {
2067 return g_platform->MonotonicallyIncreasingTime();
2068 } else {
2069 base::TimeDelta delta = base::TimeTicks::Now() - kInitialTicks;
2070 return delta.InMillisecondsF();
2071 }
2072}
2074 double performance_timestamp) {
2075 // Don't use this in --verify-predictable mode, predictable timestamps don't
2076 // work well with tracing.
2077 DCHECK(!i::v8_flags.verify_predictable);
2078 base::TimeDelta delta =
2079 base::TimeDelta::FromMillisecondsD(performance_timestamp);
2080 // See TracingController::CurrentTimestampMicroseconds().
2081 int64_t internal_value = (delta + kInitialTicks).ToInternalValue();
2082 DCHECK_GE(internal_value, 0);
2083 return internal_value;
2084}
2085
2086#ifdef V8_OS_LINUX
2087void SendPerfControlCommand(const char* command) {
2088 if (Shell::options.perf_ctl_fd != -1 && Shell::options.perf_ack_fd != -1) {
2089 size_t command_len = strlen(command);
2090 ssize_t ret = write(Shell::options.perf_ctl_fd, command, command_len);
2091 if (ret == -1) {
2092 fprintf(stderr, "perf_ctl write error: %s\n", strerror(errno));
2093 }
2094 CHECK_EQ(ret, command_len);
2095
2096 char ack[5];
2097 ret = read(Shell::options.perf_ack_fd, ack, 5);
2098 if (ret == -1) {
2099 fprintf(stderr, "perf_ack read error: %s\n", strerror(errno));
2100 }
2101 CHECK_EQ(ret, 5);
2102 CHECK_EQ(strcmp(ack, "ack\n"), 0);
2103 }
2104}
2105#endif
2106
2107// performance.now() returns GetTimestamp().
2110 info.GetReturnValue().Set(GetTimestamp());
2111}
2112
2113// performance.mark() records and returns a PerformanceEntry with the current
2114// timestamp.
2117 Isolate* isolate = info.GetIsolate();
2118 Local<Context> context = isolate->GetCurrentContext();
2119
2120 if (info.Length() < 1 || !info[0]->IsString()) {
2121 ThrowError(info.GetIsolate(), "Invalid 'name' argument");
2122 return;
2123 }
2124 Local<String> name = info[0].As<String>();
2125
2126 double timestamp = GetTimestamp();
2127
2128 Local<Object> performance_entry = Object::New(isolate);
2129 performance_entry
2130 ->DefineOwnProperty(context,
2131 String::NewFromUtf8Literal(isolate, "entryType"),
2132 String::NewFromUtf8Literal(isolate, "mark"), ReadOnly)
2133 .Check();
2134 performance_entry
2135 ->DefineOwnProperty(context, String::NewFromUtf8Literal(isolate, "name"),
2136 name, ReadOnly)
2137 .Check();
2138 performance_entry
2139 ->DefineOwnProperty(context,
2140 String::NewFromUtf8Literal(isolate, "startTime"),
2141 Number::New(isolate, timestamp), ReadOnly)
2142 .Check();
2143 performance_entry
2144 ->DefineOwnProperty(context,
2145 String::NewFromUtf8Literal(isolate, "duration"),
2146 Integer::New(isolate, 0), ReadOnly)
2147 .Check();
2148
2149 info.GetReturnValue().Set(performance_entry);
2150
2151#ifdef V8_OS_LINUX
2152 if (options.scope_linux_perf_to_mark_measure) {
2153 SendPerfControlCommand("enable");
2154 }
2155#endif
2156}
2157
2158// performance.measure() records and returns a PerformanceEntry with a duration
2159// since a given mark, or since zero.
2163 Isolate* isolate = info.GetIsolate();
2164 Local<Context> context = isolate->GetCurrentContext();
2165
2166 if (info.Length() < 1 || !info[0]->IsString()) {
2167 ThrowError(info.GetIsolate(), "Invalid 'name' argument");
2168 return;
2169 }
2170 v8::Local<String> name = info[0].As<String>();
2171
2172 double start_timestamp = 0;
2173 if (info.Length() >= 2) {
2174#ifdef V8_OS_LINUX
2175 if (options.scope_linux_perf_to_mark_measure) {
2176 SendPerfControlCommand("disable");
2177 }
2178#endif
2179
2180 Local<Value> start_mark = info[1].As<Value>();
2181 if (!start_mark->IsObject()) {
2182 ThrowError(info.GetIsolate(),
2183 "Invalid 'startMark' argument: Not an Object");
2184 return;
2185 }
2186 Local<Value> start_time_field;
2187 if (!start_mark.As<Object>()
2188 ->Get(context, String::NewFromUtf8Literal(isolate, "startTime"))
2189 .ToLocal(&start_time_field)) {
2190 return;
2191 }
2192 if (!start_time_field->IsNumber()) {
2193 ThrowError(info.GetIsolate(),
2194 "Invalid 'startMark' argument: No numeric 'startTime' field");
2195 return;
2196 }
2197 start_timestamp = start_time_field.As<Number>()->Value();
2198 }
2199 if (info.Length() > 2) {
2200 ThrowError(info.GetIsolate(), "Too many arguments");
2201 return;
2202 }
2203
2204 double end_timestamp = GetTimestamp();
2205
2206 if (options.trace_enabled) {
2207 size_t hash = base::hash_combine(name->GetIdentityHash(), start_timestamp,
2208 end_timestamp);
2209
2210 String::Utf8Value utf8(isolate, name);
2212 "v8", *utf8, static_cast<uint64_t>(hash),
2213 GetTracingTimestampFromPerformanceTimestamp(start_timestamp),
2214 "startTime", start_timestamp);
2216 "v8", *utf8, static_cast<uint64_t>(hash),
2217 GetTracingTimestampFromPerformanceTimestamp(end_timestamp));
2218 }
2219
2220 Local<Object> performance_entry = Object::New(isolate);
2221 performance_entry
2222 ->DefineOwnProperty(
2223 context, String::NewFromUtf8Literal(isolate, "entryType"),
2224 String::NewFromUtf8Literal(isolate, "measure"), ReadOnly)
2225 .Check();
2226 performance_entry
2227 ->DefineOwnProperty(context, String::NewFromUtf8Literal(isolate, "name"),
2228 name, ReadOnly)
2229 .Check();
2230 performance_entry
2231 ->DefineOwnProperty(context,
2232 String::NewFromUtf8Literal(isolate, "startTime"),
2233 Number::New(isolate, start_timestamp), ReadOnly)
2234 .Check();
2235 performance_entry
2236 ->DefineOwnProperty(
2237 context, String::NewFromUtf8Literal(isolate, "duration"),
2238 Number::New(isolate, end_timestamp - start_timestamp), ReadOnly)
2239 .Check();
2240
2241 info.GetReturnValue().Set(performance_entry);
2242}
2243
2244// performance.measureMemory() implements JavaScript Memory API proposal.
2245// See https://github.com/ulan/javascript-agent-memory/blob/master/explainer.md.
2250 v8::Isolate* isolate = info.GetIsolate();
2251 Local<Context> context = isolate->GetCurrentContext();
2252 if (info.Length() >= 1 && info[0]->IsObject()) {
2253 Local<Object> object = info[0].As<Object>();
2254 Local<Value> value = TryGetValue(isolate, context, object, "detailed")
2255 .FromMaybe(Local<Value>());
2256 if (value.IsEmpty()) {
2257 // Exception was thrown and scheduled, so return from the callback.
2258 return;
2259 }
2260 if (value->IsBoolean() && value->BooleanValue(isolate)) {
2262 }
2263 }
2264 Local<v8::Promise::Resolver> promise_resolver =
2265 v8::Promise::Resolver::New(context).ToLocalChecked();
2266 info.GetIsolate()->MeasureMemory(
2267 v8::MeasureMemoryDelegate::Default(isolate, context, promise_resolver,
2268 mode),
2270 info.GetReturnValue().Set(promise_resolver->GetPromise());
2271}
2272
2273// Realm.current() returns the index of the currently active realm.
2276 Isolate* isolate = info.GetIsolate();
2277 PerIsolateData* data = PerIsolateData::Get(isolate);
2278 int index = data->RealmFind(isolate->GetEnteredOrMicrotaskContext());
2279 if (index == -1) return;
2280 info.GetReturnValue().Set(index);
2281}
2282
2283// Realm.owner(o) returns the index of the realm that created o.
2286 Isolate* isolate = info.GetIsolate();
2287 PerIsolateData* data = PerIsolateData::Get(isolate);
2288 if (info.Length() < 1 || !info[0]->IsObject()) {
2289 ThrowError(info.GetIsolate(), "Invalid argument");
2290 return;
2291 }
2292 Local<Object> object =
2293 info[0]->ToObject(isolate->GetCurrentContext()).ToLocalChecked();
2295 if (IsJSGlobalProxy(*i_object) &&
2296 i::Cast<i::JSGlobalProxy>(i_object)->IsDetached()) {
2297 return;
2298 }
2299 Local<Context> creation_context;
2300 if (!object->GetCreationContext(isolate).ToLocal(&creation_context)) {
2301 ThrowError(info.GetIsolate(), "object doesn't have creation context");
2302 return;
2303 }
2304 int index = data->RealmFind(creation_context);
2305 if (index == -1) return;
2306 info.GetReturnValue().Set(index);
2307}
2308
2309// Realm.global(i) returns the global object of realm i.
2310// (Note that properties of global objects cannot be read/written cross-realm.)
2313 PerIsolateData* data = PerIsolateData::Get(info.GetIsolate());
2314 int index = data->RealmIndexOrThrow(info, 0);
2315 if (index == -1) return;
2316 // TODO(chromium:324812): Ideally Context::Global should never return raw
2317 // global objects but return a global proxy. Currently it returns global
2318 // object when the global proxy is detached from the global object. The
2319 // following is a workaround till we fix Context::Global so we don't leak
2320 // global objects.
2321 Local<Object> global =
2322 Local<Context>::New(info.GetIsolate(), data->realms_[index])->Global();
2324 if (IsJSGlobalObject(*i_global)) {
2325 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
2326 i::DirectHandle<i::JSObject> i_global_proxy(
2327 i::Cast<i::JSGlobalObject>(i_global)->global_proxy(), i_isolate);
2328 global = Utils::ToLocal(i_global_proxy);
2329 }
2330 info.GetReturnValue().Set(global);
2331}
2332
2334 const v8::FunctionCallbackInfo<v8::Value>& info, int index,
2335 v8::MaybeLocal<Value> global_object) {
2337 const char* kGlobalHandleLabel = "d8::realm";
2338 Isolate* isolate = info.GetIsolate();
2339 TryCatch try_catch(isolate);
2340 PerIsolateData* data = PerIsolateData::Get(isolate);
2341 if (index < 0) {
2342 Global<Context>* old_realms = data->realms_;
2343 index = data->realm_count_;
2344 data->realms_ = new Global<Context>[++data->realm_count_];
2345 for (int i = 0; i < index; ++i) {
2346 Global<Context>& realm = data->realms_[i];
2347 realm.Reset(isolate, old_realms[i]);
2348 if (!realm.IsEmpty()) {
2349 realm.AnnotateStrongRetainer(kGlobalHandleLabel);
2350 }
2351 old_realms[i].Reset();
2352 }
2353 delete[] old_realms;
2354 }
2355 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
2356 Local<Context> context =
2357 Context::New(isolate, nullptr, global_template, global_object);
2358 if (context.IsEmpty()) return MaybeLocal<Context>();
2359 DCHECK(!try_catch.HasCaught());
2360 InitializeModuleEmbedderData(context);
2361 data->realms_[index].Reset(isolate, context);
2362 data->realms_[index].AnnotateStrongRetainer(kGlobalHandleLabel);
2363 info.GetReturnValue().Set(index);
2364 return context;
2365}
2366
2368 int index) {
2370 Isolate* isolate = info.GetIsolate();
2371 PerIsolateData* data = PerIsolateData::Get(isolate);
2372 Local<Context> context = data->realms_[index].Get(isolate);
2373 data->realms_[index].Reset();
2374 // ContextDisposedNotification expects the disposed context to be entered.
2375 v8::Context::Scope scope(context);
2376 isolate->ContextDisposedNotification(v8::ContextDependants::kSomeDependants);
2377}
2378
2379// Realm.create() creates a new realm with a distinct security token
2380// and returns its index.
2383 CreateRealm(info, -1, v8::MaybeLocal<Value>());
2384}
2385
2386// Realm.createAllowCrossRealmAccess() creates a new realm with the same
2387// security token as the current realm.
2392 if (CreateRealm(info, -1, v8::MaybeLocal<Value>()).ToLocal(&context)) {
2393 context->SetSecurityToken(
2394 info.GetIsolate()->GetEnteredOrMicrotaskContext()->GetSecurityToken());
2395 }
2396}
2397
2398// Realm.navigate(i) creates a new realm with a distinct security token
2399// in place of realm i.
2402 Isolate* isolate = info.GetIsolate();
2403 PerIsolateData* data = PerIsolateData::Get(isolate);
2404 int index = data->RealmIndexOrThrow(info, 0);
2405 if (index == -1) return;
2406 if (index == 0 || index == data->realm_current_ ||
2407 index == data->realm_switch_) {
2408 ThrowError(info.GetIsolate(), "Invalid realm index");
2409 return;
2410 }
2411
2412 Local<Context> context = Local<Context>::New(isolate, data->realms_[index]);
2413 v8::MaybeLocal<Value> global_object = context->Global();
2414
2415 // Context::Global doesn't return JSGlobalProxy if DetachGlobal is called in
2416 // advance.
2417 if (!global_object.IsEmpty()) {
2418 HandleScope scope(isolate);
2419 if (!IsJSGlobalProxy(
2420 *Utils::OpenDirectHandle(*global_object.ToLocalChecked()))) {
2421 global_object = v8::MaybeLocal<Value>();
2422 }
2423 }
2424
2425 DisposeRealm(info, index);
2426 CreateRealm(info, index, global_object);
2427}
2428
2429// Realm.detachGlobal(i) detaches the global objects of realm i from realm i.
2432 Isolate* isolate = info.GetIsolate();
2433 PerIsolateData* data = PerIsolateData::Get(isolate);
2434 int index = data->RealmIndexOrThrow(info, 0);
2435 if (index == -1) return;
2436 if (index == 0 || index == data->realm_current_ ||
2437 index == data->realm_switch_) {
2438 ThrowError(info.GetIsolate(), "Invalid realm index");
2439 return;
2440 }
2441
2442 HandleScope scope(isolate);
2443 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
2444 realm->DetachGlobal();
2445}
2446
2447// Realm.dispose(i) disposes the reference to the realm i.
2450 Isolate* isolate = info.GetIsolate();
2451 PerIsolateData* data = PerIsolateData::Get(isolate);
2452 int index = data->RealmIndexOrThrow(info, 0);
2453 if (index == -1) return;
2454 if (index == 0 || index == data->realm_current_ ||
2455 index == data->realm_switch_) {
2456 ThrowError(info.GetIsolate(), "Invalid realm index");
2457 return;
2458 }
2459 DisposeRealm(info, index);
2460}
2461
2462// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
2465 Isolate* isolate = info.GetIsolate();
2466 PerIsolateData* data = PerIsolateData::Get(isolate);
2467 int index = data->RealmIndexOrThrow(info, 0);
2468 if (index == -1) return;
2469 data->realm_switch_ = index;
2470}
2471
2472// Realm.eval(i, s) evaluates s in realm i and returns the result.
2475 Isolate* isolate = info.GetIsolate();
2476 PerIsolateData* data = PerIsolateData::Get(isolate);
2477 int index = data->RealmIndexOrThrow(info, 0);
2478 if (index == -1) return;
2479 if (info.Length() < 2) {
2480 ThrowError(isolate, "Invalid argument");
2481 return;
2482 }
2483
2485 if (!ReadSource(info, 1, CodeType::kString).ToLocal(&source)) {
2486 ThrowError(isolate, "Invalid argument");
2487 return;
2488 }
2489 ScriptOrigin origin =
2490 CreateScriptOrigin(isolate, String::NewFromUtf8Literal(isolate, "(d8)"),
2492
2493 if (isolate->IsExecutionTerminating()) return;
2494 ScriptCompiler::Source script_source(source, origin);
2495 Local<UnboundScript> script;
2496 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
2497 .ToLocal(&script)) {
2498 return;
2499 }
2501 {
2502 PerIsolateData::ExplicitRealmScope realm_scope(data, index);
2503 if (!script->BindToCurrentContext()
2504 ->Run(realm_scope.context())
2505 .ToLocal(&result)) {
2506 return;
2507 }
2508 }
2509 info.GetReturnValue().Set(result);
2510}
2511
2512// Realm.shared is an accessor for a single shared value across realms.
2514 const PropertyCallbackInfo<Value>& info) {
2516 Isolate* isolate = info.GetIsolate();
2517 PerIsolateData* data = PerIsolateData::Get(isolate);
2518 if (data->realm_shared_.IsEmpty()) return;
2519 info.GetReturnValue().Set(data->realm_shared_);
2520}
2521
2523 const PropertyCallbackInfo<void>& info) {
2525 Isolate* isolate = info.GetIsolate();
2526 PerIsolateData* data = PerIsolateData::Get(isolate);
2527 data->realm_shared_.Reset(isolate, value);
2528}
2529
2532 Isolate* isolate = info.GetIsolate();
2533 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2534 HandleScope handle_scope(isolate);
2535
2536 std::string file_name = i_isolate->v8_file_logger()->file_name();
2537 if (!i::LogFile::IsLoggingToTemporaryFile(file_name)) {
2538 ThrowError(isolate, "Only capturing from temporary files is supported.");
2539 return;
2540 }
2541 if (!i_isolate->v8_file_logger()->is_logging()) {
2542 ThrowError(isolate, "Logging not enabled.");
2543 return;
2544 }
2545
2546 std::string raw_log;
2547 FILE* log_file = i_isolate->v8_file_logger()->TearDownAndGetLogFile();
2548 if (!log_file) {
2549 ThrowError(isolate, "Log file does not exist.");
2550 return;
2551 }
2552
2553 bool exists = false;
2554 raw_log = i::ReadFile(log_file, &exists, true);
2555 base::Fclose(log_file);
2556
2557 if (!exists) {
2558 ThrowError(isolate, "Unable to read log file.");
2559 return;
2560 }
2562 String::NewFromUtf8(isolate, raw_log.c_str(), NewStringType::kNormal,
2563 static_cast<int>(raw_log.size()))
2564 .ToLocalChecked();
2565
2566 info.GetReturnValue().Set(result);
2567}
2568
2571 Isolate* isolate = info.GetIsolate();
2572 // Check if the argument is a valid function.
2573 if (info.Length() != 1) {
2574 ThrowError(isolate, "Expected function as single argument.");
2575 return;
2576 }
2577 auto arg_handle = Utils::OpenHandle(*info[0]);
2578 if (!IsHeapObject(*arg_handle) ||
2579 !IsJSFunctionOrBoundFunctionOrWrappedFunction(
2580 *i::Cast<i::HeapObject>(arg_handle))) {
2581 ThrowError(isolate, "Expected function as single argument.");
2582 return;
2583 }
2584
2585 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2586 HandleScope handle_scope(isolate);
2587
2588 auto callable =
2590 while (IsJSBoundFunction(*callable)) {
2592 auto bound_function = i::Cast<i::JSBoundFunction>(callable);
2593 auto bound_target = bound_function->bound_target_function();
2594 if (!IsJSFunctionOrBoundFunctionOrWrappedFunction(bound_target)) {
2596 ThrowError(isolate, "Expected function as bound target.");
2597 return;
2598 }
2599 callable = handle(
2601 i_isolate);
2602 }
2603
2605 if (!function->shared()->HasBytecodeArray()) {
2606 ThrowError(isolate, "Function has no BytecodeArray attached.");
2607 return;
2608 }
2609 i::Handle<i::BytecodeArray> bytecodes =
2610 handle(function->shared()->GetBytecodeArray(i_isolate), i_isolate);
2611 i::interpreter::BytecodeArrayIterator bytecode_iterator(bytecodes);
2612 bool has_baseline = function->shared()->HasBaselineCode();
2613 i::Handle<i::TrustedByteArray> bytecode_offsets;
2614 std::unique_ptr<i::baseline::BytecodeOffsetIterator> offset_iterator;
2615 if (has_baseline) {
2616 bytecode_offsets = handle(
2618 function->shared()->GetCode(i_isolate)->bytecode_offset_table()),
2619 i_isolate);
2620 offset_iterator = std::make_unique<i::baseline::BytecodeOffsetIterator>(
2621 bytecode_offsets, bytecodes);
2622 // A freshly initiated BytecodeOffsetIterator points to the prologue.
2623 DCHECK_EQ(offset_iterator->current_pc_start_offset(), 0);
2624 DCHECK_EQ(offset_iterator->current_bytecode_offset(),
2626 offset_iterator->Advance();
2627 }
2628 while (!bytecode_iterator.done()) {
2629 if (has_baseline) {
2630 if (offset_iterator->current_bytecode_offset() !=
2631 bytecode_iterator.current_offset()) {
2632 ThrowError(isolate, "Baseline bytecode offset mismatch.");
2633 return;
2634 }
2635 // Check that we map every address to this bytecode correctly.
2636 // The start address is exclusive and the end address inclusive.
2637 for (i::Address pc = offset_iterator->current_pc_start_offset() + 1;
2638 pc <= offset_iterator->current_pc_end_offset(); ++pc) {
2639 i::baseline::BytecodeOffsetIterator pc_lookup(bytecode_offsets,
2640 bytecodes);
2641 pc_lookup.AdvanceToPCOffset(pc);
2642 if (pc_lookup.current_bytecode_offset() !=
2643 bytecode_iterator.current_offset()) {
2644 ThrowError(isolate,
2645 "Baseline bytecode offset mismatch for PC lookup.");
2646 return;
2647 }
2648 }
2649 }
2650 bytecode_iterator.Advance();
2651 if (has_baseline && !bytecode_iterator.done()) {
2652 if (offset_iterator->done()) {
2653 ThrowError(isolate, "Missing bytecode(s) in baseline offset mapping.");
2654 return;
2655 }
2656 offset_iterator->Advance();
2657 }
2658 }
2659 if (has_baseline && !offset_iterator->done()) {
2660 ThrowError(isolate, "Excess offsets in baseline offset mapping.");
2661 return;
2662 }
2663}
2664
2667 Isolate* isolate = info.GetIsolate();
2668 isolate->InstallConditionalFeatures(isolate->GetCurrentContext());
2669}
2670
2672 Isolate* isolate = info.GetIsolate();
2673 isolate->SetWasmJSPIEnabledCallback([](auto) { return true; });
2674 isolate->InstallConditionalFeatures(isolate->GetCurrentContext());
2675}
2676
2678 Isolate* isolate = info.GetIsolate();
2679 if (i::v8_flags.correctness_fuzzer_suppressions) {
2680 // Setting denormals flushing in the middle of code is almost certain to
2681 // cause correctness issues, in a way that isn't interesting to us. Make
2682 // this a no-op instead.
2683 return;
2684 }
2685 // Check if the argument is a valid function.
2686 if (info.Length() != 1) {
2687 ThrowError(isolate, "Expected single boolean argument.");
2688 return;
2689 }
2690 Local<Value> arg = info[0];
2691 if (!arg->IsBoolean()) {
2692 ThrowError(isolate, "Expected single boolean argument.");
2693 return;
2694 }
2696}
2697
2698// async_hooks.createHook() registers functions to be called for different
2699// lifetime events of each async operation.
2702 Local<Object> wrap =
2703 PerIsolateData::Get(info.GetIsolate())->GetAsyncHooks()->CreateHook(info);
2704 info.GetReturnValue().Set(wrap);
2705}
2706
2707// async_hooks.executionAsyncId() returns the asyncId of the current execution
2708// context.
2711 Isolate* isolate = info.GetIsolate();
2712 HandleScope handle_scope(isolate);
2713 info.GetReturnValue().Set(v8::Number::New(
2714 isolate,
2715 PerIsolateData::Get(isolate)->GetAsyncHooks()->GetExecutionAsyncId()));
2716}
2717
2720 Isolate* isolate = info.GetIsolate();
2721 HandleScope handle_scope(isolate);
2722 info.GetReturnValue().Set(v8::Number::New(
2723 isolate,
2724 PerIsolateData::Get(isolate)->GetAsyncHooks()->GetTriggerAsyncId()));
2725}
2726
2728
2732
2734 v8::debug::SetDebugDelegate(info.GetIsolate(), nullptr);
2735}
2736
2739 Isolate* isolate = info.GetIsolate();
2740 if (i::v8_flags.correctness_fuzzer_suppressions) {
2741 // Setting promise hooks dynamically has unexpected timing side-effects
2742 // with certain promise optimizations. We might not get all callbacks for
2743 // previously scheduled Promises or optimized code-paths that skip Promise
2744 // creation.
2745 ThrowError(isolate,
2746 "d8.promise.setHooks is disabled with "
2747 "--correctness-fuzzer-suppressions");
2748 return;
2749 }
2750#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
2751 Local<Context> context = isolate->GetCurrentContext();
2752 HandleScope handle_scope(isolate);
2753
2754 context->SetPromiseHooks(
2755 info[0]->IsFunction() ? info[0].As<Function>() : Local<Function>(),
2756 info[1]->IsFunction() ? info[1].As<Function>() : Local<Function>(),
2757 info[2]->IsFunction() ? info[2].As<Function>() : Local<Function>(),
2758 info[3]->IsFunction() ? info[3].As<Function>() : Local<Function>());
2759
2760 info.GetReturnValue().Set(v8::Undefined(isolate));
2761#else // V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
2762 ThrowError(isolate,
2763 "d8.promise.setHooks is disabled due to missing build flag "
2764 "v8_enabale_javascript_in_promise_hooks");
2765#endif // V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
2766}
2767
2771 Isolate* isolate = info.GetIsolate();
2772 HandleScope handle_scope(isolate);
2773 Local<Context> context = isolate->GetCurrentContext();
2774
2775 ValueSerializer serializer(isolate);
2776 serializer.WriteHeader();
2777 for (int i = 0; i < info.Length(); i++) {
2778 bool ok;
2779 if (!serializer.WriteValue(context, info[i]).To(&ok)) return;
2780 }
2782 {
2783 std::pair<uint8_t*, size_t> pair = serializer.Release();
2784 buffer = ArrayBuffer::New(isolate, pair.second);
2785 memcpy(buffer->GetBackingStore()->Data(), pair.first, pair.second);
2786 free(pair.first);
2787 }
2788 info.GetReturnValue().Set(buffer);
2789}
2790
2794 Isolate* isolate = info.GetIsolate();
2795 HandleScope handle_scope(isolate);
2796 Local<Context> context = isolate->GetCurrentContext();
2797
2798 if (!info[0]->IsArrayBuffer()) {
2799 ThrowError(isolate, "Can only deserialize from an ArrayBuffer");
2800 return;
2801 }
2802 std::shared_ptr<BackingStore> backing_store =
2803 info[0].As<ArrayBuffer>()->GetBackingStore();
2804 ValueDeserializer deserializer(
2805 isolate, static_cast<const uint8_t*>(backing_store->Data()),
2806 backing_store->ByteLength());
2807 bool ok;
2808 if (!deserializer.ReadHeader(context).To(&ok)) return;
2810 if (!deserializer.ReadValue(context).ToLocal(&result)) return;
2811 info.GetReturnValue().Set(result);
2812}
2813
2817 Isolate* isolate = info.GetIsolate();
2818 HandleScope handle_scope(isolate);
2819 if (!info[0]->IsFunction()) {
2820 ThrowError(isolate, "The OnProfileEnd listener has to be a function");
2821 return;
2822 }
2823 base::MutexGuard lock_guard(&profiler_end_callback_lock_);
2824 profiler_end_callback_[isolate] =
2825 std::make_pair(Global<Function>(isolate, info[0].As<Function>()),
2826 Global<Context>(isolate, isolate->GetCurrentContext()));
2827}
2828
2830 base::MutexGuard lock_guard(&profiler_end_callback_lock_);
2831 return profiler_end_callback_.find(isolate) != profiler_end_callback_.end();
2832}
2833
2835 // If the inspector is enabled, then the installed console is not the
2836 // D8Console.
2837 if (options.enable_inspector) return;
2838 {
2839 base::MutexGuard lock_guard(&profiler_end_callback_lock_);
2840 profiler_end_callback_.erase(isolate);
2841 }
2842
2843 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2844 D8Console* console =
2845 reinterpret_cast<D8Console*>(i_isolate->console_delegate());
2846 if (console) {
2847 console->DisposeProfiler();
2848 }
2849}
2850
2853 Isolate* isolate = info.GetIsolate();
2854 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2855 D8Console* console =
2856 reinterpret_cast<D8Console*>(i_isolate->console_delegate());
2857 if (console && console->profiler()) {
2858 console->profiler()->CollectSample(isolate);
2859 }
2860}
2861
2862void Shell::TriggerOnProfileEndListener(Isolate* isolate, std::string profile) {
2863 CHECK(HasOnProfileEndListener(isolate));
2866 Local<Value> argv[1] = {
2867 String::NewFromUtf8(isolate, profile.c_str()).ToLocalChecked()};
2868 {
2869 base::MutexGuard lock_guard(&profiler_end_callback_lock_);
2870 auto& callback_pair = profiler_end_callback_[isolate];
2871 callback = callback_pair.first.Get(isolate);
2872 context = callback_pair.second.Get(isolate);
2873 }
2874 TryCatch try_catch(isolate);
2875 try_catch.SetVerbose(true);
2876 USE(callback->Call(context, Undefined(isolate), 1, argv));
2877}
2878
2880 int first_arg_index = 0) {
2881 for (int i = first_arg_index; i < info.Length(); i++) {
2882 HandleScope handle_scope(info.GetIsolate());
2883 if (i != first_arg_index) {
2884 fprintf(file, " ");
2885 }
2886
2887 // Explicitly catch potential exceptions in toString().
2888 v8::TryCatch try_catch(info.GetIsolate());
2889 Local<Value> arg = info[i];
2890 Local<String> str_obj;
2891
2892 if (arg->IsSymbol()) {
2893 arg = arg.As<Symbol>()->Description(info.GetIsolate());
2894 }
2895 if (!arg->ToString(info.GetIsolate()->GetCurrentContext())
2896 .ToLocal(&str_obj)) {
2897 try_catch.ReThrow();
2898 return;
2899 }
2900
2901 v8::String::Utf8Value str(info.GetIsolate(), str_obj);
2902 size_t n = fwrite(*str, sizeof(**str), str.length(), file);
2903 if (n != str.length()) {
2904 printf("Error in fwrite\n");
2906 }
2907 }
2908}
2909
2910void WriteAndFlush(FILE* file,
2913 WriteToFile(file, info);
2914 fprintf(file, "\n");
2915 fflush(file);
2916}
2917
2919 WriteAndFlush(stdout, info);
2920}
2921
2923 WriteAndFlush(stderr, info);
2924}
2925
2927 WriteToFile(stdout, info);
2928}
2929
2930// There are two overloads of writeFile().
2931//
2932// The first parameter is always the filename.
2933//
2934// If there are exactly 2 arguments, and the second argument is an ArrayBuffer
2935// or an ArrayBufferView, write the binary contents into the file.
2936//
2937// Otherwise, convert arguments to UTF-8 strings, and write them to the file,
2938// separated by space.
2941 String::Utf8Value file_name(info.GetIsolate(), info[0]);
2942 if (*file_name == nullptr) {
2943 ThrowError(info.GetIsolate(), "Error converting filename to string");
2944 return;
2945 }
2946 FILE* file;
2947 if (info.Length() == 2 &&
2948 (info[1]->IsArrayBuffer() || info[1]->IsArrayBufferView())) {
2949 file = base::Fopen(*file_name, "wb");
2950 if (file == nullptr) {
2951 ThrowError(info.GetIsolate(), "Error opening file");
2952 return;
2953 }
2954
2955 void* data;
2956 size_t length;
2957 if (info[1]->IsArrayBuffer()) {
2959 length = buffer->ByteLength();
2960 data = buffer->Data();
2961 } else {
2962 Local<v8::ArrayBufferView> buffer_view =
2964 length = buffer_view->ByteLength();
2965 data = static_cast<uint8_t*>(buffer_view->Buffer()->Data()) +
2966 buffer_view->ByteOffset();
2967 }
2968 fwrite(data, 1, length, file);
2969 } else {
2970 file = base::Fopen(*file_name, "w");
2971 if (file == nullptr) {
2972 ThrowError(info.GetIsolate(), "Error opening file");
2973 return;
2974 }
2975 WriteToFile(file, info, 1);
2976 }
2977 base::Fclose(file);
2978}
2979
2982 String::Utf8Value file_name(info.GetIsolate(), info[0]);
2983 if (*file_name == nullptr) {
2984 ThrowError(info.GetIsolate(), "Error converting filename to string");
2985 return;
2986 }
2987 if (info.Length() == 2) {
2988 String::Utf8Value format(info.GetIsolate(), info[1]);
2989 if (*format && std::strcmp(*format, "binary") == 0) {
2990 ReadBuffer(info);
2991 return;
2992 }
2993 }
2995 if (!ReadFile(info.GetIsolate(), *file_name).ToLocal(&source)) return;
2996 info.GetReturnValue().Set(source);
2997}
2998
2999#if V8_TARGET_OS_LINUX && V8_ENABLE_WEBASSEMBLY
3002 CHECK(i::v8_flags.experimental_wasm_memory_control);
3004 String::Utf8Value file_name(info.GetIsolate(), info[0]);
3005 if (*file_name == nullptr) {
3006 ThrowError(info.GetIsolate(), "Error converting filename to string");
3007 return;
3008 }
3009
3010 int file_descriptor = open(*file_name, O_RDWR);
3011
3013 static_cast<WasmMemoryMapDescriptor::WasmFileDescriptor>(file_descriptor);
3014 info.GetReturnValue().Set(
3015 v8::WasmMemoryMapDescriptor::New(info.GetIsolate(), wasm_fd));
3016}
3017#endif // V8_TARGET_OS_LINUX
3018
3020 static const int kBufferSize = 256;
3021 char buffer[kBufferSize];
3022 Local<String> accumulator = String::NewFromUtf8Literal(isolate, "");
3023 int length;
3024 // Flush stdout before reading stdin, as stdout isn't guaranteed to be flushed
3025 // automatically.
3026 fflush(stdout);
3027 while (true) {
3028 // Continue reading if the line ends with an escape '\\' or the line has
3029 // not been fully read into the buffer yet (does not end with '\n').
3030 // If fgets gets an error, just give up.
3031 char* input = nullptr;
3032 input = fgets(buffer, kBufferSize, stdin);
3033 if (input == nullptr) return Local<String>();
3034 length = static_cast<int>(strlen(buffer));
3035 if (length == 0) {
3036 return accumulator;
3037 } else if (buffer[length - 1] != '\n') {
3038 accumulator = String::Concat(
3039 isolate, accumulator,
3040 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
3041 .ToLocalChecked());
3042 } else if (length > 1 && buffer[length - 2] == '\\') {
3043 buffer[length - 2] = '\n';
3044 accumulator =
3045 String::Concat(isolate, accumulator,
3046 String::NewFromUtf8(isolate, buffer,
3047 NewStringType::kNormal, length - 1)
3048 .ToLocalChecked());
3049 } else {
3050 return String::Concat(
3051 isolate, accumulator,
3053 length - 1)
3054 .ToLocalChecked());
3055 }
3056 }
3057}
3058
3061 Isolate* isolate = info.GetIsolate();
3062 for (int i = 0; i < info.Length(); i++) {
3063 HandleScope handle_scope(isolate);
3064 String::Utf8Value file_name(isolate, info[i]);
3065 if (*file_name == nullptr) {
3066 std::ostringstream oss;
3067 oss << "Cannot convert file[" << i << "] name to string.";
3068 ThrowError(
3069 isolate,
3070 String::NewFromUtf8(isolate, oss.str().c_str()).ToLocalChecked());
3071 return;
3072 }
3074 if (!ReadFile(isolate, *file_name).ToLocal(&source)) return;
3075 if (!ExecuteString(
3076 info.GetIsolate(), source,
3077 String::NewFromUtf8(isolate, *file_name).ToLocalChecked(),
3078 options.quiet_load ? kNoReportExceptions : kReportExceptions)) {
3079 std::ostringstream oss;
3080 oss << "Error executing file: \"" << *file_name << '"';
3081 ThrowError(
3082 isolate,
3083 String::NewFromUtf8(isolate, oss.str().c_str()).ToLocalChecked());
3084 return;
3085 }
3086 }
3087}
3088
3089class SetTimeoutTask : public v8::Task {
3090 public:
3093 : isolate_(isolate),
3094 context_(isolate, context),
3095 callback_(isolate, callback) {}
3096
3097 void Run() override {
3098 HandleScope scope(isolate_);
3099 Local<Context> context = context_.Get(isolate_);
3101 Context::Scope context_scope(context);
3103 callback->Call(context, Undefined(isolate_), 0, nullptr);
3104 USE(result);
3105 }
3106
3107 private:
3111};
3112
3115 Isolate* isolate = info.GetIsolate();
3116 info.GetReturnValue().Set(v8::Number::New(isolate, 0));
3117 if (info.Length() == 0 || !info[0]->IsFunction()) return;
3118 Local<Function> callback = info[0].As<Function>();
3119 Local<Context> context = isolate->GetCurrentContext();
3120 g_platform->GetForegroundTaskRunner(isolate)->PostTask(
3121 std::make_unique<SetTimeoutTask>(isolate, context, callback));
3122}
3123
3124#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA
3125void Shell::GetContinuationPreservedEmbedderData(
3127 info.GetReturnValue().Set(
3128 info.GetIsolate()->GetContinuationPreservedEmbedderData());
3129}
3130#endif // V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA
3131
3134 Local<Context> context = info.GetIsolate()->GetCurrentContext();
3135 info.GetReturnValue().Set(context->GetExtrasBindingObject());
3136}
3137
3139 const v8::FunctionCallbackInfo<v8::Value>& info, int index,
3140 CodeType* code_type, Local<Value>* arguments) {
3141 Isolate* isolate = info.GetIsolate();
3142 if (info.Length() > index && info[index]->IsObject()) {
3143 Local<Object> object = info[index].As<Object>();
3144 Local<Context> context = isolate->GetCurrentContext();
3146 if (!TryGetValue(isolate, context, object, "type").ToLocal(&value)) {
3147 *code_type = CodeType::kNone;
3148 return;
3149 }
3150 if (!value->IsString()) {
3151 *code_type = CodeType::kInvalid;
3152 return;
3153 }
3154 Local<String> worker_type_string =
3155 value->ToString(context).ToLocalChecked();
3156 String::Utf8Value str(isolate, worker_type_string);
3157 if (strcmp("classic", *str) == 0) {
3158 *code_type = CodeType::kFileName;
3159 } else if (strcmp("string", *str) == 0) {
3160 *code_type = CodeType::kString;
3161 } else if (strcmp("function", *str) == 0) {
3162 *code_type = CodeType::kFunction;
3163 } else {
3164 *code_type = CodeType::kInvalid;
3165 }
3166 if (arguments != nullptr) {
3167 bool got_arguments =
3168 TryGetValue(isolate, context, object, "arguments").ToLocal(arguments);
3169 USE(got_arguments);
3170 }
3171 } else {
3172 *code_type = CodeType::kNone;
3173 }
3174}
3175
3177 Local<Value> arguments,
3178 Local<String>* source,
3179 Isolate* isolate) {
3180 Local<Context> context = isolate->GetCurrentContext();
3181 MaybeLocal<String> maybe_function_string =
3182 function->FunctionProtoToString(context);
3183 Local<String> function_string;
3184 if (!maybe_function_string.ToLocal(&function_string)) {
3185 ThrowError(isolate, "Failed to convert function to string");
3186 return false;
3187 }
3188 *source = String::NewFromUtf8Literal(isolate, "(");
3189 *source = String::Concat(isolate, *source, function_string);
3190 Local<String> middle = String::NewFromUtf8Literal(isolate, ")(");
3191 *source = String::Concat(isolate, *source, middle);
3192 if (!arguments.IsEmpty() && !arguments->IsUndefined()) {
3193 if (!arguments->IsArray()) {
3194 ThrowError(isolate, "'arguments' must be an array");
3195 return false;
3196 }
3197 Local<String> comma = String::NewFromUtf8Literal(isolate, ",");
3198 Local<Array> array = arguments.As<Array>();
3199 for (uint32_t i = 0; i < array->Length(); ++i) {
3200 if (i > 0) {
3201 *source = String::Concat(isolate, *source, comma);
3202 }
3203 MaybeLocal<Value> maybe_argument = array->Get(context, i);
3204 Local<Value> argument;
3205 if (!maybe_argument.ToLocal(&argument)) {
3206 ThrowError(isolate, "Failed to get argument");
3207 return false;
3208 }
3209 Local<String> argument_string;
3210 if (!JSON::Stringify(context, argument).ToLocal(&argument_string)) {
3211 ThrowError(isolate, "Failed to convert argument to string");
3212 return false;
3213 }
3214 *source = String::Concat(isolate, *source, argument_string);
3215 }
3216 }
3217 Local<String> suffix = String::NewFromUtf8Literal(isolate, ")");
3218 *source = String::Concat(isolate, *source, suffix);
3219 return true;
3220}
3221
3222// ReadSource() supports reading source code through `info[index]` as specified
3223// by the `default_type` or an optional options bag provided in `info[index+1]`
3224// (e.g. `options={type: 'code_type', arguments:[...]}`).
3226 const v8::FunctionCallbackInfo<v8::Value>& info, int index,
3227 CodeType default_type) {
3228 CodeType code_type;
3229 Local<Value> arguments;
3230 ReadCodeTypeAndArguments(info, index + 1, &code_type, &arguments);
3231
3232 Isolate* isolate = info.GetIsolate();
3234 if (code_type == CodeType::kNone) {
3235 code_type = default_type;
3236 }
3237 switch (code_type) {
3238 case CodeType::kFunction:
3239 if (!info[index]->IsFunction()) {
3240 return MaybeLocal<String>();
3241 }
3242 // Source: ( function_to_string )( params )
3243 if (!FunctionAndArgumentsToString(info[index].As<Function>(), arguments,
3244 &source, isolate)) {
3245 return MaybeLocal<String>();
3246 }
3247 break;
3248 case CodeType::kFileName: {
3249 if (!info[index]->IsString()) {
3250 return MaybeLocal<String>();
3251 }
3252 String::Utf8Value filename(isolate, info[index]);
3253 if (!Shell::ReadFile(isolate, *filename).ToLocal(&source)) {
3254 return MaybeLocal<String>();
3255 }
3256 break;
3257 }
3258 case CodeType::kString:
3259 if (!info[index]->IsString()) {
3260 return MaybeLocal<String>();
3261 }
3262 source = info[index].As<String>();
3263 break;
3264 case CodeType::kNone:
3265 case CodeType::kInvalid:
3266 return MaybeLocal<String>();
3267 }
3268 return source;
3269}
3270
3273 Isolate* isolate = info.GetIsolate();
3274 HandleScope handle_scope(isolate);
3275 if (info.Length() < 1 || (!info[0]->IsString() && !info[0]->IsFunction())) {
3276 ThrowError(isolate, "1st argument must be a string or a function");
3277 return;
3278 }
3279
3281 if (!ReadSource(info, 0, CodeType::kFileName).ToLocal(&source)) {
3282 ThrowError(isolate, "Invalid argument");
3283 return;
3284 }
3285
3286 if (!info.IsConstructCall()) {
3287 ThrowError(isolate, "Worker must be constructed with new");
3288 return;
3289 }
3290
3291 // Initialize the embedder field to 0; if we return early without
3292 // creating a new Worker (because the main thread is terminating) we can
3293 // early-out from the instance calls.
3294 info.This()->SetInternalField(0, v8::Integer::New(isolate, 0));
3295
3296 // By default, propagate flush denormals state.
3297 bool flush_denormals = base::FPU::GetFlushDenormals();
3298 if (info.Length() > 1 && info[1]->IsObject()) {
3300 if (!TryGetValue(isolate, isolate->GetCurrentContext(),
3301 info[1].As<Object>(), "flushDenormals")
3302 .ToLocal(&value)) {
3303 return;
3304 }
3305 if (!value->IsUndefined()) {
3306 flush_denormals = value->BooleanValue(isolate);
3307 }
3308 }
3309
3310 {
3311 // Don't allow workers to create more workers if the main thread
3312 // is waiting for existing running workers to terminate.
3313 i::ParkedMutexGuard lock_guard(
3314 reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(),
3315 workers_mutex_.Pointer());
3316 if (!allow_new_workers_) return;
3317
3318 String::Utf8Value script(isolate, source);
3319 if (!*script) {
3320 ThrowError(isolate, "Can't get worker script");
3321 return;
3322 }
3323
3324 // The C++ worker object's lifetime is shared between the Managed<Worker>
3325 // object on the heap, which the JavaScript object points to, and an
3326 // internal std::shared_ptr in the worker thread itself.
3327 auto worker = std::make_shared<Worker>(isolate, *script, flush_denormals);
3328 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3329 const size_t kWorkerSizeEstimate = 4 * 1024 * 1024; // stack + heap.
3331 i::Managed<Worker>::From(i_isolate, kWorkerSizeEstimate, worker);
3332 info.This()->SetInternalField(0, Utils::ToLocal(managed));
3334 options.apply_priority ? base::Thread::Priority::kUserBlocking
3336 if (!Worker::StartWorkerThread(isolate, worker, priority)) {
3337 ThrowError(isolate, "Can't start thread");
3338 return;
3339 }
3340 PerIsolateData::Get(isolate)->RegisterWorker(worker);
3341 }
3342}
3343
3346 Isolate* isolate = info.GetIsolate();
3347 HandleScope handle_scope(isolate);
3348
3349 if (info.Length() < 1) {
3350 ThrowError(isolate, "Invalid argument");
3351 return;
3352 }
3353
3354 std::shared_ptr<Worker> worker =
3355 GetWorkerFromInternalField(isolate, info.This());
3356 if (!worker.get()) {
3357 return;
3358 }
3359
3360 Local<Value> message = info[0];
3361 Local<Value> transfer =
3362 info.Length() >= 2 ? info[1] : Undefined(isolate).As<Value>();
3363 std::unique_ptr<SerializationData> data =
3364 Shell::SerializeValue(isolate, message, transfer);
3365 if (data) {
3366 worker->PostMessage(std::move(data));
3367 }
3368}
3369
3372 Isolate* isolate = info.GetIsolate();
3373 HandleScope handle_scope(isolate);
3374 std::shared_ptr<Worker> worker =
3375 GetWorkerFromInternalField(isolate, info.This());
3376 if (!worker.get()) {
3377 return;
3378 }
3379
3380 std::unique_ptr<SerializationData> data = worker->GetMessage(isolate);
3381 if (data) {
3383 if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) {
3384 info.GetReturnValue().Set(value);
3385 }
3386 }
3387}
3388
3389// Task processing one onmessage event received from a Worker.
3391 public:
3394 std::unique_ptr<SerializationData> data)
3395 : isolate_(isolate),
3396 context_(isolate, context),
3397 callback_(isolate, callback),
3398 data_(std::move(data)) {}
3399
3400 void Run() override {
3401 HandleScope scope(isolate_);
3402 Local<Context> context = context_.Get(isolate_);
3403 Context::Scope context_scope(context);
3404 MicrotasksScope microtasks_scope(context,
3405 MicrotasksScope::kDoNotRunMicrotasks);
3406
3407 Local<Object> global = context->Global();
3408
3409 // Get the message handler.
3410 Local<Value> onmessage = callback_.Get(isolate_);
3411 if (!onmessage->IsFunction()) return;
3412 Local<Function> onmessage_fun = onmessage.As<Function>();
3413
3414 v8::TryCatch try_catch(isolate_);
3415 try_catch.SetVerbose(true);
3417 if (Shell::DeserializeValue(isolate_, std::move(data_)).ToLocal(&value)) {
3418 DCHECK(!isolate_->IsExecutionTerminating());
3420 event
3421 ->CreateDataProperty(
3422 context,
3423 String::NewFromUtf8Literal(isolate_, "data",
3424 NewStringType::kInternalized),
3425 value)
3426 .ToChecked();
3427 Local<Value> argv[] = {event};
3428 MaybeLocal<Value> result = onmessage_fun->Call(context, global, 1, argv);
3429 USE(result);
3430 }
3431 }
3432
3433 private:
3437 std::unique_ptr<SerializationData> data_;
3438};
3439
3440// Check, on the main thread, whether a worker has any enqueued any message
3441// events. Workers post this task when posting a message, instead of posting
3442// OnMessageFromWorkerTask directly, to avoid races between message posting
3443// and onmessage subscription.
3445 public:
3447 std::shared_ptr<Worker> worker)
3448 : isolate_(isolate), worker_(std::move(worker)) {}
3449
3450 void Run() override {
3451 HandleScope scope(isolate_);
3452
3453 // Get the callback for onmessage events from this worker. It's important to
3454 // do this here, and not in OnMessageFromWorkerTask, because we may get a
3455 // CleanUpWorkerTask scheduled before the posted OnMessageFromWorkerTask
3456 // executes, which will
3457 auto callback_pair =
3458 PerIsolateData::Get(isolate_)->GetWorkerOnMessage(worker_);
3459 // Bail out if there's no callback -- leave the message queue untouched so
3460 // that we don't lose the messages and can read them with GetMessage later.
3461 // This is slightly different to browser behaviour, where events can be
3462 // missed, but it's helpful for d8's GetMessage behaviour.
3463 if (callback_pair.second.IsEmpty()) return;
3464
3465 std::unique_ptr<SerializationData> result;
3466 while ((result = worker_->TryGetMessage())) {
3467 // Each onmessage callback call is posted as a separate task.
3468 g_platform->GetForegroundTaskRunner(isolate_)->PostTask(
3469 std::make_unique<OnMessageFromWorkerTask>(
3470 isolate_, callback_pair.first, callback_pair.second,
3471 std::move(result)));
3472 }
3473 }
3474
3475 private:
3477 std::shared_ptr<Worker> worker_;
3478};
3479
3480// Unregister the given isolate from message events from the given worker.
3481// This must be done before the isolate or worker are destroyed, so that the
3482// global handles for context and callback are cleaned up correctly -- thus the
3483// event loop blocks until all workers are unregistered.
3485 public:
3486 CleanUpWorkerTask(v8::Isolate* isolate, std::shared_ptr<Worker> worker)
3487 : isolate_(isolate), worker_(std::move(worker)) {}
3488
3489 void Run() override {
3490 PerIsolateData::Get(isolate_)->UnregisterWorker(std::move(worker_));
3491 }
3492
3493 private:
3495 std::shared_ptr<Worker> worker_;
3496};
3497
3501 Isolate* isolate = info.GetIsolate();
3502 HandleScope handle_scope(isolate);
3503
3504 std::shared_ptr<Worker> worker =
3505 GetWorkerFromInternalField(isolate, info.This());
3506 if (!worker.get()) {
3507 return;
3508 }
3510 PerIsolateData::Get(isolate)->GetWorkerOnMessage(worker).second;
3511
3512 if (!callback.IsEmpty()) {
3513 info.GetReturnValue().Set(callback);
3514 }
3515}
3516
3520 Isolate* isolate = info.GetIsolate();
3521 HandleScope handle_scope(isolate);
3522
3523 if (info.Length() < 1) {
3524 ThrowError(isolate, "Invalid argument");
3525 return;
3526 }
3527
3528 std::shared_ptr<Worker> worker =
3529 GetWorkerFromInternalField(isolate, info.This());
3530 if (!worker.get()) {
3531 return;
3532 }
3533
3534 Local<Value> callback = info[0];
3535 if (!callback->IsFunction()) return;
3536
3538 worker, isolate->GetCurrentContext(), Local<Function>::Cast(callback));
3539}
3540
3543 Isolate* isolate = info.GetIsolate();
3544 HandleScope handle_scope(isolate);
3545 std::shared_ptr<Worker> worker =
3546 GetWorkerFromInternalField(isolate, info.This());
3547 if (!worker.get()) return;
3548 worker->Terminate();
3549}
3550
3554 Isolate* isolate = info.GetIsolate();
3555 HandleScope handle_scope(isolate);
3556 std::shared_ptr<Worker> worker =
3557 GetWorkerFromInternalField(isolate, info.This());
3558 if (!worker.get()) {
3559 return;
3560 }
3561
3562 reinterpret_cast<i::Isolate*>(isolate)
3563 ->main_thread_local_isolate()
3564 ->ExecuteMainThreadWhileParked([worker](const i::ParkedScope& parked) {
3565 worker->TerminateAndWaitForThread(parked);
3566 });
3567}
3568
3570 int exit_code = (*info)[0]
3571 ->Int32Value(info->GetIsolate()->GetCurrentContext())
3572 .FromMaybe(0);
3573 Isolate* isolate = info->GetIsolate();
3574 ResetOnProfileEndListener(isolate);
3575
3576 // As we exit the process anyway, we do not dispose the platform and other
3577 // global data and manually unlock to quell DCHECKs. Other isolates might
3578 // still be running, so disposing here can cause them to crash.
3579 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3580 if (i_isolate->thread_manager()->IsLockedByCurrentThread()) {
3581 i_isolate->thread_manager()->Unlock();
3582 }
3583
3584 // When disposing the shared space isolate, the workers (client isolates) need
3585 // to be terminated first.
3586 if (i_isolate->is_shared_space_isolate()) {
3588 [](const i::ParkedScope& parked) { WaitForRunningWorkers(parked); });
3589 }
3590
3591 // Reset thread-locals here only after stopping workers. They are still used
3592 // e.g. during heap verification in shared GCs.
3593 isolate->Exit();
3594
3595 OnExit(isolate, false);
3596 base::OS::ExitProcess(exit_code);
3597}
3598
3599namespace {
3600
3601bool SkipTerminationForFuzzing() {
3602 // Triggering termination from JS can cause some non-determinism thus we
3603 // skip it for correctness fuzzing.
3604 if (i::v8_flags.correctness_fuzzer_suppressions) return true;
3605 // Termination also currently breaks Fuzzilli's REPRL mechanism as the
3606 // scheduled termination will prevent the next testcase sent by Fuzzilli from
3607 // being processed. This will in turn desynchronize the communication
3608 // between d8 and Fuzzilli, leading to a crash.
3609 if (fuzzilli_reprl) return true;
3610 return false;
3611}
3612
3613} // namespace
3614
3617 if (SkipTerminationForFuzzing()) return;
3618 auto v8_isolate = info.GetIsolate();
3619 if (!v8_isolate->IsExecutionTerminating()) {
3620 // Force a termination exception for immediate termination.
3621 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
3622 i_isolate->TerminateExecution();
3623 }
3624}
3625
3629 if (SkipTerminationForFuzzing()) return;
3630 auto v8_isolate = info.GetIsolate();
3631 // Schedule a termination request, handled by an interrupt later.
3632 if (!v8_isolate->IsExecutionTerminating()) v8_isolate->TerminateExecution();
3633}
3634
3637 base::CallOnce(&quit_once_, &QuitOnce,
3638 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&info));
3639}
3640
3643 info.GetReturnValue().Set(
3644 String::NewFromUtf8(info.GetIsolate(), V8::GetVersion())
3645 .ToLocalChecked());
3646}
3647
3649 Local<v8::Value> exception_obj) {
3650 HandleScope handle_scope(isolate);
3651 Local<Context> context = isolate->GetCurrentContext();
3652 bool enter_context = context.IsEmpty();
3653 if (enter_context) {
3654 context = Local<Context>::New(isolate, evaluation_context_);
3655 context->Enter();
3656 }
3657 // Converts a V8 value to a C string.
3658 auto ToCString = [](const v8::String::Utf8Value& value) {
3659 return *value ? *value : "<string conversion failed>";
3660 };
3661
3662 v8::String::Utf8Value exception(isolate, exception_obj);
3663 const char* exception_string = ToCString(exception);
3664 if (message.IsEmpty()) {
3665 // V8 didn't provide any extra information about this error; just
3666 // print the exception.
3667 printf("%s\n", exception_string);
3668 } else if (message->GetScriptOrigin().Options().IsWasm()) {
3669 // Print wasm-function[(function index)]:(offset): (message).
3670 int function_index = message->GetWasmFunctionIndex();
3671 int offset = message->GetStartColumn(context).FromJust();
3672 printf("wasm-function[%d]:0x%x: %s\n", function_index, offset,
3673 exception_string);
3674 } else {
3675 // Print (filename):(line number): (message).
3677 message->GetScriptOrigin().ResourceName());
3678 const char* filename_string = ToCString(filename);
3679 int linenum = message->GetLineNumber(context).FromMaybe(-1);
3680 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
3681 Local<String> sourceline;
3682 if (message->GetSourceLine(context).ToLocal(&sourceline)) {
3683 // Print line of source code.
3684 v8::String::Utf8Value sourcelinevalue(isolate, sourceline);
3685 const char* sourceline_string = ToCString(sourcelinevalue);
3686 printf("%s\n", sourceline_string);
3687 // Print wavy underline (GetUnderline is deprecated).
3688 int start = message->GetStartColumn(context).FromJust();
3689 for (int i = 0; i < start; i++) {
3690 printf(" ");
3691 }
3692 int end = message->GetEndColumn(context).FromJust();
3693 for (int i = start; i < end; i++) {
3694 printf("^");
3695 }
3696 printf("\n");
3697 }
3698 }
3699 Local<Value> stack_trace_string;
3700 if (v8::TryCatch::StackTrace(context, exception_obj)
3701 .ToLocal(&stack_trace_string) &&
3702 stack_trace_string->IsString()) {
3703 v8::String::Utf8Value stack_trace(isolate, stack_trace_string.As<String>());
3704 printf("%s\n", ToCString(stack_trace));
3705 }
3706 printf("\n");
3707 if (enter_context) context->Exit();
3708}
3709
3711 const v8::TryCatch& try_catch) {
3712 if (isolate->IsExecutionTerminating()) {
3713 printf("Got Execution Termination Exception\n");
3714 } else {
3715 ReportException(isolate, try_catch.Message(), try_catch.Exception());
3716 }
3717}
3718
3719void Counter::Bind(const char* name, bool is_histogram) {
3720 base::OS::StrNCpy(name_, kMaxNameSize, name, kMaxNameSize);
3721 // Explicitly null-terminate, in case {name} is longer than {kMaxNameSize}.
3722 name_[kMaxNameSize - 1] = '\0';
3723 is_histogram_ = is_histogram;
3724}
3725
3726void Counter::AddSample(int sample) {
3727 count_.fetch_add(1, std::memory_order_relaxed);
3728 sample_total_.fetch_add(sample, std::memory_order_relaxed);
3729}
3730
3732 magic_number_ = 0xDEADFACE;
3733 max_counters_ = kMaxCounters;
3734 max_name_size_ = Counter::kMaxNameSize;
3735 counters_in_use_ = 0;
3736}
3737
3739 if (counters_in_use_ == kMaxCounters) return nullptr;
3740 return &counters_[counters_in_use_++];
3741}
3742
3743void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
3744 counters_file_ = base::OS::MemoryMappedFile::create(
3745 name, sizeof(CounterCollection), &local_counters_);
3746 void* memory =
3747 (counters_file_ == nullptr) ? nullptr : counters_file_->memory();
3748 if (memory == nullptr) {
3749 printf("Could not map counters file %s\n", name);
3751 }
3752 counters_ = static_cast<CounterCollection*>(memory);
3753 isolate->SetCounterFunction(LookupCounter);
3754 isolate->SetCreateHistogramFunction(CreateHistogram);
3755 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
3756}
3757
3758Counter* Shell::GetCounter(const char* name, bool is_histogram) {
3759 Counter* counter = nullptr;
3760 {
3761 base::MutexGuard mutex_guard(&counter_mutex_);
3762 auto map_entry = counter_map_->find(name);
3763 if (map_entry != counter_map_->end()) {
3764 counter = map_entry->second;
3765 }
3766 }
3767
3768 if (counter == nullptr) {
3769 base::MutexGuard mutex_guard(&counter_mutex_);
3770
3771 counter = (*counter_map_)[name];
3772
3773 if (counter == nullptr) {
3774 counter = counters_->GetNextCounter();
3775 if (counter == nullptr) {
3776 // Too many counters.
3777 return nullptr;
3778 }
3779 (*counter_map_)[name] = counter;
3780 counter->Bind(name, is_histogram);
3781 }
3782 }
3783
3784 DCHECK_EQ(is_histogram, counter->is_histogram());
3785 return counter;
3786}
3787
3788int* Shell::LookupCounter(const char* name) {
3789 Counter* counter = GetCounter(name, false);
3790 return counter ? counter->ptr() : nullptr;
3791}
3792
3793void* Shell::CreateHistogram(const char* name, int min, int max,
3794 size_t buckets) {
3795 return GetCounter(name, true);
3796}
3797
3798void Shell::AddHistogramSample(void* histogram, int sample) {
3799 Counter* counter = reinterpret_cast<Counter*>(histogram);
3800 counter->AddSample(sample);
3801}
3802
3803// Turn a value into a human-readable string.
3805 v8::Local<v8::Context> context =
3806 v8::Local<v8::Context>::New(isolate, evaluation_context_);
3807 if (stringify_function_.IsEmpty()) {
3808 Local<String> source =
3809 String::NewFromUtf8(isolate, stringify_source_).ToLocalChecked();
3810 Local<String> name = String::NewFromUtf8Literal(isolate, "d8-stringify");
3811 ScriptOrigin origin(name);
3812 Local<Script> script =
3813 Script::Compile(context, source, &origin).ToLocalChecked();
3814 stringify_function_.Reset(
3815 isolate, script->Run(context).ToLocalChecked().As<Function>());
3816 }
3817 Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
3818 Local<Value> argv[1] = {value};
3819 v8::TryCatch try_catch(isolate);
3820 MaybeLocal<Value> result = fun->Call(context, Undefined(isolate), 1, argv);
3821 if (result.IsEmpty()) return String::Empty(isolate);
3822 return result.ToLocalChecked().As<String>();
3823}
3824
3827 v8::Isolate* isolate = info.GetIsolate();
3828
3829 info.GetReturnValue().Set(v8::Number::New(isolate, 1));
3830}
3831
3832enum class JSApiInstanceType : uint16_t {
3833 kGenericApiObject = 0, // FunctionTemplateInfo::kNoJSApiObjectType.
3835 kNode,
3836 kElement,
3839};
3840
3842 Isolate* isolate, JSApiInstanceType instance_type) {
3843 return FunctionTemplate::New(
3844 isolate, nullptr, Local<Value>(), Local<Signature>(), 0,
3846 static_cast<uint16_t>(instance_type));
3847}
3848
3854
3856 Isolate* isolate, Local<FunctionTemplate> event_target) {
3859 node->Inherit(event_target);
3860
3861 PerIsolateData* data = PerIsolateData::Get(isolate);
3862 data->SetDomNodeCtor(node);
3863
3864 Local<ObjectTemplate> proto_template = node->PrototypeTemplate();
3865 Local<Signature> signature = v8::Signature::New(isolate, node);
3867 isolate, NodeTypeCallback, Local<Value>(), signature, 0,
3869 static_cast<uint16_t>(JSApiInstanceType::kGenericApiObject),
3870 static_cast<uint16_t>(JSApiInstanceType::kElement),
3871 static_cast<uint16_t>(JSApiInstanceType::kHTMLDivElement));
3872 nodeType->SetAcceptAnyReceiver(false);
3873 proto_template->SetAccessorProperty(
3874 String::NewFromUtf8Literal(isolate, "nodeType"), nodeType);
3875
3876 Local<FunctionTemplate> element =
3878 element->Inherit(node);
3879
3880 Local<FunctionTemplate> html_element =
3882 html_element->Inherit(element);
3883
3884 Local<FunctionTemplate> div_element =
3886 div_element->Inherit(html_element);
3887
3888 return div_element;
3889}
3890
3892 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
3893 global_template->Set(Symbol::GetToStringTag(isolate),
3894 String::NewFromUtf8Literal(isolate, "global"));
3895 global_template->Set(isolate, "version",
3896 FunctionTemplate::New(isolate, Version));
3897
3898 global_template->Set(isolate, "print", FunctionTemplate::New(isolate, Print));
3899 global_template->Set(isolate, "printErr",
3900 FunctionTemplate::New(isolate, PrintErr));
3901 global_template->Set(isolate, "write",
3902 FunctionTemplate::New(isolate, WriteStdout));
3903 if (!i::v8_flags.fuzzing) {
3904 global_template->Set(isolate, "writeFile",
3905 FunctionTemplate::New(isolate, WriteFile));
3906 }
3907 global_template->Set(isolate, "read",
3908 FunctionTemplate::New(isolate, ReadFile));
3909 global_template->Set(isolate, "readbuffer",
3910 FunctionTemplate::New(isolate, ReadBuffer));
3911 global_template->Set(isolate, "readline",
3912 FunctionTemplate::New(isolate, ReadLine));
3913 global_template->Set(isolate, "load",
3914 FunctionTemplate::New(isolate, ExecuteFile));
3915 global_template->Set(isolate, "setTimeout",
3916 FunctionTemplate::New(isolate, SetTimeout));
3917 // Some Emscripten-generated code tries to call 'quit', which in turn would
3918 // call C's exit(). This would lead to memory leaks, because there is no way
3919 // we can terminate cleanly then, so we need a way to hide 'quit'.
3920 if (!options.omit_quit) {
3921 global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
3922 }
3923 global_template->Set(isolate, "testRunner",
3925 global_template->Set(isolate, "Realm", Shell::CreateRealmTemplate(isolate));
3926 global_template->Set(isolate, "performance",
3928 global_template->Set(isolate, "Worker", Shell::CreateWorkerTemplate(isolate));
3929
3930 // Prevent fuzzers from creating side effects.
3931 if (!i::v8_flags.fuzzing) {
3932 global_template->Set(isolate, "os", Shell::CreateOSTemplate(isolate));
3933 }
3934 global_template->Set(isolate, "d8", Shell::CreateD8Template(isolate));
3935
3936 if (i::v8_flags.expose_async_hooks) {
3937 global_template->Set(isolate, "async_hooks",
3939 }
3940
3941 return global_template;
3942}
3943
3945 Local<ObjectTemplate> os_template = ObjectTemplate::New(isolate);
3946 AddOSMethods(isolate, os_template);
3947 os_template->Set(isolate, "name",
3950 os_template->Set(
3951 isolate, "d8Path",
3952 v8::String::NewFromUtf8(isolate, options.d8_path).ToLocalChecked(),
3954 return os_template;
3955}
3956
3958 Local<FunctionTemplate> worker_fun_template =
3959 FunctionTemplate::New(isolate, WorkerNew);
3960 Local<Signature> worker_signature =
3961 Signature::New(isolate, worker_fun_template);
3962 worker_fun_template->SetClassName(
3963 String::NewFromUtf8Literal(isolate, "Worker"));
3964 worker_fun_template->ReadOnlyPrototype();
3965 worker_fun_template->PrototypeTemplate()->Set(
3966 isolate, "terminate",
3967 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
3968 worker_signature));
3969 worker_fun_template->PrototypeTemplate()->Set(
3970 isolate, "terminateAndWait",
3971 FunctionTemplate::New(isolate, WorkerTerminateAndWait, Local<Value>(),
3972 worker_signature));
3973 worker_fun_template->PrototypeTemplate()->Set(
3974 isolate, "postMessage",
3975 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
3976 worker_signature));
3977 worker_fun_template->PrototypeTemplate()->Set(
3978 isolate, "getMessage",
3979 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
3980 worker_signature));
3981 worker_fun_template->PrototypeTemplate()->SetAccessorProperty(
3983 .ToLocalChecked(),
3984 FunctionTemplate::New(isolate, WorkerOnMessageGetter, Local<Value>(),
3985 worker_signature),
3986 FunctionTemplate::New(isolate, WorkerOnMessageSetter, Local<Value>(),
3987 worker_signature));
3988 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
3989 return worker_fun_template;
3990}
3991
3993 Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
3994 async_hooks_templ->Set(isolate, "createHook",
3995 FunctionTemplate::New(isolate, AsyncHooksCreateHook));
3996 async_hooks_templ->Set(
3997 isolate, "executionAsyncId",
3998 FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
3999 async_hooks_templ->Set(
4000 isolate, "triggerAsyncId",
4001 FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
4002 return async_hooks_templ;
4003}
4004
4006 Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
4007 // Reliable access to quit functionality. The "quit" method function
4008 // installed on the global object can be hidden with the --omit-quit flag
4009 // (e.g. on asan bots).
4010 test_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
4011
4012 return test_template;
4013}
4014
4016 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
4017 performance_template->Set(isolate, "now",
4018 FunctionTemplate::New(isolate, PerformanceNow));
4019 performance_template->Set(isolate, "mark",
4020 FunctionTemplate::New(isolate, PerformanceMark));
4021 performance_template->Set(isolate, "measure",
4022 FunctionTemplate::New(isolate, PerformanceMeasure));
4023 performance_template->Set(
4024 isolate, "measureMemory",
4025 FunctionTemplate::New(isolate, PerformanceMeasureMemory));
4026 return performance_template;
4027}
4028
4030 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
4031 realm_template->Set(isolate, "current",
4032 FunctionTemplate::New(isolate, RealmCurrent));
4033 realm_template->Set(isolate, "owner",
4034 FunctionTemplate::New(isolate, RealmOwner));
4035 realm_template->Set(isolate, "global",
4036 FunctionTemplate::New(isolate, RealmGlobal));
4037 realm_template->Set(isolate, "create",
4038 FunctionTemplate::New(isolate, RealmCreate));
4039 realm_template->Set(
4040 isolate, "createAllowCrossRealmAccess",
4041 FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
4042 realm_template->Set(isolate, "navigate",
4043 FunctionTemplate::New(isolate, RealmNavigate));
4044 realm_template->Set(isolate, "detachGlobal",
4045 FunctionTemplate::New(isolate, RealmDetachGlobal));
4046 realm_template->Set(isolate, "dispose",
4047 FunctionTemplate::New(isolate, RealmDispose));
4048 realm_template->Set(isolate, "switch",
4049 FunctionTemplate::New(isolate, RealmSwitch));
4050 realm_template->Set(isolate, "eval",
4051 FunctionTemplate::New(isolate, RealmEval));
4052 realm_template->SetNativeDataProperty(
4053 String::NewFromUtf8Literal(isolate, "shared"), RealmSharedGet,
4054 RealmSharedSet);
4055 return realm_template;
4056}
4057
4059 Local<ObjectTemplate> d8_template = ObjectTemplate::New(isolate);
4060 {
4061 Local<ObjectTemplate> file_template = ObjectTemplate::New(isolate);
4062 file_template->Set(isolate, "read",
4064 file_template->Set(isolate, "execute",
4066#if V8_TARGET_OS_LINUX && V8_ENABLE_WEBASSEMBLY
4067 if (i::v8_flags.experimental_wasm_memory_control) {
4068 file_template->Set(
4069 isolate, "create_wasm_memory_map_descriptor",
4071 }
4072#endif
4073 d8_template->Set(isolate, "file", file_template);
4074 }
4075 {
4076 Local<ObjectTemplate> log_template = ObjectTemplate::New(isolate);
4077 log_template->Set(isolate, "getAndStop",
4078 FunctionTemplate::New(isolate, LogGetAndStop));
4079
4080 d8_template->Set(isolate, "log", log_template);
4081 }
4082 {
4083 Local<ObjectTemplate> dom_template = ObjectTemplate::New(isolate);
4084 Local<FunctionTemplate> event_target =
4086 dom_template->Set(isolate, "EventTarget", event_target);
4087 dom_template->Set(isolate, "Div",
4088 Shell::CreateNodeTemplates(isolate, event_target));
4089 d8_template->Set(isolate, "dom", dom_template);
4090 }
4091 {
4092 Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
4093 // For different runs of correctness fuzzing the bytecode of a function
4094 // might get flushed, resulting in spurious errors.
4095 if (!i::v8_flags.correctness_fuzzer_suppressions) {
4096 test_template->Set(
4097 isolate, "verifySourcePositions",
4098 FunctionTemplate::New(isolate, TestVerifySourcePositions));
4099 }
4100 // Correctness fuzzing will attempt to compare results of tests with and
4101 // without turbo_fast_api_calls, so we don't expose the fast_c_api
4102 // constructor when --correctness_fuzzer_suppressions is on.
4103 if (options.expose_fast_api && i::v8_flags.turbo_fast_api_calls &&
4104 !i::v8_flags.correctness_fuzzer_suppressions) {
4105 test_template->Set(isolate, "FastCAPI",
4107 test_template->Set(isolate, "LeafInterfaceType",
4109 }
4110 // Allows testing code paths that are triggered when Origin Trials are
4111 // added in the browser.
4112 test_template->Set(
4113 isolate, "installConditionalFeatures",
4115
4116 // Enable JavaScript Promise Integration at runtime, to simulate
4117 // Origin Trial behavior.
4118 test_template->Set(isolate, "enableJSPI",
4120
4121 test_template->Set(
4122 isolate, "setFlushDenormals",
4124
4125 d8_template->Set(isolate, "test", test_template);
4126 }
4127 {
4128 Local<ObjectTemplate> promise_template = ObjectTemplate::New(isolate);
4129 promise_template->Set(
4130 isolate, "setHooks",
4131 FunctionTemplate::New(isolate, SetPromiseHooks, Local<Value>(),
4132 Local<Signature>(), 4));
4133 d8_template->Set(isolate, "promise", promise_template);
4134 }
4135 {
4136 Local<ObjectTemplate> debugger_template = ObjectTemplate::New(isolate);
4137 debugger_template->Set(
4138 isolate, "enable",
4139 FunctionTemplate::New(isolate, EnableDebugger, Local<Value>(),
4140 Local<Signature>(), 0));
4141 debugger_template->Set(
4142 isolate, "disable",
4143 FunctionTemplate::New(isolate, DisableDebugger, Local<Value>(),
4144 Local<Signature>(), 0));
4145 d8_template->Set(isolate, "debugger", debugger_template);
4146 }
4147 {
4148 Local<ObjectTemplate> serializer_template = ObjectTemplate::New(isolate);
4149 serializer_template->Set(
4150 isolate, "serialize",
4151 FunctionTemplate::New(isolate, SerializerSerialize));
4152 serializer_template->Set(
4153 isolate, "deserialize",
4154 FunctionTemplate::New(isolate, SerializerDeserialize, Local<Value>(),
4155 Local<Signature>(), 1));
4156 d8_template->Set(isolate, "serializer", serializer_template);
4157 }
4158 {
4159 Local<ObjectTemplate> profiler_template = ObjectTemplate::New(isolate);
4160 profiler_template->Set(
4161 isolate, "setOnProfileEndListener",
4162 FunctionTemplate::New(isolate, ProfilerSetOnProfileEndListener));
4163 profiler_template->Set(
4164 isolate, "triggerSample",
4165 FunctionTemplate::New(isolate, ProfilerTriggerSample));
4166 d8_template->Set(isolate, "profiler", profiler_template);
4167 }
4168 {
4169 Local<ObjectTemplate> constants_template = ObjectTemplate::New(isolate);
4170 if (!i::v8_flags.correctness_fuzzer_suppressions) {
4171 // Don't expose these constants in differential-fuzzing builds as they
4172 // differ with lower-limits mode.
4173 constants_template->Set(
4174 String::NewFromUtf8Literal(isolate, "maxFixedArrayCapacity",
4177 constants_template->Set(
4178 String::NewFromUtf8Literal(isolate, "maxFastArrayLength",
4180 Number::New(isolate, i::JSArray::kMaxFastArrayLength));
4181 }
4182 d8_template->Set(isolate, "constants", constants_template);
4183 }
4184#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA
4185 d8_template->Set(
4186 isolate, "getContinuationPreservedEmbedderDataViaAPIForTesting",
4187 FunctionTemplate::New(isolate, GetContinuationPreservedEmbedderData));
4188#endif // V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA
4189 d8_template->Set(isolate, "terminateNow",
4190 FunctionTemplate::New(isolate, TerminateNow));
4191 d8_template->Set(isolate, "terminate",
4192 FunctionTemplate::New(isolate, ScheduleTermination));
4193 d8_template->Set(isolate, "getExtrasBindingObject",
4194 FunctionTemplate::New(isolate, GetExtrasBindingObject));
4195 if (!options.omit_quit) {
4196 d8_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
4197 }
4198 return d8_template;
4199}
4200
4202 switch (message->ErrorLevel()) {
4207 break;
4208 }
4209
4211 Shell::ReportException(message->GetIsolate(), message, error);
4212 return;
4213 }
4214
4215 default: {
4216 UNREACHABLE();
4217 }
4218 }
4219 // Converts a V8 value to a C string.
4220 auto ToCString = [](const v8::String::Utf8Value& value) {
4221 return *value ? *value : "<string conversion failed>";
4222 };
4223 Isolate* isolate = message->GetIsolate();
4224 v8::String::Utf8Value msg(isolate, message->Get());
4225 const char* msg_string = ToCString(msg);
4226 // Print (filename):(line number): (message).
4228 message->GetScriptOrigin().ResourceName());
4229 const char* filename_string = ToCString(filename);
4230 Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
4231 int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
4232 printf("%s:%i: %s\n", filename_string, linenum, msg_string);
4233}
4234
4236 if (options.ignore_unhandled_promises) return;
4237 if (data.GetEvent() == v8::kPromiseRejectAfterResolved ||
4238 data.GetEvent() == v8::kPromiseResolveAfterResolved) {
4239 // Ignore reject/resolve after resolved.
4240 return;
4241 }
4242 v8::Local<v8::Promise> promise = data.GetPromise();
4243 v8::Isolate* isolate = promise->GetIsolate();
4244 PerIsolateData* isolate_data = PerIsolateData::Get(isolate);
4245
4246 if (data.GetEvent() == v8::kPromiseHandlerAddedAfterReject) {
4247 isolate_data->RemoveUnhandledPromise(promise);
4248 return;
4249 }
4250
4251 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
4252 bool capture_exceptions =
4254 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
4255 v8::Local<Value> exception = data.GetValue();
4256 v8::Local<Message> message;
4257 // Assume that all objects are stack-traces.
4258 if (exception->IsObject()) {
4259 message = v8::Exception::CreateMessage(isolate, exception);
4260 }
4261 if (!exception->IsNativeError() &&
4262 (message.IsEmpty() || message->GetStackTrace().IsEmpty())) {
4263 // If there is no real Error object, manually create a stack trace.
4264 exception = v8::Exception::Error(
4265 v8::String::NewFromUtf8Literal(isolate, "Unhandled Promise."));
4266 message = Exception::CreateMessage(isolate, exception);
4267 }
4268 isolate->SetCaptureStackTraceForUncaughtExceptions(capture_exceptions);
4269
4270 isolate_data->AddUnhandledPromise(promise, message, exception);
4271}
4272
4273void Shell::Initialize(Isolate* isolate, D8Console* console,
4274 bool isOnMainThread) {
4275 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
4276 isolate->SetWasmAsyncResolvePromiseCallback(
4277 D8WasmAsyncResolvePromiseCallback);
4278 if (isOnMainThread) {
4279 // Set up counters
4280 if (i::v8_flags.map_counters[0] != '\0') {
4281 MapCounters(isolate, i::v8_flags.map_counters);
4282 }
4283 // Disable default message reporting.
4284 isolate->AddMessageListenerWithErrorLevel(
4289 }
4290
4291 isolate->SetHostImportModuleDynamicallyCallback(
4293 isolate->SetHostImportModuleWithPhaseDynamicallyCallback(
4295 isolate->SetHostInitializeImportMetaObjectCallback(
4297 isolate->SetHostCreateShadowRealmContextCallback(
4299
4300 debug::SetConsoleDelegate(isolate, console);
4301}
4302
4304 const char* path) {
4305 return Shell::ReadFile(isolate, path, false).ToLocalChecked();
4306}
4307
4309 // This needs to be a critical section since this is not thread-safe
4310 i::ParkedMutexGuard lock_guard(
4311 reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(),
4312 context_mutex_.Pointer());
4313 // Initialize the global objects
4314 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
4315 EscapableHandleScope handle_scope(isolate);
4316 Local<Context> context = Context::New(isolate, nullptr, global_template);
4317 if (context.IsEmpty()) {
4318 DCHECK(isolate->IsExecutionTerminating());
4319 return {};
4320 }
4321 if (i::v8_flags.perf_prof_annotate_wasm ||
4322 i::v8_flags.vtune_prof_annotate_wasm) {
4323 isolate->SetWasmLoadSourceMapCallback(Shell::WasmLoadSourceMapCallback);
4324 }
4325 InitializeModuleEmbedderData(context);
4326 Context::Scope scope(context);
4327 if (options.include_arguments) {
4328 const std::vector<const char*>& args = options.arguments;
4329 int size = static_cast<int>(args.size());
4330 Local<Array> array = Array::New(isolate, size);
4331 for (int i = 0; i < size; i++) {
4332 Local<String> arg =
4333 v8::String::NewFromUtf8(isolate, args[i]).ToLocalChecked();
4334 Local<Number> index = v8::Number::New(isolate, i);
4335 array->Set(context, index, arg).FromJust();
4336 }
4338 isolate, "arguments", NewStringType::kInternalized);
4339 context->Global()->Set(context, name, array).FromJust();
4340 }
4341 {
4342 // setup console global.
4344 isolate, "console", NewStringType::kInternalized);
4345 Local<Value> console =
4346 context->GetExtrasBindingObject()->Get(context, name).ToLocalChecked();
4347 context->Global()->Set(context, name, console).FromJust();
4348 }
4349
4350 return handle_scope.Escape(context);
4351}
4352
4354 HandleScope handle_scope(isolate);
4355 Local<Context> context = Context::New(isolate);
4356 Context::Scope context_scope(context);
4357
4358 i::DirectHandle<i::JSObject> dispatch_counters =
4359 reinterpret_cast<i::Isolate*>(isolate)
4360 ->interpreter()
4361 ->GetDispatchCountersObject();
4362 std::ofstream dispatch_counters_stream(
4363 i::v8_flags.trace_ignition_dispatches_output_file);
4364 dispatch_counters_stream << *String::Utf8Value(
4365 isolate, JSON::Stringify(context, Utils::ToLocal(dispatch_counters))
4366 .ToLocalChecked());
4367}
4368
4369namespace {
4370int LineFromOffset(Local<debug::Script> script, int offset) {
4371 debug::Location location = script->GetSourceLocation(offset);
4372 return location.GetLineNumber();
4373}
4374
4375void WriteLcovDataForRange(std::vector<uint32_t>* lines, int start_line,
4376 int end_line, uint32_t count) {
4377 // Ensure space in the array.
4378 lines->resize(std::max(static_cast<size_t>(end_line + 1), lines->size()), 0);
4379 // Boundary lines could be shared between two functions with different
4380 // invocation counts. Take the maximum.
4381 (*lines)[start_line] = std::max((*lines)[start_line], count);
4382 (*lines)[end_line] = std::max((*lines)[end_line], count);
4383 // Invocation counts for non-boundary lines are overwritten.
4384 for (int k = start_line + 1; k < end_line; k++) (*lines)[k] = count;
4385}
4386
4387void WriteLcovDataForNamedRange(std::ostream& sink,
4388 std::vector<uint32_t>* lines,
4389 const std::string& name, int start_line,
4390 int end_line, uint32_t count) {
4391 WriteLcovDataForRange(lines, start_line, end_line, count);
4392 sink << "FN:" << start_line + 1 << "," << name << std::endl;
4393 sink << "FNDA:" << count << "," << name << std::endl;
4394}
4395} // namespace
4396
4397// Write coverage data in LCOV format. See man page for geninfo(1).
4398void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) {
4399 if (!file) return;
4400 HandleScope handle_scope(isolate);
4402 std::ofstream sink(file, std::ofstream::app);
4403 for (size_t i = 0; i < coverage.ScriptCount(); i++) {
4404 debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
4405 Local<debug::Script> script = script_data.GetScript();
4406 // Skip unnamed scripts.
4408 if (!script->Name().ToLocal(&name)) continue;
4409 std::string file_name = ToSTLString(isolate, name);
4410 // Skip scripts not backed by a file.
4411 if (!std::ifstream(file_name).good()) continue;
4412 sink << "SF:";
4413 sink << NormalizePath(file_name, GetWorkingDirectory()) << std::endl;
4414 std::vector<uint32_t> lines;
4415 for (size_t j = 0; j < script_data.FunctionCount(); j++) {
4416 debug::Coverage::FunctionData function_data =
4417 script_data.GetFunctionData(j);
4418
4419 // Write function stats.
4420 {
4422 script->GetSourceLocation(function_data.StartOffset());
4424 script->GetSourceLocation(function_data.EndOffset());
4425 int start_line = start.GetLineNumber();
4426 int end_line = end.GetLineNumber();
4427 uint32_t count = function_data.Count();
4428
4429 Local<String> function_name;
4430 std::stringstream name_stream;
4431 if (function_data.Name().ToLocal(&function_name)) {
4432 name_stream << ToSTLString(isolate, function_name);
4433 } else {
4434 name_stream << "<" << start_line + 1 << "-";
4435 name_stream << start.GetColumnNumber() << ">";
4436 }
4437
4438 WriteLcovDataForNamedRange(sink, &lines, name_stream.str(), start_line,
4439 end_line, count);
4440 }
4441
4442 // Process inner blocks.
4443 for (size_t k = 0; k < function_data.BlockCount(); k++) {
4444 debug::Coverage::BlockData block_data = function_data.GetBlockData(k);
4445 int start_line = LineFromOffset(script, block_data.StartOffset());
4446 int end_line = LineFromOffset(script, block_data.EndOffset() - 1);
4447 uint32_t count = block_data.Count();
4448 WriteLcovDataForRange(&lines, start_line, end_line, count);
4449 }
4450 }
4451 // Write per-line coverage. LCOV uses 1-based line numbers.
4452 for (size_t j = 0; j < lines.size(); j++) {
4453 sink << "DA:" << (j + 1) << "," << lines[j] << std::endl;
4454 }
4455 sink << "end_of_record" << std::endl;
4456 }
4457}
4458
4459void Shell::OnExit(v8::Isolate* isolate, bool dispose) {
4460 platform::NotifyIsolateShutdown(g_default_platform, isolate);
4461
4462 if (Worker* worker = Worker::GetCurrentWorker()) {
4463 // When invoking `quit` on a worker isolate, the worker needs to reach
4464 // State::kTerminated before invoking Isolate::Dispose. This is because the
4465 // main thread tries to terminate all workers at the end, which can happen
4466 // concurrently to Isolate::Dispose.
4467 worker->EnterTerminatedState();
4468 }
4469
4470 if (dispose) {
4471 isolate->Dispose();
4472 } else {
4473 // Normally, Dispose() prints counters. Benchmarks expect counters to be
4474 // printed on process exit, so do so manually if not disposing.
4475 isolate->DumpAndResetStats();
4476 }
4477
4478 // Simulate errors before disposing V8, as that resets flags (via
4479 // FlagList::ResetAllFlags()), but error simulation reads the random seed.
4480 if (options.simulate_errors && is_valid_fuzz_script()) {
4481 // Simulate several errors detectable by fuzzers behind a flag if the
4482 // minimum file size for fuzzing was executed.
4484 }
4485
4486 if (dispose) {
4487 V8::Dispose();
4489 }
4490
4491 if (options.dump_counters || options.dump_counters_nvp) {
4492 base::MutexGuard mutex_guard(&counter_mutex_);
4493 std::vector<std::pair<std::string, Counter*>> counters(
4494 counter_map_->begin(), counter_map_->end());
4495 std::sort(counters.begin(), counters.end());
4496
4497 if (options.dump_counters_nvp) {
4498 // Dump counters as name-value pairs.
4499 for (const auto& pair : counters) {
4500 std::string key = pair.first;
4501 Counter* counter = pair.second;
4502 if (counter->is_histogram()) {
4503 std::cout << "\"c:" << key << "\"=" << counter->count() << "\n";
4504 std::cout << "\"t:" << key << "\"=" << counter->sample_total()
4505 << "\n";
4506 } else {
4507 std::cout << "\"" << key << "\"=" << counter->count() << "\n";
4508 }
4509 }
4510 } else {
4511 // Dump counters in formatted boxes.
4512 constexpr int kNameBoxSize = 64;
4513 constexpr int kValueBoxSize = 13;
4514 std::cout << "+" << std::string(kNameBoxSize, '-') << "+"
4515 << std::string(kValueBoxSize, '-') << "+\n";
4516 std::cout << "| Name" << std::string(kNameBoxSize - 5, ' ') << "| Value"
4517 << std::string(kValueBoxSize - 6, ' ') << "|\n";
4518 std::cout << "+" << std::string(kNameBoxSize, '-') << "+"
4519 << std::string(kValueBoxSize, '-') << "+\n";
4520 for (const auto& pair : counters) {
4521 std::string key = pair.first;
4522 Counter* counter = pair.second;
4523 if (counter->is_histogram()) {
4524 std::cout << "| c:" << std::setw(kNameBoxSize - 4) << std::left << key
4525 << " | " << std::setw(kValueBoxSize - 2) << std::right
4526 << counter->count() << " |\n";
4527 std::cout << "| t:" << std::setw(kNameBoxSize - 4) << std::left << key
4528 << " | " << std::setw(kValueBoxSize - 2) << std::right
4529 << counter->sample_total() << " |\n";
4530 } else {
4531 std::cout << "| " << std::setw(kNameBoxSize - 2) << std::left << key
4532 << " | " << std::setw(kValueBoxSize - 2) << std::right
4533 << counter->count() << " |\n";
4534 }
4535 }
4536 std::cout << "+" << std::string(kNameBoxSize, '-') << "+"
4537 << std::string(kValueBoxSize, '-') << "+\n";
4538 }
4539 }
4540
4541 if (options.dump_system_memory_stats) {
4542 int peak_memory_usage = base::OS::GetPeakMemoryUsageKb();
4543 std::cout << "System peak memory usage (kb): " << peak_memory_usage
4544 << std::endl;
4545 // TODO(jdapena): call rusage platform independent call, and extract peak
4546 // memory usage to print it
4547 }
4548
4549 // Only delete the counters if we are done executing; after calling `quit`,
4550 // other isolates might still be running and accessing that memory. This is a
4551 // memory leak, which is OK in this case.
4552 if (dispose) {
4553 delete counters_file_;
4554 delete counter_map_;
4555 }
4556}
4557
4558void Dummy(char* arg) {}
4559
4561 // Initialize a fresh RNG to not interfere with JS execution.
4562 std::unique_ptr<base::RandomNumberGenerator> rng;
4563 int64_t seed = i::v8_flags.random_seed;
4564 if (seed != 0) {
4565 rng = std::make_unique<base::RandomNumberGenerator>(seed);
4566 } else {
4567 rng = std::make_unique<base::RandomNumberGenerator>();
4568 }
4569
4570 double p = rng->NextDouble();
4571 if (p < 0.1) {
4572 ControlFlowViolation();
4573 } else if (p < 0.2) {
4574 DCheck();
4575 } else if (p < 0.3) {
4576 Fatal();
4577 } else if (p < 0.4) {
4578 ObservableDifference();
4579 } else if (p < 0.5) {
4580 UndefinedBehavior();
4581 } else if (p < 0.6) {
4582 UseAfterFree();
4583 } else if (p < 0.7) {
4584 UseOfUninitializedValue();
4585 }
4586}
4587
4589 // Control flow violation caught by CFI.
4590 void (*func)() = (void (*)()) & Dummy;
4591 func();
4592}
4593
4595 // Caught in debug builds.
4596 DCHECK(false);
4597}
4598
4600 // Caught in all build types.
4601 FATAL("Fake error.");
4602}
4603
4605 // Observable difference caught by differential fuzzing.
4606 printf("___fake_difference___\n");
4607}
4608
4610 // Caught by UBSAN.
4611 int32_t val = -1;
4612 USE(val << val);
4613}
4614
4616 // Use-after-free caught by ASAN.
4617#if defined(__clang__) // GCC-12 detects this at compile time!
4618 std::vector<bool>* storage = new std::vector<bool>(3);
4619 delete storage;
4620 USE(storage->at(1));
4621#endif
4622}
4623
4625// Use-of-uninitialized-value caught by MSAN.
4626#if defined(__clang__)
4627 int uninitialized[1];
4628 if (uninitialized[0]) USE(uninitialized);
4629#endif
4630}
4631
4632char* Shell::ReadChars(const char* name, int* size_out) {
4633 if (options.read_from_tcp_port >= 0) {
4634 return ReadCharsFromTcpPort(name, size_out);
4635 }
4636
4637 FILE* file = base::OS::FOpen(name, "rb");
4638 if (file == nullptr) return nullptr;
4639
4640 fseek(file, 0, SEEK_END);
4641 size_t size = ftell(file);
4642 rewind(file);
4643
4644 char* chars = new char[size + 1];
4645 chars[size] = '\0';
4646 for (size_t i = 0; i < size;) {
4647 i += fread(&chars[i], 1, size - i, file);
4648 if (ferror(file)) {
4649 base::Fclose(file);
4650 delete[] chars;
4651 return nullptr;
4652 }
4653 }
4654 base::Fclose(file);
4655 *size_out = static_cast<int>(size);
4656 return chars;
4657}
4658
4660 const char* name) {
4661 int length;
4662 std::unique_ptr<char[]> data(ReadChars(name, &length));
4663
4664 if (data.get() == nullptr) {
4666 }
4667 std::stringstream stream(data.get());
4668 std::string line;
4669 std::vector<std::string> lines;
4670 while (std::getline(stream, line, '\n')) {
4671 lines.emplace_back(line);
4672 }
4673 // Create a Local<PrimitiveArray> off the read lines.
4674 int size = static_cast<int>(lines.size());
4675 Local<PrimitiveArray> exports = PrimitiveArray::New(isolate, size);
4676 for (int i = 0; i < size; ++i) {
4678 isolate, lines[i].c_str(), NewStringType::kNormal,
4679 static_cast<int>(lines[i].length()));
4680 Local<String> str;
4681 if (!maybe_str.ToLocal(&str)) {
4683 }
4684 exports->Set(isolate, i, str);
4685 }
4686 return exports;
4687}
4688
4691 static_assert(sizeof(char) == sizeof(uint8_t),
4692 "char and uint8_t should both have 1 byte");
4693 Isolate* isolate = info.GetIsolate();
4694 String::Utf8Value filename(isolate, info[0]);
4695 int length;
4696 if (*filename == nullptr) {
4697 ThrowError(isolate, "Error loading file");
4698 return;
4699 }
4700
4701 uint8_t* data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
4702 if (data == nullptr) {
4703 ThrowError(isolate, "Error reading file");
4704 return;
4705 }
4706 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, length);
4707 memcpy(buffer->GetBackingStore()->Data(), data, length);
4708 delete[] data;
4709
4710 info.GetReturnValue().Set(buffer);
4711}
4712
4715 info.GetReturnValue().Set(ReadFromStdin(info.GetIsolate()));
4716}
4717
4718// Reads a file into a memory blob.
4719std::unique_ptr<base::OS::MemoryMappedFile> Shell::ReadFileData(
4720 Isolate* isolate, const char* name, bool should_throw) {
4721 std::unique_ptr<base::OS::MemoryMappedFile> file(
4724 if (!file) {
4725 if (should_throw) {
4726 std::ostringstream oss;
4727 oss << "Error loading file: " << name;
4728 ThrowError(isolate,
4730 isolate, oss.str().substr(0, String::kMaxLength).c_str())
4731 .ToLocalChecked());
4732 }
4733 return nullptr;
4734 }
4735 return file;
4736}
4737
4738// Reads a file into a v8 string.
4739MaybeLocal<String> Shell::ReadFile(Isolate* isolate, const char* name,
4740 bool should_throw) {
4741 auto file = ReadFileData(isolate, name, should_throw);
4742 if (!file) {
4743 return MaybeLocal<String>();
4744 }
4745 int size = static_cast<int>(file->size());
4746 char* chars = static_cast<char*>(file->memory());
4747 if (i::v8_flags.use_external_strings && i::String::IsAscii(chars, size)) {
4749 new ExternalOwningOneByteStringResource(std::move(file));
4750 return String::NewExternalOneByte(isolate, resource);
4751 }
4752 return String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size);
4753}
4754
4755void Shell::WriteChars(const char* name, uint8_t* buffer, size_t buffer_size) {
4756 FILE* file = base::Fopen(name, "w");
4757 if (file == nullptr) return;
4758 fwrite(buffer, 1, buffer_size, file);
4759 base::Fclose(file);
4760}
4761
4762void Shell::RunShell(Isolate* isolate) {
4764 {
4765 HandleScope scope(isolate);
4766 context.Reset(isolate, Local<Context>::New(isolate, evaluation_context_));
4767 }
4768 PerIsolateData::RealmScope realm_scope(isolate, context);
4769 printf("V8 version %s\n", V8::GetVersion());
4770 while (true) {
4771 Global<Value> global_result;
4772 bool success;
4773 {
4774 HandleScope scope(isolate);
4775 Context::Scope context_scope(context.Get(isolate));
4776 printf("d8> ");
4777 Local<String> input = Shell::ReadFromStdin(isolate);
4778 if (input.IsEmpty()) break;
4779 Local<String> name = String::NewFromUtf8Literal(isolate, "(d8)");
4780 success = ExecuteString(isolate, input, name, kReportExceptions,
4781 &global_result);
4782 CHECK_EQ(success, !global_result.IsEmpty());
4783 }
4784 if (!FinishExecuting(isolate, context)) success = false;
4785 if (success) {
4786 HandleScope scope(isolate);
4787 Context::Scope context_scope(context.Get(isolate));
4788 Local<Value> result = global_result.Get(isolate);
4789 if (options.test_shell) {
4790 if (!result->IsUndefined()) {
4791 // If all went well and the result wasn't undefined then print
4792 // the returned value.
4793 v8::String::Utf8Value str(isolate, result);
4794 fwrite(*str, sizeof(**str), str.length(), stdout);
4795 printf("\n");
4796 }
4797 } else {
4798 v8::String::Utf8Value str(isolate, Stringify(isolate, result));
4799 fwrite(*str, sizeof(**str), str.length(), stdout);
4800 printf("\n");
4801 }
4802 }
4803 }
4804 printf("\n");
4805}
4806
4808 public:
4810 isolate_ = context->GetIsolate();
4811 context_.Reset(isolate_, context);
4812 }
4813 ~InspectorFrontend() override = default;
4814
4815 private:
4817 int callId,
4818 std::unique_ptr<v8_inspector::StringBuffer> message) override {
4819 Send(message->string());
4820 }
4822 std::unique_ptr<v8_inspector::StringBuffer> message) override {
4823 Send(message->string());
4824 }
4826
4827 void Send(const v8_inspector::StringView& string) {
4829 v8::HandleScope handle_scope(isolate_);
4830 int length = static_cast<int>(string.length());
4832 Local<String> message =
4833 (string.is8Bit()
4835 isolate_,
4836 reinterpret_cast<const uint8_t*>(string.characters8()),
4839 isolate_,
4840 reinterpret_cast<const uint16_t*>(string.characters16()),
4842 .ToLocalChecked();
4844 isolate_, "receive", NewStringType::kInternalized);
4845 Local<Context> context = context_.Get(isolate_);
4847 context->Global()->Get(context, callback_name).ToLocalChecked();
4848 if (callback->IsFunction()) {
4849 v8::TryCatch try_catch(isolate_);
4850 Local<Value> args[] = {message};
4851 USE(callback.As<Function>()->Call(context, Undefined(isolate_), 1, args));
4852#ifdef DEBUG
4853 if (try_catch.HasCaught()) {
4854 Local<Object> exception = try_catch.Exception().As<Object>();
4856 isolate_, "message", NewStringType::kInternalized);
4858 isolate_, "Maximum call stack size exceeded");
4859 Local<Value> value = exception->Get(context, key).ToLocalChecked();
4860 DCHECK(value->StrictEquals(expected));
4861 }
4862#endif
4863 }
4864 }
4865
4868};
4869
4871 public:
4872 InspectorClient(Isolate* isolate, const Global<Context>& global_context,
4873 bool connect) {
4874 if (!connect) return;
4875 isolate_ = isolate;
4876 Local<Context> context = global_context.Get(isolate);
4877 channel_.reset(new InspectorFrontend(context));
4878 inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
4879 session_ =
4880 inspector_->connect(1, channel_.get(), v8_inspector::StringView(),
4883 context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
4884 inspector_->contextCreated(v8_inspector::V8ContextInfo(
4885 context, kContextGroupId, v8_inspector::StringView()));
4886
4887 Local<Value> function =
4888 FunctionTemplate::New(isolate_, SendInspectorMessage)
4889 ->GetFunction(context)
4890 .ToLocalChecked();
4891 Local<String> function_name = String::NewFromUtf8Literal(
4892 isolate_, "send", NewStringType::kInternalized);
4893 CHECK(context->Global()->Set(context, function_name, function).FromJust());
4894
4895 context_.Reset(isolate_, global_context);
4896 }
4897
4898 void runMessageLoopOnPause(int contextGroupId) override {
4900 v8::HandleScope handle_scope(isolate_);
4902 isolate_, "handleInspectorMessage", NewStringType::kInternalized);
4903 Local<Context> context = context_.Get(isolate_);
4905 context->Global()->Get(context, callback_name).ToLocalChecked();
4906 if (!callback->IsFunction()) return;
4907
4908 // Running the message loop below may trigger the execution of a stackless
4909 // GC. We need to override the embedder stack state, to force scanning the
4910 // stack, if this happens.
4911 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate_)->heap();
4912 i::EmbedderStackStateScope stack_scanning_scope(
4913 heap, i::EmbedderStackStateOrigin::kExplicitInvocation,
4914 v8::StackState::kMayContainHeapPointers);
4915
4916 v8::TryCatch try_catch(isolate_);
4917 try_catch.SetVerbose(true);
4918 is_paused = true;
4919
4920 while (is_paused) {
4921 USE(callback.As<Function>()->Call(context, Undefined(isolate_), 0, {}));
4922 if (try_catch.HasCaught()) {
4923 is_paused = false;
4924 }
4925 }
4926 }
4927
4928 void quitMessageLoopOnPause() override { is_paused = false; }
4929
4930 private:
4932 InspectorClient* inspector_client = static_cast<InspectorClient*>(
4933 context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex));
4934 return inspector_client->session_.get();
4935 }
4936
4939 DCHECK_EQ(kContextGroupId, group_id);
4940 return context_.Get(isolate_);
4941 }
4942
4946 Isolate* isolate = info.GetIsolate();
4947 v8::HandleScope handle_scope(isolate);
4948 Local<Context> context = isolate->GetCurrentContext();
4949 info.GetReturnValue().Set(Undefined(isolate));
4950 Local<String> message = info[0]->ToString(context).ToLocalChecked();
4952 InspectorClient::GetSession(context);
4953 uint32_t length = message->Length();
4954 std::unique_ptr<uint16_t[]> buffer(new uint16_t[length]);
4955 message->WriteV2(isolate, 0, length, buffer.get());
4956 v8_inspector::StringView message_view(buffer.get(), length);
4957 {
4958 v8::SealHandleScope seal_handle_scope(isolate);
4959 session->dispatchProtocolMessage(message_view);
4960 }
4961 info.GetReturnValue().Set(True(isolate));
4962 }
4963
4964 static const int kContextGroupId = 1;
4965
4966 std::unique_ptr<v8_inspector::V8Inspector> inspector_;
4967 std::unique_ptr<v8_inspector::V8InspectorSession> session_;
4968 std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
4969 bool is_paused = false;
4972};
4973
4975 delete thread_;
4976 thread_ = nullptr;
4977}
4978
4979bool ends_with(const char* input, const char* suffix) {
4980 size_t input_length = strlen(input);
4981 size_t suffix_length = strlen(suffix);
4982 if (suffix_length <= input_length) {
4983 return strcmp(input + input_length - suffix_length, suffix) == 0;
4984 }
4985 return false;
4986}
4987
4989 bool success = true;
4990#ifdef V8_FUZZILLI
4991 if (fuzzilli_reprl) {
4992 HandleScope handle_scope(isolate);
4993 Local<String> file_name =
4994 String::NewFromUtf8(isolate, "fuzzcode.js", NewStringType::kNormal)
4995 .ToLocalChecked();
4996
4997 size_t script_size;
4998 CHECK_EQ(read(REPRL_CRFD, &script_size, 8), 8);
4999 char* buffer = new char[script_size + 1];
5000 char* ptr = buffer;
5001 size_t remaining = script_size;
5002 while (remaining > 0) {
5003 ssize_t rv = read(REPRL_DRFD, ptr, remaining);
5004 CHECK_GE(rv, 0);
5005 remaining -= rv;
5006 ptr += rv;
5007 }
5008 buffer[script_size] = 0;
5009
5010 Local<String> source =
5012 .ToLocalChecked();
5013 delete[] buffer;
5015 if (!Shell::ExecuteString(isolate, source, file_name,
5017 return false;
5018 }
5019 }
5020#endif // V8_FUZZILLI
5021 for (int i = begin_offset_; i < end_offset_; ++i) {
5022 const char* arg = argv_[i];
5023 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
5024 // Execute argument given to -e option directly.
5025 HandleScope handle_scope(isolate);
5026 Local<String> file_name = String::NewFromUtf8Literal(isolate, "unnamed");
5027 Local<String> source =
5028 String::NewFromUtf8(isolate, argv_[i + 1]).ToLocalChecked();
5030 if (!Shell::ExecuteString(isolate, source, file_name,
5032 success = false;
5033 break;
5034 }
5035 ++i;
5036 continue;
5037 } else if (ends_with(arg, ".mjs")) {
5039 if (!Shell::ExecuteModule(isolate, arg)) {
5040 success = false;
5041 break;
5042 }
5043 continue;
5044 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
5045 // Treat the next file as a module.
5046 arg = argv_[++i];
5048 if (!Shell::ExecuteModule(isolate, arg)) {
5049 success = false;
5050 break;
5051 }
5052 continue;
5053 } else if (strcmp(arg, "--json") == 0 && i + 1 < end_offset_) {
5054 // Treat the next file as a JSON file.
5055 arg = argv_[++i];
5057 if (!Shell::LoadJSON(isolate, arg)) {
5058 success = false;
5059 break;
5060 }
5061 continue;
5062 } else if (arg[0] == '-') {
5063 // Ignore other options. They have been parsed already.
5064 continue;
5065 }
5066
5067 // Use all other arguments as names of files to load and run.
5068 HandleScope handle_scope(isolate);
5069 Local<String> file_name =
5070 String::NewFromUtf8(isolate, arg).ToLocalChecked();
5072 if (!Shell::ReadFile(isolate, arg).ToLocal(&source)) {
5073 printf("Error reading '%s'\n", arg);
5075 }
5077 Shell::update_script_size(source->Length());
5078 if (!Shell::ExecuteString(isolate, source, file_name,
5080 success = false;
5081 break;
5082 }
5083 }
5084 return success;
5085}
5086
5088 : base::Thread(GetThreadOptions("IsolateThread")), group_(group) {}
5089
5091 v8::base::FlushDenormalsScope denormals_scope(Shell::options.flush_denormals);
5092
5093 Isolate::CreateParams create_params;
5095 Isolate* isolate = Isolate::New(create_params);
5096
5097 {
5098 Isolate::Scope isolate_scope(isolate);
5099 D8Console console(isolate);
5100 Shell::Initialize(isolate, &console, false);
5101 PerIsolateData data(isolate);
5102
5103 for (int i = 0; i < Shell::options.stress_runs; ++i) {
5105 reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate());
5106 {
5107 Global<Context> global_context;
5108 HandleScope scope(isolate);
5109 {
5111 if (!Shell::CreateEvaluationContext(isolate).ToLocal(&context)) {
5112 DCHECK(isolate->IsExecutionTerminating());
5113 break;
5114 }
5115 global_context.Reset(isolate, context);
5116 }
5117 PerIsolateData::RealmScope realm_scope(isolate, global_context);
5118 InspectorClient inspector_client(isolate, global_context,
5119 Shell::options.enable_inspector);
5120 {
5121 // We cannot use a Context::Scope here, as it keeps a local handle to
5122 // the context and SourceGroup::Execute may execute a non-nestable
5123 // task, e.g. a stackless GC.
5124 global_context.Get(isolate)->Enter();
5125 Execute(isolate);
5126 global_context.Get(isolate)->Exit();
5127 }
5128 Shell::FinishExecuting(isolate, global_context);
5129 }
5130 Shell::CollectGarbage(isolate);
5132 }
5133
5135 }
5136
5137 isolate->Dispose();
5138}
5139
5141 if (thread_ == nullptr) {
5142 thread_ = new IsolateThread(this);
5143 CHECK(thread_->Start());
5144 }
5146}
5147
5149 if (thread_ == nullptr) return;
5151}
5152
5154 USE(parked);
5155 if (thread_ == nullptr) return;
5156 thread_->Join();
5157}
5158
5159void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) {
5160 base::MutexGuard lock_guard(&mutex_);
5161 data_.push_back(std::move(data));
5162}
5163
5165 std::unique_ptr<SerializationData>* out_data) {
5166 out_data->reset();
5167 base::MutexGuard lock_guard(&mutex_);
5168 if (data_.empty()) return false;
5169 *out_data = std::move(data_[0]);
5170 data_.erase(data_.begin());
5171 return true;
5172}
5173
5175 base::MutexGuard lock_guard(&mutex_);
5176 return data_.empty();
5177}
5178
5180 base::MutexGuard lock_guard(&mutex_);
5181 data_.clear();
5182}
5183
5184Worker::Worker(Isolate* parent_isolate, const char* script,
5185 bool flush_denormals)
5186 : script_(i::StrDup(script)),
5187 flush_denormals_(flush_denormals),
5188 parent_isolate_(parent_isolate) {
5189 state_.store(State::kReady);
5190}
5191
5193 CHECK(state_.load() == State::kTerminated);
5195 delete thread_;
5196 thread_ = nullptr;
5197 delete[] script_;
5198 script_ = nullptr;
5199}
5200
5201bool Worker::is_running() const { return state_.load() == State::kRunning; }
5202
5204 std::shared_ptr<Worker> worker,
5206 auto expected = State::kReady;
5207 CHECK(
5208 worker->state_.compare_exchange_strong(expected, State::kPrepareRunning));
5209 auto thread = new WorkerThread(worker, priority);
5210 worker->thread_ = thread;
5211 if (!thread->Start()) return false;
5212 // Wait until the worker is ready to receive messages.
5213 worker->started_semaphore_.ParkedWait(
5214 reinterpret_cast<i::Isolate*>(requester)->main_thread_local_isolate());
5215 Shell::AddRunningWorker(std::move(worker));
5216 return true;
5217}
5218
5220 // Prevent a lifetime cycle from Worker -> WorkerThread -> Worker.
5221 // We must clear the worker_ field of the thread, but we keep the
5222 // worker alive via a stack root until the thread finishes execution
5223 // and removes itself from the running set. Thereafter the only
5224 // remaining reference can be from a JavaScript object via a Managed.
5225 auto worker = std::move(worker_);
5226 worker_ = nullptr;
5227 worker->ExecuteInThread();
5229}
5230
5232 public:
5234 std::shared_ptr<Worker> worker,
5235 std::unique_ptr<SerializationData> data)
5236 : i::CancelableTask(task_manager),
5237 worker_(worker),
5238 data_(std::move(data)) {}
5239
5240 void RunInternal() override { worker_->ProcessMessage(std::move(data_)); }
5241
5242 private:
5243 std::shared_ptr<Worker> worker_;
5244 std::unique_ptr<SerializationData> data_;
5245};
5246
5247void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
5248 base::MutexGuard lock_guard(&worker_mutex_);
5249 if (!is_running()) return;
5250 std::unique_ptr<v8::Task> task(new ProcessMessageTask(
5251 task_manager_, shared_from_this(), std::move(data)));
5252 task_runner_->PostNonNestableTask(std::move(task));
5253}
5254
5256 public:
5258 std::shared_ptr<Worker> worker)
5259 : i::CancelableTask(task_manager), worker_(worker) {}
5260
5261 void RunInternal() override {
5262 auto expected = Worker::State::kTerminating;
5263 CHECK(worker_->state_.compare_exchange_strong(expected,
5265 }
5266
5267 private:
5268 std::shared_ptr<Worker> worker_;
5269};
5270
5271std::unique_ptr<SerializationData> Worker::GetMessage(Isolate* requester) {
5272 std::unique_ptr<SerializationData> result;
5273 while (!out_queue_.Dequeue(&result)) {
5274 // If the worker is no longer running, and there are no messages in the
5275 // queue, don't expect any more messages from it.
5276 if (!is_running()) break;
5278 reinterpret_cast<i::Isolate*>(requester)->main_thread_local_isolate());
5279 }
5280 return result;
5281}
5282
5283std::unique_ptr<SerializationData> Worker::TryGetMessage() {
5284 std::unique_ptr<SerializationData> result;
5285 if (!out_queue_.Dequeue(&result)) {
5286 return nullptr;
5287 }
5288 return result;
5289}
5290
5292 USE(parked);
5293 Terminate();
5294 {
5295 base::MutexGuard lock_guard(&worker_mutex_);
5296 // Prevent double-joining.
5297 if (is_joined_) return;
5298 is_joined_ = true;
5299 }
5300 thread_->Join();
5301}
5302
5304 base::MutexGuard lock_guard(&worker_mutex_);
5305 auto expected = State::kRunning;
5306 if (!state_.compare_exchange_strong(expected, State::kTerminating)) return;
5307 std::unique_ptr<v8::Task> task(
5308 new TerminateTask(task_manager_, shared_from_this()));
5309 task_runner_->PostTask(std::move(task));
5310 // Also schedule an interrupt in case the worker is running code and never
5311 // returning to the event queue. Since we checked the state before, and we are
5312 // holding the {worker_mutex_}, it's safe to access the isolate.
5314}
5315
5317 base::MutexGuard lock_guard(&worker_mutex_);
5319 CHECK(!is_running());
5320 task_runner_.reset();
5321 task_manager_ = nullptr;
5322}
5323
5324void Worker::ProcessMessage(std::unique_ptr<SerializationData> data) {
5325 if (!is_running()) return;
5327 HandleScope scope(isolate_);
5328 Local<Context> context = context_.Get(isolate_);
5329 Context::Scope context_scope(context);
5330 Local<Object> global = context->Global();
5331
5332 // Get the message handler.
5333 MaybeLocal<Value> maybe_onmessage = global->Get(
5334 context, String::NewFromUtf8Literal(isolate_, "onmessage",
5336 Local<Value> onmessage;
5337 if (!maybe_onmessage.ToLocal(&onmessage) || !onmessage->IsFunction()) return;
5338 Local<Function> onmessage_fun = onmessage.As<Function>();
5339
5340 v8::TryCatch try_catch(isolate_);
5341 try_catch.SetVerbose(true);
5343 if (Shell::DeserializeValue(isolate_, std::move(data)).ToLocal(&value)) {
5346 event
5347 ->CreateDataProperty(
5348 context,
5351 value)
5352 .ToChecked();
5353 Local<Value> argv[] = {event};
5354 MaybeLocal<Value> result = onmessage_fun->Call(context, global, 1, argv);
5355 USE(result);
5356 }
5358 // Re-schedule an interrupt in case the worker is going to run more code
5359 // and never return to the event queue.
5361 }
5362}
5363
5365 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
5366 i::SaveAndSwitchContext saved_context(i_isolate, i::Context());
5368
5369 TryCatch try_catch(isolate_);
5370 try_catch.SetVerbose(true);
5371
5373 g_default_platform, isolate_,
5375 if (try_catch.HasCaught()) return;
5376 if (is_running()) {
5378 }
5379 }
5380}
5381
5382// static
5384 CHECK_NULL(current_worker_);
5385 current_worker_ = worker;
5386}
5387
5388// static
5389Worker* Worker::GetCurrentWorker() { return current_worker_; }
5390
5393
5394 Isolate::CreateParams create_params;
5396 isolate_ = Isolate::New(create_params);
5397
5398 // Make the Worker instance available to the whole thread.
5399 SetCurrentWorker(this);
5400
5401 task_runner_ = g_default_platform->GetForegroundTaskRunner(isolate_);
5403 reinterpret_cast<i::Isolate*>(isolate_)->cancelable_task_manager();
5404
5405 auto expected = State::kPrepareRunning;
5406 CHECK(state_.compare_exchange_strong(expected, State::kRunning));
5407
5408 // The Worker is now ready to receive messages.
5410
5411 {
5412 Isolate::Scope isolate_scope(isolate_);
5413 D8Console console(isolate_);
5414 Shell::Initialize(isolate_, &console, false);
5416
5417 CHECK(context_.IsEmpty());
5418
5419 {
5420 HandleScope scope(isolate_);
5423 context_.Reset(isolate_, context);
5424 CHECK(!context_.IsEmpty());
5425 }
5426 }
5427
5428 if (!context_.IsEmpty()) {
5429 {
5430 bool success;
5432 {
5433 HandleScope scope(isolate_);
5434 Local<Context> context = context_.Get(isolate_);
5435 Context::Scope context_scope(context);
5436
5437 Local<Object> global = context->Global();
5438 Local<Value> this_value = External::New(isolate_, this);
5439
5440 Local<FunctionTemplate> postmessage_fun_template =
5442 this_value);
5443 Local<Function> postmessage_fun;
5444 if (postmessage_fun_template->GetFunction(context).ToLocal(
5445 &postmessage_fun)) {
5446 global
5447 ->Set(
5448 context,
5450 isolate_, "postMessage", NewStringType::kInternalized),
5451 postmessage_fun)
5452 .FromJust();
5453 }
5454
5455 Local<FunctionTemplate> close_fun_template =
5457 Local<Function> close_fun;
5458 if (close_fun_template->GetFunction(context).ToLocal(&close_fun)) {
5459 global
5460 ->Set(context,
5463 close_fun)
5464 .FromJust();
5465 }
5466
5467 Local<FunctionTemplate> importScripts_fun_template =
5469 this_value);
5470 Local<Function> importScripts_fun;
5471 if (importScripts_fun_template->GetFunction(context).ToLocal(
5472 &importScripts_fun)) {
5473 global
5474 ->Set(context,
5476 isolate_, "importScripts",
5478 importScripts_fun)
5479 .FromJust();
5480 }
5481
5482 // First run the script
5483 Local<String> file_name =
5485 Local<String> source =
5486 String::NewFromUtf8(isolate_, script_).ToLocalChecked();
5487 success = Shell::ExecuteString(isolate_, source, file_name,
5489 }
5490 if (!Shell::FinishExecuting(isolate_, context_)) success = false;
5491 if (success) {
5492 bool handler_present;
5493 {
5494 HandleScope scope(isolate_);
5495 Local<Context> context = context_.Get(isolate_);
5496 Context::Scope context_scope(context);
5497 Local<Object> global = context->Global();
5498 // Check that there's a message handler
5499 MaybeLocal<Value> maybe_onmessage = global->Get(
5500 context,
5503 Local<Value> onmessage;
5504 handler_present =
5505 maybe_onmessage.ToLocal(&onmessage) && onmessage->IsFunction();
5506 }
5507 if (handler_present) {
5508 // Now wait for messages.
5510 }
5511 }
5512 }
5514 }
5515
5517
5519 context_.Reset();
5520 platform::NotifyIsolateShutdown(g_default_platform, isolate_);
5521 }
5522
5523 isolate_->Dispose();
5524 isolate_ = nullptr;
5525
5526 // Post nullptr to wake the thread waiting on GetMessage() if there is one.
5527 out_queue_.Enqueue(nullptr);
5529 // Also post an cleanup task to the parent isolate, so that it sees that this
5530 // worker is terminated and can clean it up in a thread-safe way.
5531 g_platform->GetForegroundTaskRunner(parent_isolate_)
5532 ->PostTask(std::make_unique<CleanUpWorkerTask>(parent_isolate_,
5533 this->shared_from_this()));
5534}
5535
5538 Isolate* isolate = info.GetIsolate();
5539 HandleScope handle_scope(isolate);
5540
5541 if (info.Length() < 1) {
5542 ThrowError(isolate, "Invalid argument");
5543 return;
5544 }
5545
5546 Local<Value> message = info[0];
5547 Local<Value> transfer = Undefined(isolate);
5548 std::unique_ptr<SerializationData> data =
5549 Shell::SerializeValue(isolate, message, transfer);
5550 if (data) {
5551 DCHECK(info.Data()->IsExternal());
5552 Local<External> this_value = info.Data().As<External>();
5553 Worker* worker = static_cast<Worker*>(this_value->Value());
5554
5555 worker->out_queue_.Enqueue(std::move(data));
5556 worker->out_semaphore_.Signal();
5557 g_platform->GetForegroundTaskRunner(worker->parent_isolate_)
5558 ->PostTask(std::make_unique<CheckMessageFromWorkerTask>(
5559 worker->parent_isolate_, worker->shared_from_this()));
5560 }
5561}
5562
5566
5569 Isolate* isolate = info.GetIsolate();
5570 HandleScope handle_scope(isolate);
5571 DCHECK(info.Data()->IsExternal());
5572 Local<External> this_value = info.Data().As<External>();
5573 Worker* worker = static_cast<Worker*>(this_value->Value());
5574 worker->Terminate();
5575}
5576
5577#ifdef V8_TARGET_OS_WIN
5578// Enable support for unicode filename path on windows.
5579// We first convert ansi encoded argv[i] to utf16 encoded, and then
5580// convert utf16 encoded to utf8 encoded with setting the argv[i]
5581// to the utf8 encoded arg. We allocate memory for the utf8 encoded
5582// arg, and we will free it and reset it to nullptr after using
5583// the filename path arg. And because Execute may be called multiple
5584// times, we need to free the allocated unicode filename when exit.
5585
5586// Save the allocated utf8 filenames, and we will free them when exit.
5587std::vector<char*> utf8_filenames;
5588#include <shellapi.h>
5589// Convert utf-16 encoded string to utf-8 encoded.
5590char* ConvertUtf16StringToUtf8(const wchar_t* str) {
5591 // On Windows wchar_t must be a 16-bit value.
5592 static_assert(sizeof(wchar_t) == 2, "wrong wchar_t size");
5593 int len =
5594 WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, FALSE);
5595 DCHECK_LT(0, len);
5596 char* utf8_str = new char[len];
5597 utf8_filenames.push_back(utf8_str);
5598 WideCharToMultiByte(CP_UTF8, 0, str, -1, utf8_str, len, nullptr, FALSE);
5599 return utf8_str;
5600}
5601
5602// Convert ansi encoded argv[i] to utf8 encoded.
5603void PreProcessUnicodeFilenameArg(char* argv[], int i) {
5604 int argc;
5605 wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
5606 argv[i] = ConvertUtf16StringToUtf8(wargv[i]);
5607 LocalFree(wargv);
5608}
5609
5610#endif
5611
5612namespace {
5613
5614bool FlagMatches(const char* flag, char** arg, bool keep_flag = false) {
5615 if (strcmp(*arg, flag) == 0) {
5616 if (!keep_flag) {
5617 *arg = nullptr;
5618 }
5619 return true;
5620 }
5621 return false;
5622}
5623
5624template <size_t N>
5625bool FlagWithArgMatches(const char (&flag)[N], char** flag_value, int argc,
5626 char* argv[], int* i) {
5627 char* current_arg = argv[*i];
5628
5629 // Compare the flag up to the last character of the flag name (not including
5630 // the null terminator).
5631 if (strncmp(current_arg, flag, N - 1) == 0) {
5632 // Match against --flag=value
5633 if (current_arg[N - 1] == '=') {
5634 *flag_value = argv[*i] + N;
5635 argv[*i] = nullptr;
5636 return true;
5637 }
5638 // Match against --flag value
5639 if (current_arg[N - 1] == '\0') {
5640 CHECK_LT(*i, argc - 1);
5641 argv[*i] = nullptr;
5642 (*i)++;
5643 *flag_value = argv[*i];
5644 argv[*i] = nullptr;
5645 return true;
5646 }
5647 }
5648
5649 flag_value = nullptr;
5650 return false;
5651}
5652
5653} // namespace
5654
5655bool Shell::SetOptions(int argc, char* argv[]) {
5656 bool logfile_per_isolate = false;
5657 options.d8_path = argv[0];
5658 for (int i = 0; i < argc; i++) {
5659 char* flag_value = nullptr;
5660 if (FlagMatches("--", &argv[i])) {
5661 i++;
5662 for (; i < argc; i++) {
5663 options.arguments.push_back(argv[i]);
5664 argv[i] = nullptr;
5665 }
5666 break;
5667 } else if (FlagMatches("--no-arguments", &argv[i])) {
5668 options.include_arguments = false;
5669 } else if (FlagMatches("--simulate-errors", &argv[i])) {
5670 options.simulate_errors = true;
5671 } else if (FlagMatches("--fuzzing", &argv[i], /*keep_flag=*/true) ||
5672 FlagMatches("--no-abort-on-contradictory-flags", &argv[i],
5673 /*keep_flag=*/true) ||
5674 FlagMatches("--noabort-on-contradictory-flags", &argv[i],
5675 /*keep_flag=*/true)) {
5677 } else if (FlagMatches("--abort-on-contradictory-flags", &argv[i],
5678 /*keep_flag=*/true)) {
5680 } else if (FlagMatches("--logfile-per-isolate", &argv[i])) {
5681 logfile_per_isolate = true;
5682 } else if (FlagMatches("--shell", &argv[i])) {
5683 options.interactive_shell = true;
5684 } else if (FlagMatches("--test", &argv[i])) {
5685 options.test_shell = true;
5686 } else if (FlagMatches("--notest", &argv[i]) ||
5687 FlagMatches("--no-test", &argv[i])) {
5688 options.test_shell = false;
5689 } else if (FlagMatches("--send-idle-notification", &argv[i])) {
5690 options.send_idle_notification = true;
5691 } else if (FlagMatches("--invoke-weak-callbacks", &argv[i])) {
5692 options.invoke_weak_callbacks = true;
5693 // TODO(v8:3351): Invoking weak callbacks does not always collect all
5694 // available garbage.
5695 options.send_idle_notification = true;
5696 } else if (FlagMatches("--omit-quit", &argv[i])) {
5697 options.omit_quit = true;
5698 } else if (FlagMatches("--no-wait-for-background-tasks", &argv[i])) {
5699 // TODO(herhut) Remove this flag once wasm compilation is fully
5700 // isolate-independent.
5701 options.wait_for_background_tasks = false;
5702 } else if (FlagMatches("-f", &argv[i], /*keep_flag=*/true)) {
5703 // Ignore any -f flags for compatibility with other stand-alone
5704 // JavaScript engines.
5705 continue;
5706 } else if (FlagMatches("--ignore-unhandled-promises", &argv[i])) {
5707 options.ignore_unhandled_promises = true;
5708 } else if (FlagMatches("--isolate", &argv[i], /*keep_flag=*/true)) {
5709 options.num_isolates++;
5710 } else if (FlagMatches("--throws", &argv[i])) {
5711 options.expected_to_throw = true;
5712 } else if (FlagMatches("--no-fail", &argv[i])) {
5713 options.no_fail = true;
5714 } else if (FlagMatches("--dump-counters", &argv[i])) {
5715 i::v8_flags.slow_histograms = true;
5716 options.dump_counters = true;
5717 } else if (FlagMatches("--dump-counters-nvp", &argv[i])) {
5718 i::v8_flags.slow_histograms = true;
5719 options.dump_counters_nvp = true;
5720 } else if (FlagMatches("--dump-system-memory-stats", &argv[i])) {
5721 options.dump_system_memory_stats = true;
5722 } else if (FlagWithArgMatches("--icu-data-file", &flag_value, argc, argv,
5723 &i)) {
5724 options.icu_data_file = flag_value;
5725 } else if (FlagWithArgMatches("--icu-locale", &flag_value, argc, argv,
5726 &i)) {
5727 options.icu_locale = flag_value;
5728#ifdef V8_USE_EXTERNAL_STARTUP_DATA
5729 } else if (FlagWithArgMatches("--snapshot_blob", &flag_value, argc, argv,
5730 &i)) {
5731 options.snapshot_blob = flag_value;
5732#endif // V8_USE_EXTERNAL_STARTUP_DATA
5733 } else if (FlagMatches("--cache", &argv[i]) ||
5734 FlagWithArgMatches("--cache", &flag_value, argc, argv, &i)) {
5735 if (!flag_value || strcmp(flag_value, "code") == 0) {
5736 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
5737 options.code_cache_options =
5739 } else if (strcmp(flag_value, "none") == 0) {
5740 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
5741 options.code_cache_options = ShellOptions::kNoProduceCache;
5742 } else if (strcmp(flag_value, "after-execute") == 0) {
5743 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
5744 options.code_cache_options =
5746 } else if (strcmp(flag_value, "full-code-cache") == 0) {
5747 options.compile_options = v8::ScriptCompiler::kEagerCompile;
5748 options.code_cache_options =
5750 } else {
5751 fprintf(stderr, "Unknown option to --cache.\n");
5752 return false;
5753 }
5754 } else if (FlagMatches("--streaming-compile", &argv[i])) {
5755 options.streaming_compile = true;
5756 } else if ((FlagMatches("--no-streaming-compile", &argv[i])) ||
5757 (FlagMatches("--nostreaming-compile", &argv[i]))) {
5758 options.streaming_compile = false;
5759 } else if (FlagMatches("--enable-tracing", &argv[i])) {
5760 options.trace_enabled = true;
5761 } else if (FlagWithArgMatches("--trace-path", &flag_value, argc, argv,
5762 &i)) {
5763 options.trace_path = flag_value;
5764 } else if (FlagWithArgMatches("--trace-config", &flag_value, argc, argv,
5765 &i)) {
5766 options.trace_config = flag_value;
5767 } else if (FlagMatches("--enable-inspector", &argv[i])) {
5768 options.enable_inspector = true;
5769 } else if (FlagWithArgMatches("--lcov", &flag_value, argc, argv, &i)) {
5770 options.lcov_file = flag_value;
5771#ifdef V8_OS_LINUX
5772 } else if (FlagMatches("--scope-linux-perf-to-mark-measure", &argv[i])) {
5773 options.scope_linux_perf_to_mark_measure = true;
5774 } else if (FlagWithArgMatches("--perf-ctl-fd", &flag_value, argc, argv,
5775 &i)) {
5776 options.perf_ctl_fd = atoi(flag_value);
5777 } else if (FlagWithArgMatches("--perf-ack-fd", &flag_value, argc, argv,
5778 &i)) {
5779 options.perf_ack_fd = atoi(flag_value);
5780#endif
5781 } else if (FlagMatches("--disable-in-process-stack-traces", &argv[i])) {
5782 options.disable_in_process_stack_traces = true;
5783#ifdef V8_OS_POSIX
5784 } else if (FlagWithArgMatches("--read-from-tcp-port", &flag_value, argc,
5785 argv, &i)) {
5786 options.read_from_tcp_port = atoi(flag_value);
5787#endif // V8_OS_POSIX
5788 } else if (FlagMatches("--enable-os-system", &argv[i])) {
5789 options.enable_os_system = true;
5790 } else if (FlagMatches("--no-apply-priority", &argv[i])) {
5791 options.apply_priority = false;
5792 } else if (FlagMatches("--quiet-load", &argv[i])) {
5793 options.quiet_load = true;
5794 } else if (FlagWithArgMatches("--thread-pool-size", &flag_value, argc, argv,
5795 &i)) {
5796 options.thread_pool_size = atoi(flag_value);
5797 } else if (FlagMatches("--stress-delay-tasks", &argv[i])) {
5798 // Delay execution of tasks by 0-100ms randomly (based on --random-seed).
5799 options.stress_delay_tasks = true;
5800 } else if (FlagMatches("--cpu-profiler", &argv[i])) {
5801 options.cpu_profiler = true;
5802 } else if (FlagMatches("--cpu-profiler-print", &argv[i])) {
5803 options.cpu_profiler = true;
5804 options.cpu_profiler_print = true;
5805 } else if (FlagMatches("--stress-deserialize", &argv[i])) {
5806 options.stress_deserialize = true;
5807 } else if (FlagMatches("--compile-only", &argv[i])) {
5808 options.compile_only = true;
5809 } else if (FlagWithArgMatches("--repeat-compile", &flag_value, argc, argv,
5810 &i)) {
5811 options.repeat_compile = atoi(flag_value);
5812 } else if (FlagWithArgMatches("--max-serializer-memory", &flag_value, argc,
5813 argv, &i)) {
5814 // Value is expressed in MB.
5815 options.max_serializer_memory = atoi(flag_value) * i::MB;
5816#ifdef V8_FUZZILLI
5817 } else if (FlagMatches("--fuzzilli-enable-builtins-coverage", &argv[i])) {
5818 options.fuzzilli_enable_builtins_coverage = true;
5819 } else if (FlagMatches("--fuzzilli-coverage-statistics", &argv[i])) {
5820 options.fuzzilli_coverage_statistics = true;
5821#endif
5822 } else if (FlagMatches("--no-fuzzy-module-file-extensions", &argv[i])) {
5823 DCHECK(options.fuzzy_module_file_extensions);
5824 options.fuzzy_module_file_extensions = false;
5825#if defined(V8_ENABLE_ETW_STACK_WALKING)
5826 } else if (FlagMatches("--enable-etw-stack-walking", &argv[i])) {
5827 options.enable_etw_stack_walking = true;
5828 // This needs to be manually triggered for JIT ETW events to work.
5829 i::v8_flags.enable_etw_stack_walking = true;
5830#if defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
5831 } else if (FlagMatches("--enable-system-instrumentation", &argv[i])) {
5832 options.enable_system_instrumentation = true;
5833 options.trace_enabled = true;
5834#endif
5835#if defined(V8_OS_WIN)
5836 // Guard this bc the flag has a lot of overhead and is not currently used
5837 // by macos
5838 i::v8_flags.interpreted_frames_native_stack = true;
5839#endif
5840#endif
5841#if V8_ENABLE_WEBASSEMBLY
5842 } else if (FlagMatches("--wasm-trap-handler", &argv[i])) {
5843 options.wasm_trap_handler = true;
5844 } else if (FlagMatches("--no-wasm-trap-handler", &argv[i])) {
5845 options.wasm_trap_handler = false;
5846#endif // V8_ENABLE_WEBASSEMBLY
5847 } else if (FlagMatches("--expose-fast-api", &argv[i])) {
5848 options.expose_fast_api = true;
5849 } else if (FlagMatches("--flush-denormals", &argv[i])) {
5850 options.flush_denormals = true;
5851 } else {
5852#ifdef V8_TARGET_OS_WIN
5853 PreProcessUnicodeFilenameArg(argv, i);
5854#endif
5855 }
5856 }
5857
5858#ifdef V8_OS_LINUX
5859 if (options.scope_linux_perf_to_mark_measure) {
5860 if (options.perf_ctl_fd == -1 || options.perf_ack_fd == -1) {
5861 fprintf(stderr,
5862 "Flag --scope-linux-perf-to-mark-measure requires both "
5863 "--perf-ctl-fd and --perf-ack-fd\n");
5864 return false;
5865 }
5866 SendPerfControlCommand("disable");
5867 }
5868#endif
5869
5870 const char* usage =
5871 "Synopsis:\n"
5872 " shell [options] [--shell] [<file>...]\n"
5873 " d8 [options] [-e <string>] [--shell] [--module|]"
5874 " <file>...]\n\n"
5875 " -e execute a string in V8\n"
5876 " --shell run an interactive JavaScript shell\n"
5877 " --module execute a file as a JavaScript module\n";
5878 using HelpOptions = i::FlagList::HelpOptions;
5879 i::v8_flags.abort_on_contradictory_flags = true;
5880 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true,
5881 HelpOptions(HelpOptions::kExit, usage));
5882 i::FlagList::ResolveContradictionsWhenFuzzing();
5883
5884 options.mock_arraybuffer_allocator = i::v8_flags.mock_arraybuffer_allocator;
5885 options.mock_arraybuffer_allocator_limit =
5886 i::v8_flags.mock_arraybuffer_allocator_limit;
5887#ifdef V8_OS_LINUX
5888 options.multi_mapped_mock_allocator = i::v8_flags.multi_mapped_mock_allocator;
5889#endif // V8_OS_LINUX
5890
5891 if (i::v8_flags.stress_snapshot && options.expose_fast_api &&
5893 FATAL("Flag --expose-fast-api is incompatible with --stress-snapshot.");
5894 }
5895
5896 // Set up isolated source groups.
5897 options.isolate_sources = new SourceGroup[options.num_isolates];
5898 internal::g_num_isolates_for_testing = options.num_isolates;
5899 SourceGroup* current = options.isolate_sources;
5900 current->Begin(argv, 1);
5901 for (int i = 1; i < argc; i++) {
5902 const char* str = argv[i];
5903 if (strcmp(str, "--isolate") == 0) {
5904 current->End(i);
5905 current++;
5906 current->Begin(argv, i + 1);
5907 } else if (strcmp(str, "--module") == 0 || strcmp(str, "--json") == 0) {
5908 // Pass on to SourceGroup, which understands these options.
5909 } else if (strncmp(str, "--", 2) == 0) {
5910 if (!i::v8_flags.correctness_fuzzer_suppressions) {
5911 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
5912 }
5913 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
5914 set_script_executed();
5915 } else if (strncmp(str, "-", 1) != 0) {
5916 // Not a flag, so it must be a script to execute.
5917 set_script_executed();
5918 }
5919 }
5920 current->End(argc);
5921
5922 if (!logfile_per_isolate && options.num_isolates) {
5923 V8::SetFlagsFromString("--no-logfile-per-isolate");
5924 }
5925
5926 return true;
5927}
5928
5929int Shell::RunMain(v8::Isolate* isolate, bool last_run) {
5930 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
5931
5932 for (int i = 1; i < options.num_isolates; ++i) {
5933 options.isolate_sources[i].StartExecuteInThread();
5934 }
5935
5936 // The Context object, created inside RunMainIsolate, is used after the method
5937 // returns in some situations:
5938 const bool keep_context_alive =
5939 last_run && (use_interactive_shell() || i::v8_flags.stress_snapshot);
5940 bool success = RunMainIsolate(isolate, keep_context_alive);
5941 CollectGarbage(isolate);
5942
5943 // Park the main thread here to prevent deadlocks in shared GCs when
5944 // waiting in JoinThread.
5946 [last_run](const i::ParkedScope& parked) {
5947 for (int i = 1; i < options.num_isolates; ++i) {
5948 if (last_run) {
5949 options.isolate_sources[i].JoinThread(parked);
5950 } else {
5951 options.isolate_sources[i].WaitForThread(parked);
5952 }
5953 }
5954 WaitForRunningWorkers(parked);
5955 });
5956
5957 // Other threads have terminated, we can now run the artificial
5958 // serialize-deserialize pass (which destructively mutates heap state).
5959 if (success && last_run && i::v8_flags.stress_snapshot) {
5960 HandleScope handle_scope(isolate);
5961 static constexpr bool kClearRecompilableData = true;
5962 auto context = v8::Local<v8::Context>::New(isolate, evaluation_context_);
5964 // Stop concurrent compiles before mutating the heap.
5965 if (i_isolate->concurrent_recompilation_enabled()) {
5968 }
5969#if V8_ENABLE_MAGLEV
5970 if (i_isolate->maglev_concurrent_dispatcher()->is_enabled()) {
5971 i_isolate->maglev_concurrent_dispatcher()->AwaitCompileJobs();
5972 }
5973#endif // V8_ENABLE_MAGLEV
5974 // TODO(jgruber,v8:10500): Don't deoptimize once we support serialization
5975 // of optimized code.
5976 i::Deoptimizer::DeoptimizeAll(i_isolate);
5977 // Trigger GC to better align with production code. Also needed by
5978 // ClearReconstructableDataForSerialization to not look into dead objects.
5979 i_isolate->heap()->CollectAllAvailableGarbage(
5980 i::GarbageCollectionReason::kSnapshotCreator);
5981 i::Snapshot::ClearReconstructableDataForSerialization(
5982 i_isolate, kClearRecompilableData);
5983 i::Snapshot::SerializeDeserializeAndVerifyForTesting(i_isolate, i_context);
5984 }
5985
5986 if (Shell::unhandled_promise_rejections_.load() > 0) {
5987 printf("%i pending unhandled Promise rejection(s) detected.\n",
5989 success = false;
5990 // RunMain may be executed multiple times, e.g. in REPRL mode, so we have to
5991 // reset this counter.
5993 }
5994 // In order to finish successfully, success must be != expected_to_throw.
5995 if (Shell::options.no_fail) return 0;
5996 // Fuzzers aren't expected to use --throws, but may pick it up from testcases.
5997 // In that case, just ignore the flag.
5998 if (i::v8_flags.fuzzing && Shell::options.expected_to_throw) return 0;
5999 return (success == Shell::options.expected_to_throw ? 1 : 0);
6000}
6001
6002bool Shell::RunMainIsolate(v8::Isolate* isolate, bool keep_context_alive) {
6003 if (options.lcov_file) {
6005 }
6006 HandleScope scope(isolate);
6007 Global<Context> global_context;
6008 {
6010 if (!CreateEvaluationContext(isolate).ToLocal(&context)) {
6011 DCHECK(isolate->IsExecutionTerminating());
6012 // We must not exit early here in REPRL mode as that would cause the next
6013 // testcase sent by Fuzzilli to be skipped, which will desynchronize the
6014 // communication between d8 and Fuzzilli, leading to a crash.
6015 DCHECK(!fuzzilli_reprl);
6016 return true;
6017 }
6018 global_context.Reset(isolate, context);
6019 if (keep_context_alive) {
6020 evaluation_context_.Reset(isolate, context);
6021 }
6022 }
6023 PerIsolateData::RealmScope realm_scope(isolate, global_context);
6024 InspectorClient inspector_client(isolate, global_context,
6025 options.enable_inspector);
6026 bool success = true;
6027 {
6028 // We cannot use a Context::Scope here, as it keeps a local handle to the
6029 // context and SourceGroup::Execute may execute a non-nestable task, e.g. a
6030 // stackless GC.
6031 global_context.Get(isolate)->Enter();
6032 if (!options.isolate_sources[0].Execute(isolate)) success = false;
6033 global_context.Get(isolate)->Exit();
6034 }
6035 if (!FinishExecuting(isolate, global_context)) success = false;
6036 WriteLcovData(isolate, options.lcov_file);
6037 return success;
6038}
6039
6041 if (options.send_idle_notification) {
6042 isolate->ContextDisposedNotification(
6044 }
6045 if (options.invoke_weak_callbacks) {
6046 // By sending a low memory notifications, we will try hard to collect all
6047 // garbage and will therefore also invoke all weak callbacks of actually
6048 // unreachable persistent handles.
6049 isolate->LowMemoryNotification();
6050 }
6051}
6052
6053namespace {
6054bool ProcessMessages(
6055 Isolate* isolate,
6056 const std::function<platform::MessageLoopBehavior()>& behavior) {
6057 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6058 i::SaveAndSwitchContext saved_context(i_isolate, i::Context());
6059 SealHandleScope shs(isolate);
6060
6061 if (isolate->IsExecutionTerminating()) return true;
6062 TryCatch try_catch(isolate);
6063 try_catch.SetVerbose(true);
6064
6065 while (true) {
6066 bool ran_a_task;
6067 ran_a_task =
6068 v8::platform::PumpMessageLoop(g_default_platform, isolate, behavior());
6069 if (isolate->IsExecutionTerminating()) return true;
6070 if (try_catch.HasCaught()) return false;
6071 if (ran_a_task) MicrotasksScope::PerformCheckpoint(isolate);
6072 if (isolate->IsExecutionTerminating()) return true;
6073
6074 // In predictable mode we push all background tasks into the foreground
6075 // task queue of the {kProcessGlobalPredictablePlatformWorkerTaskQueue}
6076 // isolate. We execute all background tasks after running one foreground
6077 // task.
6078 if (i::v8_flags.verify_predictable) {
6079 TryCatch inner_try_catch(isolate);
6080 inner_try_catch.SetVerbose(true);
6084 ran_a_task = true;
6085 if (inner_try_catch.HasCaught()) return false;
6086 if (isolate->IsExecutionTerminating()) return true;
6087 }
6088 }
6089
6090 if (!ran_a_task) break;
6091 }
6092 if (g_default_platform->IdleTasksEnabled(isolate)) {
6093 v8::platform::RunIdleTasks(g_default_platform, isolate,
6095 if (try_catch.HasCaught()) return false;
6096 if (isolate->IsExecutionTerminating()) return true;
6097 }
6098 return true;
6099}
6100} // anonymous namespace
6101
6103 auto get_waiting_behaviour = [isolate]() {
6104 if (options.wait_for_background_tasks &&
6105 isolate->HasPendingBackgroundTasks()) {
6107 }
6108 if (PerIsolateData::Get(isolate)->HasRunningSubscribedWorkers()) {
6110 }
6112 };
6113 if (i::v8_flags.verify_predictable) {
6114 bool ran_tasks = ProcessMessages(
6115 isolate, [] { return platform::MessageLoopBehavior::kDoNotWait; });
6116 if (get_waiting_behaviour() ==
6118 FATAL(
6119 "There is outstanding work after executing all tasks in predictable "
6120 "mode -- this would deadlock.");
6121 }
6122 return ran_tasks;
6123 }
6124 return ProcessMessages(isolate, get_waiting_behaviour);
6125}
6126
6127bool Shell::FinishExecuting(Isolate* isolate, const Global<Context>& context) {
6128 if (!CompleteMessageLoop(isolate)) return false;
6129 HandleScope scope(isolate);
6130 // We cannot use a Context::Scope here, as it keeps a local handle to the
6131 // context and HandleUnhandledPromiseRejections may execute a non-nestable
6132 // task, e.g. a stackless GC.
6133 context.Get(isolate)->Enter();
6134 bool result = HandleUnhandledPromiseRejections(isolate);
6135 context.Get(isolate)->Exit();
6136 return result;
6137}
6138
6140 return ProcessMessages(
6141 isolate, []() { return platform::MessageLoopBehavior::kDoNotWait; });
6142}
6143
6145 if (options.ignore_unhandled_promises) return true;
6146 PerIsolateData* data = PerIsolateData::Get(isolate);
6147 int count = data->HandleUnhandledPromiseRejections();
6150 return count == 0;
6151}
6152
6154 public:
6155 explicit Serializer(Isolate* isolate)
6156 : isolate_(isolate),
6157 serializer_(isolate, this),
6158 current_memory_usage_(0) {}
6159
6160 Serializer(const Serializer&) = delete;
6162
6164 Local<Value> transfer) {
6165 bool ok;
6166 DCHECK(!data_);
6167 data_.reset(new SerializationData);
6168 if (!PrepareTransfer(context, transfer).To(&ok)) {
6169 return Nothing<bool>();
6170 }
6171 serializer_.WriteHeader();
6172
6173 if (!serializer_.WriteValue(context, value).To(&ok)) {
6174 data_.reset();
6175 return Nothing<bool>();
6176 }
6177
6178 if (!FinalizeTransfer().To(&ok)) {
6179 return Nothing<bool>();
6180 }
6181
6182 std::pair<uint8_t*, size_t> pair = serializer_.Release();
6183 data_->data_.reset(pair.first);
6184 data_->size_ = pair.second;
6185 return Just(true);
6186 }
6187
6188 std::unique_ptr<SerializationData> Release() { return std::move(data_); }
6189
6190 void AppendBackingStoresTo(std::vector<std::shared_ptr<BackingStore>>* to) {
6191 to->insert(to->end(), std::make_move_iterator(backing_stores_.begin()),
6192 std::make_move_iterator(backing_stores_.end()));
6193 backing_stores_.clear();
6194 }
6195
6196 protected:
6197 // Implements ValueSerializer::Delegate.
6198 void ThrowDataCloneError(Local<String> message) override {
6199 isolate_->ThrowException(Exception::Error(message));
6200 }
6201
6203 Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override {
6205 for (size_t index = 0; index < shared_array_buffers_.size(); ++index) {
6206 if (shared_array_buffers_[index] == shared_array_buffer) {
6207 return Just<uint32_t>(static_cast<uint32_t>(index));
6208 }
6209 }
6210
6211 size_t index = shared_array_buffers_.size();
6212 shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
6213 data_->sab_backing_stores_.push_back(
6214 shared_array_buffer->GetBackingStore());
6215 return Just<uint32_t>(static_cast<uint32_t>(index));
6216 }
6217
6219 Isolate* isolate, Local<WasmModuleObject> module) override {
6221 for (size_t index = 0; index < wasm_modules_.size(); ++index) {
6222 if (wasm_modules_[index] == module) {
6223 return Just<uint32_t>(static_cast<uint32_t>(index));
6224 }
6225 }
6226
6227 size_t index = wasm_modules_.size();
6228 wasm_modules_.emplace_back(isolate_, module);
6229 data_->compiled_wasm_modules_.push_back(module->GetCompiledModule());
6230 return Just<uint32_t>(static_cast<uint32_t>(index));
6231 }
6232
6233 void* ReallocateBufferMemory(void* old_buffer, size_t size,
6234 size_t* actual_size) override {
6235 // Not accurate, because we don't take into account reallocated buffers,
6236 // but this is fine for testing.
6237 current_memory_usage_ += size;
6238 if (current_memory_usage_ > Shell::options.max_serializer_memory) {
6239 return nullptr;
6240 }
6241
6242 void* result = base::Realloc(old_buffer, size);
6243 *actual_size = result ? size : 0;
6244 return result;
6245 }
6246
6247 void FreeBufferMemory(void* buffer) override { base::Free(buffer); }
6248
6250 SharedValueConveyor&& conveyor) override {
6251 data_->shared_value_conveyor_.emplace(std::move(conveyor));
6252 return true;
6253 }
6254
6255 private:
6257 if (transfer->IsArray()) {
6258 Local<Array> transfer_array = transfer.As<Array>();
6259 uint32_t length = transfer_array->Length();
6260 for (uint32_t i = 0; i < length; ++i) {
6261 Local<Value> element;
6262 if (transfer_array->Get(context, i).ToLocal(&element)) {
6263 if (!element->IsArrayBuffer()) {
6264 isolate_->ThrowError(
6265 "Transfer array elements must be an ArrayBuffer");
6266 return Nothing<bool>();
6267 }
6268
6269 Local<ArrayBuffer> array_buffer = element.As<ArrayBuffer>();
6270
6271 if (std::find(array_buffers_.begin(), array_buffers_.end(),
6272 array_buffer) != array_buffers_.end()) {
6273 isolate_->ThrowError(
6274 "ArrayBuffer occurs in the transfer array more than once");
6275 return Nothing<bool>();
6276 }
6277
6278 serializer_.TransferArrayBuffer(
6279 static_cast<uint32_t>(array_buffers_.size()), array_buffer);
6280 array_buffers_.emplace_back(isolate_, array_buffer);
6281 } else {
6282 return Nothing<bool>();
6283 }
6284 }
6285 return Just(true);
6286 } else if (transfer->IsUndefined()) {
6287 return Just(true);
6288 } else {
6289 isolate_->ThrowError("Transfer list must be an Array or undefined");
6290 return Nothing<bool>();
6291 }
6292 }
6293
6295 for (const auto& global_array_buffer : array_buffers_) {
6296 Local<ArrayBuffer> array_buffer =
6297 Local<ArrayBuffer>::New(isolate_, global_array_buffer);
6298 if (!array_buffer->IsDetachable()) {
6299 isolate_->ThrowError(
6300 "ArrayBuffer is not detachable and could not be transferred");
6301 return Nothing<bool>();
6302 }
6303
6304 auto backing_store = array_buffer->GetBackingStore();
6305 data_->backing_stores_.push_back(std::move(backing_store));
6306 if (array_buffer->Detach(v8::Local<v8::Value>()).IsNothing()) {
6307 return Nothing<bool>();
6308 }
6309 }
6310
6311 return Just(true);
6312 }
6313
6314 // This must come before ValueSerializer as it caches this value.
6317 std::unique_ptr<SerializationData> data_;
6318 std::vector<Global<ArrayBuffer>> array_buffers_;
6319 std::vector<Global<SharedArrayBuffer>> shared_array_buffers_;
6320 std::vector<Global<WasmModuleObject>> wasm_modules_;
6321 std::vector<std::shared_ptr<v8::BackingStore>> backing_stores_;
6323};
6324
6326 public:
6327 Deserializer(Isolate* isolate, std::unique_ptr<SerializationData> data)
6328 : isolate_(isolate),
6329 deserializer_(isolate, data->data(), data->size(), this),
6330 data_(std::move(data)) {
6331 deserializer_.SetSupportsLegacyWireFormat(true);
6332 }
6333
6334 Deserializer(const Deserializer&) = delete;
6336
6338 bool read_header;
6339 if (!deserializer_.ReadHeader(context).To(&read_header)) {
6340 return MaybeLocal<Value>();
6341 }
6342
6343 uint32_t index = 0;
6344 for (const auto& backing_store : data_->backing_stores()) {
6345 Local<ArrayBuffer> array_buffer =
6346 ArrayBuffer::New(isolate_, std::move(backing_store));
6347 deserializer_.TransferArrayBuffer(index++, array_buffer);
6348 }
6349
6350 return deserializer_.ReadValue(context);
6351 }
6352
6354 Isolate* isolate, uint32_t clone_id) override {
6356 if (clone_id < data_->sab_backing_stores().size()) {
6357 return SharedArrayBuffer::New(
6358 isolate_, std::move(data_->sab_backing_stores().at(clone_id)));
6359 }
6361 }
6362
6364 Isolate* isolate, uint32_t transfer_id) override {
6366 if (transfer_id >= data_->compiled_wasm_modules().size()) return {};
6367 return WasmModuleObject::FromCompiledModule(
6368 isolate_, data_->compiled_wasm_modules().at(transfer_id));
6369 }
6370
6373 if (data_->shared_value_conveyor()) {
6374 return &data_->shared_value_conveyor().value();
6375 }
6376 return nullptr;
6377 }
6378
6379 private:
6382 std::unique_ptr<SerializationData> data_;
6383};
6384
6386 public:
6391 static int GetStressRuns() {
6392 if (i::v8_flags.stress_runs != 0) return i::v8_flags.stress_runs;
6393#ifdef DEBUG
6394 // In debug mode the code runs much slower so stressing will only make two
6395 // runs.
6396 return 2;
6397#else
6398 return 5;
6399#endif
6400 }
6401
6405 static void DeoptimizeAll(Isolate* isolate) {
6406 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6407 i::HandleScope scope(i_isolate);
6408 i::Deoptimizer::DeoptimizeAll(i_isolate);
6409 }
6410};
6411
6412std::unique_ptr<SerializationData> Shell::SerializeValue(
6413 Isolate* isolate, Local<Value> value, Local<Value> transfer) {
6414 bool ok;
6415 Local<Context> context = isolate->GetCurrentContext();
6416 Serializer serializer(isolate);
6417 std::unique_ptr<SerializationData> data;
6418 if (serializer.WriteValue(context, value, transfer).To(&ok)) {
6419 data = serializer.Release();
6420 }
6421 return data;
6422}
6423
6425 Isolate* isolate, std::unique_ptr<SerializationData> data) {
6426 Local<Context> context = isolate->GetCurrentContext();
6427 Deserializer deserializer(isolate, std::move(data));
6428 return deserializer.ReadValue(context);
6429}
6430
6431void Shell::AddRunningWorker(std::shared_ptr<Worker> worker) {
6432 workers_mutex_.Pointer()->AssertHeld(); // caller should hold the mutex.
6433 running_workers_.insert(worker);
6434}
6435
6436void Shell::RemoveRunningWorker(const std::shared_ptr<Worker>& worker) {
6437 base::MutexGuard lock_guard(workers_mutex_.Pointer());
6438 auto it = running_workers_.find(worker);
6439 if (it != running_workers_.end()) running_workers_.erase(it);
6440}
6441
6443 // Make a copy of running_workers_, because we don't want to call
6444 // Worker::Terminate while holding the workers_mutex_ lock. Otherwise, if a
6445 // worker is about to create a new Worker, it would deadlock.
6446 std::unordered_set<std::shared_ptr<Worker>> workers_copy;
6447 {
6448 base::MutexGuard lock_guard(workers_mutex_.Pointer());
6449 allow_new_workers_ = false;
6450 workers_copy.swap(running_workers_);
6451 }
6452
6453 for (auto& worker : workers_copy) {
6454 worker->TerminateAndWaitForThread(parked);
6455 }
6456
6457 // Now that all workers are terminated, we can re-enable Worker creation.
6458 base::MutexGuard lock_guard(workers_mutex_.Pointer());
6459 DCHECK(running_workers_.empty());
6460 allow_new_workers_ = true;
6461}
6462
6463namespace {
6464
6465#ifdef V8_OS_POSIX
6466void d8_sigterm_handler(int signal, siginfo_t* info, void* context) {
6467 // Dump stacktraces when terminating d8 instances with SIGTERM.
6468 // SIGKILL is not intercepted.
6469 if (signal == SIGTERM) {
6470 FATAL("d8: Received SIGTERM signal (likely due to a TIMEOUT)\n");
6471 } else {
6472 UNREACHABLE();
6473 }
6474}
6475#endif // V8_OS_POSIX
6476
6477void d8_install_sigterm_handler() {
6478#ifdef V8_OS_POSIX
6479 CHECK(!i::v8_flags.fuzzing);
6480 struct sigaction sa;
6481 sa.sa_sigaction = d8_sigterm_handler;
6482 sigemptyset(&sa.sa_mask);
6483 sa.sa_flags = 0;
6484 if (sigaction(SIGTERM, &sa, NULL) == -1) {
6485 FATAL("Could not install SIGTERM handler");
6486 }
6487#endif // V8_OS_POSIX
6488}
6489
6490} // namespace
6491
6492int Shell::Main(int argc, char* argv[]) {
6493#if defined(V8_ENABLE_PARTITION_ALLOC)
6494#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
6495 allocator_shim::ConfigurePartitionsForTesting();
6496 allocator_shim::internal::PartitionAllocMalloc::Allocator()
6497 ->EnableThreadCacheIfSupported();
6498#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
6499#endif
6501 if (!SetOptions(argc, argv)) return 1;
6502 if (!i::v8_flags.fuzzing) d8_install_sigterm_handler();
6503
6504 v8::base::FlushDenormalsScope denormals_scope(options.flush_denormals);
6505
6506 v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
6507
6508#ifdef V8_OS_DARWIN
6509 if (options.apply_priority) {
6510 struct task_category_policy category = {.role =
6511 TASK_FOREGROUND_APPLICATION};
6512 task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY,
6513 (task_policy_t)&category, TASK_CATEGORY_POLICY_COUNT);
6514 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
6515 }
6516#endif
6517
6518#ifdef V8_INTL_SUPPORT
6519 if (options.icu_locale != nullptr) {
6520 icu::Locale locale(options.icu_locale);
6521 UErrorCode error_code = U_ZERO_ERROR;
6522 icu::Locale::setDefault(locale, error_code);
6523 }
6524#endif // V8_INTL_SUPPORT
6525
6526 v8::platform::InProcessStackDumping in_process_stack_dumping =
6527 options.disable_in_process_stack_traces
6530
6531 std::ofstream trace_file;
6532 std::unique_ptr<platform::tracing::TracingController> tracing;
6533 if (options.trace_enabled && !i::v8_flags.verify_predictable) {
6534 tracing = std::make_unique<platform::tracing::TracingController>();
6535
6536 if (!options.enable_etw_stack_walking) {
6537 const char* trace_path =
6538 options.trace_path ? options.trace_path : "v8_trace.json";
6539 trace_file.open(trace_path);
6540 if (!trace_file.good()) {
6541 printf("Cannot open trace file '%s' for writing: %s.\n", trace_path,
6542 strerror(errno));
6543 return 1;
6544 }
6545 }
6546
6547#ifdef V8_USE_PERFETTO
6548 // Set up the in-process backend that the tracing controller will connect
6549 // to.
6550 perfetto::TracingInitArgs init_args;
6551 init_args.backends = perfetto::BackendType::kInProcessBackend;
6552 perfetto::Tracing::Initialize(init_args);
6553
6554 tracing->InitializeForPerfetto(&trace_file);
6555#else
6556 platform::tracing::TraceBuffer* trace_buffer = nullptr;
6557#if defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
6558 if (options.enable_system_instrumentation) {
6559 trace_buffer =
6563 CreateSystemInstrumentationTraceWriter());
6564 }
6565#endif // V8_ENABLE_SYSTEM_INSTRUMENTATION
6566 if (!trace_buffer) {
6567 trace_buffer =
6571 trace_file));
6572 }
6573 tracing->Initialize(trace_buffer);
6574#endif // V8_USE_PERFETTO
6575 }
6576
6578
6579 platform::tracing::TracingController* tracing_controller = tracing.get();
6580 if (i::v8_flags.single_threaded) {
6582 v8::platform::IdleTaskSupport::kEnabled, in_process_stack_dumping,
6583 std::move(tracing));
6584 } else {
6586 options.thread_pool_size, v8::platform::IdleTaskSupport::kEnabled,
6587 in_process_stack_dumping, std::move(tracing),
6588 options.apply_priority ? v8::platform::PriorityMode::kApply
6590 }
6591 g_default_platform = g_platform.get();
6592 if (i::v8_flags.predictable) {
6593 g_platform = MakePredictablePlatform(std::move(g_platform));
6594 }
6595 if (options.stress_delay_tasks) {
6596 int64_t random_seed = i::v8_flags.fuzzer_random_seed;
6597 if (!random_seed) random_seed = i::v8_flags.random_seed;
6598 // If random_seed is still 0 here, the {DelayedTasksPlatform} will choose a
6599 // random seed.
6600 g_platform = MakeDelayedTasksPlatform(std::move(g_platform), random_seed);
6601 }
6602
6603 if (i::v8_flags.trace_turbo_cfg_file == nullptr) {
6604 V8::SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
6605 }
6606 if (i::v8_flags.redirect_code_traces_to == nullptr) {
6607 V8::SetFlagsFromString("--redirect-code-traces-to=code.asm");
6608 }
6609 v8::V8::InitializePlatform(g_platform.get());
6610
6611 // Disable flag freezing if we are producing a code cache, because for that we
6612 // modify v8_flags.hash_seed (below).
6613 if (options.code_cache_options != ShellOptions::kNoProduceCache) {
6614 i::v8_flags.freeze_flags_after_init = false;
6615 }
6616
6618 if (options.snapshot_blob) {
6619 v8::V8::InitializeExternalStartupDataFromFile(options.snapshot_blob);
6620 } else {
6622 }
6623 int result = 0;
6624 Isolate::CreateParams create_params;
6625 ShellArrayBufferAllocator shell_array_buffer_allocator;
6626 MockArrayBufferAllocator mock_arraybuffer_allocator;
6627 const size_t memory_limit =
6628 options.mock_arraybuffer_allocator_limit * options.num_isolates;
6629 MockArrayBufferAllocatiorWithLimit mock_arraybuffer_allocator_with_limit(
6630 memory_limit >= options.mock_arraybuffer_allocator_limit
6631 ? memory_limit
6632 : std::numeric_limits<size_t>::max());
6633#ifdef V8_OS_LINUX
6634 MultiMappedAllocator multi_mapped_mock_allocator;
6635#endif // V8_OS_LINUX
6636 if (options.mock_arraybuffer_allocator) {
6637 if (memory_limit) {
6638 Shell::array_buffer_allocator = &mock_arraybuffer_allocator_with_limit;
6639 } else {
6640 Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
6641 }
6642#ifdef V8_OS_LINUX
6643 } else if (options.multi_mapped_mock_allocator) {
6644 Shell::array_buffer_allocator = &multi_mapped_mock_allocator;
6645#endif // V8_OS_LINUX
6646 } else {
6647 Shell::array_buffer_allocator = &shell_array_buffer_allocator;
6648 }
6650#ifdef ENABLE_VTUNE_JIT_INTERFACE
6651 if (i::v8_flags.enable_vtunejit) {
6652 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
6653 }
6654#endif // ENABLE_VTUNE_JIT_INTERFACE
6655 create_params.constraints.ConfigureDefaults(
6658
6660 if (options.dump_counters || options.dump_counters_nvp ||
6661 i::TracingFlags::is_gc_stats_enabled()) {
6662 create_params.counter_lookup_callback = LookupCounter;
6663 create_params.create_histogram_callback = CreateHistogram;
6664 create_params.add_histogram_sample_callback = AddHistogramSample;
6665 }
6666
6667#if V8_ENABLE_WEBASSEMBLY
6668 if (V8_TRAP_HANDLER_SUPPORTED && options.wasm_trap_handler) {
6669 constexpr bool kUseDefaultTrapHandler = true;
6670 if (!v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultTrapHandler)) {
6671 FATAL("Could not register trap handler");
6672 }
6673 }
6674#endif // V8_ENABLE_WEBASSEMBLY
6675
6676 if (i::v8_flags.experimental) {
6677 // This message is printed to stderr so that it is also visible in
6678 // Clusterfuzz reports.
6679 fprintf(stderr,
6680 "V8 is running with experimental features enabled. Stability and "
6681 "security will suffer.\n");
6682 }
6683
6684 Isolate* isolate = Isolate::New(create_params);
6685
6686#ifdef V8_FUZZILLI
6687 // Let the parent process (Fuzzilli) know we are ready.
6688 if (options.fuzzilli_enable_builtins_coverage) {
6689 cov_init_builtins_edges(static_cast<uint32_t>(
6690 i::BasicBlockProfiler::Get()
6691 ->GetCoverageBitmap(reinterpret_cast<i::Isolate*>(isolate))
6692 .size()));
6693 }
6694 char helo[] = "HELO";
6695 if (write(REPRL_CWFD, helo, 4) != 4 || read(REPRL_CRFD, helo, 4) != 4) {
6696 fuzzilli_reprl = false;
6697 }
6698
6699 if (memcmp(helo, "HELO", 4) != 0) {
6700 FATAL("REPRL: Invalid response from parent");
6701 }
6702#endif // V8_FUZZILLI
6703
6704 {
6705 Isolate::Scope scope(isolate);
6706 D8Console console(isolate);
6707 Initialize(isolate, &console);
6708 PerIsolateData data(isolate);
6709
6710 // Fuzzilli REPRL = read-eval-print-loop
6711 do {
6712#ifdef V8_FUZZILLI
6713 if (fuzzilli_reprl) {
6714 unsigned action = 0;
6715 ssize_t nread = read(REPRL_CRFD, &action, 4);
6716 if (nread != 4 || action != 'cexe') {
6717 FATAL("REPRL: Unknown action: %u", action);
6718 }
6719 }
6720#endif // V8_FUZZILLI
6721
6722 result = 0;
6723
6724 if (options.trace_enabled) {
6725 platform::tracing::TraceConfig* trace_config;
6726 if (options.trace_config) {
6727 int size = 0;
6728 char* trace_config_json_str = ReadChars(options.trace_config, &size);
6730 isolate, trace_config_json_str);
6731 delete[] trace_config_json_str;
6732 } else {
6733 trace_config =
6735 if (options.enable_system_instrumentation) {
6736 trace_config->AddIncludedCategory("disabled-by-default-v8.compile");
6737 }
6738 }
6739 tracing_controller->StartTracing(trace_config);
6740 }
6741
6742 CpuProfiler* cpu_profiler;
6743 if (options.cpu_profiler) {
6744 cpu_profiler = CpuProfiler::New(isolate);
6745 cpu_profiler->StartProfiling(String::Empty(isolate),
6747 }
6748
6749 if (i::v8_flags.stress_runs > 0) {
6750 options.stress_runs = i::v8_flags.stress_runs;
6751 for (int i = 0; i < options.stress_runs && result == 0; i++) {
6752 printf("============ Run %d/%d ============\n", i + 1,
6753 options.stress_runs.get());
6754 bool last_run = i == options.stress_runs - 1;
6755 result = RunMain(isolate, last_run);
6756 }
6757 } else if (options.code_cache_options != ShellOptions::kNoProduceCache) {
6758 // Park the main thread here in case the new isolate wants to perform
6759 // a shared GC to prevent a deadlock.
6760 reinterpret_cast<i::Isolate*>(isolate)
6761 ->main_thread_local_isolate()
6762 ->ExecuteMainThreadWhileParked([&result]() {
6763 printf("============ Run: Produce code cache ============\n");
6764 // First run to produce the cache
6765 Isolate::CreateParams create_params2;
6766 create_params2.array_buffer_allocator =
6768 // Use a different hash seed.
6769 i::v8_flags.hash_seed = i::v8_flags.hash_seed ^ 1337;
6770 Isolate* isolate2 = Isolate::New(create_params2);
6771 // Restore old hash seed.
6772 i::v8_flags.hash_seed = i::v8_flags.hash_seed ^ 1337;
6773 {
6774 Isolate::Scope isolate_scope(isolate2);
6775 D8Console console2(isolate2);
6776 Initialize(isolate2, &console2);
6777 PerIsolateData data2(isolate2);
6778
6779 result = RunMain(isolate2, false);
6780 ResetOnProfileEndListener(isolate2);
6781 }
6782 // D8WasmAsyncResolvePromiseTask may be still in the runner at
6783 // this point. We need to terminate the task runners before the
6784 // Isolate to avoid retaining stray tasks with v8::Global pointing
6785 // into a reclaimed Isolate.
6786 platform::NotifyIsolateShutdown(g_default_platform, isolate2);
6787 isolate2->Dispose();
6788 });
6789
6790 // Change the options to consume cache
6791 DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
6792 options.compile_options ==
6794 options.compile_options.Overwrite(
6796 options.code_cache_options.Overwrite(ShellOptions::kNoProduceCache);
6797
6798 printf("============ Run: Consume code cache ============\n");
6799 // Second run to consume the cache in current isolate
6800 result = RunMain(isolate, true);
6801 options.compile_options.Overwrite(
6803 } else {
6804 bool last_run = true;
6805 result = RunMain(isolate, last_run);
6806 }
6807
6808 // Run interactive shell if explicitly requested or if no script has been
6809 // executed, but never on --test
6810 if (use_interactive_shell()) {
6811 RunShell(isolate);
6812 }
6813
6814 if (i::v8_flags.trace_ignition_dispatches_output_file != nullptr) {
6815 WriteIgnitionDispatchCountersFile(isolate);
6816 }
6817
6818 if (options.cpu_profiler) {
6819 CpuProfile* profile =
6820 cpu_profiler->StopProfiling(String::Empty(isolate));
6821 if (options.cpu_profiler_print) {
6822 const internal::ProfileNode* root =
6823 reinterpret_cast<const internal::ProfileNode*>(
6824 profile->GetTopDownRoot());
6825 root->Print(0);
6826 }
6827 profile->Delete();
6828 cpu_profiler->Dispose();
6829 }
6830
6831#ifdef V8_FUZZILLI
6832 // Send result to parent (fuzzilli) and reset edge guards.
6833 if (fuzzilli_reprl) {
6834 int status = result << 8;
6835 std::vector<bool> bitmap;
6836 if (options.fuzzilli_enable_builtins_coverage) {
6837 bitmap = i::BasicBlockProfiler::Get()->GetCoverageBitmap(
6838 reinterpret_cast<i::Isolate*>(isolate));
6840 }
6841 if (options.fuzzilli_coverage_statistics) {
6842 int tot = 0;
6843 for (bool b : bitmap) {
6844 if (b) tot++;
6845 }
6846 static int iteration_counter = 0;
6847 std::ofstream covlog("covlog.txt", std::ios::app);
6848 covlog << iteration_counter << "\t" << tot << "\t"
6850 << bitmap.size() << std::endl;
6851 iteration_counter++;
6852 }
6853 // In REPRL mode, stdout and stderr can be regular files, so they need
6854 // to be flushed after every execution
6855 fflush(stdout);
6856 fflush(stderr);
6857 CHECK_EQ(write(REPRL_CWFD, &status, 4), 4);
6859 if (options.fuzzilli_enable_builtins_coverage) {
6860 i::BasicBlockProfiler::Get()->ResetCounts(
6861 reinterpret_cast<i::Isolate*>(isolate));
6862 }
6863 }
6864#endif // V8_FUZZILLI
6865 } while (fuzzilli_reprl);
6866
6867 // Shut down contexts and collect garbage.
6868 cached_code_map_.clear();
6869 evaluation_context_.Reset();
6870 stringify_function_.Reset();
6871 ResetOnProfileEndListener(isolate);
6872 CollectGarbage(isolate);
6873 }
6874 OnExit(isolate, true);
6875
6876 // Delete the platform explicitly here to write the tracing output to the
6877 // tracing file.
6878 if (options.trace_enabled) {
6879 tracing_controller->StopTracing();
6880 }
6881 g_platform.reset();
6882
6883#ifdef V8_TARGET_OS_WIN
6884 // We need to free the allocated utf8 filenames in
6885 // PreProcessUnicodeFilenameArg.
6886 for (char* utf8_str : utf8_filenames) {
6887 delete[] utf8_str;
6888 }
6889 utf8_filenames.clear();
6890#endif
6891
6892 return result;
6893}
6894
6895} // namespace v8
6896
6897int main(int argc, char* argv[]) { return v8::Shell::Main(argc, argv); }
6898
6899#undef CHECK
6900#undef DCHECK
Isolate * isolate_
RegisterAllocator * allocator_
uint8_t data_[MAX_STACK_LENGTH]
const char * name
Definition builtins.cc:39
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static Local< ArrayBuffer > New(Isolate *isolate, size_t byte_length, BackingStoreInitializationMode initialization_mode=BackingStoreInitializationMode::kZeroInitialized)
Definition api.cc:9044
static Local< Array > New(Isolate *isolate, int length=0)
Definition api.cc:8119
Local< Object > CreateHook(const v8::FunctionCallbackInfo< v8::Value > &info)
void Run() override
Definition d8.cc:3450
CheckMessageFromWorkerTask(v8::Isolate *isolate, std::shared_ptr< Worker > worker)
Definition d8.cc:3446
std::shared_ptr< Worker > worker_
Definition d8.cc:3477
v8::Isolate * isolate_
Definition d8.cc:3494
void Run() override
Definition d8.cc:3489
std::shared_ptr< Worker > worker_
Definition d8.cc:3495
CleanUpWorkerTask(v8::Isolate *isolate, std::shared_ptr< Worker > worker)
Definition d8.cc:3486
static Local< Context > New(Isolate *isolate, ExtensionConfiguration *extensions=nullptr, MaybeLocal< ObjectTemplate > global_template=MaybeLocal< ObjectTemplate >(), MaybeLocal< Value > global_object=MaybeLocal< Value >(), DeserializeInternalFieldsCallback internal_fields_deserializer=DeserializeInternalFieldsCallback(), MicrotaskQueue *microtask_queue=nullptr, DeserializeContextDataCallback context_data_deserializer=DeserializeContextDataCallback(), DeserializeAPIWrapperCallback api_wrapper_deserializer=DeserializeAPIWrapperCallback())
Definition api.cc:6778
void Enter()
Definition api.cc:818
Counter * GetNextCounter()
Definition d8.cc:3738
bool is_histogram() const
Definition d8.h:59
int sample_total() const
Definition d8.h:56
static const int kMaxNameSize
Definition d8.h:48
int * ptr()
Definition d8.h:51
int count() const
Definition d8.h:55
void Bind(const char *name, bool histogram)
Definition d8.cc:3719
void AddSample(int32_t sample)
Definition d8.cc:3726
void Delete()
Definition api.cc:11320
CpuProfilingStatus StartProfiling(Local< String > title, CpuProfilingOptions options, std::unique_ptr< DiscardedSamplesDelegate > delegate=nullptr)
Definition api.cc:11475
static CpuProfiler * New(Isolate *isolate, CpuProfilingNamingMode=kDebugNaming, CpuProfilingLoggingMode=kLazyLogging)
Definition api.cc:11391
CpuProfile * StopProfiling(Local< String > title)
Definition api.cc:11493
void Dispose()
Definition api.cc:11420
static int GetStressRuns()
Definition d8.cc:6391
static void DeoptimizeAll(Isolate *isolate)
Definition d8.cc:6405
Deserializer(Isolate *isolate, std::unique_ptr< SerializationData > data)
Definition d8.cc:6327
Isolate * isolate_
Definition d8.cc:6380
Deserializer & operator=(const Deserializer &)=delete
Deserializer(const Deserializer &)=delete
const SharedValueConveyor * GetSharedValueConveyor(Isolate *isolate) override
Definition d8.cc:6371
MaybeLocal< WasmModuleObject > GetWasmModuleFromId(Isolate *isolate, uint32_t transfer_id) override
Definition d8.cc:6363
std::unique_ptr< SerializationData > data_
Definition d8.cc:6382
ValueDeserializer deserializer_
Definition d8.cc:6381
MaybeLocal< SharedArrayBuffer > GetSharedArrayBufferFromId(Isolate *isolate, uint32_t clone_id) override
Definition d8.cc:6353
MaybeLocal< Value > ReadValue(Local< Context > context)
Definition d8.cc:6337
size_t GetMoreData(const uint8_t **src) override
Definition d8.cc:607
DummySourceStream(Isolate *isolate, Local< String > source)
Definition d8.cc:601
std::unique_ptr< uint16_t[]> source_buffer_
Definition d8.cc:619
uint32_t source_length_
Definition d8.cc:618
V8_INLINE Local< T > Escape(Local< T > value)
static Local< Message > CreateMessage(Isolate *isolate, Local< Value > exception)
Definition api.cc:11142
static Local< Value > TypeError(Local< String > message, Local< Value > options={})
static Local< Value > SyntaxError(Local< String > message, Local< Value > options={})
static Local< Value > Error(Local< String > message, Local< Value > options={})
size_t length() const override
Definition d8.cc:525
ExternalOwningOneByteStringResource(std::unique_ptr< base::OS::MemoryMappedFile > file)
Definition d8.cc:519
std::unique_ptr< base::OS::MemoryMappedFile > file_
Definition d8.cc:528
const char * data() const override
Definition d8.cc:522
static Local< External > New(Isolate *isolate, void *value)
Definition api.cc:7483
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, const CFunction *c_function=nullptr, uint16_t instance_type=0, uint16_t allowed_receiver_instance_type_range_start=0, uint16_t allowed_receiver_instance_type_range_end=0)
Definition api.cc:1101
static MaybeLocal< Function > New(Local< Context > context, FunctionCallback callback, Local< Value > data=Local< Value >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect)
Definition api.cc:5348
V8_WARN_UNUSED_RESULT MaybeLocal< Value > Call(v8::Isolate *isolate, Local< Context > context, Local< Value > recv, int argc, Local< Value > argv[])
Definition api.cc:5400
static void ControlFlowViolation()
Definition d8.cc:4588
static void ObservableDifference()
Definition d8.cc:4604
static void UseAfterFree()
Definition d8.cc:4615
static void Fatal()
Definition d8.cc:4599
static void UseOfUninitializedValue()
Definition d8.cc:4624
static void UndefinedBehavior()
Definition d8.cc:4609
static void SimulateErrors()
Definition d8.cc:4560
static void DCheck()
Definition d8.cc:4594
void runMessageLoopOnPause(int contextGroupId) override
Definition d8.cc:4898
Global< Context > context_
Definition d8.cc:4970
static v8_inspector::V8InspectorSession * GetSession(Local< Context > context)
Definition d8.cc:4931
void quitMessageLoopOnPause() override
Definition d8.cc:4928
Isolate * isolate_
Definition d8.cc:4971
InspectorClient(Isolate *isolate, const Global< Context > &global_context, bool connect)
Definition d8.cc:4872
std::unique_ptr< v8_inspector::V8Inspector > inspector_
Definition d8.cc:4966
static void SendInspectorMessage(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:4943
std::unique_ptr< v8_inspector::V8InspectorSession > session_
Definition d8.cc:4967
std::unique_ptr< v8_inspector::V8Inspector::Channel > channel_
Definition d8.cc:4968
Local< Context > ensureDefaultContextInGroup(int group_id) override
Definition d8.cc:4937
void flushProtocolNotifications() override
Definition d8.cc:4825
~InspectorFrontend() override=default
void sendResponse(int callId, std::unique_ptr< v8_inspector::StringBuffer > message) override
Definition d8.cc:4816
void sendNotification(std::unique_ptr< v8_inspector::StringBuffer > message) override
Definition d8.cc:4821
Isolate * isolate_
Definition d8.cc:4866
Global< Context > context_
Definition d8.cc:4867
void Send(const v8_inspector::StringView &string)
Definition d8.cc:4827
InspectorFrontend(Local< Context > context)
Definition d8.cc:4809
static Local< Integer > New(Isolate *isolate, int32_t value)
Definition api.cc:9568
void SetWasmJSPIEnabledCallback(WasmJSPIEnabledCallback callback)
void Dispose()
Definition api.cc:10100
V8_INLINE void SetData(uint32_t slot, void *data)
void InstallConditionalFeatures(Local< Context > context)
Definition api.cc:10793
static Isolate * New(const CreateParams &params)
Definition api.cc:10089
void TerminateExecution()
Definition api.cc:9888
bool IsExecutionTerminating()
Definition api.cc:9893
static V8_WARN_UNUSED_RESULT MaybeLocal< String > Stringify(Local< Context > context, Local< Value > json_object, Local< String > gap=Local< String >())
Definition api.cc:3188
static V8_WARN_UNUSED_RESULT MaybeLocal< Value > Parse(Local< Context > context, Local< String > json_string)
Definition api.cc:3172
V8_INLINE Local< S > As() const
static V8_INLINE Local< T > Cast(Local< S > that)
static V8_INLINE Local< T > New(Isolate *isolate, Local< T > that)
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local< S > *out) const
V8_INLINE Local< T > ToLocalChecked()
V8_INLINE bool IsEmpty() const
V8_INLINE bool IsJust() const
Definition v8-maybe.h:36
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
static std::unique_ptr< MeasureMemoryDelegate > Default(Isolate *isolate, Local< Context > context, Local< Promise::Resolver > promise_resolver, MeasureMemoryMode mode)
Definition api.cc:10417
static void PerformCheckpoint(Isolate *isolate)
Definition api.cc:11011
static Local< Module > CreateSyntheticModule(Isolate *isolate, Local< String > module_name, const MemorySpan< const Local< String > > &export_names, SyntheticModuleEvaluationSteps evaluation_steps)
Definition api.cc:2271
static Local< Number > New(Isolate *isolate, double value)
Definition api.cc:9557
static Local< ObjectTemplate > New(Isolate *isolate, Local< FunctionTemplate > constructor=Local< FunctionTemplate >())
Definition api.cc:1376
static Local< Object > New(Isolate *isolate)
Definition api.cc:7756
V8_WARN_UNUSED_RESULT MaybeLocal< Value > Get(Local< Context > context, Local< Value > key)
Definition api.cc:4577
v8::Global< v8::Value > callback_
Definition d8.cc:3436
void Run() override
Definition d8.cc:3400
OnMessageFromWorkerTask(v8::Isolate *isolate, v8::Local< v8::Context > context, v8::Local< v8::Value > callback, std::unique_ptr< SerializationData > data)
Definition d8.cc:3392
v8::Global< v8::Context > context_
Definition d8.cc:3435
std::unique_ptr< SerializationData > data_
Definition d8.cc:3437
v8::Isolate * isolate_
Definition d8.cc:3434
virtual size_t AllocatePageSize()=0
ExplicitRealmScope(PerIsolateData *data, int index)
Definition d8.cc:2021
Local< Context > context() const
Definition d8.cc:2035
RealmScope(Isolate *isolate, const Global< Context > &context)
Definition d8.cc:2005
PerIsolateData * data_
Definition d8.h:310
std::pair< Local< Context >, Local< Function > > GetWorkerOnMessage(const std::shared_ptr< Worker > &worker) const
Definition d8.cc:1991
Local< FunctionTemplate > GetDomNodeCtor() const
Definition d8.cc:1956
void UnregisterWorker(const std::shared_ptr< Worker > &worker)
Definition d8.cc:2000
void AddDynamicImportData(DynamicImportData *)
Definition d8.cc:1936
AsyncHooks * GetAsyncHooks()
Definition d8.h:329
static PerIsolateData * Get(Isolate *isolate)
Definition d8.h:300
void SubscribeWorkerOnMessage(const std::shared_ptr< Worker > &worker, Local< Context > context, Local< Function > callback)
Definition d8.cc:1974
Global< Context > * realms_
Definition d8.h:363
std::set< std::shared_ptr< Worker > > registered_workers_
Definition d8.h:378
Isolate * isolate_
Definition d8.h:359
void SetDomNodeCtor(Local< FunctionTemplate > ctor)
Definition d8.cc:1960
Global< FunctionTemplate > test_api_object_ctor_
Definition d8.h:372
void RemoveUnhandledPromise(Local< Promise > promise)
Definition d8.cc:1894
AsyncHooks * async_hooks_wrapper_
Definition d8.h:368
bool HasRunningSubscribedWorkers()
Definition d8.cc:1964
bool ignore_unhandled_promises_
Definition d8.h:365
void RegisterWorker(std::shared_ptr< Worker > worker)
Definition d8.cc:1970
Global< FunctionTemplate > dom_node_ctor_
Definition d8.h:373
int realm_current_
Definition d8.h:361
int RealmFind(Local< Context > context)
Definition d8.cc:2039
int realm_switch_
Definition d8.h:362
PerIsolateData(Isolate *isolate)
Definition d8.cc:1873
void DeleteDynamicImportData(DynamicImportData *)
Definition d8.cc:1941
int realm_count_
Definition d8.h:360
void AddUnhandledPromise(Local< Promise > promise, Local< Message > message, Local< Value > exception)
Definition d8.cc:1907
Local< FunctionTemplate > GetTestApiObjectCtor() const
Definition d8.cc:1948
int RealmIndexOrThrow(const v8::FunctionCallbackInfo< v8::Value > &info, int arg_offset)
Definition d8.cc:2046
std::map< std::shared_ptr< Worker >, std::pair< Global< Context >, Global< Function > > > worker_message_callbacks_
Definition d8.h:381
std::vector< std::tuple< Global< Promise >, Global< Message >, Global< Value > > > unhandled_promises_
Definition d8.h:367
void SetTestApiObjectCtor(Local< FunctionTemplate > ctor)
Definition d8.cc:1952
int HandleUnhandledPromiseRejections()
Definition d8.cc:1917
V8_INLINE void AnnotateStrongRetainer(const char *label)
V8_INLINE Local< T > Get(Isolate *isolate) const
static Local< PrimitiveArray > New(Isolate *isolate, int length)
Definition api.cc:2035
std::shared_ptr< Worker > worker_
Definition d8.cc:5243
std::unique_ptr< SerializationData > data_
Definition d8.cc:5244
void RunInternal() override
Definition d8.cc:5240
ProcessMessageTask(i::CancelableTaskManager *task_manager, std::shared_ptr< Worker > worker, std::unique_ptr< SerializationData > data)
Definition d8.cc:5233
static V8_WARN_UNUSED_RESULT MaybeLocal< Resolver > New(Local< Context > context)
Definition api.cc:8640
void ConfigureDefaults(uint64_t physical_memory, uint64_t virtual_memory_limit)
Definition api.cc:529
static V8_EXPORT void InitializeBeforeThreadCreation()
Definition v8.cc:319
static CachedData * CreateCodeCache(Local< UnboundScript > unbound_script)
Definition api.cc:2673
static V8_WARN_UNUSED_RESULT MaybeLocal< Module > CompileModule(Isolate *isolate, Source *source, CompileOptions options=kNoCompileOptions, NoCacheReason no_cache_reason=kNoCacheNoReason)
Definition api.cc:2454
static V8_WARN_UNUSED_RESULT MaybeLocal< Script > Compile(Local< Context > context, Source *source, CompileOptions options=kNoCompileOptions, NoCacheReason no_cache_reason=kNoCacheNoReason)
Definition api.cc:2438
static V8_WARN_UNUSED_RESULT MaybeLocal< UnboundScript > CompileUnboundScript(Isolate *isolate, Source *source, CompileOptions options=kNoCompileOptions, NoCacheReason no_cache_reason=kNoCacheNoReason)
Definition api.cc:2428
static ScriptStreamingTask * StartStreaming(Isolate *isolate, StreamedSource *source, ScriptType type=ScriptType::kClassic, CompileOptions options=kNoCompileOptions, CompileHintCallback compile_hint_callback=nullptr, void *compile_hint_callback_data=nullptr)
Definition api.cc:2540
V8_INLINE Local< Data > GetHostDefinedOptions() const
Definition v8-message.h:206
static V8_WARN_UNUSED_RESULT MaybeLocal< Script > Compile(Local< Context > context, Local< String > source, ScriptOrigin *origin=nullptr)
Definition api.cc:2718
void Enqueue(std::unique_ptr< SerializationData > data)
Definition d8.cc:5159
bool Dequeue(std::unique_ptr< SerializationData > *data)
Definition d8.cc:5164
std::vector< Global< SharedArrayBuffer > > shared_array_buffers_
Definition d8.cc:6319
std::vector< std::shared_ptr< v8::BackingStore > > backing_stores_
Definition d8.cc:6321
Maybe< bool > PrepareTransfer(Local< Context > context, Local< Value > transfer)
Definition d8.cc:6256
std::vector< Global< WasmModuleObject > > wasm_modules_
Definition d8.cc:6320
Maybe< uint32_t > GetWasmModuleTransferId(Isolate *isolate, Local< WasmModuleObject > module) override
Definition d8.cc:6218
Serializer(Isolate *isolate)
Definition d8.cc:6155
Isolate * isolate_
Definition d8.cc:6315
bool AdoptSharedValueConveyor(Isolate *isolate, SharedValueConveyor &&conveyor) override
Definition d8.cc:6249
Maybe< uint32_t > GetSharedArrayBufferId(Isolate *isolate, Local< SharedArrayBuffer > shared_array_buffer) override
Definition d8.cc:6202
Maybe< bool > FinalizeTransfer()
Definition d8.cc:6294
void AppendBackingStoresTo(std::vector< std::shared_ptr< BackingStore > > *to)
Definition d8.cc:6190
std::unique_ptr< SerializationData > data_
Definition d8.cc:6317
void ThrowDataCloneError(Local< String > message) override
Definition d8.cc:6198
Maybe< bool > WriteValue(Local< Context > context, Local< Value > value, Local< Value > transfer)
Definition d8.cc:6163
Serializer & operator=(const Serializer &)=delete
std::vector< Global< ArrayBuffer > > array_buffers_
Definition d8.cc:6318
Serializer(const Serializer &)=delete
void * ReallocateBufferMemory(void *old_buffer, size_t size, size_t *actual_size) override
Definition d8.cc:6233
std::unique_ptr< SerializationData > Release()
Definition d8.cc:6188
ValueSerializer serializer_
Definition d8.cc:6316
void FreeBufferMemory(void *buffer) override
Definition d8.cc:6247
size_t current_memory_usage_
Definition d8.cc:6322
v8::Isolate * isolate_
Definition d8.cc:3108
v8::Global< v8::Function > callback_
Definition d8.cc:3110
SetTimeoutTask(v8::Isolate *isolate, v8::Local< v8::Context > context, v8::Local< v8::Function > callback)
Definition d8.cc:3091
v8::Global< v8::Context > context_
Definition d8.cc:3109
void Run() override
Definition d8.cc:3097
@ kProduceCache
Definition d8.h:394
@ kProduceCacheAfterExecute
Definition d8.h:395
@ kNoProduceCache
Definition d8.h:393
DisallowReassignment< int > stress_runs
Definition d8.h:450
static void RealmCurrent(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2274
static void InstallConditionalFeatures(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2665
static void WriteChars(const char *name, uint8_t *buffer, size_t buffer_size)
Definition d8.cc:4755
static void WriteStdout(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2926
static int Main(int argc, char *argv[])
Definition d8.cc:6492
static CounterCollection * counters_
Definition d8.h:806
CodeType
Definition d8.h:533
static void WorkerTerminateAndWait(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3551
static MaybeLocal< Promise > HostImportModuleDynamically(Local< Context > context, Local< Data > host_defined_options, Local< Value > resource_name, Local< String > specifier, Local< FixedArray > import_attributes)
Definition d8.cc:1471
static MaybeLocal< Context > CreateEvaluationContext(Isolate *isolate)
Definition d8.cc:4308
static void AddHistogramSample(void *histogram, int sample)
Definition d8.cc:3798
static base::OS::MemoryMappedFile * counters_file_
Definition d8.h:807
static void update_script_size(int size)
Definition d8.h:773
static std::map< Isolate *, std::pair< Global< Function >, Global< Context > > > profiler_end_callback_
Definition d8.h:798
static void RealmGlobal(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2311
static Local< ObjectTemplate > CreatePerformanceTemplate(Isolate *isolate)
Definition d8.cc:4015
static void RealmCreate(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2381
static void PerformanceMark(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2115
static Global< Function > stringify_function_
Definition d8.h:794
static void ScheduleTermination(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3626
static bool ExecuteModule(Isolate *isolate, const char *file_name)
Definition d8.cc:1739
static std::unique_ptr< base::OS::MemoryMappedFile > ReadFileData(Isolate *isolate, const char *name, bool should_throw=true)
Definition d8.cc:4719
static std::map< std::string, std::unique_ptr< ScriptCompiler::CachedData > > cached_code_map_
Definition d8.h:879
static Local< FunctionTemplate > CreateLeafInterfaceTypeTemplate(Isolate *isolate)
Definition d8-test.cc:1962
static MaybeLocal< Value > DeserializeValue(Isolate *isolate, std::unique_ptr< SerializationData > data)
Definition d8.cc:6424
static Local< FunctionTemplate > CreateEventTargetTemplate(Isolate *isolate)
Definition d8.cc:3849
static void PerformanceMeasure(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2160
static Local< ObjectTemplate > CreateD8Template(Isolate *isolate)
Definition d8.cc:4058
static void WorkerOnMessageGetter(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3498
static void ProfilerTriggerSample(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2851
static base::LazyMutex cached_code_mutex_
Definition d8.h:877
static char * ReadChars(const char *name, int *size_out)
Definition d8.cc:4632
static void ReadCodeTypeAndArguments(const v8::FunctionCallbackInfo< v8::Value > &info, int index, CodeType *code_type, Local< Value > *arguments=nullptr)
Definition d8.cc:3138
static void CreateWasmMemoryMapDescriptor(const v8::FunctionCallbackInfo< v8::Value > &info)
static void WriteLcovData(v8::Isolate *isolate, const char *file)
Definition d8.cc:4398
static void RealmDetachGlobal(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2430
static void AsyncHooksExecutionAsyncId(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2709
static std::unordered_set< std::shared_ptr< Worker > > running_workers_
Definition d8.h:813
static bool RunMainIsolate(Isolate *isolate, bool keep_context_alive)
Definition d8.cc:6002
static void ResetOnProfileEndListener(Isolate *isolate)
Definition d8.cc:2834
static void SetFlushDenormals(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2677
static Local< ObjectTemplate > CreateRealmTemplate(Isolate *isolate)
Definition d8.cc:4029
static base::OnceType quit_once_
Definition d8.h:793
static void WorkerPostMessage(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3344
static void PerformanceMeasureMemory(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2246
static void RealmSharedGet(Local< Name > property, const PropertyCallbackInfo< Value > &info)
Definition d8.cc:2513
static void EnableDebugger(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2729
static void WaitForRunningWorkers(const i::ParkedScope &parked)
Definition d8.cc:6442
static Local< String > WasmLoadSourceMapCallback(Isolate *isolate, const char *name)
Definition d8.cc:4303
static void * CreateHistogram(const char *name, int min, int max, size_t buckets)
Definition d8.cc:3793
static void NodeTypeCallback(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3825
static void WorkerTerminate(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3541
static void SerializerSerialize(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2768
static bool ExecuteString(Isolate *isolate, Local< String > source, Local< String > name, ReportExceptions report_exceptions, Global< Value > *out_result=nullptr)
Definition d8.cc:934
static int RunMain(Isolate *isolate, bool last_run)
Definition d8.cc:5929
static MaybeLocal< PrimitiveArray > ReadLines(Isolate *isolate, const char *name)
Definition d8.cc:4659
static void RealmSharedSet(Local< Name > property, Local< Value > value, const PropertyCallbackInfo< void > &info)
Definition d8.cc:2522
static void AsyncHooksTriggerAsyncId(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2718
static void ReadBuffer(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:4689
static void RealmSwitch(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2463
static void HostInitializeImportMetaObject(Local< Context > context, Local< Module > module, Local< Object > meta)
Definition d8.cc:1508
static Local< ObjectTemplate > CreateTestRunnerTemplate(Isolate *isolate)
Definition d8.cc:4005
static void ModuleResolutionSuccessCallback(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:1426
static bool allow_new_workers_
Definition d8.h:812
static int DeserializationRunCount()
Definition d8.h:788
static void Quit(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3635
static void AsyncHooksCreateHook(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2700
static void WriteFile(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2939
static MaybeLocal< Context > HostCreateShadowRealmContext(Local< Context > initiator_context)
Definition d8.cc:1525
static void Version(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3641
static void RunShell(Isolate *isolate)
Definition d8.cc:4762
static void TestVerifySourcePositions(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2569
static base::LazyMutex workers_mutex_
Definition d8.h:811
static void SetPromiseHooks(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2737
static MaybeLocal< Object > FetchModuleSource(v8::Local< v8::Module > origin_module, v8::Local< v8::Context > context, const std::string &file_name, ModuleType module_type)
Definition d8.cc:1179
static std::atomic< bool > valid_fuzz_script_
Definition d8.h:817
static base::Mutex counter_mutex_
Definition d8.h:802
static Local< ObjectTemplate > CreateOSTemplate(Isolate *isolate)
Definition d8.cc:3944
static const base::TimeTicks kInitialTicks
Definition d8.h:809
static void DoHostImportModuleDynamically(void *data)
Definition d8.cc:1595
static base::Mutex profiler_end_callback_lock_
Definition d8.h:796
static Counter * GetCounter(const char *name, bool is_histogram)
Definition d8.cc:3758
static void TriggerOnProfileEndListener(Isolate *isolate, std::string profile)
Definition d8.cc:2862
static Local< FunctionTemplate > CreateNodeTemplates(Isolate *isolate, Local< FunctionTemplate > event_target)
Definition d8.cc:3855
static bool FunctionAndArgumentsToString(Local< Function > function, Local< Value > arguments, Local< String > *source, Isolate *isolate)
Definition d8.cc:3176
static void OnExit(Isolate *isolate, bool dispose)
Definition d8.cc:4459
static void RemoveRunningWorker(const std::shared_ptr< Worker > &worker)
Definition d8.cc:6436
static bool SetOptions(int argc, char *argv[])
Definition d8.cc:5655
static void RealmDispose(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2448
static MaybeLocal< Context > CreateRealm(const v8::FunctionCallbackInfo< v8::Value > &info, int index, v8::MaybeLocal< Value > global_object)
Definition d8.cc:2333
static Local< FunctionTemplate > CreateWorkerTemplate(Isolate *isolate)
Definition d8.cc:3957
static void ReadLine(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:4713
static void SerializerDeserialize(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2791
static bool LoadJSON(Isolate *isolate, const char *file_name)
Definition d8.cc:1839
static Local< ObjectTemplate > CreateAsyncHookTemplate(Isolate *isolate)
Definition d8.cc:3992
static void WorkerOnMessageSetter(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3517
static int * LookupCounter(const char *name)
Definition d8.cc:3788
static void PerformanceNow(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2108
static MaybeLocal< String > ReadFile(Isolate *isolate, const char *name, bool should_throw=true)
Definition d8.cc:4739
static CounterCollection local_counters_
Definition d8.h:805
static void WriteIgnitionDispatchCountersFile(v8::Isolate *isolate)
Definition d8.cc:4353
static CounterMap * counter_map_
Definition d8.h:801
static void LogGetAndStop(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2530
static uint64_t GetTracingTimestampFromPerformanceTimestamp(double performance_timestamp)
Definition d8.cc:2073
static void PromiseRejectCallback(v8::PromiseRejectMessage reject_message)
Definition d8.cc:4235
static bool HandleUnhandledPromiseRejections(Isolate *isolate)
Definition d8.cc:6144
static void QuitOnce(v8::FunctionCallbackInfo< v8::Value > *info)
Definition d8.cc:3569
static double GetTimestamp()
Definition d8.cc:2065
static bool HasOnProfileEndListener(Isolate *isolate)
Definition d8.cc:2829
static void EnableJSPI(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2671
static void SetTimeout(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3113
static void set_script_executed()
Definition d8.h:767
static MaybeLocal< Module > FetchModuleTree(v8::Local< v8::Module > origin_module, v8::Local< v8::Context > context, const std::string &file_name, ModuleType module_type)
Definition d8.cc:1233
ReportExceptions
Definition d8.h:525
@ kReportExceptions
Definition d8.h:526
static std::atomic< bool > script_executed_
Definition d8.h:816
static Global< Context > evaluation_context_
Definition d8.h:792
static bool CompleteMessageLoop(Isolate *isolate)
Definition d8.cc:6102
static void Initialize(Isolate *isolate, D8Console *console, bool isOnMainThread=true)
Definition d8.cc:4273
static void ExecuteFile(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3059
static Local< String > Stringify(Isolate *isolate, Local< Value > value)
Definition d8.cc:3804
static std::unique_ptr< SerializationData > SerializeValue(Isolate *isolate, Local< Value > value, Local< Value > transfer)
Definition d8.cc:6412
static void CollectGarbage(Isolate *isolate)
Definition d8.cc:6040
static std::atomic< int > unhandled_promise_rejections_
Definition d8.h:880
static ArrayBuffer::Allocator * array_buffer_allocator
Definition d8.h:761
static void TerminateNow(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3615
static void RealmCreateAllowCrossRealmAccess(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2388
static Local< FunctionTemplate > CreateTestFastCApiTemplate(Isolate *isolate)
Definition d8-test.cc:1474
static void StoreInCodeCache(Isolate *isolate, Local< Value > name, const ScriptCompiler::CachedData *data)
Definition d8.cc:580
static void RealmEval(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2473
static void RealmOwner(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2284
static MaybeLocal< String > ReadSource(const v8::FunctionCallbackInfo< v8::Value > &info, int index, CodeType default_type)
Definition d8.cc:3225
static void DisableDebugger(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2733
static void RealmNavigate(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2400
static void AddRunningWorker(std::shared_ptr< Worker > worker)
Definition d8.cc:6431
static void ProfilerSetOnProfileEndListener(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2814
static MaybeLocal< Promise > HostImportModuleWithPhaseDynamically(Local< Context > context, Local< Data > host_defined_options, Local< Value > resource_name, Local< String > specifier, ModuleImportPhase phase, Local< FixedArray > import_attributes)
Definition d8.cc:1480
static base::LazyMutex context_mutex_
Definition d8.h:808
static Local< ObjectTemplate > CreateGlobalTemplate(Isolate *isolate)
Definition d8.cc:3891
static ScriptCompiler::CachedData * LookupCodeCache(Isolate *isolate, Local< Value > name)
Definition d8.cc:560
static void DisposeRealm(const v8::FunctionCallbackInfo< v8::Value > &info, int index)
Definition d8.cc:2367
static MaybeLocal< Value > JSONModuleEvaluationSteps(Local< Context > context, Local< Module > module)
Definition d8.cc:1367
static ShellOptions options
Definition d8.h:760
static void ModuleResolutionFailureCallback(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:1450
static void ReportException(Isolate *isolate, Local< Message > message, Local< Value > exception)
Definition d8.cc:3648
static void Print(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2918
static void PrintErr(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2922
static void WorkerGetMessage(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3370
static void MapCounters(v8::Isolate *isolate, const char *name)
Definition d8.cc:3743
static bool EmptyMessageQueues(Isolate *isolate)
Definition d8.cc:6139
static void GetExtrasBindingObject(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3132
static void WorkerNew(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:3271
static Local< String > ReadFromStdin(Isolate *isolate)
Definition d8.cc:3019
static bool FinishExecuting(Isolate *isolate, const Global< Context > &context)
Definition d8.cc:6127
static MaybeLocal< T > CompileString(Isolate *isolate, Local< Context > context, Local< String > source, const ScriptOrigin &origin)
Definition d8.cc:687
static Local< Signature > New(Isolate *isolate, Local< FunctionTemplate > receiver=Local< FunctionTemplate >())
Definition api.cc:1204
IsolateThread(SourceGroup *group)
Definition d8.cc:5087
void JoinThread(const i::ParkedScope &parked)
Definition d8.cc:5153
void Begin(char **argv, int offset)
Definition d8.h:100
base::Thread * thread_
Definition d8.h:129
i::ParkingSemaphore next_semaphore_
Definition d8.h:127
void StartExecuteInThread()
Definition d8.cc:5140
void ExecuteInThread()
Definition d8.cc:5090
i::ParkingSemaphore done_semaphore_
Definition d8.h:128
bool Execute(Isolate *isolate)
Definition d8.cc:4988
void WaitForThread(const i::ParkedScope &parked)
Definition d8.cc:5148
void Run() override
Definition d8.cc:636
static void StartThreadForTaskAndJoin(v8::ScriptCompiler::ScriptStreamingTask *task)
Definition d8.cc:626
StreamerThread(v8::ScriptCompiler::ScriptStreamingTask *task)
Definition d8.cc:633
v8::ScriptCompiler::ScriptStreamingTask * task_
Definition d8.cc:639
size_t length() const
static V8_WARN_UNUSED_RESULT Local< String > NewFromUtf8Literal(Isolate *isolate, const char(&literal)[N], NewStringType type=NewStringType::kNormal)
static constexpr int kMaxLength
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromUtf8(Isolate *isolate, const char *data, NewStringType type=NewStringType::kNormal, int length=-1)
Definition api.cc:7593
static Local< String > Concat(Isolate *isolate, Local< String > left, Local< String > right)
Definition api.cc:7613
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewExternalOneByte(Isolate *isolate, ExternalOneByteStringResource *resource)
Definition api.cc:7656
static V8_INLINE Local< String > Empty(Isolate *isolate)
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromTwoByte(Isolate *isolate, const uint16_t *data, NewStringType type=NewStringType::kNormal, int length=-1)
Definition api.cc:7606
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromOneByte(Isolate *isolate, const uint8_t *data, NewStringType type=NewStringType::kNormal, int length=-1)
Definition api.cc:7599
static Local< Symbol > GetToStringTag(Isolate *isolate)
std::shared_ptr< Worker > worker_
Definition d8.cc:5268
TerminateTask(i::CancelableTaskManager *task_manager, std::shared_ptr< Worker > worker)
Definition d8.cc:5257
void RunInternal() override
Definition d8.cc:5261
void SetVerbose(bool value)
Definition api.cc:2856
Local< v8::Message > Message() const
Definition api.cc:2829
bool HasTerminated() const
Definition api.cc:2787
Local< Value > Exception() const
Definition api.cc:2798
static V8_WARN_UNUSED_RESULT MaybeLocal< Value > StackTrace(Local< Context > context, Local< Value > exception)
Definition api.cc:2806
Local< Value > ReThrow()
Definition api.cc:2792
bool HasCaught() const
Definition api.cc:2781
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
Definition api.h:274
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
static void DisposePlatform()
Definition api.cc:6389
static const char * GetVersion()
Definition api.cc:6574
static void InitializeExternalStartupDataFromFile(const char *snapshot_blob)
Definition api.cc:6570
static void InitializePlatform(Platform *platform)
Definition api.cc:6385
static void InitializeExternalStartupData(const char *directory_path)
Definition api.cc:6565
static bool InitializeICUDefaultLocation(const char *exec_path, const char *icu_data_file=nullptr)
Definition api.cc:6560
static V8_INLINE bool Initialize()
static void SetFlagsFromString(const char *str)
Definition api.cc:432
static bool Dispose()
Definition api.cc:6513
static bool EnableWebAssemblyTrapHandler(bool use_v8_signal_handler)
Definition api.cc:6479
V8_WARN_UNUSED_RESULT Maybe< bool > ReadHeader(Local< Context > context)
Definition api.cc:3404
V8_WARN_UNUSED_RESULT MaybeLocal< Value > ReadValue(Local< Context > context)
Definition api.cc:3435
V8_WARN_UNUSED_RESULT std::pair< uint8_t *, size_t > Release()
Definition api.cc:3320
V8_WARN_UNUSED_RESULT Maybe< bool > WriteValue(Local< Context > context, Local< Value > value)
Definition api.cc:3309
void WriteHeader()
Definition api.cc:3303
bool BooleanValue(Isolate *isolate) const
Definition api.cc:3738
static Local< WasmMemoryMapDescriptor > New(Isolate *isolate, WasmFileDescriptor fd)
Definition api.cc:8907
static MaybeLocal< WasmModuleObject > Compile(Isolate *isolate, MemorySpan< const uint8_t > wire_bytes)
Definition api.cc:8876
void Run() override
Definition d8.cc:5219
std::shared_ptr< Worker > worker_
Definition d8.h:256
i::CancelableTaskManager * task_manager_
Definition d8.h:279
char * script_
Definition d8.h:270
bool flush_denormals_
Definition d8.h:271
std::shared_ptr< TaskRunner > task_runner_
Definition d8.h:278
void ExecuteInThread()
Definition d8.cc:5391
std::unique_ptr< SerializationData > TryGetMessage()
Definition d8.cc:5283
base::Thread * thread_
Definition d8.h:269
void ProcessMessage(std::unique_ptr< SerializationData > data)
Definition d8.cc:5324
i::ParkingSemaphore started_semaphore_
Definition d8.h:275
friend class ProcessMessageTask
Definition d8.h:231
bool is_joined_
Definition d8.h:273
base::Mutex worker_mutex_
Definition d8.h:283
friend class TerminateTask
Definition d8.h:232
static void Close(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:5567
Worker(Isolate *parent_isolate, const char *script, bool flush_denormals)
Definition d8.cc:5184
Global< Context > context_
Definition d8.h:291
static void PostMessageOut(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:5536
void PostMessage(std::unique_ptr< SerializationData > data)
Definition d8.cc:5247
void EnterTerminatedState()
Definition d8.cc:5316
std::atomic< State > state_
Definition d8.h:272
i::ParkingSemaphore out_semaphore_
Definition d8.h:266
Isolate * isolate_
Definition d8.h:287
void Terminate()
Definition d8.cc:5303
static bool StartWorkerThread(Isolate *requester, std::shared_ptr< Worker > worker, base::Thread::Priority priority)
Definition d8.cc:5203
std::unique_ptr< SerializationData > GetMessage(Isolate *requester)
Definition d8.cc:5271
static void SetCurrentWorker(Worker *worker)
Definition d8.cc:5383
void TerminateAndWaitForThread(const i::ParkedScope &parked)
Definition d8.cc:5291
~Worker()
Definition d8.cc:5192
bool is_running() const
Definition d8.cc:5201
SerializationDataQueue out_queue_
Definition d8.h:267
void ProcessMessages()
Definition d8.cc:5364
static void ImportScripts(const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:5563
Isolate * parent_isolate_
Definition d8.h:288
static Worker * GetCurrentWorker()
Definition d8.cc:5389
static V8_BASE_EXPORT bool GetFlushDenormals()
Definition fpu.cc:96
static V8_BASE_EXPORT void SetFlushDenormals(bool)
Definition fpu.cc:97
static MemoryMappedFile * create(const char *name, size_t size, void *initial)
static MemoryMappedFile * open(const char *name, FileMode mode=FileMode::kReadWrite)
static void ExitProcess(int exit_code)
static FILE * FOpen(const char *path, const char *mode)
static int GetPeakMemoryUsageKb()
static void StrNCpy(char *dest, int length, const char *src, size_t n)
static int64_t AmountOfPhysicalMemory()
Definition sys-info.cc:66
static int64_t AmountOfVirtualMemory()
Definition sys-info.cc:120
Thread(const Options &options)
V8_WARN_UNUSED_RESULT bool Start()
static constexpr int64_t kMillisecondsPerSecond
Definition time.h:45
static constexpr TimeDelta FromMillisecondsD(double milliseconds)
Definition time.h:97
double InMillisecondsF() const
Definition time.cc:226
static TimeTicks Now()
Definition time.cc:736
BlockData GetBlockData(size_t i) const
MaybeLocal< String > Name() const
FunctionData GetFunctionData(size_t i) const
Local< debug::Script > GetScript() const
static void SelectMode(Isolate *isolate, CoverageMode mode)
static Coverage CollectPrecise(Isolate *isolate)
V8_EXPORT_PRIVATE void CollectAllAvailableGarbage(GarbageCollectionReason gc_reason)
Definition heap.cc:1327
debug::ConsoleDelegate * console_delegate()
Definition isolate.h:1045
bool is_shared_space_isolate() const
Definition isolate.h:2292
LocalIsolate * main_thread_local_isolate()
Definition isolate.h:2183
OptimizingCompileDispatcher * optimizing_compile_dispatcher()
Definition isolate.h:1715
ThreadManager * thread_manager() const
Definition isolate.h:1422
Tagged< Object > TerminateExecution()
Definition isolate.cc:1950
V8FileLogger * v8_file_logger() const
Definition isolate.h:1192
bool get_capture_stack_trace_for_uncaught_exceptions() const
Definition isolate.cc:3619
bool concurrent_recompilation_enabled()
Definition isolate.h:1705
LocalHeap * main_thread_local_heap()
Definition isolate.cc:7479
Tagged< Object > StackOverflow()
Definition isolate.cc:1862
V8_INLINE void ExecuteMainThreadWhileParked(Callback callback)
V8_INLINE void ExecuteMainThreadWhileParked(Callback callback)
V8_INLINE void ParkedWait(LocalIsolate *local_isolate)
PendingCompilationErrorHandler * pending_error_handler()
Definition parse-info.h:268
AstValueFactory * ast_value_factory() const
Definition parse-info.h:310
Handle< Script > CreateScript(IsolateT *isolate, DirectHandle< String > source, MaybeDirectHandle< FixedArray > maybe_wrapped_arguments, ScriptOriginOptions origin_options, NativesFlag natives=NOT_NATIVES_CODE)
V8_EXPORT_PRIVATE void ReportErrors(Isolate *isolate, Handle< Script > script) const
void PrepareErrors(IsolateT *isolate, AstValueFactory *ast_value_factory)
void Print(int indent) const
bool IsLockedByCurrentThread() const
Definition v8threads.h:73
V8_EXPORT_PRIVATE void Unlock()
Definition v8threads.cc:155
V8_EXPORT_PRIVATE std::string file_name() const
Definition log.cc:2438
V8_EXPORT_PRIVATE bool is_logging()
Definition log.cc:1336
V8_EXPORT_PRIVATE FILE * TearDownAndGetLogFile()
Definition log.cc:2449
static TraceBuffer * CreateTraceBufferRingBuffer(size_t max_chunks, TraceWriter *trace_writer)
static const size_t kRingBufferChunks
Definition v8-tracing.h:167
void AddIncludedCategory(const char *included_category)
static TraceConfig * CreateDefaultTraceConfig()
static TraceWriter * CreateJSONTraceWriter(std::ostream &stream)
void StartTracing(TraceConfig *trace_config)
virtual void dispatchProtocolMessage(StringView message)=0
static std::unique_ptr< V8Inspector > create(v8::Isolate *, V8InspectorClient *)
T const result_
Register const index_
base::Mutex & mutex_
void sanitizer_cov_reset_edgeguards()
Definition cov.cc:33
uint32_t sanitizer_cov_count_discovered_edges()
Definition cov.cc:88
void cov_update_builtins_basic_block_coverage(const std::vector< bool > &cov_map)
Definition cov.cc:129
void cov_init_builtins_edges(uint32_t num_edges)
Definition cov.cc:112
size_t count_
Definition sweeper.cc:55
int start
uint32_t count
int end
Handle< Context > context_
Handle< Script > script_
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
#define REPRL_DRFD
Definition fuzzilli.h:17
#define REPRL_CWFD
Definition fuzzilli.h:16
#define REPRL_CRFD
Definition fuzzilli.h:15
v8::Global< v8::Promise::Resolver > resolver_
std::string filename
int main(int argc, const char *argv[])
Isolate * isolate
OptionalOpIndex index
int32_t offset
const int limit_
Definition isolate.cc:1114
TNode< Context > context
TNode< Object > callback
ZoneVector< RpoNumber > & result
LiftoffAssembler::CacheState state
const char * name_
size_t priority
Counters * counters_
InstructionOperand source
int r
Definition mul-fft.cc:298
STL namespace.
V8_INLINE size_t hash_combine(size_t seed, size_t hash)
Definition hashing.h:77
void CallOnce(OnceType *once, std::function< void()> init_func)
Definition once.h:90
int Fclose(FILE *stream)
Definition wrappers.h:22
void EnsureConsoleOutput()
Definition platform.h:435
std::atomic< uint8_t > OnceType
Definition once.h:67
FILE * Fopen(const char *filename, const char *mode)
Definition wrappers.h:14
LazyStaticInstance< Mutex, DefaultConstructTrait< Mutex >, ThreadSafeInitOnceTrait >::type LazyMutex
Definition mutex.h:103
void SetConsoleDelegate(Isolate *v8_isolate, ConsoleDelegate *delegate)
void SetDebugDelegate(Isolate *v8_isolate, DebugDelegate *delegate)
constexpr int kFunctionEntryBytecodeOffset
Definition globals.h:854
constexpr NullMaybeHandleType kNullMaybeHandle
void * AllocatePages(v8::PageAllocator *page_allocator, void *hint, size_t size, size_t alignment, PageAllocator::Permission access)
constexpr int N
int g_num_isolates_for_testing
Definition runtime.cc:382
bool V8_EXPORT ValidateCallbackInfo(const FunctionCallbackInfo< void > &info)
Definition api.cc:12301
size_t AllocatePageSize()
@ kD8ModuleEmbedderDataTag
V8_EXPORT_PRIVATE FlagValues v8_flags
LanguageMode construct_language_mode(bool strict_bit)
Definition globals.h:786
std::string ReadFile(const char *filename, bool *exists, bool verbose)
Definition utils.cc:178
void FreePages(v8::PageAllocator *page_allocator, void *address, const size_t size)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage * MB
Definition flags.cc:2197
static constexpr int kMaxFixedArrayCapacity
Definition fixed-array.h:32
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
std::unique_ptr< v8::Platform > NewSingleThreadedDefaultPlatform(IdleTaskSupport idle_task_support, InProcessStackDumping in_process_stack_dumping, std::unique_ptr< v8::TracingController > tracing_controller)
void RunIdleTasks(v8::Platform *platform, v8::Isolate *isolate, double idle_time_in_seconds)
void NotifyIsolateShutdown(v8::Platform *platform, Isolate *isolate)
std::unique_ptr< v8::Platform > NewDefaultPlatform(int thread_pool_size, IdleTaskSupport idle_task_support, InProcessStackDumping in_process_stack_dumping, std::unique_ptr< v8::TracingController > tracing_controller, PriorityMode priority_mode)
bool PumpMessageLoop(v8::Platform *platform, v8::Isolate *isolate, MessageLoopBehavior behavior)
static platform::tracing::TraceConfig * CreateTraceConfigFromJSON(v8::Isolate *isolate, const char *json_str)
Definition d8.cc:505
v8_inspector::String16 String
Definition string-util.h:26
@ ReadOnly
Definition v8-object.h:143
ModuleType
Definition d8.h:37
V8_INLINE Local< Primitive > Null(Isolate *isolate)
std::unordered_map< std::string, Counter * > CounterMap
Definition d8.h:86
bool ends_with(const char *input, const char *suffix)
Definition d8.cc:4979
@ kPromiseHandlerAddedAfterReject
Definition v8-promise.h:149
@ kPromiseRejectAfterResolved
Definition v8-promise.h:150
@ kPromiseResolveAfterResolved
Definition v8-promise.h:151
void WriteToFile(FILE *file, const v8::FunctionCallbackInfo< v8::Value > &info, int first_arg_index=0)
Definition d8.cc:2879
Maybe< T > Nothing()
Definition v8-maybe.h:112
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
void(*)(PromiseRejectMessage message) PromiseRejectCallback
Definition v8-promise.h:170
V8_INLINE Local< Primitive > Undefined(Isolate *isolate)
static void PrintMessageCallback(Local< Message > message, Local< Value > error)
Definition d8.cc:4201
Local< FunctionTemplate > NewDOMFunctionTemplate(Isolate *isolate, JSApiInstanceType instance_type)
Definition d8.cc:3841
constexpr Isolate * kProcessGlobalPredictablePlatformWorkerTaskQueue
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&a)[N])
std::unique_ptr< Platform > MakePredictablePlatform(std::unique_ptr< Platform > platform)
bool check_d8_flag_contradictions
Definition d8.cc:556
void WriteAndFlush(FILE *file, const v8::FunctionCallbackInfo< v8::Value > &info)
Definition d8.cc:2910
WasmAsyncSuccess
void Dummy(char *arg)
Definition d8.cc:4558
std::unique_ptr< Platform > MakeDelayedTasksPlatform(std::unique_ptr< Platform > platform, int64_t random_seed)
static v8::debug::DebugDelegate dummy_delegate
Definition d8.cc:2727
JSApiInstanceType
Definition d8.cc:3832
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
ModuleImportPhase
MeasureMemoryMode
ScriptType
Definition v8-script.h:397
#define V8_ONCE_INIT
Definition once.h:69
#define UNREACHABLE()
Definition logging.h:67
#define FATAL(...)
Definition logging.h:47
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_GE(lhs, rhs)
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define CHECK_GT(lhs, rhs)
#define CHECK_LT(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_NULL(val)
#define CHECK_NOT_NULL(val)
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
const AsyncStreamingDecoder::MoreFunctionsCanBeSerializedCallback callback_
Global< String > specifier
Definition d8.cc:1411
DynamicImportData(Isolate *isolate_, Local< Context > context_, Local< Value > referrer_, Local< String > specifier_, ModuleImportPhase phase_, Local< FixedArray > import_attributes_, Local< Promise::Resolver > resolver_)
Definition d8.cc:1393
Global< Value > referrer
Definition d8.cc:1410
ModuleImportPhase phase
Definition d8.cc:1412
Global< Context > context
Definition d8.cc:1409
Global< Promise::Resolver > resolver
Definition d8.cc:1414
Isolate * isolate
Definition d8.cc:1406
Global< FixedArray > import_attributes
Definition d8.cc:1413
CounterLookupCallback counter_lookup_callback
Definition v8-isolate.h:306
CreateHistogramCallback create_histogram_callback
Definition v8-isolate.h:314
ResourceConstraints constraints
Definition v8-isolate.h:294
AddHistogramSampleCallback add_histogram_sample_callback
Definition v8-isolate.h:315
JitCodeEventHandler code_event_handler
Definition v8-isolate.h:289
ArrayBuffer::Allocator * array_buffer_allocator
Definition v8-isolate.h:326
Symbol file
#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0( category_group, name, id, timestamp)
#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1( category_group, name, id, timestamp, arg1_name, arg1_val)
#define V8_TRAP_HANDLER_SUPPORTED
#define V8_TARGET_OS_STRING
Definition v8config.h:262
#define V8_NOINLINE
Definition v8config.h:586
std::unique_ptr< ValueMirror > value
std::unique_ptr< ValueMirror > key
unsigned long DWORD