blob: 4ec93bb0e7679e56cbfa5e31b46e7d11beb3288d [file] [log] [blame]
// 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 <sstream>
#include <string>
#include <utility> // For move
#include <vector>
#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"
#include "src/objects/primitive-heap-object.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/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/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/sandbox/external-pointer.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/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_DARWIN || V8_OS_FREEBSD
#include <signal.h>
#include "include/v8-wasm-trap-handler-posix.h"
#include "src/trap-handler/handler-inside-posix.h"
#endif
#if V8_OS_WIN
#include <windows.h>
// This has to come after windows.h.
#include <versionhelpers.h>
#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<i::Script> script) {
i::Handle<i::Object> scriptName(script->GetNameOrSourceURL(), isolate);
i::Handle<i::Object> source_map_url(script->source_mapping_url(), isolate);
i::Handle<i::Object> 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<v8::Isolate*>(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;
}
Local<PrimitiveArray> 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<i::FixedArray> options =
Utils::OpenHandle(*host_defined_options_.As<FixedArray>());
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_SANDBOXED_POINTERS
// ArrayBufferAllocator to use when sandboxed pointers are used in which case
// all ArrayBuffer backing stores need to be allocated inside the sandbox.
// 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<uint8_t*>(new_data) + old_length, 0,
new_length - old_length);
}
return new_data;
}
};
#endif // V8_SANDBOXED_POINTERS
struct SnapshotCreatorData {
explicit SnapshotCreatorData(Isolate* isolate)
: isolate_(isolate),
default_context_(),
contexts_(isolate),
created_(false) {}
static SnapshotCreatorData* cast(void* data) {
return reinterpret_cast<SnapshotCreatorData*>(data);
}
ArrayBufferAllocator allocator_;
Isolate* isolate_;
Persistent<Context> default_context_;
SerializeInternalFieldsCallback default_embedder_fields_serializer_;
PersistentValueVector<Context> contexts_;
std::vector<SerializeInternalFieldsCallback> 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<i::Isolate*>(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> 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> 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<i::Isolate*>(data->isolate_);
i::HandleScope scope(isolate);
i::Handle<i::Object> obj(i::Object(object), isolate);
i::Handle<i::ArrayList> list;
if (!isolate->heap()->serialized_objects().IsArrayList()) {
list = i::ArrayList::New(isolate, 1);
} else {
list = i::Handle<i::ArrayList>(
i::ArrayList::cast(isolate->heap()->serialized_objects()), isolate);
}
size_t index = static_cast<size_t>(list->Length());
list = i::ArrayList::Add(isolate, list, obj);
isolate->heap()->SetSerializedObjects(*list);
return index;
}
size_t SnapshotCreator::AddData(Local<Context> context, i::Address object) {
DCHECK_NE(object, i::kNullAddress);
DCHECK(!SnapshotCreatorData::cast(data_)->created_);
i::Handle<i::Context> ctx = Utils::OpenHandle(*context);
i::Isolate* isolate = ctx->GetIsolate();
i::HandleScope scope(isolate);
i::Handle<i::Object> obj(i::Object(object), isolate);
i::Handle<i::ArrayList> list;
if (!ctx->serialized_objects().IsArrayList()) {
list = i::ArrayList::New(isolate, 1);
} else {
list = i::Handle<i::ArrayList>(
i::ArrayList::cast(ctx->serialized_objects()), isolate);
}
size_t index = static_cast<size_t>(list->Length());
list = i::ArrayList::Add(isolate, list, obj);
ctx->set_serialized_objects(*list);
return index;
}
namespace {
void ConvertSerializedObjectsToFixedArray(Local<Context> context) {
i::Handle<i::Context> 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<i::ArrayList> list(i::ArrayList::cast(ctx->serialized_objects()),
isolate);
i::Handle<i::FixedArray> 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<i::ArrayList> list(
i::ArrayList::cast(isolate->heap()->serialized_objects()), isolate);
i::Handle<i::FixedArray> 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<i::Isolate*>(data->isolate_);
DCHECK(!data->created_);
DCHECK(!data->default_context_.IsEmpty());
const int num_additional_contexts = static_cast<int>(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<i::FixedArray> global_proxy_sizes =
isolate->factory()->NewFixedArray(num_additional_contexts,
i::AllocationType::kOld);
for (int i = 0; i < num_additional_contexts; i++) {
i::Handle<i::Context> 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<i::Context> 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<i::Context> 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<SerializeInternalFieldsCallback> 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)
: 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)));
}
}
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<i::Object> 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<void>::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<i::Object> 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<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);
}
Value* Eternalize(Isolate* v8_isolate, Value* value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Object object = *Utils::OpenHandle(value);
int index = -1;
isolate->eternal_handles()->Create(isolate, object, &index);
return reinterpret_cast<Value*>(
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<i::Isolate*>(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(
!internal_isolate->was_locker_ever_used() ||
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<i::Isolate*>(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<i::Isolate*>(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<i::Isolate*>(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<i::Isolate*>(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<i::Context> 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<i::Context> 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<Context> backup_incumbent_context)
: backup_incumbent_context_(backup_incumbent_context) {
DCHECK(!backup_incumbent_context_.IsEmpty());
i::Handle<i::Context> 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<i::Context> 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<i::EmbedderDataArray> EmbedderDataFor(Context* context,
int index, bool can_grow,
const char* location) {
i::Handle<i::Context> 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<i::EmbedderDataArray>();
// TODO(ishell): remove cast once embedder_data slot has a proper type.
i::Handle<i::EmbedderDataArray> 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<i::EmbedderDataArray>();
}
data = i::EmbedderDataArray::EnsureCapacity(isolate, data, index);
env->set_embedder_data(*data);
return data;
}
uint32_t Context::GetNumberOfEmbedderDataFields() {
i::Handle<i::Context> 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<uint32_t>(
i::EmbedderDataArray::cast(context->embedder_data()).length());
}
v8::Local<v8::Value> Context::SlowGetEmbedderData(int index) {
const char* location = "v8::Context::GetEmbedderData()";
i::Handle<i::EmbedderDataArray> data =
EmbedderDataFor(this, index, false, location);
if (data.is_null()) return Local<Value>();
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
i::Handle<i::Object> result(i::EmbedderDataSlot(*data, index).load_tagged(),
isolate);
return Utils::ToLocal(result);
}
void Context::SetEmbedderData(int index, v8::Local<Value> value) {
const char* location = "v8::Context::SetEmbedderData()";
i::Handle<i::EmbedderDataArray> data =
EmbedderDataFor(this, index, true, location);
if (data.is_null()) return;
i::Handle<i::Object> 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<i::EmbedderDataArray> 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<i::EmbedderDataArray> 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> name, v8::Local<Data> 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<i::PropertyAttributes>(attribute));
}
void Template::SetPrivate(v8::Local<Private> name, v8::Local<Data> value,
v8::PropertyAttribute attribute) {
Set(Utils::ToLocal(Utils::OpenHandle(reinterpret_cast<Name*>(*name))), value,
attribute);
}
void Template::SetAccessorProperty(v8::Local<v8::Name> name,
v8::Local<FunctionTemplate> getter,
v8::Local<FunctionTemplate> 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<i::PropertyAttributes>(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<ObjectTemplate> ObjectTemplateNew(
i::Isolate* isolate, v8::Local<FunctionTemplate> constructor,
bool do_not_cache);
Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
auto self = Utils::OpenHandle(this);
i::Isolate* i_isolate = self->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::HeapObject> result(self->GetPrototypeTemplate(), i_isolate);
if (result->IsUndefined(i_isolate)) {
// Do not cache prototype objects.
result = Utils::OpenHandle(
*ObjectTemplateNew(i_isolate, Local<FunctionTemplate>(), true));
i::FunctionTemplateInfo::SetPrototypeTemplate(i_isolate, self, result);
}
return ToApiHandle<ObjectTemplate>(result);
}
void FunctionTemplate::SetPrototypeProviderTemplate(
Local<FunctionTemplate> prototype_provider) {
auto self = Utils::OpenHandle(this);
i::Isolate* i_isolate = self->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::FunctionTemplateInfo> 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<i::FunctionTemplateInfo> info,
const char* func) {
DCHECK_IMPLIES(info->instantiated(), info->published());
Utils::ApiCheck(!info->published(), func,
"FunctionTemplate already instantiated");
}
void FunctionTemplate::Inherit(v8::Local<FunctionTemplate> 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<FunctionTemplate> FunctionTemplateNew(
i::Isolate* 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 = {},
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<i::Struct> struct_obj = isolate->factory()->NewStruct(
i::FUNCTION_TEMPLATE_INFO_TYPE, i::AllocationType::kOld);
i::Handle<i::FunctionTemplateInfo> obj =
i::Handle<i::FunctionTemplateInfo>::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> FunctionTemplate::New(
Isolate* 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*>(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<FunctionTemplate>();
}
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
return 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>{},
instance_type, allowed_receiver_instance_type_range_start,
allowed_receiver_instance_type_range_end);
}
Local<FunctionTemplate> FunctionTemplate::NewWithCFunctionOverloads(
Isolate* 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*>(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<FunctionTemplate>();
}
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
return FunctionTemplateNew(i_isolate, callback, data, signature, length,
behavior, false, Local<Private>(),
side_effect_type, c_function_overloads);
}
Local<FunctionTemplate> FunctionTemplate::NewWithCache(
Isolate* 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*>(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> Signature::New(Isolate* isolate,
Local<FunctionTemplate> receiver) {
return Utils::SignatureToLocal(Utils::OpenHandle(*receiver));
}
Local<AccessorSignature> AccessorSignature::New(
Isolate* isolate, Local<FunctionTemplate> receiver) {
return Utils::AccessorSignatureToLocal(Utils::OpenHandle(*receiver));
}
#define SET_FIELD_WRAPPED(isolate, obj, setter, cdata) \
do { \
i::Handle<i::Object> foreign = FromCData(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::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<i::CallHandlerInfo> 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<v8::Isolate*>(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<i::FixedArray> function_overloads =
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::Handle<i::Object> address =
FromCData(isolate, c_function.GetAddress());
function_overloads->set(
i::FunctionTemplateInfo::kFunctionOverloadEntrySize * i, *address);
i::Handle<i::Object> 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 <typename Getter, typename Setter>
i::Handle<i::AccessorInfo> MakeAccessorInfo(
i::Isolate* isolate, v8::Local<Name> name, Getter getter, Setter setter,
v8::Local<Value> data, v8::AccessControl settings,
v8::Local<AccessorSignature> signature, bool is_special_data_property,
bool replace_on_access) {
i::Handle<i::AccessorInfo> 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<Setter>(&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<i::Name> accessor_name = Utils::OpenHandle(*name);
if (!accessor_name->IsUniqueName()) {
accessor_name = isolate->factory()->InternalizeString(
i::Handle<i::String>::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<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
i::Handle<i::FunctionTemplateInfo> handle = Utils::OpenHandle(this, true);
if (!Utils::ApiCheck(!handle.is_null(),
"v8::FunctionTemplate::InstanceTemplate()",
"Reading from empty handle")) {
return Local<ObjectTemplate>();
}
i::Isolate* isolate = handle->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
if (handle->GetInstanceTemplate().IsUndefined(isolate)) {
Local<ObjectTemplate> templ =
ObjectTemplate::New(isolate, ToApiHandle<FunctionTemplate>(handle));
i::FunctionTemplateInfo::SetInstanceTemplate(isolate, handle,
Utils::OpenHandle(*templ));
}
i::Handle<i::ObjectTemplateInfo> 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<String> 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> ObjectTemplate::New(
Isolate* isolate, v8::Local<FunctionTemplate> constructor) {
return New(reinterpret_cast<i::Isolate*>(isolate), constructor);
}
static Local<ObjectTemplate> ObjectTemplateNew(
i::Isolate* isolate, v8::Local<FunctionTemplate> constructor,
bool do_not_cache) {
LOG_API(isolate, ObjectTemplate, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Struct> struct_obj = isolate->factory()->NewStruct(
i::OBJECT_TEMPLATE_INFO_TYPE, i::AllocationType::kOld);
i::Handle<i::ObjectTemplateInfo> obj =
i::Handle<i::ObjectTemplateInfo>::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> ObjectTemplate::New(
i::Isolate* isolate, v8::Local<FunctionTemplate> 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<i::FunctionTemplateInfo> 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<i::FunctionTemplateInfo>(info, isolate);
}
Local<FunctionTemplate> templ =
FunctionTemplate::New(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::FunctionTemplateInfo> constructor = Utils::OpenHandle(*templ);
i::FunctionTemplateInfo::SetInstanceTemplate(
isolate, constructor, Utils::OpenHandle(object_template));
Utils::OpenHandle(object_template)->set_constructor(*constructor);
return constructor;
}
template <typename Getter, typename Setter, typename Data, typename Template>
static void TemplateSetAccessor(
Template* template_obj, v8::Local<Name> name, Getter getter, Setter setter,
Data data, AccessControl settings, PropertyAttribute attribute,
v8::Local<AccessorSignature> 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<i::AccessorInfo> 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<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(isolate, info, accessor_info);
}
void Template::SetNativeDataProperty(
v8::Local<String> name, AccessorGetterCallback getter,
AccessorSetterCallback setter, v8::Local<Value> data,
PropertyAttribute attribute, v8::Local<AccessorSignature> 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> name, AccessorNameGetterCallback getter,
AccessorNameSetterCallback setter, v8::Local<Value> data,
PropertyAttribute attribute, v8::Local<AccessorSignature> 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> 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,
DEFAULT, attribute, Local<AccessorSignature>(), true,
true, getter_side_effect_type, setter_side_effect_type);
}
void Template::SetIntrinsicDataProperty(Local<Name> 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<i::PropertyAttributes>(attribute));
}
void ObjectTemplate::SetAccessor(v8::Local<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter,
v8::Local<Value> data, AccessControl settings,
PropertyAttribute attribute,
v8::Local<AccessorSignature> 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> name,
AccessorNameGetterCallback getter,
AccessorNameSetterCallback setter,
v8::Local<Value> data, AccessControl settings,
PropertyAttribute attribute,
v8::Local<AccessorSignature> 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 <typename Getter, typename Setter, typename Query, typename Descriptor,
typename Deleter, typename Enumerator, typename Definer>
static i::Handle<i::InterceptorInfo> CreateInterceptorInfo(
i::Isolate* isolate, Getter getter, Setter setter, Query query,
Descriptor descriptor, Deleter remover, Enumerator enumerator,
Definer definer, Local<Value> data, PropertyHandlerFlags flags) {
auto obj = i::Handle<i::InterceptorInfo>::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<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kOnlyInterceptStrings)));
obj->set_all_can_read(static_cast<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kAllCanRead));
obj->set_non_masking(static_cast<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kNonMasking));
obj->set_has_no_side_effect(
static_cast<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kHasNoSideEffect));
if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
}
obj->set_data(*Utils::OpenHandle(*data));
return obj;
}
template <typename Getter, typename Setter, typename Query, typename Descriptor,
typename Deleter, typename Enumerator, typename Definer>
static i::Handle<i::InterceptorInfo> CreateNamedInterceptorInfo(
i::Isolate* isolate, Getter getter, Setter setter, Query query,
Descriptor descriptor, Deleter remover, Enumerator enumerator,
Definer definer, Local<Value> data, PropertyHandlerFlags flags) {
auto interceptor =
CreateInterceptorInfo(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>
static i::Handle<i::InterceptorInfo> CreateIndexedInterceptorInfo(
i::Isolate* isolate, Getter getter, Setter setter, Query query,
Descriptor descriptor, Deleter remover, Enumerator enumerator,
Definer definer, Local<Value> data, PropertyHandlerFlags flags) {
auto interceptor =
CreateInterceptorInfo(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>
static 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* 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<Value> 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<i::Struct> struct_info = isolate->factory()->NewStruct(
i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld);
i::Handle<i::AccessCheckInfo> info =
i::Handle<i::AccessCheckInfo>::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<v8::Isolate*>(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<Value> 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<i::Struct> struct_info = isolate->factory()->NewStruct(
i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld);
i::Handle<i::AccessCheckInfo> info =
i::Handle<i::AccessCheckInfo>::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<v8::Isolate*>(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<Value> 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<i::CallHandlerInfo> 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<v8::Isolate*>(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<ExternalSourceStream> stream, Encoding encoding)
: impl_(new i::ScriptStreamingData(std::move(stream), encoding)) {}
ScriptCompiler::StreamedSource::~StreamedSource() = default;
Local<Script> UnboundScript::BindToCurrentContext() {
auto function_info =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = function_info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::JSFunction> function =
i::Factory::JSFunctionBuilder{isolate, function_info,
isolate->native_context()}
.Build();
return ToApiHandle<Script>(function);
}
int UnboundScript::GetId() const {
auto function_info = i::SharedFunctionInfo::cast(*Utils::OpenHandle(this));
i::Isolate* isolate = function_info.GetIsolate();
LOG_API(isolate, UnboundScript, GetId);
return i::Script::cast(function_info.script()).id();
}
int UnboundScript::GetLineNumber(int code_pos) {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
LOG_API(isolate, UnboundScript, GetLineNumber);
if (obj->script().IsScript()) {
i::Handle<i::Script> script(i::Script::cast(obj->script()), isolate);
return i::Script::GetLineNumber(script, code_pos);
} else {
return -1;
}
}
Local<Value> UnboundScript::GetScriptName() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
LOG_API(isolate, UnboundScript, GetName);
if (obj->script().IsScript()) {
i::Object name = i::Script::cast(obj->script()).name();
return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
} else {
return Local<String>();
}
}
Local<Value> UnboundScript::GetSourceURL() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
LOG_API(isolate, UnboundScript, GetSourceURL);
if (obj->script().IsScript()) {
i::Object url = i::Script::cast(obj->script()).source_url();
return Utils::ToLocal(i::Handle<i::Object>(url, isolate));
} else {
return Local<String>();
}
}
Local<Value> UnboundScript::GetSourceMappingURL() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
LOG_API(isolate, UnboundScript, GetSourceMappingURL);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
if (obj->script().IsScript()) {
i::Object url = i::Script::cast(obj->script()).source_mapping_url();
return Utils::ToLocal(i::Handle<i::Object>(url, 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 isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
ENTER_V8(isolate, context, Script, Run, MaybeLocal<Value>(),
InternalEscapableScope);
i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
i::NestedTimedHistogramScope execute_timer(isolate->counters()->execute(),
isolate);
i::AggregatingHistogramTimerScope histogram_timer(
isolate->counters()->compile_lazy());
auto fun = i::Handle<i::JSFunction>::cast(Utils::OpenHandle(this));
// TODO(crbug.com/1193459): remove once ablation study is completed
base::ElapsedTimer timer;
base::TimeDelta delta;
if (i::FLAG_script_delay > 0) {
delta = v8::base::TimeDelta::FromMillisecondsD(i::FLAG_script_delay);
}
if (i::FLAG_script_delay_once > 0 && !isolate->did_run_script_delay()) {
delta = v8::base::TimeDelta::FromMillisecondsD(i::FLAG_script_delay_once);
isolate->set_did_run_script_delay(true);
}
if (i::FLAG_script_delay_fraction > 0.0) {
timer.Start();
} else if (delta.InMicroseconds() > 0) {
timer.Start();
while (timer.Elapsed() < delta) {
// Busy wait.
}
}
if (V8_UNLIKELY(i::FLAG_experimental_web_snapshots)) {
i::Handle<i::HeapObject> maybe_script =
handle(fun->shared().script(), isolate);
if (maybe_script->IsScript() &&
i::Script::cast(*maybe_script).type() == i::Script::TYPE_WEB_SNAPSHOT) {
i::WebSnapshotDeserializer deserializer(
reinterpret_cast<i::Isolate*>(v8_isolate),
i::Handle<i::Script>::cast(maybe_script));
deserializer.Deserialize();
RETURN_ON_FAILED_EXECUTION(Value);
Local<Value> result = v8::Undefined(v8_isolate);
RETURN_ESCAPED(result);
}
}
i::Handle<i::Object> receiver = isolate->global_proxy();
// TODO(cbruni, chromium:1244145): Remove once migrated to the context.
i::Handle<i::Object> options(
i::Script::cast(fun->shared().script()).host_defined_options(), isolate);
Local<Value> result;
has_pending_exception = !ToLocal<Value>(
i::Execution::CallScript(isolate, fun, receiver, options), &result);
if (i::FLAG_script_delay_fraction > 0.0) {
delta = v8::base::TimeDelta::FromMillisecondsD(
timer.Elapsed().InMillisecondsF() * i::FLAG_script_delay_fraction);
timer.Restart();
while (timer.Elapsed() < delta) {
// Busy wait.
}
}
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
Local<Value> ScriptOrModule::GetResourceName() {
i::Handle<i::ScriptOrModule> obj = Utils::OpenHandle(this);
i::Isolate* isolate = i::GetIsolateFromWritableObject(*obj);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Object> val(obj->resource_name(), isolate);
return ToApiHandle<Value>(val);
}
Local<PrimitiveArray> ScriptOrModule::GetHostDefinedOptions() {
return HostDefinedOptions().As<PrimitiveArray>();
}
Local<Data> ScriptOrModule::HostDefinedOptions() {
i::Handle<i::ScriptOrModule> obj = Utils::OpenHandle(this);
i::Isolate* isolate = i::GetIsolateFromWritableObject(*obj);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Object> val(obj->host_defined_options(), isolate);
return ToApiHandle<Data>(val);
}
Local<UnboundScript> Script::GetUnboundScript() {
i::DisallowGarbageCollection no_gc;
i::Handle<i::JSFunction> obj = Utils::OpenHandle(this);
i::SharedFunctionInfo sfi = (*obj).shared();
i::Isolate* isolate = sfi.GetIsolate();
return ToApiHandle<UnboundScript>(i::handle(sfi, isolate));
}
Local<Value> Script::GetResourceName() {
i::DisallowGarbageCollection no_gc;
i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
i::SharedFunctionInfo sfi = (*func).shared();
i::Isolate* isolate = func->GetIsolate();
CHECK(sfi.script().IsScript());
return ToApiHandle<Value>(
i::handle(i::Script::cast(sfi.script()).name(), isolate));
}
// static
Local<PrimitiveArray> PrimitiveArray::New(Isolate* v8_isolate, int length) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
Utils::ApiCheck(length >= 0, "v8::PrimitiveArray::New",
"length must be equal or greater than zero");
i::Handle<i::FixedArray> array = isolate->factory()->NewFixedArray(length);
return ToApiHandle<PrimitiveArray>(array);
}
int PrimitiveArray::Length() const {
i::Handle<i::FixedArray> array = Utils::OpenHandle(this);
return array->length();
}
void PrimitiveArray::Set(Isolate* v8_isolate, int index,
Local<Primitive> item) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Handle<i::FixedArray> array = Utils::OpenHandle(this);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(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");
i::Handle<i::Object> i_item = Utils::OpenHandle(*item);
array->set(index, *i_item);
}
Local<Primitive> PrimitiveArray::Get(Isolate* v8_isolate, int index) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Handle<i::FixedArray> array = Utils::OpenHandle(this);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(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");
i::Handle<i::Object> i_item(array->get(index), isolate);
return ToApiHandle<Primitive>(i_item);
}
void v8::PrimitiveArray::CheckCast(v8::Data* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(
obj->IsFixedArray(), "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 {
i::Handle<i::FixedArray> self = Utils::OpenHandle(this);
return self->length();
}
Local<Data> FixedArray::Get(Local<Context> context, int i) const {
i::Handle<i::FixedArray> self = Utils::OpenHandle(this);
auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
CHECK_LT(i, self->length());
i::Handle<i::Object> entry(self->get(i), isolate);
return ToApiHandle<Data>(entry);
}
Local<String> ModuleRequest::GetSpecifier() const {
i::Handle<i::ModuleRequest> self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
return ToApiHandle<String>(i::handle(self->specifier(), isolate));
}
int ModuleRequest::GetSourceOffset() const {
return Utils::OpenHandle(this)->position();
}
Local<FixedArray> ModuleRequest::GetImportAssertions() const {
i::Handle<i::ModuleRequest> self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
return ToApiHandle<FixedArray>(i::handle(self->import_assertions(), isolate));
}
Module::Status Module::GetStatus() const {
i::Handle<i::Module> self = Utils::OpenHandle(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:
case i::Module::kEvaluatingAsync:
return kEvaluating;
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");
i::Handle<i::Module> self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
return ToApiHandle<Value>(i::handle(self->GetException(), isolate));
}
Local<FixedArray> Module::GetModuleRequests() const {
i::Handle<i::Module> self = Utils::OpenHandle(this);
if (self->IsSyntheticModule()) {
// Synthetic modules are leaf nodes in the module graph. They have no
// ModuleRequests.
return ToApiHandle<FixedArray>(
self->GetReadOnlyRoots().empty_fixed_array_handle());
} else {
i::Isolate* isolate = self->GetIsolate();
i::Handle<i::FixedArray> module_requests(
i::Handle<i::SourceTextModule>::cast(self)->info().module_requests(),
isolate);
return ToApiHandle<FixedArray>(module_requests);
}
}
Location Module::SourceOffsetToLocation(int offset) const {
i::Handle<i::Module> self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
Utils::ApiCheck(
self->IsSourceTextModule(), "v8::Module::SourceOffsetToLocation",
"v8::Module::SourceOffsetToLocation must be used on an SourceTextModule");
i::Handle<i::Script> script(
i::Handle<i::SourceTextModule>::cast(self)->GetScript(), isolate);
i::Script::PositionInfo info;
i::Script::GetPositionInfo(script, offset, &info, i::Script::WITH_OFFSET);
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");
i::Handle<i::Module> self = Utils::OpenHandle(this);
auto isolate = self->GetIsolate();
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::JSModuleNamespace> module_namespace =
i::Module::GetModuleNamespace(isolate, self);
return ToApiHandle<Value>(module_namespace);
}
Local<UnboundModuleScript> Module::GetUnboundModuleScript() {
i::Handle<i::Module> self = Utils::OpenHandle(this);
Utils::ApiCheck(
self->IsSourceTextModule(), "v8::Module::GetUnboundModuleScript",
"v8::Module::GetUnboundModuleScript must be used on an SourceTextModule");
auto isolate = self->GetIsolate();
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate);
return ToApiHandle<UnboundModuleScript>(i::handle(
i::Handle<i::SourceTextModule>::cast(self)->GetSharedFunctionInfo(),
isolate));
}
int Module::ScriptId() const {
i::Module self = *Utils::OpenHandle(this);
Utils::ApiCheck(self.IsSourceTextModule(), "v8::Module::ScriptId",
"v8::Module::ScriptId must be used on an SourceTextModule");
ASSERT_NO_SCRIPT_NO_EXCEPTION(self.GetIsolate());
return i::SourceTextModule::cast(self).GetScript().id();
}
bool Module::IsGraphAsync() const {
Utils::ApiCheck(
GetStatus() >= kInstantiated, "v8::Module::IsGraphAsync",
"v8::Module::IsGraphAsync must be used on an instantiated module");
i::Module self = *Utils::OpenHandle(this);
auto isolate = self.GetIsolate();
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate);
return self.IsGraphAsync(isolate);
}
bool Module::IsSourceTextModule() const {
return Utils::OpenHandle(this)->IsSourceTextModule();
}
bool Module::IsSyntheticModule() const {
return Utils::OpenHandle(this)->IsSyntheticModule();
}
int Module::GetIdentityHash() const { return Utils::OpenHandle(this)->hash(); }
Maybe<bool> Module::InstantiateModule(Local<Context> context,
Module::ResolveModuleCallback callback) {
auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
ENTER_V8(isolate, context, Module, InstantiateModule, Nothing<bool>(),
i::HandleScope);
has_pending_exception = !i::Module::Instantiate(
isolate, Utils::OpenHandle(this), context, callback, nullptr);
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
return Just(true);
}
MaybeLocal<Value> Module::Evaluate(Local<Context> context) {
auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
ENTER_V8(isolate, context, Module, Evaluate, MaybeLocal<Value>(),
InternalEscapableScope);
i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
i::NestedTimedHistogramScope execute_timer(isolate->counters()->execute(),
isolate);
i::AggregatingHistogramTimerScope timer(isolate->counters()->compile_lazy());
i::Handle<i::Module> self = Utils::OpenHandle(this);
Utils::ApiCheck(self->status() >= i::Module::kLinked, "Module::Evaluate",
"Expected instantiated module");
Local<Value> result;
has_pending_exception = !ToLocal(i::Module::Evaluate(isolate, self), &result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
Local<Module> Module::CreateSyntheticModule(
Isolate* isolate, Local<String> module_name,
const std::vector<Local<v8::String>>& export_names,
v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) {
auto i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::String> i_module_name = Utils::OpenHandle(*module_name);
i::Handle<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::Handle<i::String> str = i_isolate->factory()->InternalizeString(
Utils::OpenHandle(*export_names[i]));
i_export_names->set(i, *str);
}
return v8::Utils::ToLocal(
i::Handle<i::Module>(i_isolate->factory()->NewSyntheticModule(
i_module_name, i_export_names, evaluation_steps)));
}
Maybe<bool> Module::SetSyntheticModuleExport(Isolate* isolate,
Local<String> export_name,
Local<v8::Value> export_value) {
auto i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::String> i_export_name = Utils::OpenHandle(*export_name);
i::Handle<i::Object> i_export_value = Utils::OpenHandle(*export_value);
i::Handle<i::Module> self = Utils::OpenHandle(this);
Utils::ApiCheck(self->IsSyntheticModule(),
"v8::Module::SyntheticModuleSetExport",
"v8::Module::SyntheticModuleSetExport must only be called on "
"a SyntheticModule");
ENTER_V8_NO_SCRIPT(i_isolate, isolate->GetCurrentContext(), Module,
SetSyntheticModuleExport, Nothing<bool>(), i::HandleScope);
has_pending_exception =
i::SyntheticModule::SetExport(i_isolate,
i::Handle<i::SyntheticModule>::cast(self),
i_export_name, i_export_value)
.IsNothing();
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
return Just(true);
}
namespace {
i::ScriptDetails GetScriptDetails(
i::Isolate* 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()
? 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 isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler");
ENTER_V8_NO_SCRIPT(isolate, v8_isolate->GetCurrentContext(), ScriptCompiler,
CompileUnbound, MaybeLocal<UnboundScript>(),
InternalEscapableScope);
i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
i::Handle<i::SharedFunctionInfo> result;
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileScript");
i::ScriptDetails script_details = GetScriptDetails(
isolate, source->resource_name, source->resource_line_offset,
source->resource_column_offset, source->source_map_url,
source->host_defined_options, source->resource_options);
i::MaybeHandle<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(
isolate, str, script_details, deserialize_task.get(), options,
no_cache_reason, i::NOT_NATIVES_CODE);
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(
isolate, str, script_details, cached_data.get(), options,
no_cache_reason, i::NOT_NATIVES_CODE);
source->cached_data->rejected = cached_data->rejected();
}
} else {
// Compile without any cache.
maybe_function_info = i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, script_details, options, no_cache_reason,
i::NOT_NATIVES_CODE);
}
has_pending_exception = !maybe_function_info.ToHandle(&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::CompileUnboundScript",
"v8::ScriptCompiler::CompileModule must be used to compile modules");
return CompileUnboundInternal(v8_isolate, source, options, no_cache_reason);
}
MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
Source* source,
CompileOptions options,
NoCacheReason no_cache_reason) {
Utils::ApiCheck(
!source->GetResourceOptions().IsModule(), "v8::ScriptCompiler::Compile",
"v8::ScriptCompiler::CompileModule must be used to compile modules");
auto isolate = context->GetIsolate();
MaybeLocal<UnboundScript> maybe =
CompileUnboundInternal(isolate, source, options, no_cache_reason);
Local<UnboundScript> result;
if (!maybe.ToLocal(&result)) return MaybeLocal<Script>();
v8::Context::Scope scope(context);
return result->BindToCurrentContext();
}
MaybeLocal<Module> ScriptCompiler::CompileModule(
Isolate* isolate, Source* source, CompileOptions options,
NoCacheReason no_cache_reason) {
Utils::ApiCheck(options == kNoCompileOptions || options == kConsumeCodeCache,
"v8::ScriptCompiler::CompileModule",
"Invalid CompileOptions");
Utils::ApiCheck(source->GetResourceOptions().IsModule(),
"v8::ScriptCompiler::CompileModule",
"Invalid ScriptOrigin: is_module must be true");
MaybeLocal<UnboundScript> maybe =
CompileUnboundInternal(isolate, source, options, no_cache_reason);
Local<UnboundScript> unbound;
if (!maybe.ToLocal(&unbound)) return MaybeLocal<Module>();
i::Handle<i::SharedFunctionInfo> shared = Utils::OpenHandle(*unbound);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
return ToApiHandle<Module>(i_isolate->factory()->NewSourceTextModule(shared));
}
namespace {
bool IsIdentifier(i::Isolate* isolate, i::Handle<i::String> string) {
string = i::String::Flatten(isolate, string);
const int length = string->length();
if (length == 0) return false;
if (!i::IsIdentifierStart(string->Get(0))) return false;
i::DisallowGarbageCollection no_gc;
i::String::FlatContent flat = string->GetFlatContent(no_gc);
if (flat.IsOneByte()) {
auto vector = flat.ToOneByteVector();
for (int i = 1; i < length; i++) {
if (!i::IsIdentifierPart(vector[i])) return false;
}
} else {
auto vector = flat.ToUC16Vector();
for (int i = 1; i < length; i++) {
if (!i::IsIdentifierPart(vector[i])) return false;
}
}
return true;
}
} // namespace
// static
V8_WARN_UNUSED_RESULT MaybeLocal<Function> ScriptCompiler::CompileFunction(
Local<Context> context, Source* source, size_t arguments_count,
Local<String> arguments[], size_t context_extension_count,
Local<Object> context_extensions[], CompileOptions options,
NoCacheReason no_cache_reason) {
return CompileFunctionInternal(context, source, arguments_count, arguments,
context_extension_count, context_extensions,
options, no_cache_reason, nullptr);
}
// static
MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
Local<Context> context, Source* source, size_t arguments_count,
Local<String> arguments[], size_t context_extension_count,
Local<Object> context_extensions[], CompileOptions options,
NoCacheReason no_cache_reason,
Local<ScriptOrModule>* script_or_module_out) {
return CompileFunctionInternal(
context, source, arguments_count, arguments, context_extension_count,
context_extensions, options, no_cache_reason, script_or_module_out);
}
MaybeLocal<Function> S