// 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 // For min #include // For isnan. #include #include #include #include // For move #include #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-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-unwinder-state.h" #include "include/v8-util.h" #include "include/v8-wasm.h" #include "src/api/api-inl.h" #include "src/api/api-natives.h" #include "src/base/functional.h" #include "src/base/logging.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/baseline/baseline-batch-compiler.h" #include "src/builtins/accessors.h" #include "src/builtins/builtins-utils.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" #if V8_ENABLE_WEBASSEMBLY #include "src/debug/debug-wasm-objects.h" #endif // V8_ENABLE_WEBASSEMBLY #include "src/debug/liveedit.h" #include "src/deoptimizer/deoptimizer.h" #include "src/diagnostics/gdb-jit.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/runtime-profiler.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/heap/embedder-tracing.h" #include "src/heap/heap-inl.h" #include "src/heap/heap-write-barrier.h" #include "src/heap/safepoint.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/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/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" #include "src/objects/js-collection-inl.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/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/stack-frame-info-inl.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/runtime/runtime.h" #include "src/security/external-pointer.h" #include "src/security/vm-cage.h" #include "src/snapshot/code-serializer.h" #include "src/snapshot/embedded/embedded-data.h" #include "src/snapshot/snapshot.h" #include "src/snapshot/startup-serializer.h" // For SerializedHandleChecker. #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/version.h" #include "src/web-snapshot/web-snapshot.h" #if V8_ENABLE_WEBASSEMBLY #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_MACOSX || V8_OS_FREEBSD #include #include "include/v8-wasm-trap-handler-posix.h" #include "src/trap-handler/handler-inside-posix.h" #endif #if V8_OS_WIN #include // This has to come after windows.h. #include #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 #if defined(V8_ENABLE_SYSTEM_INSTRUMENTATION) #include "src/diagnostics/system-jit-win.h" #endif #endif // V8_OS_WIN // Has to be the last include (doesn't have include guards): #include "src/api/api-macros.h" #define TRACE_BS(...) \ do { \ if (i::FLAG_trace_backing_store) PrintF(__VA_ARGS__); \ } while (false) namespace v8 { static ScriptOrigin GetScriptOriginForScript(i::Isolate* isolate, i::Handle script) { i::Handle scriptName(script->GetNameOrSourceURL(), isolate); i::Handle source_map_url(script->source_mapping_url(), isolate); i::Handle host_defined_options(script->host_defined_options(), isolate); ScriptOriginOptions options(script->origin_options()); bool is_wasm = false; #if V8_ENABLE_WEBASSEMBLY is_wasm = script->type() == i::Script::TYPE_WASM; #endif // V8_ENABLE_WEBASSEMBLY v8::ScriptOrigin origin( reinterpret_cast(isolate), 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; } ScriptOrigin::ScriptOrigin( Local resource_name, Local line_offset, Local column_offset, Local is_shared_cross_origin, Local script_id, Local source_map_url, Local is_opaque, Local is_wasm, Local is_module, Local host_defined_options) : ScriptOrigin( Isolate::GetCurrent(), resource_name, line_offset.IsEmpty() ? 0 : static_cast(line_offset->Value()), column_offset.IsEmpty() ? 0 : static_cast(column_offset->Value()), !is_shared_cross_origin.IsEmpty() && is_shared_cross_origin->IsTrue(), static_cast(script_id.IsEmpty() ? -1 : script_id->Value()), source_map_url, !is_opaque.IsEmpty() && is_opaque->IsTrue(), !is_wasm.IsEmpty() && is_wasm->IsTrue(), !is_module.IsEmpty() && is_module->IsTrue(), host_defined_options) {} ScriptOrigin::ScriptOrigin(Local resource_name, int line_offset, int column_offset, bool is_shared_cross_origin, int script_id, Local source_map_url, bool is_opaque, bool is_wasm, bool is_module, Local host_defined_options) : isolate_(Isolate::GetCurrent()), resource_name_(resource_name), resource_line_offset_(line_offset), resource_column_offset_(column_offset), options_(is_shared_cross_origin, is_opaque, is_wasm, is_module), script_id_(script_id), source_map_url_(source_map_url), host_defined_options_(host_defined_options) {} Local ScriptOrigin::HostDefinedOptions() const { // TODO(cbruni, chromium:1244145): remove once migrated to the context. Utils::ApiCheck(!host_defined_options_->IsFixedArray(), "ScriptOrigin::HostDefinedOptions", "HostDefinedOptions is not a PrimitiveArray, please use " "ScriptOrigin::GetHostDefinedOptions()"); i::Handle options = Utils::OpenHandle(*host_defined_options_.As()); return Utils::PrimitiveArrayToLocal(options); } // --- E x c e p t i o n B e h a v i o r --- void i::FatalProcessOutOfMemory(i::Isolate* isolate, const char* location) { i::V8::FatalProcessOutOfMemory(isolate, location, false); } // 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* isolate, const char* location, bool is_heap_oom) { char last_few_messages[Heap::kTraceRingBufferSize + 1]; char js_stacktrace[Heap::kStacktraceBufferSize + 1]; i::HeapStats heap_stats; if (isolate == nullptr) { isolate = Isolate::TryGetCurrent(); } if (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)); // Note that the embedder's oom handler is also not available and therefore // won't be called in this case. We just crash. FATAL("Fatal process out of memory: %s", 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 (isolate->heap()->HasBeenSetUp()) { // BUG(1718): Don't use the take_snapshot since we don't support // HeapObjectIterator here without doing a special GC. isolate->heap()->RecordStats(&heap_stats, false); if (!FLAG_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(isolate, location, is_heap_oom); // If the fatal error handler returns, we stop execution. FATAL("API fatal error handler returned after process out of memory"); } void Utils::ReportApiFailure(const char* location, const char* message) { i::Isolate* isolate = i::Isolate::TryGetCurrent(); FatalErrorCallback callback = nullptr; if (isolate != nullptr) { callback = 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); } isolate->SignalFatalError(); } void Utils::ReportOOMFailure(i::Isolate* isolate, const char* location, bool is_heap_oom) { OOMErrorCallback oom_callback = isolate->oom_behavior(); if (oom_callback == nullptr) { // TODO(wfh): Remove this fallback once Blink is setting OOM handler. See // crbug.com/614440. FatalErrorCallback fatal_callback = isolate->exception_behavior(); if (fatal_callback == nullptr) { base::OS::PrintError("\n#\n# Fatal %s OOM in %s\n#\n\n", is_heap_oom ? "javascript" : "process", location); #ifdef V8_FUZZILLI exit(0); #else base::OS::Abort(); #endif // V8_FUZZILLI } else { fatal_callback(location, is_heap_oom ? "Allocation failed - JavaScript heap out of memory" : "Allocation failed - process out of memory"); } } else { oom_callback(location, is_heap_oom); } isolate->SignalFatalError(); } void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { i::V8::SetSnapshotBlob(snapshot_blob); } namespace { #ifdef V8_HEAP_SANDBOX // ArrayBufferAllocator to use when the heap sandbox is enabled, in which case // all ArrayBuffer backing stores need to be allocated inside the virtual // memory cage. Note, the current implementation is extremely inefficient as it // uses the BoundedPageAllocator. In the future, we'll need a proper allocator // implementation. class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: ArrayBufferAllocator() { CHECK(page_allocator_); } void* Allocate(size_t length) override { return page_allocator_->AllocatePages(nullptr, RoundUp(length, page_size_), page_size_, PageAllocator::kReadWrite); } void* AllocateUninitialized(size_t length) override { return Allocate(length); } void Free(void* data, size_t length) override { page_allocator_->FreePages(data, RoundUp(length, page_size_)); } private: PageAllocator* page_allocator_ = internal::GetArrayBufferPageAllocator(); const size_t page_size_ = page_allocator_->AllocatePageSize(); }; #else class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: void* Allocate(size_t length) override { #if V8_OS_AIX && _LINUX_SOURCE_COMPAT // Work around for GCC bug on AIX // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839 void* data = __linux_calloc(length, 1); #else void* data = base::Calloc(length, 1); #endif return data; } void* AllocateUninitialized(size_t length) override { #if V8_OS_AIX && _LINUX_SOURCE_COMPAT // Work around for GCC bug on AIX // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839 void* data = __linux_malloc(length); #else void* data = base::Malloc(length); #endif return data; } void Free(void* data, size_t) override { base::Free(data); } void* Reallocate(void* data, size_t old_length, size_t new_length) override { #if V8_OS_AIX && _LINUX_SOURCE_COMPAT // Work around for GCC bug on AIX // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839 void* new_data = __linux_realloc(data, new_length); #else void* new_data = base::Realloc(data, new_length); #endif if (new_length > old_length) { memset(reinterpret_cast(new_data) + old_length, 0, new_length - old_length); } return new_data; } }; #endif // V8_HEAP_SANDBOX struct SnapshotCreatorData { explicit SnapshotCreatorData(Isolate* isolate) : isolate_(isolate), default_context_(), contexts_(isolate), created_(false) {} static SnapshotCreatorData* cast(void* data) { return reinterpret_cast(data); } ArrayBufferAllocator allocator_; Isolate* isolate_; Persistent default_context_; SerializeInternalFieldsCallback default_embedder_fields_serializer_; PersistentValueVector contexts_; std::vector embedder_fields_serializers_; bool created_; }; } // namespace SnapshotCreator::SnapshotCreator(Isolate* isolate, const intptr_t* external_references, StartupData* existing_snapshot) { SnapshotCreatorData* data = new SnapshotCreatorData(isolate); i::Isolate* internal_isolate = reinterpret_cast(isolate); internal_isolate->set_array_buffer_allocator(&data->allocator_); internal_isolate->set_api_external_references(external_references); internal_isolate->enable_serializer(); isolate->Enter(); const StartupData* blob = existing_snapshot ? existing_snapshot : i::Snapshot::DefaultSnapshotBlob(); if (blob && blob->raw_size > 0) { internal_isolate->set_snapshot_blob(blob); i::Snapshot::Initialize(internal_isolate); } else { internal_isolate->InitWithoutSnapshot(); } data_ = data; // Disable batch compilation during snapshot creation. internal_isolate->baseline_batch_compiler()->set_enabled(false); } SnapshotCreator::SnapshotCreator(const intptr_t* external_references, StartupData* existing_snapshot) : SnapshotCreator(Isolate::Allocate(), external_references, existing_snapshot) {} SnapshotCreator::~SnapshotCreator() { SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(data->created_); Isolate* isolate = data->isolate_; isolate->Exit(); isolate->Dispose(); delete data; } Isolate* SnapshotCreator::GetIsolate() { return SnapshotCreatorData::cast(data_)->isolate_; } void SnapshotCreator::SetDefaultContext( Local context, SerializeInternalFieldsCallback callback) { DCHECK(!context.IsEmpty()); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(!data->created_); DCHECK(data->default_context_.IsEmpty()); Isolate* isolate = data->isolate_; CHECK_EQ(isolate, context->GetIsolate()); data->default_context_.Reset(isolate, context); data->default_embedder_fields_serializer_ = callback; } size_t SnapshotCreator::AddContext(Local context, SerializeInternalFieldsCallback callback) { DCHECK(!context.IsEmpty()); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(!data->created_); Isolate* isolate = data->isolate_; CHECK_EQ(isolate, context->GetIsolate()); size_t index = data->contexts_.Size(); data->contexts_.Append(context); data->embedder_fields_serializers_.push_back(callback); return index; } size_t SnapshotCreator::AddData(i::Address object) { DCHECK_NE(object, i::kNullAddress); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); DCHECK(!data->created_); i::Isolate* isolate = reinterpret_cast(data->isolate_); i::HandleScope scope(isolate); i::Handle obj(i::Object(object), isolate); i::Handle list; if (!isolate->heap()->serialized_objects().IsArrayList()) { list = i::ArrayList::New(isolate, 1); } else { list = i::Handle( i::ArrayList::cast(isolate->heap()->serialized_objects()), isolate); } size_t index = static_cast(list->Length()); list = i::ArrayList::Add(isolate, list, obj); isolate->heap()->SetSerializedObjects(*list); return index; } size_t SnapshotCreator::AddData(Local context, i::Address object) { DCHECK_NE(object, i::kNullAddress); DCHECK(!SnapshotCreatorData::cast(data_)->created_); i::Handle ctx = Utils::OpenHandle(*context); i::Isolate* isolate = ctx->GetIsolate(); i::HandleScope scope(isolate); i::Handle obj(i::Object(object), isolate); i::Handle list; if (!ctx->serialized_objects().IsArrayList()) { list = i::ArrayList::New(isolate, 1); } else { list = i::Handle( i::ArrayList::cast(ctx->serialized_objects()), isolate); } size_t index = static_cast(list->Length()); list = i::ArrayList::Add(isolate, list, obj); ctx->set_serialized_objects(*list); return index; } namespace { void ConvertSerializedObjectsToFixedArray(Local context) { i::Handle ctx = Utils::OpenHandle(*context); i::Isolate* isolate = ctx->GetIsolate(); if (!ctx->serialized_objects().IsArrayList()) { ctx->set_serialized_objects(i::ReadOnlyRoots(isolate).empty_fixed_array()); } else { i::Handle list(i::ArrayList::cast(ctx->serialized_objects()), isolate); i::Handle elements = i::ArrayList::Elements(isolate, list); ctx->set_serialized_objects(*elements); } } void ConvertSerializedObjectsToFixedArray(i::Isolate* isolate) { if (!isolate->heap()->serialized_objects().IsArrayList()) { isolate->heap()->SetSerializedObjects( i::ReadOnlyRoots(isolate).empty_fixed_array()); } else { i::Handle list( i::ArrayList::cast(isolate->heap()->serialized_objects()), isolate); i::Handle elements = i::ArrayList::Elements(isolate, list); isolate->heap()->SetSerializedObjects(*elements); } } } // anonymous namespace StartupData SnapshotCreator::CreateBlob( SnapshotCreator::FunctionCodeHandling function_code_handling) { SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); i::Isolate* isolate = reinterpret_cast(data->isolate_); DCHECK(!data->created_); DCHECK(!data->default_context_.IsEmpty()); const int num_additional_contexts = static_cast(data->contexts_.Size()); const int num_contexts = num_additional_contexts + 1; // The default context. // Create and store lists of embedder-provided data needed during // serialization. { i::HandleScope scope(isolate); // Convert list of context-independent data to FixedArray. ConvertSerializedObjectsToFixedArray(isolate); // Convert lists of context-dependent data to FixedArray. ConvertSerializedObjectsToFixedArray( data->default_context_.Get(data->isolate_)); for (int i = 0; i < num_additional_contexts; i++) { ConvertSerializedObjectsToFixedArray(data->contexts_.Get(i)); } // We need to store the global proxy size upfront in case we need the // bootstrapper to create a global proxy before we deserialize the context. i::Handle global_proxy_sizes = isolate->factory()->NewFixedArray(num_additional_contexts, i::AllocationType::kOld); for (int i = 0; i < num_additional_contexts; i++) { i::Handle context = v8::Utils::OpenHandle(*data->contexts_.Get(i)); global_proxy_sizes->set(i, i::Smi::FromInt(context->global_proxy().Size())); } isolate->heap()->SetSerializedGlobalProxySizes(*global_proxy_sizes); } // We might rehash strings and re-sort descriptors. Clear the lookup cache. isolate->descriptor_lookup_cache()->Clear(); // If we don't do this then we end up with a stray root pointing at the // context even after we have disposed of the context. isolate->heap()->CollectAllAvailableGarbage( i::GarbageCollectionReason::kSnapshotCreator); { i::HandleScope scope(isolate); isolate->heap()->CompactWeakArrayLists(); } i::Snapshot::ClearReconstructableDataForSerialization( isolate, function_code_handling == FunctionCodeHandling::kClear); i::GlobalSafepointScope global_safepoint(isolate); i::DisallowGarbageCollection no_gc_from_here_on; // Create a vector with all contexts and clear associated Persistent fields. // Note these contexts may be dead after calling Clear(), but will not be // collected until serialization completes and the DisallowGarbageCollection // scope above goes out of scope. std::vector contexts; contexts.reserve(num_contexts); { i::HandleScope scope(isolate); contexts.push_back( *v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_))); data->default_context_.Reset(); for (int i = 0; i < num_additional_contexts; i++) { i::Handle context = v8::Utils::OpenHandle(*data->contexts_.Get(i)); contexts.push_back(*context); } data->contexts_.Clear(); } // Check that values referenced by global/eternal handles are accounted for. i::SerializedHandleChecker handle_checker(isolate, &contexts); CHECK(handle_checker.CheckGlobalAndEternalHandles()); // Create a vector with all embedder fields serializers. std::vector embedder_fields_serializers; embedder_fields_serializers.reserve(num_contexts); embedder_fields_serializers.push_back( data->default_embedder_fields_serializer_); for (int i = 0; i < num_additional_contexts; i++) { embedder_fields_serializers.push_back( data->embedder_fields_serializers_[i]); } data->created_ = true; return i::Snapshot::Create(isolate, &contexts, embedder_fields_serializers, global_safepoint, no_gc_from_here_on); } 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::SetFlagsFromString(const char* str) { SetFlagsFromString(str, strlen(str)); } void V8::SetFlagsFromString(const char* str, size_t length) { i::FlagList::SetFlagsFromString(str, length); i::FlagList::EnforceFlagImplications(); } 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_(std::move(extension)) {} // static void RegisteredExtension::Register(std::unique_ptr 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) { 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(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(virtual_memory_limit / 8))); } } namespace internal { i::Address* GlobalizeTracedReference( i::Isolate* isolate, i::Address* obj, internal::Address* slot, GlobalHandleDestructionMode destruction_mode, GlobalHandleStoreMode store_mode) { LOG_API(isolate, TracedGlobal, New); #ifdef DEBUG Utils::ApiCheck((slot != nullptr), "v8::GlobalizeTracedReference", "the address slot must be not null"); #endif i::Handle result = isolate->global_handles()->CreateTraced( *obj, slot, destruction_mode, store_mode); #ifdef VERIFY_HEAP if (i::FLAG_verify_heap) { i::Object(*obj).ObjectVerify(isolate); } #endif // VERIFY_HEAP return result.location(); } void MoveTracedGlobalReference(internal::Address** from, internal::Address** to) { GlobalHandles::MoveTracedGlobal(from, to); } void CopyTracedGlobalReference(const internal::Address* const* from, internal::Address** to) { GlobalHandles::CopyTracedGlobal(from, to); } void DisposeTracedGlobal(internal::Address* location) { GlobalHandles::DestroyTraced(location); } void SetFinalizationCallbackTraced(internal::Address* location, void* parameter, WeakCallbackInfo::Callback callback) { GlobalHandles::SetFinalizationCallbackForTraced(location, parameter, callback); } } // namespace internal namespace api_internal { i::Address* GlobalizeReference(i::Isolate* isolate, i::Address* obj) { LOG_API(isolate, Persistent, New); i::Handle result = isolate->global_handles()->Create(*obj); #ifdef VERIFY_HEAP if (i::FLAG_verify_heap) { i::Object(*obj).ObjectVerify(isolate); } #endif // VERIFY_HEAP return result.location(); } i::Address* CopyGlobalReference(i::Address* from) { i::Handle 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::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); } Value* Eternalize(Isolate* v8_isolate, Value* value) { i::Isolate* isolate = reinterpret_cast(v8_isolate); i::Object object = *Utils::OpenHandle(value); int index = -1; isolate->eternal_handles()->Create(isolate, object, &index); return reinterpret_cast( 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* isolate) { Initialize(isolate); } void HandleScope::Initialize(Isolate* isolate) { i::Isolate* internal_isolate = reinterpret_cast(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( !v8::Locker::WasEverUsed() || internal_isolate->thread_manager()->IsLockedByCurrentThread() || internal_isolate->serializer_enabled(), "HandleScope::HandleScope", "Entering the V8 API without proper locking in place"); i::HandleScopeData* current = internal_isolate->handle_scope_data(); isolate_ = internal_isolate; prev_next_ = current->next; prev_limit_ = current->limit; current->level++; } HandleScope::~HandleScope() { i::HandleScope::CloseScope(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* isolate) { return i::HandleScope::NumberOfHandles( reinterpret_cast(isolate)); } i::Address* HandleScope::CreateHandle(i::Isolate* isolate, i::Address value) { return i::HandleScope::CreateHandle(isolate, value); } EscapableHandleScope::EscapableHandleScope(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast(v8_isolate); escape_slot_ = CreateHandle(isolate, i::ReadOnlyRoots(isolate).the_hole_value().ptr()); Initialize(v8_isolate); } i::Address* EscapableHandleScope::Escape(i::Address* escape_value) { i::Heap* heap = reinterpret_cast(GetIsolate())->heap(); Utils::ApiCheck(i::Object(*escape_slot_).IsTheHole(heap->isolate()), "EscapableHandleScope::Escape", "Escape value set twice"); if (escape_value == nullptr) { *escape_slot_ = i::ReadOnlyRoots(heap).undefined_value().ptr(); return nullptr; } *escape_slot_ = *escape_value; return escape_slot_; } void* EscapableHandleScope::operator new(size_t) { base::OS::Abort(); } void* EscapableHandleScope::operator new[](size_t) { base::OS::Abort(); } void EscapableHandleScope::operator delete(void*, size_t) { base::OS::Abort(); } void EscapableHandleScope::operator delete[](void*, size_t) { base::OS::Abort(); } SealHandleScope::SealHandleScope(Isolate* isolate) : isolate_(reinterpret_cast(isolate)) { i::HandleScopeData* current = 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 = 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_; } void* SealHandleScope::operator new(size_t) { base::OS::Abort(); } void* SealHandleScope::operator new[](size_t) { base::OS::Abort(); } void SealHandleScope::operator delete(void*, size_t) { base::OS::Abort(); } void SealHandleScope::operator delete[](void*, size_t) { base::OS::Abort(); } bool Data::IsModule() const { return Utils::OpenHandle(this)->IsModule(); } bool Data::IsFixedArray() const { return Utils::OpenHandle(this)->IsFixedArray(); } bool Data::IsValue() const { i::DisallowGarbageCollection no_gc; i::Object self = *Utils::OpenHandle(this); if (self.IsSmi()) return true; i::HeapObject heap_object = i::HeapObject::cast(self); DCHECK(!heap_object.IsTheHole()); if (heap_object.IsSymbol()) { return !i::Symbol::cast(heap_object).is_private(); } return heap_object.IsPrimitiveHeapObject() || heap_object.IsJSReceiver(); } bool Data::IsPrivate() const { return Utils::OpenHandle(this)->IsPrivateSymbol(); } bool Data::IsObjectTemplate() const { return Utils::OpenHandle(this)->IsObjectTemplateInfo(); } bool Data::IsFunctionTemplate() const { return Utils::OpenHandle(this)->IsFunctionTemplateInfo(); } bool Data::IsContext() const { return Utils::OpenHandle(this)->IsContext(); } void Context::Enter() { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); impl->EnterContext(*env); impl->SaveContext(isolate->context()); isolate->set_context(*env); } void Context::Exit() { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); if (!Utils::ApiCheck(impl->LastEnteredContextWas(*env), "v8::Context::Exit()", "Cannot exit non-entered context")) { return; } impl->LeaveContext(); isolate->set_context(impl->RestoreContext()); } Context::BackupIncumbentScope::BackupIncumbentScope( Local backup_incumbent_context) : backup_incumbent_context_(backup_incumbent_context) { DCHECK(!backup_incumbent_context_.IsEmpty()); i::Handle env = Utils::OpenHandle(*backup_incumbent_context_); i::Isolate* isolate = env->GetIsolate(); js_stack_comparable_address_ = i::SimulatorStack::RegisterJSStackComparableAddress(isolate); prev_ = isolate->top_backup_incumbent_scope(); isolate->set_top_backup_incumbent_scope(this); } Context::BackupIncumbentScope::~BackupIncumbentScope() { i::Handle env = Utils::OpenHandle(*backup_incumbent_context_); i::Isolate* isolate = env->GetIsolate(); i::SimulatorStack::UnregisterJSStackComparableAddress(isolate); isolate->set_top_backup_incumbent_scope(prev_); } STATIC_ASSERT(i::Internals::kEmbedderDataSlotSize == i::kEmbedderDataSlotSize); static i::Handle EmbedderDataFor(Context* context, int index, bool can_grow, const char* location) { i::Handle env = Utils::OpenHandle(context); i::Isolate* isolate = env->GetIsolate(); ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate); bool ok = Utils::ApiCheck(env->IsNativeContext(), location, "Not a native context") && Utils::ApiCheck(index >= 0, location, "Negative index"); if (!ok) return i::Handle(); // TODO(ishell): remove cast once embedder_data slot has a proper type. i::Handle data( i::EmbedderDataArray::cast(env->embedder_data()), isolate); if (index < data->length()) return data; if (!Utils::ApiCheck(can_grow && index < i::EmbedderDataArray::kMaxLength, location, "Index too large")) { return i::Handle(); } data = i::EmbedderDataArray::EnsureCapacity(isolate, data, index); env->set_embedder_data(*data); return data; } uint32_t Context::GetNumberOfEmbedderDataFields() { i::Handle context = Utils::OpenHandle(this); ASSERT_NO_SCRIPT_NO_EXCEPTION(context->GetIsolate()); Utils::ApiCheck(context->IsNativeContext(), "Context::GetNumberOfEmbedderDataFields", "Not a native context"); // TODO(ishell): remove cast once embedder_data slot has a proper type. return static_cast( i::EmbedderDataArray::cast(context->embedder_data()).length()); } v8::Local Context::SlowGetEmbedderData(int index) { const char* location = "v8::Context::GetEmbedderData()"; i::Handle data = EmbedderDataFor(this, index, false, location); if (data.is_null()) return Local(); i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); i::Handle result(i::EmbedderDataSlot(*data, index).load_tagged(), isolate); return Utils::ToLocal(result); } void Context::SetEmbedderData(int index, v8::Local value) { const char* location = "v8::Context::SetEmbedderData()"; i::Handle data = EmbedderDataFor(this, index, true, location); if (data.is_null()) return; i::Handle val = Utils::OpenHandle(*value); i::EmbedderDataSlot::store_tagged(*data, index, *val); DCHECK_EQ(*Utils::OpenHandle(*value), *Utils::OpenHandle(*GetEmbedderData(index))); } void* Context::SlowGetAlignedPointerFromEmbedderData(int index) { const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); i::HandleScope handle_scope(isolate); i::Handle data = EmbedderDataFor(this, index, false, location); if (data.is_null()) return nullptr; void* result; Utils::ApiCheck( i::EmbedderDataSlot(*data, index).ToAlignedPointer(isolate, &result), location, "Pointer is not aligned"); return result; } void Context::SetAlignedPointerInEmbedderData(int index, void* value) { const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); i::Handle data = EmbedderDataFor(this, index, true, location); bool ok = i::EmbedderDataSlot(*data, index).store_aligned_pointer(isolate, value); Utils::ApiCheck(ok, location, "Pointer is not aligned"); DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index)); } // --- T e m p l a t e --- static void InitializeTemplate(i::TemplateInfo that, int type, bool do_not_cache) { that.set_number_of_properties(0); that.set_tag(type); int serial_number = do_not_cache ? i::TemplateInfo::kDoNotCache : i::TemplateInfo::kUncached; that.set_serial_number(serial_number); } void Template::Set(v8::Local name, v8::Local value, v8::PropertyAttribute attribute) { auto templ = Utils::OpenHandle(this); i::Isolate* isolate = templ->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto value_obj = Utils::OpenHandle(*value); Utils::ApiCheck(!value_obj->IsJSReceiver() || value_obj->IsTemplateInfo(), "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 (value_obj->IsObjectTemplateInfo()) { templ->set_serial_number(i::TemplateInfo::kDoNotCache); } i::ApiNatives::AddDataProperty(isolate, templ, Utils::OpenHandle(*name), value_obj, static_cast(attribute)); } void Template::SetPrivate(v8::Local name, v8::Local value, v8::PropertyAttribute attribute) { Set(Utils::ToLocal(Utils::OpenHandle(reinterpret_cast(*name))), value, attribute); } void Template::SetAccessorProperty(v8::Local name, v8::Local getter, v8::Local setter, v8::PropertyAttribute attribute, v8::AccessControl access_control) { // TODO(verwaest): Remove |access_control|. DCHECK_EQ(v8::DEFAULT, access_control); auto templ = Utils::OpenHandle(this); auto isolate = templ->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); DCHECK(!name.IsEmpty()); DCHECK(!getter.IsEmpty() || !setter.IsEmpty()); i::HandleScope scope(isolate); i::ApiNatives::AddAccessorProperty( isolate, templ, Utils::OpenHandle(*name), Utils::OpenHandle(*getter, true), Utils::OpenHandle(*setter, true), static_cast(attribute)); } // --- F u n c t i o n T e m p l a t e --- static void InitializeFunctionTemplate(i::FunctionTemplateInfo info, bool do_not_cache) { InitializeTemplate(info, Consts::FUNCTION_TEMPLATE, do_not_cache); info.set_flag(0); } static Local ObjectTemplateNew( i::Isolate* isolate, v8::Local constructor, bool do_not_cache); Local FunctionTemplate::PrototypeTemplate() { auto self = Utils::OpenHandle(this); i::Isolate* i_isolate = self->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); i::Handle result(self->GetPrototypeTemplate(), i_isolate); if (result->IsUndefined(i_isolate)) { // Do not cache prototype objects. result = Utils::OpenHandle( *ObjectTemplateNew(i_isolate, Local(), true)); i::FunctionTemplateInfo::SetPrototypeTemplate(i_isolate, self, result); } return ToApiHandle(result); } void FunctionTemplate::SetPrototypeProviderTemplate( Local prototype_provider) { auto self = Utils::OpenHandle(this); i::Isolate* i_isolate = self->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); i::Handle result = Utils::OpenHandle(*prototype_provider); Utils::ApiCheck(self->GetPrototypeTemplate().IsUndefined(i_isolate), "v8::FunctionTemplate::SetPrototypeProviderTemplate", "Protoype must be undefined"); Utils::ApiCheck(self->GetParentTemplate().IsUndefined(i_isolate), "v8::FunctionTemplate::SetPrototypeProviderTemplate", "Prototype provider must be empty"); i::FunctionTemplateInfo::SetPrototypeProviderTemplate(i_isolate, self, result); } static void EnsureNotPublished(i::Handle info, const char* func) { DCHECK_IMPLIES(info->instantiated(), info->published()); Utils::ApiCheck(!info->published(), func, "FunctionTemplate already instantiated"); } void FunctionTemplate::Inherit(v8::Local value) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::Inherit"); i::Isolate* i_isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); Utils::ApiCheck(info->GetPrototypeProviderTemplate().IsUndefined(i_isolate), "v8::FunctionTemplate::Inherit", "Protoype provider must be empty"); i::FunctionTemplateInfo::SetParentTemplate(i_isolate, info, Utils::OpenHandle(*value)); } static Local FunctionTemplateNew( i::Isolate* isolate, FunctionCallback callback, v8::Local data, v8::Local signature, int length, ConstructorBehavior behavior, bool do_not_cache, v8::Local cached_property_name = v8::Local(), SideEffectType side_effect_type = SideEffectType::kHasSideEffect, const MemorySpan& c_function_overloads = {}, uint8_t instance_type = 0, uint8_t allowed_receiver_instance_type_range_start = 0, uint8_t allowed_receiver_instance_type_range_end = 0) { i::Handle struct_obj = isolate->factory()->NewStruct( i::FUNCTION_TEMPLATE_INFO_TYPE, i::AllocationType::kOld); i::Handle obj = i::Handle::cast(struct_obj); { // Disallow GC until all fields of obj have acceptable types. i::DisallowGarbageCollection no_gc; i::FunctionTemplateInfo raw = *obj; InitializeFunctionTemplate(raw, do_not_cache); raw.set_length(length); raw.set_undetectable(false); raw.set_needs_access_check(false); raw.set_accept_any_receiver(true); if (!signature.IsEmpty()) { raw.set_signature(*Utils::OpenHandle(*signature)); } raw.set_cached_property_name( cached_property_name.IsEmpty() ? i::ReadOnlyRoots(isolate).the_hole_value() : *Utils::OpenHandle(*cached_property_name)); if (behavior == ConstructorBehavior::kThrow) raw.set_remove_prototype(true); raw.SetInstanceType(instance_type); raw.set_allowed_receiver_instance_type_range_start( allowed_receiver_instance_type_range_start); raw.set_allowed_receiver_instance_type_range_end( allowed_receiver_instance_type_range_end); } if (callback != nullptr) { Utils::ToLocal(obj)->SetCallHandler(callback, data, side_effect_type, c_function_overloads); } return Utils::ToLocal(obj); } Local FunctionTemplate::New( Isolate* isolate, FunctionCallback callback, v8::Local data, v8::Local 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(isolate); // Changes to the environment cannot be captured in the snapshot. Expect no // function templates when the isolate is created for serialization. LOG_API(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(); } ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); return FunctionTemplateNew( i_isolate, callback, data, signature, length, behavior, false, Local(), side_effect_type, c_function ? MemorySpan{c_function, 1} : MemorySpan{}, instance_type, allowed_receiver_instance_type_range_start, allowed_receiver_instance_type_range_end); } Local FunctionTemplate::NewWithCFunctionOverloads( Isolate* isolate, FunctionCallback callback, v8::Local data, v8::Local signature, int length, ConstructorBehavior behavior, SideEffectType side_effect_type, const MemorySpan& c_function_overloads) { i::Isolate* i_isolate = reinterpret_cast(isolate); LOG_API(i_isolate, FunctionTemplate, New); if (!Utils::ApiCheck( c_function_overloads.size() == 0 || behavior == ConstructorBehavior::kThrow, "FunctionTemplate::NewWithCFunctionOverloads", "Fast API calls are not supported for constructor functions.")) { return Local(); } ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); return FunctionTemplateNew(i_isolate, callback, data, signature, length, behavior, false, Local(), side_effect_type, c_function_overloads); } Local FunctionTemplate::NewWithCache( Isolate* isolate, FunctionCallback callback, Local cache_property, Local data, Local signature, int length, SideEffectType side_effect_type) { i::Isolate* i_isolate = reinterpret_cast(isolate); LOG_API(i_isolate, FunctionTemplate, NewWithCache); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); return FunctionTemplateNew(i_isolate, callback, data, signature, length, ConstructorBehavior::kAllow, false, cache_property, side_effect_type); } Local Signature::New(Isolate* isolate, Local receiver) { return Utils::SignatureToLocal(Utils::OpenHandle(*receiver)); } Local AccessorSignature::New( Isolate* isolate, Local receiver) { return Utils::AccessorSignatureToLocal(Utils::OpenHandle(*receiver)); } #define SET_FIELD_WRAPPED(isolate, obj, setter, cdata) \ do { \ i::Handle foreign = FromCData(isolate, cdata); \ (obj)->setter(*foreign); \ } while (false) void FunctionTemplate::SetCallHandler( FunctionCallback callback, v8::Local data, SideEffectType side_effect_type, const MemorySpan& c_function_overloads) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetCallHandler"); i::Isolate* isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); i::Handle obj = isolate->factory()->NewCallHandlerInfo( side_effect_type == SideEffectType::kHasNoSideEffect); SET_FIELD_WRAPPED(isolate, obj, set_callback, callback); SET_FIELD_WRAPPED(isolate, obj, set_js_callback, obj->redirected_callback()); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast(isolate)); } obj->set_data(*Utils::OpenHandle(*data)); if (c_function_overloads.size() > 0) { // 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::Handle function_overloads = isolate->factory()->NewFixedArray(static_cast( c_function_overloads.size() * i::FunctionTemplateInfo::kFunctionOverloadEntrySize)); int function_count = static_cast(c_function_overloads.size()); for (int i = 0; i < function_count; i++) { const CFunction& c_function = c_function_overloads.data()[i]; i::Handle address = FromCData(isolate, c_function.GetAddress()); function_overloads->set( i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i, *address); i::Handle signature = FromCData(isolate, c_function.GetTypeInfo()); function_overloads->set( i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i + 1, *signature); } i::FunctionTemplateInfo::SetCFunctionOverloads(isolate, info, function_overloads); } info->set_call_code(*obj, kReleaseStore); } namespace { template i::Handle MakeAccessorInfo( i::Isolate* isolate, v8::Local name, Getter getter, Setter setter, v8::Local data, v8::AccessControl settings, v8::Local signature, bool is_special_data_property, bool replace_on_access) { i::Handle obj = isolate->factory()->NewAccessorInfo(); SET_FIELD_WRAPPED(isolate, obj, set_getter, getter); DCHECK_IMPLIES(replace_on_access, is_special_data_property && setter == nullptr); if (is_special_data_property && setter == nullptr) { setter = reinterpret_cast(&i::Accessors::ReconfigureToDataProperty); } SET_FIELD_WRAPPED(isolate, obj, set_setter, setter); i::Address redirected = obj->redirected_getter(); if (redirected != i::kNullAddress) { SET_FIELD_WRAPPED(isolate, obj, set_js_getter, redirected); } i::Handle accessor_name = Utils::OpenHandle(*name); if (!accessor_name->IsUniqueName()) { accessor_name = isolate->factory()->InternalizeString( i::Handle::cast(accessor_name)); } i::DisallowGarbageCollection no_gc; i::AccessorInfo raw_obj = *obj; if (data.IsEmpty()) { raw_obj.set_data(i::ReadOnlyRoots(isolate).undefined_value()); } else { raw_obj.set_data(*Utils::OpenHandle(*data)); } raw_obj.set_name(*accessor_name); raw_obj.set_is_special_data_property(is_special_data_property); raw_obj.set_replace_on_access(replace_on_access); if (settings & ALL_CAN_READ) raw_obj.set_all_can_read(true); if (settings & ALL_CAN_WRITE) raw_obj.set_all_can_write(true); raw_obj.set_initial_property_attributes(i::NONE); if (!signature.IsEmpty()) { raw_obj.set_expected_receiver_type(*Utils::OpenHandle(*signature)); } return obj; } } // namespace Local FunctionTemplate::InstanceTemplate() { i::Handle handle = Utils::OpenHandle(this, true); if (!Utils::ApiCheck(!handle.is_null(), "v8::FunctionTemplate::InstanceTemplate()", "Reading from empty handle")) { return Local(); } i::Isolate* isolate = handle->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); if (handle->GetInstanceTemplate().IsUndefined(isolate)) { Local templ = ObjectTemplate::New(isolate, ToApiHandle(handle)); i::FunctionTemplateInfo::SetInstanceTemplate(isolate, handle, Utils::OpenHandle(*templ)); } i::Handle result( i::ObjectTemplateInfo::cast(handle->GetInstanceTemplate()), isolate); return Utils::ToLocal(result); } void FunctionTemplate::SetLength(int length) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetLength"); auto isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); info->set_length(length); } void FunctionTemplate::SetClassName(Local name) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetClassName"); auto isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); info->set_class_name(*Utils::OpenHandle(*name)); } void FunctionTemplate::SetAcceptAnyReceiver(bool value) { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::SetAcceptAnyReceiver"); auto isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); info->set_accept_any_receiver(value); } void FunctionTemplate::ReadOnlyPrototype() { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::ReadOnlyPrototype"); auto isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); info->set_read_only_prototype(true); } void FunctionTemplate::RemovePrototype() { auto info = Utils::OpenHandle(this); EnsureNotPublished(info, "v8::FunctionTemplate::RemovePrototype"); auto isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); info->set_remove_prototype(true); } // --- O b j e c t T e m p l a t e --- Local ObjectTemplate::New( Isolate* isolate, v8::Local constructor) { return New(reinterpret_cast(isolate), constructor); } static Local ObjectTemplateNew( i::Isolate* isolate, v8::Local constructor, bool do_not_cache) { LOG_API(isolate, ObjectTemplate, New); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::Handle struct_obj = isolate->factory()->NewStruct( i::OBJECT_TEMPLATE_INFO_TYPE, i::AllocationType::kOld); i::Handle obj = i::Handle::cast(struct_obj); { // Disallow GC until all fields of obj have acceptable types. i::DisallowGarbageCollection no_gc; i::ObjectTemplateInfo raw = *obj; InitializeTemplate(raw, Consts::OBJECT_TEMPLATE, do_not_cache); raw.set_data(0); if (!constructor.IsEmpty()) { raw.set_constructor(*Utils::OpenHandle(*constructor)); } } return Utils::ToLocal(obj); } Local ObjectTemplate::New( i::Isolate* isolate, v8::Local constructor) { return ObjectTemplateNew(isolate, constructor, false); } // Ensure that the object template has a constructor. If no // constructor is available we create one. static i::Handle EnsureConstructor( i::Isolate* isolate, ObjectTemplate* object_template) { i::Object obj = Utils::OpenHandle(object_template)->constructor(); if (!obj.IsUndefined(isolate)) { i::FunctionTemplateInfo info = i::FunctionTemplateInfo::cast(obj); return i::Handle(info, isolate); } Local templ = FunctionTemplate::New(reinterpret_cast(isolate)); i::Handle constructor = Utils::OpenHandle(*templ); i::FunctionTemplateInfo::SetInstanceTemplate( isolate, constructor, Utils::OpenHandle(object_template)); Utils::OpenHandle(object_template)->set_constructor(*constructor); return constructor; } template static void TemplateSetAccessor( Template* template_obj, v8::Local name, Getter getter, Setter setter, Data data, AccessControl settings, PropertyAttribute attribute, v8::Local signature, bool is_special_data_property, bool replace_on_access, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { auto info = Utils::OpenHandle(template_obj); auto isolate = info->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); i::Handle accessor_info = MakeAccessorInfo(isolate, name, getter, setter, data, settings, signature, is_special_data_property, replace_on_access); { i::DisallowGarbageCollection no_gc; i::AccessorInfo raw = *accessor_info; raw.set_initial_property_attributes( static_cast(attribute)); raw.set_getter_side_effect_type(getter_side_effect_type); raw.set_setter_side_effect_type(setter_side_effect_type); } i::ApiNatives::AddNativeDataProperty(isolate, info, accessor_info); } void Template::SetNativeDataProperty( v8::Local name, AccessorGetterCallback getter, AccessorSetterCallback setter, v8::Local data, PropertyAttribute attribute, v8::Local signature, AccessControl settings, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, signature, true, false, getter_side_effect_type, setter_side_effect_type); } void Template::SetNativeDataProperty( v8::Local name, AccessorNameGetterCallback getter, AccessorNameSetterCallback setter, v8::Local data, PropertyAttribute attribute, v8::Local signature, AccessControl settings, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, signature, true, false, getter_side_effect_type, setter_side_effect_type); } void Template::SetLazyDataProperty(v8::Local name, AccessorNameGetterCallback getter, v8::Local data, PropertyAttribute attribute, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, static_cast(nullptr), data, DEFAULT, attribute, Local(), true, true, getter_side_effect_type, setter_side_effect_type); } void Template::SetIntrinsicDataProperty(Local name, Intrinsic intrinsic, PropertyAttribute attribute) { auto templ = Utils::OpenHandle(this); i::Isolate* isolate = templ->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); i::ApiNatives::AddDataProperty(isolate, templ, Utils::OpenHandle(*name), intrinsic, static_cast(attribute)); } void ObjectTemplate::SetAccessor(v8::Local name, AccessorGetterCallback getter, AccessorSetterCallback setter, v8::Local data, AccessControl settings, PropertyAttribute attribute, v8::Local signature, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, signature, i::FLAG_disable_old_api_accessors, false, getter_side_effect_type, setter_side_effect_type); } void ObjectTemplate::SetAccessor(v8::Local name, AccessorNameGetterCallback getter, AccessorNameSetterCallback setter, v8::Local data, AccessControl settings, PropertyAttribute attribute, v8::Local signature, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { TemplateSetAccessor(this, name, getter, setter, data, settings, attribute, signature, i::FLAG_disable_old_api_accessors, false, getter_side_effect_type, setter_side_effect_type); } template static i::Handle CreateInterceptorInfo( i::Isolate* isolate, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { auto obj = i::Handle::cast(isolate->factory()->NewStruct( i::INTERCEPTOR_INFO_TYPE, i::AllocationType::kOld)); obj->set_flags(0); if (getter != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_getter, getter); if (setter != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_setter, setter); if (query != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_query, query); if (descriptor != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_descriptor, descriptor); if (remover != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_deleter, remover); if (enumerator != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_enumerator, enumerator); if (definer != nullptr) SET_FIELD_WRAPPED(isolate, obj, set_definer, definer); obj->set_can_intercept_symbols( !(static_cast(flags) & static_cast(PropertyHandlerFlags::kOnlyInterceptStrings))); obj->set_all_can_read(static_cast(flags) & static_cast(PropertyHandlerFlags::kAllCanRead)); obj->set_non_masking(static_cast(flags) & static_cast(PropertyHandlerFlags::kNonMasking)); obj->set_has_no_side_effect( static_cast(flags) & static_cast(PropertyHandlerFlags::kHasNoSideEffect)); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast(isolate)); } obj->set_data(*Utils::OpenHandle(*data)); return obj; } template static i::Handle CreateNamedInterceptorInfo( i::Isolate* isolate, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { auto interceptor = CreateInterceptorInfo(isolate, getter, setter, query, descriptor, remover, enumerator, definer, data, flags); interceptor->set_is_named(true); return interceptor; } template static i::Handle CreateIndexedInterceptorInfo( i::Isolate* isolate, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { auto interceptor = CreateInterceptorInfo(isolate, getter, setter, query, descriptor, remover, enumerator, definer, data, flags); interceptor->set_is_named(false); return interceptor; } template static void ObjectTemplateSetNamedPropertyHandler( ObjectTemplate* templ, Getter getter, Setter setter, Query query, Descriptor descriptor, Deleter remover, Enumerator enumerator, Definer definer, Local data, PropertyHandlerFlags flags) { i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, templ); EnsureNotPublished(cons, "ObjectTemplateSetNamedPropertyHandler"); auto obj = CreateNamedInterceptorInfo(isolate, getter, setter, query, descriptor, remover, enumerator, definer, data, flags); i::FunctionTemplateInfo::SetNamedPropertyHandler(isolate, cons, obj); } 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* isolate = Utils::OpenHandle(this)->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::MarkAsUndetectable"); cons->set_undetectable(true); } void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback, Local data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallback"); i::Handle struct_info = isolate->factory()->NewStruct( i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); i::Handle info = i::Handle::cast(struct_info); SET_FIELD_WRAPPED(isolate, info, set_callback, callback); info->set_named_interceptor(i::Object()); info->set_indexed_interceptor(i::Object()); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast(isolate)); } info->set_data(*Utils::OpenHandle(*data)); i::FunctionTemplateInfo::SetAccessCheckInfo(isolate, cons, info); cons->set_needs_access_check(true); } void ObjectTemplate::SetAccessCheckCallbackAndHandler( AccessCheckCallback callback, const NamedPropertyHandlerConfiguration& named_handler, const IndexedPropertyHandlerConfiguration& indexed_handler, Local data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallbackWithHandler"); i::Handle struct_info = isolate->factory()->NewStruct( i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); i::Handle info = i::Handle::cast(struct_info); SET_FIELD_WRAPPED(isolate, info, set_callback, callback); auto named_interceptor = CreateNamedInterceptorInfo( 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( 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(isolate)); } info->set_data(*Utils::OpenHandle(*data)); i::FunctionTemplateInfo::SetAccessCheckInfo(isolate, cons, info); cons->set_needs_access_check(true); } void ObjectTemplate::SetHandler( const IndexedPropertyHandlerConfiguration& config) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetHandler"); auto obj = CreateIndexedInterceptorInfo( isolate, config.getter, config.setter, config.query, config.descriptor, config.deleter, config.enumerator, config.definer, config.data, config.flags); i::FunctionTemplateInfo::SetIndexedPropertyHandler(isolate, cons, obj); } void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback, Local data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetCallAsFunctionHandler"); i::Handle obj = isolate->factory()->NewCallHandlerInfo(); SET_FIELD_WRAPPED(isolate, obj, set_callback, callback); SET_FIELD_WRAPPED(isolate, obj, set_js_callback, obj->redirected_callback()); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast(isolate)); } obj->set_data(*Utils::OpenHandle(*data)); i::FunctionTemplateInfo::SetInstanceCallHandler(isolate, cons, obj); } int ObjectTemplate::InternalFieldCount() const { return Utils::OpenHandle(this)->embedder_field_count(); } void ObjectTemplate::SetInternalFieldCount(int value) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (!Utils::ApiCheck(i::Smi::IsValid(value), "v8::ObjectTemplate::SetInternalFieldCount()", "Invalid embedder field count")) { return; } ENTER_V8_NO_SCRIPT_NO_EXCEPTION(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(isolate, this); } Utils::OpenHandle(this)->set_embedder_field_count(value); } bool ObjectTemplate::IsImmutableProto() const { return Utils::OpenHandle(this)->immutable_proto(); } void ObjectTemplate::SetImmutableProto() { auto self = Utils::OpenHandle(this); i::Isolate* isolate = self->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); self->set_immutable_proto(true); } bool ObjectTemplate::IsCodeLike() const { return Utils::OpenHandle(this)->code_like(); } void ObjectTemplate::SetCodeLike() { auto self = Utils::OpenHandle(this); i::Isolate* isolate = self->GetIsolate(); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate); self->set_code_like(true); } // --- S c r i p t s --- // Internally, UnboundScript is a SharedFunctionInfo, 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::StreamedSource::StreamedSource( std::unique_ptr stream, Encoding encoding) : impl_(new i::ScriptStreamingData(std::move(stream), encoding)) {} ScriptCompiler::StreamedSource::~StreamedSource() = default; Local