| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/api/api.h" |
| |
| #include <algorithm> // For min |
| #include <cmath> // For isnan. |
| #include <limits> |
| #include <optional> |
| #include <sstream> |
| #include <string> |
| #include <utility> // For move |
| #include <vector> |
| |
| #include "include/v8-array-buffer.h" |
| #include "include/v8-callbacks.h" |
| #include "include/v8-cppgc.h" |
| #include "include/v8-date.h" |
| #include "include/v8-embedder-state-scope.h" |
| #include "include/v8-extension.h" |
| #include "include/v8-external-memory-accounter.h" |
| #include "include/v8-fast-api-calls.h" |
| #include "include/v8-function.h" |
| #include "include/v8-json.h" |
| #include "include/v8-locker.h" |
| #include "include/v8-primitive-object.h" |
| #include "include/v8-profiler.h" |
| #include "include/v8-source-location.h" |
| #include "include/v8-template.h" |
| #include "include/v8-unwinder-state.h" |
| #include "include/v8-util.h" |
| #include "include/v8-wasm.h" |
| #include "src/api/api-arguments.h" |
| #include "src/api/api-inl.h" |
| #include "src/api/api-natives.h" |
| #include "src/base/hashing.h" |
| #include "src/base/logging.h" |
| #include "src/base/platform/memory.h" |
| #include "src/base/platform/platform.h" |
| #include "src/base/platform/time.h" |
| #include "src/base/safe_conversions.h" |
| #include "src/base/utils/random-number-generator.h" |
| #include "src/base/vector.h" |
| #include "src/builtins/accessors.h" |
| #include "src/builtins/builtins-utils.h" |
| #include "src/codegen/compilation-cache.h" |
| #include "src/codegen/compiler.h" |
| #include "src/codegen/cpu-features.h" |
| #include "src/codegen/script-details.h" |
| #include "src/common/assert-scope.h" |
| #include "src/common/globals.h" |
| #include "src/compiler-dispatcher/lazy-compile-dispatcher.h" |
| #include "src/date/date.h" |
| #include "src/debug/debug.h" |
| #include "src/deoptimizer/deoptimizer.h" |
| #include "src/execution/embedder-state.h" |
| #include "src/execution/execution.h" |
| #include "src/execution/frames-inl.h" |
| #include "src/execution/isolate-inl.h" |
| #include "src/execution/messages.h" |
| #include "src/execution/microtask-queue.h" |
| #include "src/execution/simulator.h" |
| #include "src/execution/v8threads.h" |
| #include "src/execution/vm-state-inl.h" |
| #include "src/handles/global-handles.h" |
| #include "src/handles/persistent-handles.h" |
| #include "src/handles/shared-object-conveyor-handles.h" |
| #include "src/handles/traced-handles-inl.h" |
| #include "src/heap/heap-inl.h" |
| #include "src/heap/heap-layout-inl.h" |
| #include "src/heap/heap-write-barrier.h" |
| #include "src/heap/safepoint.h" |
| #include "src/heap/visit-object.h" |
| #include "src/init/bootstrapper.h" |
| #include "src/init/icu_util.h" |
| #include "src/init/startup-data-util.h" |
| #include "src/init/v8.h" |
| #include "src/json/json-parser.h" |
| #include "src/json/json-stringifier.h" |
| #include "src/logging/counters-scopes.h" |
| #include "src/logging/metrics.h" |
| #include "src/logging/runtime-call-stats-scope.h" |
| #include "src/logging/tracing-flags.h" |
| #include "src/numbers/conversions-inl.h" |
| #include "src/objects/api-callbacks.h" |
| #include "src/objects/backing-store.h" |
| #include "src/objects/contexts.h" |
| #include "src/objects/embedder-data-array-inl.h" |
| #include "src/objects/embedder-data-slot-inl.h" |
| #include "src/objects/hash-table-inl.h" |
| #include "src/objects/heap-object.h" |
| #include "src/objects/instance-type-inl.h" |
| #include "src/objects/instance-type.h" |
| #include "src/objects/js-array-buffer-inl.h" |
| #include "src/objects/js-array-inl.h" |
| #include "src/objects/js-collection-inl.h" |
| #include "src/objects/js-objects.h" |
| #include "src/objects/js-promise-inl.h" |
| #include "src/objects/js-regexp-inl.h" |
| #include "src/objects/js-weak-refs-inl.h" |
| #include "src/objects/module-inl.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/objects/oddball.h" |
| #include "src/objects/ordered-hash-table-inl.h" |
| #include "src/objects/primitive-heap-object.h" |
| #include "src/objects/property-descriptor.h" |
| #include "src/objects/property-details.h" |
| #include "src/objects/property.h" |
| #include "src/objects/prototype.h" |
| #include "src/objects/shared-function-info.h" |
| #include "src/objects/slots.h" |
| #include "src/objects/smi.h" |
| #include "src/objects/string.h" |
| #include "src/objects/synthetic-module-inl.h" |
| #include "src/objects/templates.h" |
| #include "src/objects/value-serializer.h" |
| #include "src/parsing/parse-info.h" |
| #include "src/parsing/parser.h" |
| #include "src/parsing/pending-compilation-error-handler.h" |
| #include "src/parsing/scanner-character-streams.h" |
| #include "src/profiler/cpu-profiler.h" |
| #include "src/profiler/heap-profiler.h" |
| #include "src/profiler/heap-snapshot-generator-inl.h" |
| #include "src/profiler/profile-generator-inl.h" |
| #include "src/profiler/tick-sample.h" |
| #include "src/regexp/regexp-utils.h" |
| #include "src/roots/static-roots.h" |
| #include "src/runtime/runtime.h" |
| #include "src/sandbox/external-pointer.h" |
| #include "src/sandbox/isolate.h" |
| #include "src/sandbox/sandbox.h" |
| #include "src/snapshot/code-serializer.h" |
| #include "src/snapshot/embedded/embedded-data.h" |
| #include "src/snapshot/snapshot.h" |
| #include "src/strings/char-predicates-inl.h" |
| #include "src/strings/string-hasher.h" |
| #include "src/strings/unicode-inl.h" |
| #include "src/tracing/trace-event.h" |
| #include "src/utils/detachable-vector.h" |
| #include "src/utils/identity-map.h" |
| #include "src/utils/version.h" |
| |
| #if V8_ENABLE_WEBASSEMBLY |
| #include "src/debug/debug-wasm-objects.h" |
| #include "src/trap-handler/trap-handler.h" |
| #include "src/wasm/streaming-decoder.h" |
| #include "src/wasm/value-type.h" |
| #include "src/wasm/wasm-engine.h" |
| #include "src/wasm/wasm-js.h" |
| #include "src/wasm/wasm-objects-inl.h" |
| #include "src/wasm/wasm-result.h" |
| #include "src/wasm/wasm-serialization.h" |
| #endif // V8_ENABLE_WEBASSEMBLY |
| |
| #if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD |
| #include <signal.h> |
| #include <unistd.h> |
| |
| #if V8_ENABLE_WEBASSEMBLY |
| #include "include/v8-wasm-trap-handler-posix.h" |
| #include "src/trap-handler/handler-inside-posix.h" |
| #endif // V8_ENABLE_WEBASSEMBLY |
| |
| #endif // V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD |
| |
| #if V8_OS_WIN |
| #include "include/v8-wasm-trap-handler-win.h" |
| #include "src/trap-handler/handler-inside-win.h" |
| #if defined(V8_OS_WIN64) |
| #include "src/base/platform/wrappers.h" |
| #include "src/diagnostics/unwinding-info-win64.h" |
| #endif // V8_OS_WIN64 |
| #endif // V8_OS_WIN |
| |
| #if defined(V8_ENABLE_ETW_STACK_WALKING) |
| #include "src/diagnostics/etw-jit-win.h" |
| #endif // V8_ENABLE_ETW_STACK_WALKING |
| |
| // Has to be the last include (doesn't have include guards): |
| #include "src/api/api-macros.h" |
| |
| namespace v8 { |
| |
| static OOMErrorCallback g_oom_error_callback = nullptr; |
| |
| static ScriptOrigin GetScriptOriginForScript( |
| i::Isolate* i_isolate, i::DirectHandle<i::Script> script) { |
| i::DirectHandle<i::Object> scriptName(script->GetNameOrSourceURL(), |
| i_isolate); |
| i::DirectHandle<i::Object> source_map_url(script->source_mapping_url(), |
| i_isolate); |
| i::DirectHandle<i::Object> host_defined_options( |
| script->host_defined_options(), i_isolate); |
| ScriptOriginOptions options(script->origin_options()); |
| bool is_wasm = false; |
| #if V8_ENABLE_WEBASSEMBLY |
| is_wasm = script->type() == i::Script::Type::kWasm; |
| #endif // V8_ENABLE_WEBASSEMBLY |
| v8::ScriptOrigin origin( |
| Utils::ToLocal(scriptName), script->line_offset(), |
| script->column_offset(), options.IsSharedCrossOrigin(), script->id(), |
| Utils::ToLocal(source_map_url), options.IsOpaque(), is_wasm, |
| options.IsModule(), Utils::ToLocal(host_defined_options)); |
| return origin; |
| } |
| |
| // --- E x c e p t i o n B e h a v i o r --- |
| |
| // When V8 cannot allocate memory FatalProcessOutOfMemory is called. The default |
| // OOM error handler is called and execution is stopped. |
| void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, |
| const OOMDetails& details) { |
| char last_few_messages[Heap::kTraceRingBufferSize + 1]; |
| char js_stacktrace[Heap::kStacktraceBufferSize + 1]; |
| i::HeapStats heap_stats; |
| |
| if (i_isolate == nullptr) { |
| i_isolate = Isolate::TryGetCurrent(); |
| } |
| |
| if (i_isolate == nullptr) { |
| // If the Isolate is not available for the current thread we cannot retrieve |
| // memory information from the Isolate. Write easy-to-recognize values on |
| // the stack. |
| memset(last_few_messages, 0x0BADC0DE, Heap::kTraceRingBufferSize + 1); |
| memset(js_stacktrace, 0x0BADC0DE, Heap::kStacktraceBufferSize + 1); |
| memset(&heap_stats, 0xBADC0DE, sizeof(heap_stats)); |
| // Give the embedder a chance to handle the condition. If it doesn't, |
| // just crash. |
| if (g_oom_error_callback) g_oom_error_callback(location, details); |
| base::FatalOOM(base::OOMType::kProcess, location); |
| UNREACHABLE(); |
| } |
| |
| memset(last_few_messages, 0, Heap::kTraceRingBufferSize + 1); |
| memset(js_stacktrace, 0, Heap::kStacktraceBufferSize + 1); |
| |
| intptr_t start_marker; |
| heap_stats.start_marker = &start_marker; |
| size_t ro_space_size; |
| heap_stats.ro_space_size = &ro_space_size; |
| size_t ro_space_capacity; |
| heap_stats.ro_space_capacity = &ro_space_capacity; |
| size_t new_space_size; |
| heap_stats.new_space_size = &new_space_size; |
| size_t new_space_capacity; |
| heap_stats.new_space_capacity = &new_space_capacity; |
| size_t old_space_size; |
| heap_stats.old_space_size = &old_space_size; |
| size_t old_space_capacity; |
| heap_stats.old_space_capacity = &old_space_capacity; |
| size_t code_space_size; |
| heap_stats.code_space_size = &code_space_size; |
| size_t code_space_capacity; |
| heap_stats.code_space_capacity = &code_space_capacity; |
| size_t map_space_size; |
| heap_stats.map_space_size = &map_space_size; |
| size_t map_space_capacity; |
| heap_stats.map_space_capacity = &map_space_capacity; |
| size_t lo_space_size; |
| heap_stats.lo_space_size = &lo_space_size; |
| size_t code_lo_space_size; |
| heap_stats.code_lo_space_size = &code_lo_space_size; |
| size_t global_handle_count; |
| heap_stats.global_handle_count = &global_handle_count; |
| size_t weak_global_handle_count; |
| heap_stats.weak_global_handle_count = &weak_global_handle_count; |
| size_t pending_global_handle_count; |
| heap_stats.pending_global_handle_count = &pending_global_handle_count; |
| size_t near_death_global_handle_count; |
| heap_stats.near_death_global_handle_count = &near_death_global_handle_count; |
| size_t free_global_handle_count; |
| heap_stats.free_global_handle_count = &free_global_handle_count; |
| size_t memory_allocator_size; |
| heap_stats.memory_allocator_size = &memory_allocator_size; |
| size_t memory_allocator_capacity; |
| heap_stats.memory_allocator_capacity = &memory_allocator_capacity; |
| size_t malloced_memory; |
| heap_stats.malloced_memory = &malloced_memory; |
| size_t malloced_peak_memory; |
| heap_stats.malloced_peak_memory = &malloced_peak_memory; |
| size_t objects_per_type[LAST_TYPE + 1] = {0}; |
| heap_stats.objects_per_type = objects_per_type; |
| size_t size_per_type[LAST_TYPE + 1] = {0}; |
| heap_stats.size_per_type = size_per_type; |
| int os_error; |
| heap_stats.os_error = &os_error; |
| heap_stats.last_few_messages = last_few_messages; |
| heap_stats.js_stacktrace = js_stacktrace; |
| intptr_t end_marker; |
| heap_stats.end_marker = &end_marker; |
| if (i_isolate->heap()->HasBeenSetUp()) { |
| // BUG(1718): Don't use the take_snapshot since we don't support |
| // HeapObjectIterator here without doing a special GC. |
| i_isolate->heap()->RecordStats(&heap_stats, false); |
| if (!v8_flags.correctness_fuzzer_suppressions) { |
| char* first_newline = strchr(last_few_messages, '\n'); |
| if (first_newline == nullptr || first_newline[1] == '\0') |
| first_newline = last_few_messages; |
| base::OS::PrintError("\n<--- Last few GCs --->\n%s\n", first_newline); |
| base::OS::PrintError("\n<--- JS stacktrace --->\n%s\n", js_stacktrace); |
| } |
| } |
| Utils::ReportOOMFailure(i_isolate, location, details); |
| if (g_oom_error_callback) g_oom_error_callback(location, details); |
| // If the fatal error handler returns, we stop execution. |
| FATAL("API fatal error handler returned after process out of memory"); |
| } |
| |
| void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, |
| const char* detail) { |
| OOMDetails details; |
| details.detail = detail; |
| FatalProcessOutOfMemory(i_isolate, location, details); |
| } |
| |
| void Utils::ReportApiFailure(const char* location, const char* message) { |
| i::Isolate* i_isolate = i::Isolate::TryGetCurrent(); |
| FatalErrorCallback callback = nullptr; |
| if (i_isolate != nullptr) { |
| callback = i_isolate->exception_behavior(); |
| } |
| if (callback == nullptr) { |
| base::OS::PrintError("\n#\n# Fatal error in %s\n# %s\n#\n\n", location, |
| message); |
| base::OS::Abort(); |
| } else { |
| callback(location, message); |
| } |
| i_isolate->SignalFatalError(); |
| } |
| |
| void Utils::ReportOOMFailure(i::Isolate* i_isolate, const char* location, |
| const OOMDetails& details) { |
| if (auto oom_callback = i_isolate->oom_behavior()) { |
| oom_callback(location, details); |
| } else { |
| // TODO(wfh): Remove this fallback once Blink is setting OOM handler. See |
| // crbug.com/614440. |
| FatalErrorCallback fatal_callback = i_isolate->exception_behavior(); |
| if (fatal_callback == nullptr) { |
| base::OOMType type = details.is_heap_oom ? base::OOMType::kJavaScript |
| : base::OOMType::kProcess; |
| base::FatalOOM(type, location); |
| UNREACHABLE(); |
| } else { |
| fatal_callback(location, |
| details.is_heap_oom |
| ? "Allocation failed - JavaScript heap out of memory" |
| : "Allocation failed - process out of memory"); |
| } |
| } |
| i_isolate->SignalFatalError(); |
| } |
| |
| void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { |
| i::V8::SetSnapshotBlob(snapshot_blob); |
| } |
| |
| namespace { |
| |
| #ifdef V8_ENABLE_SANDBOX |
| // ArrayBufferAllocator to use when the sandbox is enabled in which case all |
| // ArrayBuffer backing stores need to be allocated inside the sandbox. |
| class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { |
| public: |
| void* Allocate(size_t length) override { |
| return allocator_->Allocate(length); |
| } |
| |
| void* AllocateUninitialized(size_t length) override { |
| return Allocate(length); |
| } |
| |
| void Free(void* data, size_t length) override { |
| return allocator_->Free(data); |
| } |
| |
| private: |
| // Backend allocator shared by all ArrayBufferAllocator instances. This way, |
| // there is a single region of virtual address space reserved inside the |
| // sandbox from which all ArrayBufferAllocators allocate their memory, |
| // instead of each allocator creating their own region, which may cause |
| // address space exhaustion inside the sandbox. |
| // TODO(chromium:1340224): replace this with a more efficient allocator. |
| class BackendAllocator { |
| public: |
| BackendAllocator() { |
| CHECK(i::Sandbox::current()->is_initialized()); |
| VirtualAddressSpace* vas = i::Sandbox::current()->address_space(); |
| vas_ = vas; |
| constexpr size_t max_backing_memory_size = 8ULL * i::GB; |
| constexpr size_t min_backing_memory_size = 1ULL * i::GB; |
| size_t backing_memory_size = max_backing_memory_size; |
| i::Address backing_memory_base = 0; |
| while (!backing_memory_base && |
| backing_memory_size >= min_backing_memory_size) { |
| backing_memory_base = vas->AllocatePages( |
| VirtualAddressSpace::kNoHint, backing_memory_size, kChunkSize, |
| PagePermissions::kNoAccess); |
| if (!backing_memory_base) { |
| backing_memory_size /= 2; |
| } |
| } |
| if (!backing_memory_base) { |
| i::V8::FatalProcessOutOfMemory( |
| nullptr, |
| "Could not reserve backing memory for ArrayBufferAllocators"); |
| } |
| DCHECK(IsAligned(backing_memory_base, kChunkSize)); |
| |
| region_alloc_ = std::make_unique<base::RegionAllocator>( |
| backing_memory_base, backing_memory_size, kAllocationGranularity); |
| end_of_accessible_region_ = region_alloc_->begin(); |
| |
| // Install an on-merge callback to discard or decommit unused pages. |
| region_alloc_->set_on_merge_callback([this](i::Address start, |
| size_t size) { |
| mutex_.AssertHeld(); |
| i::Address end = start + size; |
| if (end == region_alloc_->end() && |
| start <= end_of_accessible_region_ - kChunkSize) { |
| // Can shrink the accessible region. |
| i::Address new_end_of_accessible_region = RoundUp(start, kChunkSize); |
| size_t size_to_decommit = |
| end_of_accessible_region_ - new_end_of_accessible_region; |
| if (!vas_->DecommitPages(new_end_of_accessible_region, |
| size_to_decommit)) { |
| i::V8::FatalProcessOutOfMemory( |
| nullptr, "ArrayBufferAllocator::BackendAllocator()"); |
| } |
| end_of_accessible_region_ = new_end_of_accessible_region; |
| } else if (size >= 2 * kChunkSize) { |
| // Can discard pages. The pages stay accessible, so the size of the |
| // accessible region doesn't change. |
| i::Address chunk_start = RoundUp(start, kChunkSize); |
| i::Address chunk_end = RoundDown(start + size, kChunkSize); |
| if (!vas_->DiscardSystemPages(chunk_start, chunk_end - chunk_start)) { |
| i::V8::FatalProcessOutOfMemory( |
| nullptr, "ArrayBufferAllocator::BackendAllocator()"); |
| } |
| } |
| }); |
| } |
| |
| ~BackendAllocator() { |
| // The sandbox may already have been torn down, in which case there's no |
| // need to free any memory. |
| if (i::Sandbox::current()->is_initialized()) { |
| vas_->FreePages(region_alloc_->begin(), region_alloc_->size()); |
| } |
| } |
| |
| BackendAllocator(const BackendAllocator&) = delete; |
| BackendAllocator& operator=(const BackendAllocator&) = delete; |
| |
| void* Allocate(size_t length) { |
| base::MutexGuard guard(&mutex_); |
| |
| length = RoundUp(length, kAllocationGranularity); |
| i::Address region = region_alloc_->AllocateRegion(length); |
| if (region == base::RegionAllocator::kAllocationFailure) return nullptr; |
| |
| // Check if the memory is inside the accessible region. If not, grow it. |
| i::Address end = region + length; |
| size_t length_to_memset = length; |
| if (end > end_of_accessible_region_) { |
| i::Address new_end_of_accessible_region = RoundUp(end, kChunkSize); |
| size_t size = new_end_of_accessible_region - end_of_accessible_region_; |
| if (!vas_->SetPagePermissions(end_of_accessible_region_, size, |
| PagePermissions::kReadWrite)) { |
| if (!region_alloc_->FreeRegion(region)) { |
| i::V8::FatalProcessOutOfMemory( |
| nullptr, "ArrayBufferAllocator::BackendAllocator::Allocate()"); |
| } |
| return nullptr; |
| } |
| |
| // The pages that were inaccessible are guaranteed to be zeroed, so only |
| // memset until the previous end of the accessible region. |
| length_to_memset = end_of_accessible_region_ - region; |
| end_of_accessible_region_ = new_end_of_accessible_region; |
| } |
| |
| void* mem = reinterpret_cast<void*>(region); |
| memset(mem, 0, length_to_memset); |
| return mem; |
| } |
| |
| void Free(void* data) { |
| base::MutexGuard guard(&mutex_); |
| region_alloc_->FreeRegion(reinterpret_cast<i::Address>(data)); |
| } |
| |
| static BackendAllocator* SharedInstance() { |
| static base::LeakyObject<BackendAllocator> instance; |
| return instance.get(); |
| } |
| |
| private: |
| // Use a region allocator with a "page size" of 128 bytes as a reasonable |
| // compromise between the number of regions it has to manage and the amount |
| // of memory wasted due to rounding allocation sizes up to the page size. |
| static constexpr size_t kAllocationGranularity = 128; |
| // The backing memory's accessible region is grown in chunks of this size. |
| static constexpr size_t kChunkSize = 1 * i::MB; |
| |
| std::unique_ptr<base::RegionAllocator> region_alloc_; |
| size_t end_of_accessible_region_; |
| VirtualAddressSpace* vas_ = nullptr; |
| base::Mutex mutex_; |
| }; |
| |
| BackendAllocator* allocator_ = BackendAllocator::SharedInstance(); |
| }; |
| |
| #else |
| |
| class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { |
| public: |
| void* Allocate(size_t length) override { return base::Calloc(length, 1); } |
| |
| void* AllocateUninitialized(size_t length) override { |
| return base::Malloc(length); |
| } |
| |
| void Free(void* data, size_t) override { base::Free(data); } |
| }; |
| #endif // V8_ENABLE_SANDBOX |
| |
| } // namespace |
| |
| SnapshotCreator::SnapshotCreator(Isolate* v8_isolate, |
| const intptr_t* external_references, |
| const StartupData* existing_snapshot, |
| bool owns_isolate) |
| : impl_(new i::SnapshotCreatorImpl( |
| reinterpret_cast<i::Isolate*>(v8_isolate), external_references, |
| existing_snapshot, owns_isolate)) {} |
| |
| SnapshotCreator::SnapshotCreator(const intptr_t* external_references, |
| const StartupData* existing_snapshot) |
| : SnapshotCreator(nullptr, external_references, existing_snapshot) {} |
| |
| SnapshotCreator::SnapshotCreator(const v8::Isolate::CreateParams& params) |
| : impl_(new i::SnapshotCreatorImpl(params)) {} |
| |
| SnapshotCreator::SnapshotCreator(v8::Isolate* isolate, |
| const v8::Isolate::CreateParams& params) |
| : impl_(new i::SnapshotCreatorImpl(reinterpret_cast<i::Isolate*>(isolate), |
| params)) {} |
| |
| SnapshotCreator::~SnapshotCreator() { |
| DCHECK_NOT_NULL(impl_); |
| delete impl_; |
| } |
| |
| Isolate* SnapshotCreator::GetIsolate() { |
| return reinterpret_cast<v8::Isolate*>(impl_->isolate()); |
| } |
| |
| void SnapshotCreator::SetDefaultContext( |
| Local<Context> context, |
| SerializeInternalFieldsCallback internal_fields_serializer, |
| SerializeContextDataCallback context_data_serializer, |
| SerializeAPIWrapperCallback api_wrapper_serializer) { |
| impl_->SetDefaultContext( |
| Utils::OpenDirectHandle(*context), |
| i::SerializeEmbedderFieldsCallback(internal_fields_serializer, |
| context_data_serializer, |
| api_wrapper_serializer)); |
| } |
| |
| size_t SnapshotCreator::AddContext( |
| Local<Context> context, |
| SerializeInternalFieldsCallback internal_fields_serializer, |
| SerializeContextDataCallback context_data_serializer, |
| SerializeAPIWrapperCallback api_wrapper_serializer) { |
| return impl_->AddContext( |
| Utils::OpenDirectHandle(*context), |
| i::SerializeEmbedderFieldsCallback(internal_fields_serializer, |
| context_data_serializer, |
| api_wrapper_serializer)); |
| } |
| |
| size_t SnapshotCreator::AddData(i::Address object) { |
| return impl_->AddData(object); |
| } |
| |
| size_t SnapshotCreator::AddData(Local<Context> context, i::Address object) { |
| return impl_->AddData(Utils::OpenDirectHandle(*context), object); |
| } |
| |
| StartupData SnapshotCreator::CreateBlob( |
| SnapshotCreator::FunctionCodeHandling function_code_handling) { |
| return impl_->CreateBlob(function_code_handling); |
| } |
| |
| bool StartupData::CanBeRehashed() const { |
| DCHECK(i::Snapshot::VerifyChecksum(this)); |
| return i::Snapshot::ExtractRehashability(this); |
| } |
| |
| bool StartupData::IsValid() const { return i::Snapshot::VersionIsValid(this); } |
| |
| void V8::SetDcheckErrorHandler(DcheckErrorCallback that) { |
| v8::base::SetDcheckFunction(that); |
| } |
| |
| void V8::SetFatalErrorHandler(V8FatalErrorCallback that) { |
| v8::base::SetFatalFunction(that); |
| } |
| |
| void V8::SetFlagsFromString(const char* str) { |
| SetFlagsFromString(str, strlen(str)); |
| } |
| |
| void V8::SetFlagsFromString(const char* str, size_t length) { |
| i::FlagList::SetFlagsFromString(str, length); |
| } |
| |
| void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { |
| using HelpOptions = i::FlagList::HelpOptions; |
| i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags, |
| HelpOptions(HelpOptions::kDontExit)); |
| } |
| |
| RegisteredExtension* RegisteredExtension::first_extension_ = nullptr; |
| |
| RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension) |
| : extension_(std::move(extension)) {} |
| |
| // static |
| void RegisteredExtension::Register(std::unique_ptr<Extension> extension) { |
| RegisteredExtension* new_extension = |
| new RegisteredExtension(std::move(extension)); |
| new_extension->next_ = first_extension_; |
| first_extension_ = new_extension; |
| } |
| |
| // static |
| void RegisteredExtension::UnregisterAll() { |
| RegisteredExtension* re = first_extension_; |
| while (re != nullptr) { |
| RegisteredExtension* next = re->next(); |
| delete re; |
| re = next; |
| } |
| first_extension_ = nullptr; |
| } |
| |
| namespace { |
| class ExtensionResource : public String::ExternalOneByteStringResource { |
| public: |
| ExtensionResource() : data_(nullptr), length_(0) {} |
| ExtensionResource(const char* data, size_t length) |
| : data_(data), length_(length) {} |
| const char* data() const override { return data_; } |
| size_t length() const override { return length_; } |
| void Dispose() override {} |
| |
| private: |
| const char* data_; |
| size_t length_; |
| }; |
| } // anonymous namespace |
| |
| void RegisterExtension(std::unique_ptr<Extension> extension) { |
| RegisteredExtension::Register(std::move(extension)); |
| } |
| |
| Extension::Extension(const char* name, const char* source, int dep_count, |
| const char** deps, int source_length) |
| : name_(name), |
| source_length_(source_length >= 0 |
| ? source_length |
| : (source ? static_cast<int>(strlen(source)) : 0)), |
| dep_count_(dep_count), |
| deps_(deps), |
| auto_enable_(false) { |
| source_ = new ExtensionResource(source, source_length_); |
| CHECK(source != nullptr || source_length_ == 0); |
| } |
| |
| void ResourceConstraints::ConfigureDefaultsFromHeapSize( |
| size_t initial_heap_size_in_bytes, size_t maximum_heap_size_in_bytes) { |
| CHECK_LE(initial_heap_size_in_bytes, maximum_heap_size_in_bytes); |
| if (maximum_heap_size_in_bytes == 0) { |
| return; |
| } |
| size_t young_generation, old_generation; |
| i::Heap::GenerationSizesFromHeapSize(maximum_heap_size_in_bytes, |
| &young_generation, &old_generation); |
| set_max_young_generation_size_in_bytes( |
| std::max(young_generation, i::Heap::MinYoungGenerationSize())); |
| set_max_old_generation_size_in_bytes( |
| std::max(old_generation, i::Heap::MinOldGenerationSize())); |
| if (initial_heap_size_in_bytes > 0) { |
| i::Heap::GenerationSizesFromHeapSize(initial_heap_size_in_bytes, |
| &young_generation, &old_generation); |
| // We do not set lower bounds for the initial sizes. |
| set_initial_young_generation_size_in_bytes(young_generation); |
| set_initial_old_generation_size_in_bytes(old_generation); |
| } |
| if (i::kPlatformRequiresCodeRange) { |
| set_code_range_size_in_bytes( |
| std::min(i::kMaximalCodeRangeSize, maximum_heap_size_in_bytes)); |
| } |
| } |
| |
| void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory, |
| uint64_t virtual_memory_limit) { |
| size_t heap_size = i::Heap::HeapSizeFromPhysicalMemory(physical_memory); |
| size_t young_generation, old_generation; |
| i::Heap::GenerationSizesFromHeapSize(heap_size, &young_generation, |
| &old_generation); |
| set_max_young_generation_size_in_bytes(young_generation); |
| set_max_old_generation_size_in_bytes(old_generation); |
| |
| if (virtual_memory_limit > 0 && i::kPlatformRequiresCodeRange) { |
| set_code_range_size_in_bytes( |
| std::min(i::kMaximalCodeRangeSize, |
| static_cast<size_t>(virtual_memory_limit / 8))); |
| } |
| } |
| |
| #ifdef ENABLE_SLOW_DCHECKS |
| namespace api_internal { |
| void StackAllocated<true>::VerifyOnStack() const { |
| if (internal::StackAllocatedCheck::Get()) { |
| SLOW_DCHECK(::heap::base::Stack::IsOnStack(this)); |
| } |
| } |
| } // namespace api_internal |
| #endif |
| |
| namespace internal { |
| |
| void VerifyHandleIsNonEmpty(bool is_empty) { |
| Utils::ApiCheck(!is_empty, "v8::ReturnValue", |
| "SetNonEmpty() called with empty handle."); |
| } |
| |
| i::Address* GlobalizeTracedReference( |
| i::Isolate* i_isolate, i::Address value, internal::Address* slot, |
| TracedReferenceStoreMode store_mode, |
| TracedReferenceHandling reference_handling) { |
| return i_isolate->traced_handles() |
| ->Create(value, slot, store_mode, reference_handling) |
| .location(); |
| } |
| |
| void MoveTracedReference(internal::Address** from, internal::Address** to) { |
| TracedHandles::Move(from, to); |
| } |
| |
| void CopyTracedReference(const internal::Address* const* from, |
| internal::Address** to) { |
| TracedHandles::Copy(from, to); |
| } |
| |
| void DisposeTracedReference(internal::Address* location) { |
| TracedHandles::Destroy(location); |
| } |
| |
| #if V8_STATIC_ROOTS_BOOL |
| |
| // Check static root constants exposed in v8-internal.h. |
| |
| namespace { |
| constexpr InstanceTypeChecker::TaggedAddressRange kStringMapRange = |
| *InstanceTypeChecker::UniqueMapRangeOfInstanceTypeRange(FIRST_STRING_TYPE, |
| LAST_STRING_TYPE); |
| } // namespace |
| |
| #define EXPORTED_STATIC_ROOTS_PTR_MAPPING(V) \ |
| V(UndefinedValue, i::StaticReadOnlyRoot::kUndefinedValue) \ |
| V(NullValue, i::StaticReadOnlyRoot::kNullValue) \ |
| V(TrueValue, i::StaticReadOnlyRoot::kTrueValue) \ |
| V(FalseValue, i::StaticReadOnlyRoot::kFalseValue) \ |
| V(EmptyString, i::StaticReadOnlyRoot::kempty_string) \ |
| V(TheHoleValue, i::StaticReadOnlyRoot::kTheHoleValue) \ |
| V(StringMapLowerBound, kStringMapRange.first) \ |
| V(StringMapUpperBound, kStringMapRange.second) |
| |
| static_assert(std::is_same_v<Internals::Tagged_t, Tagged_t>); |
| // Ensure they have the correct value. |
| #define CHECK_STATIC_ROOT(name, value) \ |
| static_assert(Internals::StaticReadOnlyRoot::k##name == value); |
| EXPORTED_STATIC_ROOTS_PTR_MAPPING(CHECK_STATIC_ROOT) |
| #undef CHECK_STATIC_ROOT |
| #define PLUS_ONE(...) +1 |
| static constexpr int kNumberOfCheckedStaticRoots = |
| 0 EXPORTED_STATIC_ROOTS_PTR_MAPPING(PLUS_ONE); |
| #undef EXPORTED_STATIC_ROOTS_PTR_MAPPING |
| static_assert(Internals::StaticReadOnlyRoot::kNumberOfExportedStaticRoots == |
| kNumberOfCheckedStaticRoots); |
| |
| #endif // V8_STATIC_ROOTS_BOOL |
| |
| } // namespace internal |
| |
| namespace api_internal { |
| |
| i::Address* GlobalizeReference(i::Isolate* i_isolate, i::Address value) { |
| API_RCS_SCOPE(i_isolate, Persistent, New); |
| i::IndirectHandle<i::Object> result = |
| i_isolate->global_handles()->Create(value); |
| #ifdef VERIFY_HEAP |
| if (i::v8_flags.verify_heap) { |
| i::Object::ObjectVerify(i::Tagged<i::Object>(value), i_isolate); |
| } |
| #endif // VERIFY_HEAP |
| return result.location(); |
| } |
| |
| i::Address* CopyGlobalReference(i::Address* from) { |
| i::IndirectHandle<i::Object> result = i::GlobalHandles::CopyGlobal(from); |
| return result.location(); |
| } |
| |
| void MoveGlobalReference(internal::Address** from, internal::Address** to) { |
| i::GlobalHandles::MoveGlobal(from, to); |
| } |
| |
| void MakeWeak(i::Address* location, void* parameter, |
| WeakCallbackInfo<void>::Callback weak_callback, |
| WeakCallbackType type) { |
| i::GlobalHandles::MakeWeak(location, parameter, weak_callback, type); |
| } |
| |
| void MakeWeak(i::Address** location_addr) { |
| i::GlobalHandles::MakeWeak(location_addr); |
| } |
| |
| void* ClearWeak(i::Address* location) { |
| return i::GlobalHandles::ClearWeakness(location); |
| } |
| |
| void AnnotateStrongRetainer(i::Address* location, const char* label) { |
| i::GlobalHandles::AnnotateStrongRetainer(location, label); |
| } |
| |
| void DisposeGlobal(i::Address* location) { |
| i::GlobalHandles::Destroy(location); |
| } |
| |
| i::Address* Eternalize(Isolate* v8_isolate, Value* value) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| i::Tagged<i::Object> object = *Utils::OpenDirectHandle(value); |
| int index = -1; |
| i_isolate->eternal_handles()->Create(i_isolate, object, &index); |
| return i_isolate->eternal_handles()->Get(index).location(); |
| } |
| |
| void FromJustIsNothing() { |
| Utils::ApiCheck(false, "v8::FromJust", "Maybe value is Nothing"); |
| } |
| |
| void ToLocalEmpty() { |
| Utils::ApiCheck(false, "v8::ToLocalChecked", "Empty MaybeLocal"); |
| } |
| |
| void InternalFieldOutOfBounds(int index) { |
| Utils::ApiCheck(0 <= index && index < kInternalFieldsInWeakCallback, |
| "WeakCallbackInfo::GetInternalField", |
| "Internal field out of bounds"); |
| } |
| |
| } // namespace api_internal |
| |
| // --- H a n d l e s --- |
| |
| HandleScope::HandleScope(Isolate* v8_isolate) { Initialize(v8_isolate); } |
| |
| void HandleScope::Initialize(Isolate* v8_isolate) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| // We do not want to check the correct usage of the Locker class all over the |
| // place, so we do it only here: Without a HandleScope, an embedder can do |
| // almost nothing, so it is enough to check in this central place. |
| // We make an exception if the serializer is enabled, which means that the |
| // Isolate is exclusively used to create a snapshot. |
| Utils::ApiCheck(!i_isolate->was_locker_ever_used() || |
| i_isolate->thread_manager()->IsLockedByCurrentThread() || |
| i_isolate->serializer_enabled(), |
| "HandleScope::HandleScope", |
| "Entering the V8 API without proper locking in place"); |
| i::HandleScopeData* current = i_isolate->handle_scope_data(); |
| i_isolate_ = i_isolate; |
| prev_next_ = current->next; |
| prev_limit_ = current->limit; |
| current->level++; |
| #ifdef V8_ENABLE_CHECKS |
| scope_level_ = current->level; |
| #endif |
| } |
| |
| HandleScope::~HandleScope() { |
| #ifdef V8_ENABLE_CHECKS |
| CHECK_EQ(scope_level_, i_isolate_->handle_scope_data()->level); |
| #endif |
| i::HandleScope::CloseScope(i_isolate_, prev_next_, prev_limit_); |
| } |
| |
| void* HandleScope::operator new(size_t) { base::OS::Abort(); } |
| void* HandleScope::operator new[](size_t) { base::OS::Abort(); } |
| void HandleScope::operator delete(void*, size_t) { base::OS::Abort(); } |
| void HandleScope::operator delete[](void*, size_t) { base::OS::Abort(); } |
| |
| int HandleScope::NumberOfHandles(Isolate* v8_isolate) { |
| return i::HandleScope::NumberOfHandles( |
| reinterpret_cast<i::Isolate*>(v8_isolate)); |
| } |
| |
| i::Address* HandleScope::CreateHandle(i::Isolate* i_isolate, i::Address value) { |
| return i::HandleScope::CreateHandle(i_isolate, value); |
| } |
| |
| #ifdef V8_ENABLE_DIRECT_HANDLE |
| |
| i::Address* HandleScope::CreateHandleForCurrentIsolate(i::Address value) { |
| i::Isolate* i_isolate = i::Isolate::Current(); |
| return i::HandleScope::CreateHandle(i_isolate, value); |
| } |
| |
| #endif // V8_ENABLE_DIRECT_HANDLE |
| |
| EscapableHandleScopeBase::EscapableHandleScopeBase(Isolate* v8_isolate) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| escape_slot_ = CreateHandle( |
| i_isolate, i::ReadOnlyRoots(i_isolate).the_hole_value().ptr()); |
| Initialize(v8_isolate); |
| } |
| |
| i::Address* EscapableHandleScopeBase::EscapeSlot(i::Address* escape_value) { |
| DCHECK_NOT_NULL(escape_value); |
| DCHECK(i::IsTheHole(i::Tagged<i::Object>(*escape_slot_), |
| reinterpret_cast<i::Isolate*>(GetIsolate()))); |
| *escape_slot_ = *escape_value; |
| return escape_slot_; |
| } |
| |
| SealHandleScope::SealHandleScope(Isolate* v8_isolate) |
| : i_isolate_(reinterpret_cast<i::Isolate*>(v8_isolate)) { |
| i::HandleScopeData* current = i_isolate_->handle_scope_data(); |
| prev_limit_ = current->limit; |
| current->limit = current->next; |
| prev_sealed_level_ = current->sealed_level; |
| current->sealed_level = current->level; |
| } |
| |
| SealHandleScope::~SealHandleScope() { |
| i::HandleScopeData* current = i_isolate_->handle_scope_data(); |
| DCHECK_EQ(current->next, current->limit); |
| current->limit = prev_limit_; |
| DCHECK_EQ(current->level, current->sealed_level); |
| current->sealed_level = prev_sealed_level_; |
| } |
| |
| bool Data::IsModule() const { |
| return i::IsModule(*Utils::OpenDirectHandle(this)); |
| } |
| bool Data::IsFixedArray() const { |
| return i::IsFixedArray(*Utils::OpenDirectHandle(this)); |
| } |
| |
| bool Data::IsValue() const { |
| i::DisallowGarbageCollection no_gc; |
| i::Tagged<i::Object> self = *Utils::OpenDirectHandle(this); |
| if (i::IsSmi(self)) return true; |
| i::Tagged<i::HeapObject> heap_object = i::Cast<i::HeapObject>(self); |
| DCHECK(!IsTheHole(heap_object)); |
| if (i::IsSymbol(heap_object)) { |
| return !i::Cast<i::Symbol>(heap_object)->is_private(); |
| } |
| return IsPrimitiveHeapObject(heap_object) || IsJSReceiver(heap_object); |
| } |
| |
| bool Data::IsPrivate() const { |
| return i::IsPrivateSymbol(*Utils::OpenDirectHandle(this)); |
| } |
| |
| bool Data::IsObjectTemplate() const { |
| return i::IsObjectTemplateInfo(*Utils::OpenDirectHandle(this)); |
| } |
| |
| bool Data::IsFunctionTemplate() const { |
| return i::IsFunctionTemplateInfo(*Utils::OpenDirectHandle(this)); |
| } |
| |
| bool Data::IsContext() const { |
| return i::IsContext(*Utils::OpenDirectHandle(this)); |
| } |
| |
| void Context::Enter() { |
| i::DisallowGarbageCollection no_gc; |
| i::Tagged<i::NativeContext> env = *Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = env->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScopeImplementer* impl = i_isolate->handle_scope_implementer(); |
| impl->EnterContext(env); |
| impl->SaveContext(i_isolate->context()); |
| i_isolate->set_context(env); |
| } |
| |
| void Context::Exit() { |
| auto env = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = env->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScopeImplementer* impl = i_isolate->handle_scope_implementer(); |
| if (!Utils::ApiCheck(impl->LastEnteredContextWas(*env), "v8::Context::Exit()", |
| "Cannot exit non-entered context")) { |
| return; |
| } |
| impl->LeaveContext(); |
| i_isolate->set_context(impl->RestoreContext()); |
| } |
| |
| Context::BackupIncumbentScope::BackupIncumbentScope( |
| Local<Context> backup_incumbent_context) |
| : backup_incumbent_context_(backup_incumbent_context) { |
| DCHECK(!backup_incumbent_context_.IsEmpty()); |
| |
| auto env = Utils::OpenDirectHandle(*backup_incumbent_context_); |
| i::Isolate* i_isolate = env->GetIsolate(); |
| |
| js_stack_comparable_address_ = |
| i::SimulatorStack::RegisterJSStackComparableAddress(i_isolate); |
| |
| prev_ = i_isolate->top_backup_incumbent_scope(); |
| i_isolate->set_top_backup_incumbent_scope(this); |
| // Enforce slow incumbent computation in order to make it find this |
| // BackupIncumbentScope. |
| i_isolate->clear_topmost_script_having_context(); |
| } |
| |
| Context::BackupIncumbentScope::~BackupIncumbentScope() { |
| auto env = Utils::OpenDirectHandle(*backup_incumbent_context_); |
| i::Isolate* i_isolate = env->GetIsolate(); |
| |
| i::SimulatorStack::UnregisterJSStackComparableAddress(i_isolate); |
| |
| i_isolate->set_top_backup_incumbent_scope(prev_); |
| } |
| |
| static_assert(i::Internals::kEmbedderDataSlotSize == i::kEmbedderDataSlotSize); |
| static_assert(i::Internals::kEmbedderDataSlotExternalPointerOffset == |
| i::EmbedderDataSlot::kExternalPointerOffset); |
| |
| static i::DirectHandle<i::EmbedderDataArray> EmbedderDataFor( |
| Context* context, int index, bool can_grow, const char* location) { |
| auto env = Utils::OpenDirectHandle(context); |
| i::Isolate* i_isolate = env->GetIsolate(); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| bool ok = Utils::ApiCheck(i::IsNativeContext(*env), location, |
| "Not a native context") && |
| Utils::ApiCheck(index >= 0, location, "Negative index"); |
| if (!ok) return {}; |
| // TODO(ishell): remove cast once embedder_data slot has a proper type. |
| i::DirectHandle<i::EmbedderDataArray> data( |
| i::Cast<i::EmbedderDataArray>(env->embedder_data()), i_isolate); |
| if (index < data->length()) return data; |
| if (!Utils::ApiCheck(can_grow && index < i::EmbedderDataArray::kMaxLength, |
| location, "Index too large")) { |
| return {}; |
| } |
| data = i::EmbedderDataArray::EnsureCapacity(i_isolate, data, index); |
| env->set_embedder_data(*data); |
| return data; |
| } |
| |
| uint32_t Context::GetNumberOfEmbedderDataFields() { |
| auto context = Utils::OpenDirectHandle(this); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(context->GetIsolate()); |
| Utils::ApiCheck(i::IsNativeContext(*context), |
| "Context::GetNumberOfEmbedderDataFields", |
| "Not a native context"); |
| // TODO(ishell): remove cast once embedder_data slot has a proper type. |
| return static_cast<uint32_t>( |
| i::Cast<i::EmbedderDataArray>(context->embedder_data())->length()); |
| } |
| |
| v8::Local<v8::Value> Context::SlowGetEmbedderData(int index) { |
| const char* location = "v8::Context::GetEmbedderData()"; |
| i::DirectHandle<i::EmbedderDataArray> data = |
| EmbedderDataFor(this, index, false, location); |
| if (data.is_null()) return Local<Value>(); |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| return Utils::ToLocal(i::direct_handle( |
| i::EmbedderDataSlot(*data, index).load_tagged(), i_isolate)); |
| } |
| |
| void Context::SetEmbedderData(int index, v8::Local<Value> value) { |
| const char* location = "v8::Context::SetEmbedderData()"; |
| i::DirectHandle<i::EmbedderDataArray> data = |
| EmbedderDataFor(this, index, true, location); |
| if (data.is_null()) return; |
| auto val = Utils::OpenDirectHandle(*value); |
| i::EmbedderDataSlot::store_tagged(*data, index, *val); |
| DCHECK_EQ(*Utils::OpenDirectHandle(*value), |
| *Utils::OpenDirectHandle(*GetEmbedderData(index))); |
| } |
| |
| void* Context::SlowGetAlignedPointerFromEmbedderData(int index) { |
| const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| i::HandleScope handle_scope(i_isolate); |
| i::DirectHandle<i::EmbedderDataArray> data = |
| EmbedderDataFor(this, index, false, location); |
| if (data.is_null()) return nullptr; |
| void* result; |
| Utils::ApiCheck( |
| i::EmbedderDataSlot(*data, index).ToAlignedPointer(i_isolate, &result), |
| location, "Pointer is not aligned"); |
| return result; |
| } |
| |
| void Context::SetAlignedPointerInEmbedderData(int index, void* value) { |
| const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| i::DirectHandle<i::EmbedderDataArray> data = |
| EmbedderDataFor(this, index, true, location); |
| bool ok = i::EmbedderDataSlot(*data, index) |
| .store_aligned_pointer(i_isolate, *data, value); |
| Utils::ApiCheck(ok, location, "Pointer is not aligned"); |
| DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index)); |
| } |
| |
| // --- T e m p l a t e --- |
| |
| void Template::Set(v8::Local<Name> name, v8::Local<Data> value, |
| v8::PropertyAttribute attribute) { |
| auto templ = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = templ->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto value_obj = Utils::OpenDirectHandle(*value); |
| |
| Utils::ApiCheck(!IsJSReceiver(*value_obj) || IsTemplateInfo(*value_obj), |
| "v8::Template::Set", |
| "Invalid value, must be a primitive or a Template"); |
| |
| // The template cache only performs shallow clones, if we set an |
| // ObjectTemplate as a property value then we can not cache the receiver |
| // template. |
| if (i::IsObjectTemplateInfo(*value_obj)) { |
| templ->set_serial_number(i::TemplateInfo::kDoNotCache); |
| } |
| |
| i::ApiNatives::AddDataProperty(i_isolate, templ, |
| Utils::OpenDirectHandle(*name), value_obj, |
| static_cast<i::PropertyAttributes>(attribute)); |
| } |
| |
| void Template::SetPrivate(v8::Local<Private> name, v8::Local<Data> value, |
| v8::PropertyAttribute attribute) { |
| Set(Local<Name>::Cast(name), value, attribute); |
| } |
| |
| void Template::SetAccessorProperty(v8::Local<v8::Name> name, |
| v8::Local<FunctionTemplate> getter, |
| v8::Local<FunctionTemplate> setter, |
| v8::PropertyAttribute attribute) { |
| auto templ = Utils::OpenDirectHandle(this); |
| auto i_isolate = templ->GetIsolateChecked(); |
| i::DirectHandle<i::FunctionTemplateInfo> i_getter; |
| if (!getter.IsEmpty()) { |
| i_getter = Utils::OpenDirectHandle(*getter); |
| Utils::ApiCheck(i_getter->has_callback(i_isolate), |
| "v8::Template::SetAccessorProperty", |
| "Getter must have a call handler"); |
| } |
| i::DirectHandle<i::FunctionTemplateInfo> i_setter; |
| if (!setter.IsEmpty()) { |
| i_setter = Utils::OpenDirectHandle(*setter); |
| Utils::ApiCheck(i_setter->has_callback(i_isolate), |
| "v8::Template::SetAccessorProperty", |
| "Setter must have a call handler"); |
| } |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| DCHECK(!name.IsEmpty()); |
| DCHECK(!getter.IsEmpty() || !setter.IsEmpty()); |
| i::HandleScope scope(i_isolate); |
| i::ApiNatives::AddAccessorProperty( |
| i_isolate, templ, Utils::OpenDirectHandle(*name), i_getter, i_setter, |
| static_cast<i::PropertyAttributes>(attribute)); |
| } |
| |
| // --- F u n c t i o n T e m p l a t e --- |
| |
| Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::HeapObject> heap_obj(self->GetPrototypeTemplate(), |
| i_isolate); |
| if (i::IsUndefined(*heap_obj, i_isolate)) { |
| // Do not cache prototype objects. |
| constexpr bool do_not_cache = true; |
| i::DirectHandle<i::ObjectTemplateInfo> proto_template = |
| i_isolate->factory()->NewObjectTemplateInfo({}, do_not_cache); |
| i::FunctionTemplateInfo::SetPrototypeTemplate(i_isolate, self, |
| proto_template); |
| return Utils::ToLocal(proto_template); |
| } |
| return ToApiHandle<ObjectTemplate>(heap_obj); |
| } |
| |
| void FunctionTemplate::SetPrototypeProviderTemplate( |
| Local<FunctionTemplate> prototype_provider) { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::FunctionTemplateInfo> result = |
| Utils::OpenDirectHandle(*prototype_provider); |
| Utils::ApiCheck(i::IsUndefined(self->GetPrototypeTemplate(), i_isolate), |
| "v8::FunctionTemplate::SetPrototypeProviderTemplate", |
| "Protoype must be undefined"); |
| Utils::ApiCheck(i::IsUndefined(self->GetParentTemplate(), i_isolate), |
| "v8::FunctionTemplate::SetPrototypeProviderTemplate", |
| "Prototype provider must be empty"); |
| i::FunctionTemplateInfo::SetPrototypeProviderTemplate(i_isolate, self, |
| result); |
| } |
| |
| namespace { |
| static void EnsureNotPublished(i::DirectHandle<i::FunctionTemplateInfo> info, |
| const char* func) { |
| DCHECK_IMPLIES(info->instantiated(), info->published()); |
| Utils::ApiCheck(!info->published(), func, |
| "FunctionTemplate already instantiated"); |
| } |
| |
| i::DirectHandle<i::FunctionTemplateInfo> FunctionTemplateNew( |
| i::Isolate* i_isolate, FunctionCallback callback, v8::Local<Value> data, |
| v8::Local<Signature> signature, int length, ConstructorBehavior behavior, |
| bool do_not_cache, |
| v8::Local<Private> cached_property_name = v8::Local<Private>(), |
| SideEffectType side_effect_type = SideEffectType::kHasSideEffect, |
| const MemorySpan<const CFunction>& c_function_overloads = {}) { |
| i::DirectHandle<i::FunctionTemplateInfo> obj = |
| i_isolate->factory()->NewFunctionTemplateInfo(length, do_not_cache); |
| { |
| // Disallow GC until all fields of obj have acceptable types. |
| i::DisallowGarbageCollection no_gc; |
| i::Tagged<i::FunctionTemplateInfo> raw = *obj; |
| if (!signature.IsEmpty()) { |
| raw->set_signature(*Utils::OpenDirectHandle(*signature)); |
| } |
| if (!cached_property_name.IsEmpty()) { |
| raw->set_cached_property_name( |
| *Utils::OpenDirectHandle(*cached_property_name)); |
| } |
| if (behavior == ConstructorBehavior::kThrow) { |
| raw->set_remove_prototype(true); |
| } |
| } |
| if (callback != nullptr) { |
| Utils::ToLocal(obj)->SetCallHandler(callback, data, side_effect_type, |
| c_function_overloads); |
| } |
| return obj; |
| } |
| } // namespace |
| |
| void FunctionTemplate::Inherit(v8::Local<FunctionTemplate> value) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::Inherit"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| Utils::ApiCheck( |
| i::IsUndefined(info->GetPrototypeProviderTemplate(), i_isolate), |
| "v8::FunctionTemplate::Inherit", "Protoype provider must be empty"); |
| i::FunctionTemplateInfo::SetParentTemplate(i_isolate, info, |
| Utils::OpenDirectHandle(*value)); |
| } |
| |
| Local<FunctionTemplate> FunctionTemplate::New( |
| Isolate* v8_isolate, FunctionCallback callback, v8::Local<Value> data, |
| v8::Local<Signature> signature, int length, ConstructorBehavior behavior, |
| SideEffectType side_effect_type, const CFunction* c_function, |
| uint16_t instance_type, uint16_t allowed_receiver_instance_type_range_start, |
| uint16_t allowed_receiver_instance_type_range_end) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| // Changes to the environment cannot be captured in the snapshot. Expect no |
| // function templates when the isolate is created for serialization. |
| API_RCS_SCOPE(i_isolate, FunctionTemplate, New); |
| |
| if (!Utils::ApiCheck( |
| !c_function || behavior == ConstructorBehavior::kThrow, |
| "FunctionTemplate::New", |
| "Fast API calls are not supported for constructor functions")) { |
| return Local<FunctionTemplate>(); |
| } |
| |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::FunctionTemplateInfo> templ = FunctionTemplateNew( |
| i_isolate, callback, data, signature, length, behavior, false, |
| Local<Private>(), side_effect_type, |
| c_function ? MemorySpan<const CFunction>{c_function, 1} |
| : MemorySpan<const CFunction>{}); |
| |
| if (instance_type) { |
| if (!Utils::ApiCheck( |
| base::IsInRange(static_cast<int>(instance_type), |
| i::Internals::kFirstEmbedderJSApiObjectType, |
| i::Internals::kLastEmbedderJSApiObjectType), |
| "FunctionTemplate::New", |
| "instance_type is outside the range of valid JSApiObject types")) { |
| return Local<FunctionTemplate>(); |
| } |
| templ->SetInstanceType(instance_type); |
| } |
| |
| if (allowed_receiver_instance_type_range_start || |
| allowed_receiver_instance_type_range_end) { |
| if (!Utils::ApiCheck(i::Internals::kFirstEmbedderJSApiObjectType <= |
| allowed_receiver_instance_type_range_start && |
| allowed_receiver_instance_type_range_start <= |
| allowed_receiver_instance_type_range_end && |
| allowed_receiver_instance_type_range_end <= |
| i::Internals::kLastEmbedderJSApiObjectType, |
| "FunctionTemplate::New", |
| "allowed receiver instance type range is outside the " |
| "range of valid JSApiObject types")) { |
| return Local<FunctionTemplate>(); |
| } |
| templ->SetAllowedReceiverInstanceTypeRange( |
| allowed_receiver_instance_type_range_start, |
| allowed_receiver_instance_type_range_end); |
| } |
| return Utils::ToLocal(templ); |
| } |
| |
| Local<FunctionTemplate> FunctionTemplate::NewWithCFunctionOverloads( |
| Isolate* v8_isolate, FunctionCallback callback, v8::Local<Value> data, |
| v8::Local<Signature> signature, int length, ConstructorBehavior behavior, |
| SideEffectType side_effect_type, |
| const MemorySpan<const CFunction>& c_function_overloads) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| API_RCS_SCOPE(i_isolate, FunctionTemplate, New); |
| |
| // Check that all overloads of the fast API callback have different numbers of |
| // parameters. Since the number of overloads is supposed to be small, just |
| // comparing them with each other should be fine. |
| for (size_t i = 0; i < c_function_overloads.size(); ++i) { |
| for (size_t j = i + 1; j < c_function_overloads.size(); ++j) { |
| CHECK_NE(c_function_overloads.data()[i].ArgumentCount(), |
| c_function_overloads.data()[j].ArgumentCount()); |
| } |
| } |
| |
| if (!Utils::ApiCheck( |
| c_function_overloads.empty() || |
| behavior == ConstructorBehavior::kThrow, |
| "FunctionTemplate::NewWithCFunctionOverloads", |
| "Fast API calls are not supported for constructor functions")) { |
| return Local<FunctionTemplate>(); |
| } |
| |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::FunctionTemplateInfo> templ = FunctionTemplateNew( |
| i_isolate, callback, data, signature, length, behavior, false, |
| Local<Private>(), side_effect_type, c_function_overloads); |
| return Utils::ToLocal(templ); |
| } |
| |
| Local<FunctionTemplate> FunctionTemplate::NewWithCache( |
| Isolate* v8_isolate, FunctionCallback callback, |
| Local<Private> cache_property, Local<Value> data, |
| Local<Signature> signature, int length, SideEffectType side_effect_type) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| API_RCS_SCOPE(i_isolate, FunctionTemplate, NewWithCache); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::FunctionTemplateInfo> templ = FunctionTemplateNew( |
| i_isolate, callback, data, signature, length, ConstructorBehavior::kAllow, |
| false, cache_property, side_effect_type); |
| return Utils::ToLocal(templ); |
| } |
| |
| Local<Signature> Signature::New(Isolate* v8_isolate, |
| Local<FunctionTemplate> receiver) { |
| return Local<Signature>::Cast(receiver); |
| } |
| |
| #define SET_FIELD_WRAPPED(i_isolate, obj, setter, cdata, tag) \ |
| do { \ |
| i::DirectHandle<i::UnionOf<i::Smi, i::Foreign>> foreign = \ |
| FromCData<tag>(i_isolate, cdata); \ |
| (obj)->setter(*foreign); \ |
| } while (false) |
| |
| void FunctionTemplate::SetCallHandler( |
| FunctionCallback callback, v8::Local<Value> data, |
| SideEffectType side_effect_type, |
| const MemorySpan<const CFunction>& c_function_overloads) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::SetCallHandler"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| info->set_has_side_effects(side_effect_type != |
| SideEffectType::kHasNoSideEffect); |
| info->set_callback(i_isolate, reinterpret_cast<i::Address>(callback)); |
| if (data.IsEmpty()) { |
| data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate)); |
| } |
| // "Release" callback and callback data fields. |
| info->set_callback_data(*Utils::OpenDirectHandle(*data), kReleaseStore); |
| |
| if (!c_function_overloads.empty()) { |
| // Stores the data for a sequence of CFunction overloads into a single |
| // FixedArray, as [address_0, signature_0, ... address_n-1, signature_n-1]. |
| i::DirectHandle<i::FixedArray> function_overloads = |
| i_isolate->factory()->NewFixedArray(static_cast<int>( |
| c_function_overloads.size() * |
| i::FunctionTemplateInfo::kFunctionOverloadEntrySize)); |
| int function_count = static_cast<int>(c_function_overloads.size()); |
| for (int i = 0; i < function_count; i++) { |
| const CFunction& c_function = c_function_overloads.data()[i]; |
| i::DirectHandle<i::Object> address = FromCData<internal::kCFunctionTag>( |
| i_isolate, c_function.GetAddress()); |
| function_overloads->set( |
| i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i, *address); |
| i::DirectHandle<i::Object> signature = |
| FromCData<internal::kCFunctionInfoTag>(i_isolate, |
| c_function.GetTypeInfo()); |
| function_overloads->set( |
| i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i + 1, |
| *signature); |
| } |
| i::FunctionTemplateInfo::SetCFunctionOverloads(i_isolate, info, |
| function_overloads); |
| } |
| } |
| |
| namespace { |
| |
| template <typename Getter, typename Setter> |
| i::DirectHandle<i::AccessorInfo> MakeAccessorInfo(i::Isolate* i_isolate, |
| v8::Local<Name> name, |
| Getter getter, Setter setter, |
| v8::Local<Value> data, |
| bool replace_on_access) { |
| i::DirectHandle<i::AccessorInfo> obj = |
| i_isolate->factory()->NewAccessorInfo(); |
| obj->set_getter(i_isolate, reinterpret_cast<i::Address>(getter)); |
| DCHECK_IMPLIES(replace_on_access, setter == nullptr); |
| if (setter == nullptr) { |
| setter = reinterpret_cast<Setter>(&i::Accessors::ReconfigureToDataProperty); |
| } |
| obj->set_setter(i_isolate, reinterpret_cast<i::Address>(setter)); |
| |
| auto accessor_name = Utils::OpenDirectHandle(*name); |
| if (!IsUniqueName(*accessor_name)) { |
| accessor_name = i_isolate->factory()->InternalizeString( |
| i::Cast<i::String>(accessor_name)); |
| } |
| i::DisallowGarbageCollection no_gc; |
| i::Tagged<i::AccessorInfo> raw_obj = *obj; |
| if (data.IsEmpty()) { |
| raw_obj->set_data(i::ReadOnlyRoots(i_isolate).undefined_value()); |
| } else { |
| raw_obj->set_data(*Utils::OpenDirectHandle(*data)); |
| } |
| raw_obj->set_name(*accessor_name); |
| raw_obj->set_replace_on_access(replace_on_access); |
| raw_obj->set_initial_property_attributes(i::NONE); |
| return obj; |
| } |
| |
| } // namespace |
| |
| Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() { |
| auto constructor = Utils::OpenDirectHandle(this, true); |
| if (!Utils::ApiCheck(!constructor.is_null(), |
| "v8::FunctionTemplate::InstanceTemplate()", |
| "Reading from empty handle")) { |
| return Local<ObjectTemplate>(); |
| } |
| i::Isolate* i_isolate = constructor->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| auto maybe_templ = constructor->GetInstanceTemplate(); |
| if (!i::IsUndefined(maybe_templ, i_isolate)) { |
| return Utils::ToLocal(i::direct_handle( |
| i::Cast<i::ObjectTemplateInfo>(maybe_templ), i_isolate)); |
| } |
| constexpr bool do_not_cache = false; |
| i::DirectHandle<i::ObjectTemplateInfo> templ = |
| i_isolate->factory()->NewObjectTemplateInfo(constructor, do_not_cache); |
| i::FunctionTemplateInfo::SetInstanceTemplate(i_isolate, constructor, templ); |
| return Utils::ToLocal(templ); |
| } |
| |
| void FunctionTemplate::SetLength(int length) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::SetLength"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_length(length); |
| } |
| |
| void FunctionTemplate::SetClassName(Local<String> name) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::SetClassName"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_class_name(*Utils::OpenDirectHandle(*name)); |
| } |
| |
| void FunctionTemplate::SetInterfaceName(Local<String> name) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::SetInterfaceName"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_interface_name(*Utils::OpenDirectHandle(*name)); |
| } |
| |
| void FunctionTemplate::SetExceptionContext(ExceptionContext context) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::SetExceptionContext"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_exception_context(static_cast<uint32_t>(context)); |
| } |
| |
| void FunctionTemplate::SetAcceptAnyReceiver(bool value) { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::SetAcceptAnyReceiver"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_accept_any_receiver(value); |
| } |
| |
| void FunctionTemplate::ReadOnlyPrototype() { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::ReadOnlyPrototype"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_read_only_prototype(true); |
| } |
| |
| void FunctionTemplate::RemovePrototype() { |
| auto info = Utils::OpenDirectHandle(this); |
| EnsureNotPublished(info, "v8::FunctionTemplate::RemovePrototype"); |
| i::Isolate* i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| info->set_remove_prototype(true); |
| } |
| |
| // --- O b j e c t T e m p l a t e --- |
| |
| Local<ObjectTemplate> ObjectTemplate::New( |
| Isolate* v8_isolate, v8::Local<FunctionTemplate> constructor) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| API_RCS_SCOPE(i_isolate, ObjectTemplate, New); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| constexpr bool do_not_cache = false; |
| i::DirectHandle<i::ObjectTemplateInfo> obj = |
| i_isolate->factory()->NewObjectTemplateInfo( |
| Utils::OpenDirectHandle(*constructor, true), do_not_cache); |
| return Utils::ToLocal(obj); |
| } |
| |
| namespace { |
| // Ensure that the object template has a constructor. If no |
| // constructor is available we create one. |
| i::DirectHandle<i::FunctionTemplateInfo> EnsureConstructor( |
| i::Isolate* i_isolate, ObjectTemplate* object_template) { |
| i::Tagged<i::Object> obj = |
| Utils::OpenDirectHandle(object_template)->constructor(); |
| if (!IsUndefined(obj, i_isolate)) { |
| i::Tagged<i::FunctionTemplateInfo> info = |
| i::Cast<i::FunctionTemplateInfo>(obj); |
| return i::DirectHandle<i::FunctionTemplateInfo>(info, i_isolate); |
| } |
| Local<FunctionTemplate> templ = |
| FunctionTemplate::New(reinterpret_cast<Isolate*>(i_isolate)); |
| auto constructor = Utils::OpenDirectHandle(*templ); |
| i::FunctionTemplateInfo::SetInstanceTemplate( |
| i_isolate, constructor, Utils::OpenDirectHandle(object_template)); |
| Utils::OpenDirectHandle(object_template)->set_constructor(*constructor); |
| return constructor; |
| } |
| |
| template <typename Getter, typename Setter, typename Data, typename Template> |
| void TemplateSetAccessor(Template* template_obj, v8::Local<Name> name, |
| Getter getter, Setter setter, Data data, |
| PropertyAttribute attribute, bool replace_on_access, |
| SideEffectType getter_side_effect_type, |
| SideEffectType setter_side_effect_type) { |
| auto info = Utils::OpenDirectHandle(template_obj); |
| auto i_isolate = info->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| i::DirectHandle<i::AccessorInfo> accessor_info = MakeAccessorInfo( |
| i_isolate, name, getter, setter, data, replace_on_access); |
| { |
| i::DisallowGarbageCollection no_gc; |
| i::Tagged<i::AccessorInfo> raw = *accessor_info; |
| raw->set_initial_property_attributes( |
| static_cast<i::PropertyAttributes>(attribute)); |
| raw->set_getter_side_effect_type(getter_side_effect_type); |
| raw->set_setter_side_effect_type(setter_side_effect_type); |
| } |
| i::ApiNatives::AddNativeDataProperty(i_isolate, info, accessor_info); |
| } |
| } // namespace |
| |
| void Template::SetNativeDataProperty(v8::Local<Name> name, |
| AccessorNameGetterCallback getter, |
| AccessorNameSetterCallback setter, |
| v8::Local<Value> data, |
| PropertyAttribute attribute, |
| SideEffectType getter_side_effect_type, |
| SideEffectType setter_side_effect_type) { |
| TemplateSetAccessor(this, name, getter, setter, data, attribute, false, |
| getter_side_effect_type, setter_side_effect_type); |
| } |
| |
| void Template::SetLazyDataProperty(v8::Local<Name> name, |
| AccessorNameGetterCallback getter, |
| v8::Local<Value> data, |
| PropertyAttribute attribute, |
| SideEffectType getter_side_effect_type, |
| SideEffectType setter_side_effect_type) { |
| TemplateSetAccessor( |
| this, name, getter, static_cast<AccessorNameSetterCallback>(nullptr), |
| data, attribute, true, getter_side_effect_type, setter_side_effect_type); |
| } |
| |
| void Template::SetIntrinsicDataProperty(Local<Name> name, Intrinsic intrinsic, |
| PropertyAttribute attribute) { |
| auto templ = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = templ->GetIsolateChecked(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| i::ApiNatives::AddDataProperty(i_isolate, templ, |
| Utils::OpenDirectHandle(*name), intrinsic, |
| static_cast<i::PropertyAttributes>(attribute)); |
| } |
| |
| namespace { |
| enum class PropertyType { kNamed, kIndexed }; |
| template <PropertyType property_type, typename Getter, typename Setter, |
| typename Query, typename Descriptor, typename Deleter, |
| typename Enumerator, typename Definer> |
| i::DirectHandle<i::InterceptorInfo> CreateInterceptorInfo( |
| i::Isolate* i_isolate, Getter getter, Setter setter, Query query, |
| Descriptor descriptor, Deleter remover, Enumerator enumerator, |
| Definer definer, Local<Value> data, |
| base::Flags<PropertyHandlerFlags> flags) { |
| // TODO(saelo): instead of an in-sandbox struct with a lot of external |
| // pointers (with different tags), consider creating an object in trusted |
| // space instead. That way, only a single reference going out of the sandbox |
| // would be required. |
| auto obj = i::Cast<i::InterceptorInfo>(i_isolate->factory()->NewStruct( |
| i::INTERCEPTOR_INFO_TYPE, i::AllocationType::kOld)); |
| obj->set_flags(0); |
| |
| #define CALLBACK_TAG(NAME) \ |
| property_type == PropertyType::kNamed \ |
| ? internal::kApiNamedProperty##NAME##CallbackTag \ |
| : internal::kApiIndexedProperty##NAME##CallbackTag; |
| |
| if (getter != nullptr) { |
| constexpr internal::ExternalPointerTag tag = CALLBACK_TAG(Getter); |
| SET_FIELD_WRAPPED(i_isolate, obj, set_getter, getter, tag); |
| } |
| if (setter != nullptr) { |
| constexpr internal::ExternalPointerTag tag = CALLBACK_TAG(Setter); |
| SET_FIELD_WRAPPED(i_isolate, obj, set_setter, setter, tag); |
| } |
| if (query != nullptr) { |
| constexpr internal::ExternalPointerTag tag = CALLBACK_TAG(Query); |
| SET_FIELD_WRAPPED(i_isolate, obj, set_query, query, tag); |
| } |
| if (descriptor != nullptr) { |
| constexpr internal::ExternalPointerTag tag = CALLBACK_TAG(Descriptor); |
| SET_FIELD_WRAPPED(i_isolate, obj, set_descriptor, descriptor, tag); |
| } |
| if (remover != nullptr) { |
| constexpr internal::ExternalPointerTag tag = CALLBACK_TAG(Deleter); |
| SET_FIELD_WRAPPED(i_isolate, obj, set_deleter, remover, tag); |
| } |
| if (enumerator != nullptr) { |
| SET_FIELD_WRAPPED(i_isolate, obj, set_enumerator, enumerator, |
| internal::kApiIndexedPropertyEnumeratorCallbackTag); |
| } |
| if (definer != nullptr) { |
| constexpr internal::ExternalPointerTag tag = CALLBACK_TAG(Definer); |
| SET_FIELD_WRAPPED(i_isolate, obj, set_definer, definer, tag); |
| } |
| |
| #undef CALLBACK_TAG |
| |
| obj->set_can_intercept_symbols( |
| !(flags & PropertyHandlerFlags::kOnlyInterceptStrings)); |
| obj->set_non_masking(flags & PropertyHandlerFlags::kNonMasking); |
| obj->set_has_no_side_effect(flags & PropertyHandlerFlags::kHasNoSideEffect); |
| |
| if (data.IsEmpty()) { |
| data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate)); |
| } |
| obj->set_data(*Utils::OpenDirectHandle(*data)); |
| return obj; |
| } |
| |
| template <typename Getter, typename Setter, typename Query, typename Descriptor, |
| typename Deleter, typename Enumerator, typename Definer> |
| i::DirectHandle<i::InterceptorInfo> CreateNamedInterceptorInfo( |
| i::Isolate* i_isolate, Getter getter, Setter setter, Query query, |
| Descriptor descriptor, Deleter remover, Enumerator enumerator, |
| Definer definer, Local<Value> data, |
| base::Flags<PropertyHandlerFlags> flags) { |
| auto interceptor = CreateInterceptorInfo<PropertyType::kNamed>( |
| i_isolate, getter, setter, query, descriptor, remover, enumerator, |
| definer, data, flags); |
| interceptor->set_is_named(true); |
| return interceptor; |
| } |
| |
| template <typename Getter, typename Setter, typename Query, typename Descriptor, |
| typename Deleter, typename Enumerator, typename Definer> |
| i::DirectHandle<i::InterceptorInfo> CreateIndexedInterceptorInfo( |
| i::Isolate* i_isolate, Getter getter, Setter setter, Query query, |
| Descriptor descriptor, Deleter remover, Enumerator enumerator, |
| Definer definer, Local<Value> data, |
| base::Flags<PropertyHandlerFlags> flags) { |
| auto interceptor = CreateInterceptorInfo<PropertyType::kIndexed>( |
| i_isolate, getter, setter, query, descriptor, remover, enumerator, |
| definer, data, flags); |
| interceptor->set_is_named(false); |
| return interceptor; |
| } |
| |
| template <typename Getter, typename Setter, typename Query, typename Descriptor, |
| typename Deleter, typename Enumerator, typename Definer> |
| void ObjectTemplateSetNamedPropertyHandler( |
| ObjectTemplate* templ, Getter getter, Setter setter, Query query, |
| Descriptor descriptor, Deleter remover, Enumerator enumerator, |
| Definer definer, Local<Value> data, PropertyHandlerFlags flags) { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(templ)->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto cons = EnsureConstructor(i_isolate, templ); |
| EnsureNotPublished(cons, "ObjectTemplateSetNamedPropertyHandler"); |
| auto obj = |
| CreateNamedInterceptorInfo(i_isolate, getter, setter, query, descriptor, |
| remover, enumerator, definer, data, flags); |
| i::FunctionTemplateInfo::SetNamedPropertyHandler(i_isolate, cons, obj); |
| } |
| } // namespace |
| |
| void ObjectTemplate::SetHandler( |
| const NamedPropertyHandlerConfiguration& config) { |
| ObjectTemplateSetNamedPropertyHandler( |
| this, config.getter, config.setter, config.query, config.descriptor, |
| config.deleter, config.enumerator, config.definer, config.data, |
| config.flags); |
| } |
| |
| void ObjectTemplate::MarkAsUndetectable() { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto cons = EnsureConstructor(i_isolate, this); |
| EnsureNotPublished(cons, "v8::ObjectTemplate::MarkAsUndetectable"); |
| cons->set_undetectable(true); |
| } |
| |
| void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback, |
| Local<Value> data) { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto cons = EnsureConstructor(i_isolate, this); |
| EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallback"); |
| |
| i::DirectHandle<i::Struct> struct_info = i_isolate->factory()->NewStruct( |
| i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); |
| auto info = i::Cast<i::AccessCheckInfo>(struct_info); |
| |
| SET_FIELD_WRAPPED(i_isolate, info, set_callback, callback, |
| internal::kApiAccessCheckCallbackTag); |
| info->set_named_interceptor(i::Smi::zero()); |
| info->set_indexed_interceptor(i::Smi::zero()); |
| |
| if (data.IsEmpty()) { |
| data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate)); |
| } |
| info->set_data(*Utils::OpenDirectHandle(*data)); |
| |
| i::FunctionTemplateInfo::SetAccessCheckInfo(i_isolate, cons, info); |
| cons->set_needs_access_check(true); |
| } |
| |
| void ObjectTemplate::SetAccessCheckCallbackAndHandler( |
| AccessCheckCallback callback, |
| const NamedPropertyHandlerConfiguration& named_handler, |
| const IndexedPropertyHandlerConfiguration& indexed_handler, |
| Local<Value> data) { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto cons = EnsureConstructor(i_isolate, this); |
| EnsureNotPublished(cons, |
| "v8::ObjectTemplate::SetAccessCheckCallbackWithHandler"); |
| |
| i::DirectHandle<i::Struct> struct_info = i_isolate->factory()->NewStruct( |
| i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); |
| auto info = i::Cast<i::AccessCheckInfo>(struct_info); |
| |
| SET_FIELD_WRAPPED(i_isolate, info, set_callback, callback, |
| internal::kApiAccessCheckCallbackTag); |
| auto named_interceptor = CreateNamedInterceptorInfo( |
| i_isolate, named_handler.getter, named_handler.setter, |
| named_handler.query, named_handler.descriptor, named_handler.deleter, |
| named_handler.enumerator, named_handler.definer, named_handler.data, |
| named_handler.flags); |
| info->set_named_interceptor(*named_interceptor); |
| auto indexed_interceptor = CreateIndexedInterceptorInfo( |
| i_isolate, indexed_handler.getter, indexed_handler.setter, |
| indexed_handler.query, indexed_handler.descriptor, |
| indexed_handler.deleter, indexed_handler.enumerator, |
| indexed_handler.definer, indexed_handler.data, indexed_handler.flags); |
| info->set_indexed_interceptor(*indexed_interceptor); |
| |
| if (data.IsEmpty()) { |
| data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate)); |
| } |
| info->set_data(*Utils::OpenDirectHandle(*data)); |
| |
| i::FunctionTemplateInfo::SetAccessCheckInfo(i_isolate, cons, info); |
| cons->set_needs_access_check(true); |
| } |
| |
| void ObjectTemplate::SetHandler( |
| const IndexedPropertyHandlerConfiguration& config) { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto cons = EnsureConstructor(i_isolate, this); |
| EnsureNotPublished(cons, "v8::ObjectTemplate::SetHandler"); |
| auto obj = CreateIndexedInterceptorInfo( |
| i_isolate, config.getter, config.setter, config.query, config.descriptor, |
| config.deleter, config.enumerator, config.definer, config.data, |
| config.flags); |
| i::FunctionTemplateInfo::SetIndexedPropertyHandler(i_isolate, cons, obj); |
| } |
| |
| void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback, |
| Local<Value> data) { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| auto cons = EnsureConstructor(i_isolate, this); |
| EnsureNotPublished(cons, "v8::ObjectTemplate::SetCallAsFunctionHandler"); |
| DCHECK_NOT_NULL(callback); |
| |
| // This template is just a container for callback and data values and thus |
| // it's not supposed to be instantiated. Don't cache it. |
| constexpr bool do_not_cache = true; |
| constexpr int length = 0; |
| i::DirectHandle<i::FunctionTemplateInfo> templ = |
| i_isolate->factory()->NewFunctionTemplateInfo(length, do_not_cache); |
| templ->set_is_object_template_call_handler(true); |
| Utils::ToLocal(templ)->SetCallHandler(callback, data); |
| i::FunctionTemplateInfo::SetInstanceCallHandler(i_isolate, cons, templ); |
| } |
| |
| int ObjectTemplate::InternalFieldCount() const { |
| return Utils::OpenDirectHandle(this)->embedder_field_count(); |
| } |
| |
| void ObjectTemplate::SetInternalFieldCount(int value) { |
| i::Isolate* i_isolate = Utils::OpenDirectHandle(this)->GetIsolate(); |
| if (!Utils::ApiCheck(i::Smi::IsValid(value), |
| "v8::ObjectTemplate::SetInternalFieldCount()", |
| "Invalid embedder field count")) { |
| return; |
| } |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| if (value > 0) { |
| // The embedder field count is set by the constructor function's |
| // construct code, so we ensure that there is a constructor |
| // function to do the setting. |
| EnsureConstructor(i_isolate, this); |
| } |
| Utils::OpenDirectHandle(this)->set_embedder_field_count(value); |
| } |
| |
| bool ObjectTemplate::IsImmutableProto() const { |
| return Utils::OpenDirectHandle(this)->immutable_proto(); |
| } |
| |
| void ObjectTemplate::SetImmutableProto() { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| self->set_immutable_proto(true); |
| } |
| |
| bool ObjectTemplate::IsCodeLike() const { |
| return Utils::OpenDirectHandle(this)->code_like(); |
| } |
| |
| void ObjectTemplate::SetCodeLike() { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| self->set_code_like(true); |
| } |
| |
| Local<DictionaryTemplate> DictionaryTemplate::New( |
| Isolate* isolate, MemorySpan<const std::string_view> names) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| API_RCS_SCOPE(i_isolate, DictionaryTemplate, New); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| return Utils::ToLocal(i::DictionaryTemplateInfo::Create(i_isolate, names)); |
| } |
| |
| Local<Object> DictionaryTemplate::NewInstance( |
| Local<Context> context, MemorySpan<MaybeLocal<Value>> property_values) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); |
| API_RCS_SCOPE(i_isolate, DictionaryTemplate, NewInstance); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| auto self = Utils::OpenDirectHandle(this); |
| return ToApiHandle<Object>(i::DictionaryTemplateInfo::NewInstance( |
| Utils::OpenDirectHandle(*context), self, property_values)); |
| } |
| |
| // --- S c r i p t s --- |
| |
| // Internally, UnboundScript and UnboundModuleScript are SharedFunctionInfos, |
| // and Script is a JSFunction. |
| |
| ScriptCompiler::CachedData::CachedData(const uint8_t* data_, int length_, |
| BufferPolicy buffer_policy_) |
| : data(data_), |
| length(length_), |
| rejected(false), |
| buffer_policy(buffer_policy_) {} |
| |
| ScriptCompiler::CachedData::~CachedData() { |
| if (buffer_policy == BufferOwned) { |
| delete[] data; |
| } |
| } |
| |
| ScriptCompiler::CachedData::CompatibilityCheckResult |
| ScriptCompiler::CachedData::CompatibilityCheck(Isolate* isolate) { |
| i::AlignedCachedData aligned(data, length); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| i::SerializedCodeSanityCheckResult result; |
| i::SerializedCodeData scd = |
| i::SerializedCodeData::FromCachedDataWithoutSource( |
| i_isolate->AsLocalIsolate(), &aligned, &result); |
| return static_cast<ScriptCompiler::CachedData::CompatibilityCheckResult>( |
| result); |
| } |
| |
| ScriptCompiler::StreamedSource::StreamedSource( |
| std::unique_ptr<ExternalSourceStream> stream, Encoding encoding) |
| : impl_(new i::ScriptStreamingData(std::move(stream), encoding)) {} |
| |
| ScriptCompiler::StreamedSource::~StreamedSource() = default; |
| |
| Local<Script> UnboundScript::BindToCurrentContext() { |
| auto function_info = Utils::OpenDirectHandle(this); |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*function_info)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*function_info); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::JSFunction> function = |
| i::Factory::JSFunctionBuilder{i_isolate, function_info, |
| i_isolate->native_context()} |
| .Build(); |
| return ToApiHandle<Script>(function); |
| } |
| |
| int UnboundScript::GetId() const { |
| auto function_info = Utils::OpenDirectHandle(this); |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*function_info)); |
| API_RCS_SCOPE(i::GetIsolateFromWritableObject(*function_info), UnboundScript, |
| GetId); |
| return i::Cast<i::Script>(function_info->script())->id(); |
| } |
| |
| int UnboundScript::GetLineNumber(int code_pos) { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| API_RCS_SCOPE(i_isolate, UnboundScript, GetLineNumber); |
| i::DirectHandle<i::Script> script(i::Cast<i::Script>(obj->script()), |
| i_isolate); |
| return i::Script::GetLineNumber(script, code_pos); |
| } else { |
| return -1; |
| } |
| } |
| |
| int UnboundScript::GetColumnNumber(int code_pos) { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| API_RCS_SCOPE(i_isolate, UnboundScript, GetColumnNumber); |
| i::DirectHandle<i::Script> script(i::Cast<i::Script>(obj->script()), |
| i_isolate); |
| return i::Script::GetColumnNumber(script, code_pos); |
| } else { |
| return -1; |
| } |
| } |
| |
| Local<Value> UnboundScript::GetScriptName() { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| API_RCS_SCOPE(i_isolate, UnboundScript, GetName); |
| i::Tagged<i::Object> name = i::Cast<i::Script>(obj->script())->name(); |
| return Utils::ToLocal(i::direct_handle(name, i_isolate)); |
| } else { |
| return Local<String>(); |
| } |
| } |
| |
| Local<Value> UnboundScript::GetSourceURL() { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| API_RCS_SCOPE(i_isolate, UnboundScript, GetSourceURL); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::Tagged<i::Object> url = i::Cast<i::Script>(obj->script())->source_url(); |
| return Utils::ToLocal(i::direct_handle(url, i_isolate)); |
| } else { |
| return Local<String>(); |
| } |
| } |
| |
| Local<Value> UnboundScript::GetSourceMappingURL() { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| API_RCS_SCOPE(i_isolate, UnboundScript, GetSourceMappingURL); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::Tagged<i::Object> url = |
| i::Cast<i::Script>(obj->script())->source_mapping_url(); |
| return Utils::ToLocal(i::direct_handle(url, i_isolate)); |
| } else { |
| return Local<String>(); |
| } |
| } |
| |
| Local<Value> UnboundModuleScript::GetSourceURL() { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| API_RCS_SCOPE(i_isolate, UnboundModuleScript, GetSourceURL); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::Tagged<i::Object> url = i::Cast<i::Script>(obj->script())->source_url(); |
| return Utils::ToLocal(i::direct_handle(url, i_isolate)); |
| } else { |
| return Local<String>(); |
| } |
| } |
| |
| Local<Value> UnboundModuleScript::GetSourceMappingURL() { |
| auto obj = Utils::OpenDirectHandle(this); |
| if (i::IsScript(obj->script())) { |
| // TODO(jgruber): Remove this DCHECK once Function::GetUnboundScript is |
| // gone. |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*obj)); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| API_RCS_SCOPE(i_isolate, UnboundModuleScript, GetSourceMappingURL); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::Tagged<i::Object> url = |
| i::Cast<i::Script>(obj->script())->source_mapping_url(); |
| return Utils::ToLocal(i::direct_handle(url, i_isolate)); |
| } else { |
| return Local<String>(); |
| } |
| } |
| |
| MaybeLocal<Value> Script::Run(Local<Context> context) { |
| return Run(context, Local<Data>()); |
| } |
| |
| MaybeLocal<Value> Script::Run(Local<Context> context, |
| Local<Data> host_defined_options) { |
| auto v8_isolate = context->GetIsolate(); |
| auto i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| TRACE_EVENT_CALL_STATS_SCOPED(i_isolate, "v8", "V8.Execute"); |
| ENTER_V8(i_isolate, context, Script, Run, InternalEscapableScope); |
| i::TimerEventScope<i::TimerEventExecute> timer_scope(i_isolate); |
| i::NestedTimedHistogramScope execute_timer(i_isolate->counters()->execute(), |
| i_isolate); |
| i::AggregatingHistogramTimerScope histogram_timer( |
| i_isolate->counters()->compile_lazy()); |
| |
| #if defined(V8_ENABLE_ETW_STACK_WALKING) |
| // In case ETW has been activated, tasks to log existing code are |
| // created. But in case the task runner does not run those before |
| // starting to execute code (as it happens in d8, that will run |
| // first the code from prompt), then that code will not have |
| // JIT instrumentation on time. |
| // |
| // To avoid this, on running scripts check first if JIT code log is |
| // pending and generate immediately. |
| if (i::v8_flags.enable_etw_stack_walking || |
| i::v8_flags.enable_etw_by_custom_filter_only) { |
| i::ETWJITInterface::MaybeSetHandlerNow(i_isolate); |
| } |
| #endif // V8_ENABLE_ETW_STACK_WALKING |
| auto fun = i::Cast<i::JSFunction>(Utils::OpenDirectHandle(this)); |
| i::DirectHandle<i::Object> receiver = i_isolate->global_proxy(); |
| // TODO(cbruni, chromium:1244145): Remove once migrated to the context. |
| i::DirectHandle<i::Object> options( |
| i::Cast<i::Script>(fun->shared()->script())->host_defined_options(), |
| i_isolate); |
| Local<Value> result; |
| has_exception = !ToLocal<Value>( |
| i::Execution::CallScript(i_isolate, fun, receiver, options), &result); |
| |
| RETURN_ON_FAILED_EXECUTION(Value); |
| RETURN_ESCAPED(result); |
| } |
| |
| Local<Value> ScriptOrModule::GetResourceName() { |
| auto obj = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| return ToApiHandle<Value>(i::direct_handle(obj->resource_name(), i_isolate)); |
| } |
| |
| Local<Data> ScriptOrModule::HostDefinedOptions() { |
| auto obj = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*obj); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| return ToApiHandle<Data>( |
| i::direct_handle(obj->host_defined_options(), i_isolate)); |
| } |
| |
| Local<UnboundScript> Script::GetUnboundScript() { |
| i::DisallowGarbageCollection no_gc; |
| auto obj = Utils::OpenDirectHandle(this); |
| i::DirectHandle<i::SharedFunctionInfo> sfi(obj->shared(), obj->GetIsolate()); |
| DCHECK(!i::HeapLayout::InReadOnlySpace(*sfi)); |
| return ToApiHandle<UnboundScript>(sfi); |
| } |
| |
| Local<Value> Script::GetResourceName() { |
| i::DisallowGarbageCollection no_gc; |
| auto func = Utils::OpenDirectHandle(this); |
| i::Tagged<i::SharedFunctionInfo> sfi = func->shared(); |
| CHECK(IsScript(sfi->script())); |
| i::Isolate* i_isolate = func->GetIsolate(); |
| return ToApiHandle<Value>( |
| i::direct_handle(i::Cast<i::Script>(sfi->script())->name(), i_isolate)); |
| } |
| |
| std::vector<int> Script::GetProducedCompileHints() const { |
| i::DisallowGarbageCollection no_gc; |
| auto func = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = func->GetIsolate(); |
| i::Tagged<i::SharedFunctionInfo> sfi = func->shared(); |
| CHECK(IsScript(sfi->script())); |
| i::Tagged<i::Script> script = i::Cast<i::Script>(sfi->script()); |
| i::Tagged<i::Object> maybe_array_list = |
| script->compiled_lazy_function_positions(); |
| std::vector<int> result; |
| if (!IsUndefined(maybe_array_list, i_isolate)) { |
| i::Tagged<i::ArrayList> array_list = |
| i::Cast<i::ArrayList>(maybe_array_list); |
| result.reserve(array_list->length()); |
| for (int i = 0; i < array_list->length(); ++i) { |
| i::Tagged<i::Object> item = array_list->get(i); |
| CHECK(IsSmi(item)); |
| result.push_back(i::Smi::ToInt(item)); |
| } |
| } |
| return result; |
| } |
| |
| Local<CompileHintsCollector> Script::GetCompileHintsCollector() const { |
| i::DisallowGarbageCollection no_gc; |
| auto func = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = func->GetIsolate(); |
| i::Tagged<i::SharedFunctionInfo> sfi = func->shared(); |
| CHECK(IsScript(sfi->script())); |
| i::DirectHandle<i::Script> script(i::Cast<i::Script>(sfi->script()), |
| i_isolate); |
| return ToApiHandle<CompileHintsCollector>(script); |
| } |
| |
| std::vector<int> CompileHintsCollector::GetCompileHints( |
| Isolate* v8_isolate) const { |
| i::DisallowGarbageCollection no_gc; |
| auto script = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| i::Tagged<i::Object> maybe_array_list = |
| script->compiled_lazy_function_positions(); |
| std::vector<int> result; |
| if (!IsUndefined(maybe_array_list, i_isolate)) { |
| i::Tagged<i::ArrayList> array_list = |
| i::Cast<i::ArrayList>(maybe_array_list); |
| result.reserve(array_list->length()); |
| for (int i = 0; i < array_list->length(); ++i) { |
| i::Tagged<i::Object> item = array_list->get(i); |
| CHECK(IsSmi(item)); |
| result.push_back(i::Smi::ToInt(item)); |
| } |
| } |
| return result; |
| } |
| |
| // static |
| Local<PrimitiveArray> PrimitiveArray::New(Isolate* v8_isolate, int length) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| Utils::ApiCheck(length >= 0, "v8::PrimitiveArray::New", |
| "length must be equal or greater than zero"); |
| i::DirectHandle<i::FixedArray> array = |
| i_isolate->factory()->NewFixedArray(length); |
| return ToApiHandle<PrimitiveArray>(array); |
| } |
| |
| int PrimitiveArray::Length() const { |
| return Utils::OpenDirectHandle(this)->length(); |
| } |
| |
| void PrimitiveArray::Set(Isolate* v8_isolate, int index, |
| Local<Primitive> item) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| auto array = Utils::OpenDirectHandle(this); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| Utils::ApiCheck(index >= 0 && index < array->length(), |
| "v8::PrimitiveArray::Set", |
| "index must be greater than or equal to 0 and less than the " |
| "array length"); |
| array->set(index, *Utils::OpenDirectHandle(*item)); |
| } |
| |
| Local<Primitive> PrimitiveArray::Get(Isolate* v8_isolate, int index) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| auto array = Utils::OpenDirectHandle(this); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| Utils::ApiCheck(index >= 0 && index < array->length(), |
| "v8::PrimitiveArray::Get", |
| "index must be greater than or equal to 0 and less than the " |
| "array length"); |
| return ToApiHandle<Primitive>(i::direct_handle(array->get(index), i_isolate)); |
| } |
| |
| void v8::PrimitiveArray::CheckCast(v8::Data* that) { |
| auto obj = Utils::OpenDirectHandle(that); |
| Utils::ApiCheck( |
| i::IsFixedArray(*obj), "v8::PrimitiveArray::Cast", |
| "Value is not a PrimitiveArray; this is a temporary issue, v8::Data and " |
| "v8::PrimitiveArray will not be compatible in the future"); |
| } |
| |
| int FixedArray::Length() const { |
| return Utils::OpenDirectHandle(this)->length(); |
| } |
| |
| Local<Data> FixedArray::Get(Local<Context> context, int i) const { |
| auto self = Utils::OpenDirectHandle(this); |
| auto i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); |
| CHECK_LT(i, self->length()); |
| return ToApiHandle<Data>(i::direct_handle(self->get(i), i_isolate)); |
| } |
| |
| Local<String> ModuleRequest::GetSpecifier() const { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| return ToApiHandle<String>(i::direct_handle(self->specifier(), i_isolate)); |
| } |
| |
| ModuleImportPhase ModuleRequest::GetPhase() const { |
| auto self = Utils::OpenDirectHandle(this); |
| return self->phase(); |
| } |
| |
| int ModuleRequest::GetSourceOffset() const { |
| return Utils::OpenDirectHandle(this)->position(); |
| } |
| |
| Local<FixedArray> ModuleRequest::GetImportAttributes() const { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| return ToApiHandle<FixedArray>( |
| i::direct_handle(self->import_attributes(), i_isolate)); |
| } |
| |
| Module::Status Module::GetStatus() const { |
| auto self = Utils::OpenDirectHandle(this); |
| switch (self->status()) { |
| case i::Module::kUnlinked: |
| case i::Module::kPreLinking: |
| return kUninstantiated; |
| case i::Module::kLinking: |
| return kInstantiating; |
| case i::Module::kLinked: |
| return kInstantiated; |
| case i::Module::kEvaluating: |
| return kEvaluating; |
| case i::Module::kEvaluatingAsync: |
| // TODO(syg): Expose kEvaluatingAsync in API as well. |
| case i::Module::kEvaluated: |
| return kEvaluated; |
| case i::Module::kErrored: |
| return kErrored; |
| } |
| UNREACHABLE(); |
| } |
| |
| Local<Value> Module::GetException() const { |
| Utils::ApiCheck(GetStatus() == kErrored, "v8::Module::GetException", |
| "Module status must be kErrored"); |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| return ToApiHandle<Value>(i::direct_handle(self->GetException(), i_isolate)); |
| } |
| |
| Local<FixedArray> Module::GetModuleRequests() const { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| if (i::IsSyntheticModule(*self)) { |
| // Synthetic modules are leaf nodes in the module graph. They have no |
| // ModuleRequests. |
| return ToApiHandle<FixedArray>(i_isolate->factory()->empty_fixed_array()); |
| } else { |
| return ToApiHandle<FixedArray>(i::direct_handle( |
| i::Cast<i::SourceTextModule>(self)->info()->module_requests(), |
| i_isolate)); |
| } |
| } |
| |
| Location Module::SourceOffsetToLocation(int offset) const { |
| auto self = Utils::OpenDirectHandle(this); |
| i::Isolate* i_isolate = self->GetIsolate(); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::HandleScope scope(i_isolate); |
| Utils::ApiCheck( |
| i::IsSourceTextModule(*self), "v8::Module::SourceOffsetToLocation", |
| "v8::Module::SourceOffsetToLocation must be used on an SourceTextModule"); |
| i::DirectHandle<i::Script> script( |
| i::Cast<i::SourceTextModule>(self)->GetScript(), i_isolate); |
| i::Script::PositionInfo info; |
| i::Script::GetPositionInfo(script, offset, &info); |
| return v8::Location(info.line, info.column); |
| } |
| |
| Local<Value> Module::GetModuleNamespace() { |
| Utils::ApiCheck( |
| GetStatus() >= kInstantiated, "v8::Module::GetModuleNamespace", |
| "v8::Module::GetModuleNamespace must be used on an instantiated module"); |
| auto self = Utils::OpenHandle(this); |
| auto i_isolate = self->GetIsolate(); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| i::DirectHandle<i::JSModuleNamespace> module_namespace = |
| i::Module::GetModuleNamespace(i_isolate, self); |
| return ToApiHandle<Value>(module_namespace); |
| } |
| |
| Local<UnboundModuleScript> Module::GetUnboundModuleScript() { |
| auto self = Utils::OpenDirectHandle(this); |
| Utils::ApiCheck( |
| i::IsSourceTextModule(*self), "v8::Module::GetUnboundModuleScript", |
| "v8::Module::GetUnboundModuleScript must be used on an SourceTextModule"); |
| auto i_isolate = self->GetIsolate(); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| return ToApiHandle<UnboundModuleScript>(i::direct_handle( |
| i::Cast<i::SourceTextModule>(self)->GetSharedFunctionInfo(), i_isolate)); |
| } |
| |
| int Module::ScriptId() const { |
| i::Tagged<i::Module> self = *Utils::OpenDirectHandle(this); |
| Utils::ApiCheck(i::IsSourceTextModule(self), "v8::Module::ScriptId", |
| "v8::Module::ScriptId must be used on an SourceTextModule"); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(self->GetIsolate()); |
| return i::Cast<i::SourceTextModule>(self)->GetScript()->id(); |
| } |
| |
| bool Module::HasTopLevelAwait() const { |
| i::Tagged<i::Module> self = *Utils::OpenDirectHandle(this); |
| if (!i::IsSourceTextModule(self)) return false; |
| return i::Cast<i::SourceTextModule>(self)->has_toplevel_await(); |
| } |
| |
| bool Module::IsGraphAsync() const { |
| Utils::ApiCheck( |
| GetStatus() >= kInstantiated, "v8::Module::IsGraphAsync", |
| "v8::Module::IsGraphAsync must be used on an instantiated module"); |
| i::Tagged<i::Module> self = *Utils::OpenDirectHandle(this); |
| auto i_isolate = self->GetIsolate(); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| return self->IsGraphAsync(i_isolate); |
| } |
| |
| bool Module::IsSourceTextModule() const { |
| auto self = Utils::OpenDirectHandle(this); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(self->GetIsolate()); |
| return i::IsSourceTextModule(*self); |
| } |
| |
| bool Module::IsSyntheticModule() const { |
| auto self = Utils::OpenDirectHandle(this); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(self->GetIsolate()); |
| return i::IsSyntheticModule(*self); |
| } |
| |
| int Module::GetIdentityHash() const { |
| auto self = Utils::OpenDirectHandle(this); |
| DCHECK_NO_SCRIPT_NO_EXCEPTION(self->GetIsolate()); |
| return self->hash(); |
| } |
| |
| Maybe<bool> Module::InstantiateModule(Local<Context> context, |
| ResolveModuleCallback module_callback, |
| ResolveSourceCallback source_callback) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); |
| ENTER_V8(i_isolate, context, Module, InstantiateModule, i::HandleScope); |
| has_exception = |
| !i::Module::Instantiate(i_isolate, Utils::OpenHandle(this), context, |
| module_callback, source_callback); |
| RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); |
| return Just(true); |
| } |
| |
| MaybeLocal<Value> Module::Evaluate(Local<Context> context) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); |
| TRACE_EVENT_CALL_STATS_SCOPED(i_isolate, "v8", "V8.Execute"); |
| ENTER_V8(i_isolate, context, Module, Evaluate, InternalEscapableScope); |
| i::TimerEventScope<i::TimerEventExecute> timer_scope(i_isolate); |
| i::NestedTimedHistogramScope execute_timer(i_isolate->counters()->execute(), |
| i_isolate); |
| i::AggregatingHistogramTimerScope timer( |
| i_isolate->counters()->compile_lazy()); |
| |
| auto self = Utils::OpenHandle(this); |
| Utils::ApiCheck(self->status() >= i::Module::kLinked, "Module::Evaluate", |
| "Expected instantiated module"); |
| |
| Local<Value> result; |
| has_exception = !ToLocal(i::Module::Evaluate(i_isolate, self), &result); |
| RETURN_ON_FAILED_EXECUTION(Value); |
| RETURN_ESCAPED(result); |
| } |
| |
| Local<Module> Module::CreateSyntheticModule( |
| Isolate* v8_isolate, Local<String> module_name, |
| const MemorySpan<const Local<String>>& export_names, |
| v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); |
| auto i_module_name = Utils::OpenDirectHandle(*module_name); |
| i::DirectHandle<i::FixedArray> i_export_names = |
| i_isolate->factory()->NewFixedArray( |
| static_cast<int>(export_names.size())); |
| for (int i = 0; i < i_export_names->length(); ++i) { |
| i::DirectHandle<i::String> str = i_isolate->factory()->InternalizeString( |
| Utils::OpenDirectHandle(*export_names[i])); |
| i_export_names->set(i, *str); |
| } |
| return v8::Utils::ToLocal( |
| i::DirectHandle<i::Module>(i_isolate->factory()->NewSyntheticModule( |
| i_module_name, i_export_names, evaluation_steps))); |
| } |
| |
| Maybe<bool> Module::SetSyntheticModuleExport(Isolate* v8_isolate, |
| Local<String> export_name, |
| Local<v8::Value> export_value) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| auto i_export_name = Utils::OpenDirectHandle(*export_name); |
| auto i_export_value = Utils::OpenDirectHandle(*export_value); |
| auto self = Utils::OpenDirectHandle(this); |
| Utils::ApiCheck(i::IsSyntheticModule(*self), |
| "v8::Module::SyntheticModuleSetExport", |
| "v8::Module::SyntheticModuleSetExport must only be called on " |
| "a SyntheticModule"); |
| ENTER_V8_NO_SCRIPT(i_isolate, v8_isolate->GetCurrentContext(), Module, |
| SetSyntheticModuleExport, i::HandleScope); |
| has_exception = i::SyntheticModule::SetExport( |
| i_isolate, i::Cast<i::SyntheticModule>(self), |
| i_export_name, i_export_value) |
| .IsNothing(); |
| RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); |
| return Just(true); |
| } |
| |
| std::pair<LocalVector<Module>, LocalVector<Message>> |
| Module::GetStalledTopLevelAwaitMessages(Isolate* isolate) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| auto self = Utils::OpenDirectHandle(this); |
| Utils::ApiCheck(i::IsSourceTextModule(*self), |
| "v8::Module::GetStalledTopLevelAwaitMessages", |
| "v8::Module::GetStalledTopLevelAwaitMessages must only be " |
| "called on a SourceTextModule"); |
| std::pair<i::DirectHandleVector<i::SourceTextModule>, |
| i::DirectHandleVector<i::JSMessageObject>> |
| stalled_awaits = |
| i::Cast<i::SourceTextModule>(self)->GetStalledTopLevelAwaitMessages( |
| i_isolate); |
| |
| LocalVector<Module> modules(isolate); |
| if (size_t stalled_awaits_count = stalled_awaits.first.size(); |
| stalled_awaits_count > 0) { |
| modules.reserve(stalled_awaits_count); |
| for (auto module : stalled_awaits.first) |
| modules.push_back(ToApiHandle<Module>(module)); |
| } |
| LocalVector<Message> messages(isolate); |
| if (size_t stalled_awaits_count = stalled_awaits.second.size(); |
| stalled_awaits_count > 0) { |
| messages.reserve(stalled_awaits_count); |
| for (auto message : stalled_awaits.second) |
| messages.push_back(ToApiHandle<Message>(message)); |
| } |
| |
| return {modules, messages}; |
| } |
| |
| namespace { |
| |
| i::ScriptDetails GetScriptDetails( |
| i::Isolate* i_isolate, Local<Value> resource_name, int resource_line_offset, |
| int resource_column_offset, Local<Value> source_map_url, |
| Local<Data> host_defined_options, ScriptOriginOptions origin_options) { |
| i::ScriptDetails script_details(Utils::OpenHandle(*(resource_name), true), |
| origin_options); |
| script_details.line_offset = resource_line_offset; |
| script_details.column_offset = resource_column_offset; |
| script_details.host_defined_options = |
| host_defined_options.IsEmpty() |
| ? i_isolate->factory()->empty_fixed_array() |
| : Utils::OpenHandle(*(host_defined_options)); |
| if (!source_map_url.IsEmpty()) { |
| script_details.source_map_url = Utils::OpenHandle(*(source_map_url)); |
| } |
| return script_details; |
| } |
| |
| } // namespace |
| |
| MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( |
| Isolate* v8_isolate, Source* source, CompileOptions options, |
| NoCacheReason no_cache_reason) { |
| auto i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| TRACE_EVENT_CALL_STATS_SCOPED(i_isolate, "v8", "V8.ScriptCompiler"); |
| ENTER_V8_NO_SCRIPT(i_isolate, v8_isolate->GetCurrentContext(), ScriptCompiler, |
| CompileUnbound, InternalEscapableScope); |
| |
| auto str = Utils::OpenHandle(*(source->source_string)); |
| |
| i::DirectHandle<i::SharedFunctionInfo> result; |
| TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileScript"); |
| i::ScriptDetails script_details = GetScriptDetails( |
| i_isolate, source->resource_name, source->resource_line_offset, |
| source->resource_column_offset, source->source_map_url, |
| source->host_defined_options, source->resource_options); |
| |
| i::MaybeDirectHandle<i::SharedFunctionInfo> maybe_function_info; |
| if (options & kConsumeCodeCache) { |
| if (source->consume_cache_task) { |
| // Take ownership of the internal deserialization task and clear it off |
| // the consume task on the source. |
| DCHECK_NOT_NULL(source->consume_cache_task->impl_); |
| std::unique_ptr<i::BackgroundDeserializeTask> deserialize_task = |
| std::move(source->consume_cache_task->impl_); |
| maybe_function_info = |
| i::Compiler::GetSharedFunctionInfoForScriptWithDeserializeTask( |
| i_isolate, str, script_details, deserialize_task.get(), options, |
| no_cache_reason, i::NOT_NATIVES_CODE, |
| &source->compilation_details); |
| source->cached_data->rejected = deserialize_task->rejected(); |
| } else { |
| DCHECK(source->cached_data); |
| // AlignedCachedData takes care of pointer-aligning the data. |
| auto cached_data = std::make_unique<i::AlignedCachedData>( |
| source->cached_data->data, source->cached_data->length); |
| maybe_function_info = |
| i::Compiler::GetSharedFunctionInfoForScriptWithCachedData( |
| i_isolate, str, script_details, cached_data.get(), options, |
| no_cache_reason, i::NOT_NATIVES_CODE, |
| &source->compilation_details); |
| source->cached_data->rejected = cached_data->rejected(); |
| } |
| } else if (options & kConsumeCompileHints) { |
| maybe_function_info = |
| i::Compiler::GetSharedFunctionInfoForScriptWithCompileHints( |
| i_isolate, str, script_details, source->compile_hint_callback, |
| source->compile_hint_callback_data, options, no_cache_reason, |
| i::NOT_NATIVES_CODE, &source->compilation_details); |
| } else { |
| // Compile without any cache. |
| maybe_function_info = i::Compiler::GetSharedFunctionInfoForScript( |
| i_isolate, str, script_details, options, no_cache_reason, |
| i::NOT_NATIVES_CODE, &source->compilation_details); |
| } |
| |
| has_exception = !maybe_function_info.ToHandle(&result); |
| DCHECK_IMPLIES(!has_exception, !i::HeapLayout::InReadOnlySpace(*result)); |
| RETURN_ON_FAILED_EXECUTION(UnboundScript); |
| RETURN_ESCAPED(ToApiHandle<UnboundScript>(result)); |
| } |
| |
| MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundScript( |
| Isolate* v8_isolate, Source* source, CompileOptions options, |
| NoCacheReason no_cache_reason) { |
| Utils::ApiCheck( |
| !source->GetResourceOptions().IsModule(), |
| "v8::ScriptCompiler::CompileUnbo
|