diff options
Diffstat (limited to 'deps/v8/src/api.cc')
-rw-r--r-- | deps/v8/src/api.cc | 2122 |
1 files changed, 1144 insertions, 978 deletions
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index bf35154843..6858a325c4 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -15,6 +15,7 @@ #include "include/v8-experimental.h" #include "include/v8-profiler.h" #include "include/v8-testing.h" +#include "include/v8-util.h" #include "src/accessors.h" #include "src/api-experimental.h" #include "src/api-natives.h" @@ -35,11 +36,14 @@ #include "src/debug/debug.h" #include "src/deoptimizer.h" #include "src/execution.h" +#include "src/frames-inl.h" #include "src/gdb-jit.h" #include "src/global-handles.h" +#include "src/globals.h" #include "src/icu_util.h" #include "src/isolate-inl.h" #include "src/json-parser.h" +#include "src/json-stringifier.h" #include "src/messages.h" #include "src/parsing/parser.h" #include "src/parsing/scanner-character-streams.h" @@ -48,14 +52,15 @@ #include "src/profiler/heap-profiler.h" #include "src/profiler/heap-snapshot-generator-inl.h" #include "src/profiler/profile-generator-inl.h" -#include "src/profiler/sampler.h" -#include "src/property.h" +#include "src/profiler/tick-sample.h" #include "src/property-descriptor.h" #include "src/property-details.h" +#include "src/property.h" #include "src/prototype.h" -#include "src/runtime/runtime.h" #include "src/runtime-profiler.h" +#include "src/runtime/runtime.h" #include "src/simulator.h" +#include "src/snapshot/code-serializer.h" #include "src/snapshot/natives.h" #include "src/snapshot/snapshot.h" #include "src/startup-data-util.h" @@ -65,58 +70,61 @@ #include "src/v8threads.h" #include "src/version.h" #include "src/vm-state-inl.h" - +#include "src/wasm/wasm-module.h" namespace v8 { -#define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) - +#define LOG_API(isolate, class_name, function_name) \ + i::RuntimeCallTimerScope _runtime_timer( \ + isolate, &i::RuntimeCallStats::API_##class_name##_##function_name); \ + TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED( \ + isolate, &internal::tracing::TraceEventStatsTable:: \ + API_##class_name##_##function_name); \ + LOG(isolate, ApiEntryCall("v8::" #class_name "::" #function_name)) #define ENTER_V8(isolate) i::VMState<v8::OTHER> __state__((isolate)) - -#define PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \ - bailout_value, HandleScopeClass, \ - do_callback) \ - if (IsExecutionTerminatingCheck(isolate)) { \ - return bailout_value; \ - } \ - HandleScopeClass handle_scope(isolate); \ - CallDepthScope call_depth_scope(isolate, context, do_callback); \ - LOG_API(isolate, function_name); \ - ENTER_V8(isolate); \ +#define PREPARE_FOR_EXECUTION_GENERIC(isolate, context, class_name, \ + function_name, bailout_value, \ + HandleScopeClass, do_callback) \ + if (IsExecutionTerminatingCheck(isolate)) { \ + return bailout_value; \ + } \ + HandleScopeClass handle_scope(isolate); \ + CallDepthScope<do_callback> call_depth_scope(isolate, context); \ + LOG_API(isolate, class_name, function_name); \ + ENTER_V8(isolate); \ bool has_pending_exception = false - -#define PREPARE_FOR_EXECUTION_WITH_CONTEXT( \ - context, function_name, bailout_value, HandleScopeClass, do_callback) \ - auto isolate = context.IsEmpty() \ - ? i::Isolate::Current() \ - : reinterpret_cast<i::Isolate*>(context->GetIsolate()); \ - PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \ +#define PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \ + bailout_value, HandleScopeClass, \ + do_callback) \ + auto isolate = context.IsEmpty() \ + ? i::Isolate::Current() \ + : reinterpret_cast<i::Isolate*>(context->GetIsolate()); \ + PREPARE_FOR_EXECUTION_GENERIC(isolate, context, class_name, function_name, \ bailout_value, HandleScopeClass, do_callback); +#define PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, class_name, function_name, \ + T) \ + PREPARE_FOR_EXECUTION_GENERIC(isolate, Local<Context>(), class_name, \ + function_name, MaybeLocal<T>(), \ + InternalEscapableScope, false); -#define PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, function_name, T) \ - PREPARE_FOR_EXECUTION_GENERIC(isolate, Local<Context>(), function_name, \ - MaybeLocal<T>(), InternalEscapableScope, \ - false); +#define PREPARE_FOR_EXECUTION(context, class_name, function_name, T) \ + PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \ + MaybeLocal<T>(), InternalEscapableScope, \ + false) +#define PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, class_name, \ + function_name, T) \ + PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \ + MaybeLocal<T>(), InternalEscapableScope, \ + true) -#define PREPARE_FOR_EXECUTION(context, function_name, T) \ - PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, MaybeLocal<T>(), \ - InternalEscapableScope, false) - - -#define PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, function_name, T) \ - PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, MaybeLocal<T>(), \ - InternalEscapableScope, true) - - -#define PREPARE_FOR_EXECUTION_PRIMITIVE(context, function_name, T) \ - PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, Nothing<T>(), \ - i::HandleScope, false) - +#define PREPARE_FOR_EXECUTION_PRIMITIVE(context, class_name, function_name, T) \ + PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \ + Nothing<T>(), i::HandleScope, false) #define EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, value) \ do { \ @@ -167,28 +175,34 @@ void CheckMicrotasksScopesConsistency(i::Isolate* isolate) { } #endif - +template <bool do_callback> class CallDepthScope { public: - explicit CallDepthScope(i::Isolate* isolate, Local<Context> context, - bool do_callback) - : isolate_(isolate), - context_(context), - escaped_(false), - do_callback_(do_callback) { + explicit CallDepthScope(i::Isolate* isolate, Local<Context> context) + : isolate_(isolate), context_(context), escaped_(false) { // TODO(dcarney): remove this when blink stops crashing. DCHECK(!isolate_->external_caught_exception()); isolate_->IncrementJsCallsFromApiCounter(); isolate_->handle_scope_implementer()->IncrementCallDepth(); - if (!context_.IsEmpty()) context_->Enter(); - if (do_callback_) isolate_->FireBeforeCallEnteredCallback(); + if (!context.IsEmpty()) { + i::Handle<i::Context> env = Utils::OpenHandle(*context); + i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); + if (isolate->context() != nullptr && + isolate->context()->native_context() == env->native_context() && + impl->LastEnteredContextWas(env)) { + context_ = Local<Context>(); + } else { + context_->Enter(); + } + } + if (do_callback) isolate_->FireBeforeCallEnteredCallback(); } ~CallDepthScope() { if (!context_.IsEmpty()) context_->Exit(); if (!escaped_) isolate_->handle_scope_implementer()->DecrementCallDepth(); - if (do_callback_) isolate_->FireCallCompletedCallback(); + if (do_callback) isolate_->FireCallCompletedCallback(); #ifdef DEBUG - if (do_callback_) CheckMicrotasksScopesConsistency(isolate_); + if (do_callback) CheckMicrotasksScopesConsistency(isolate_); #endif } @@ -238,9 +252,8 @@ void i::FatalProcessOutOfMemory(const char* location) { i::V8::FatalProcessOutOfMemory(location, false); } - -// When V8 cannot allocated memory FatalProcessOutOfMemory is called. -// The default fatal error handler is called and execution is stopped. +// When V8 cannot allocate memory FatalProcessOutOfMemory is called. The default +// OOM error handler is called and execution is stopped. void i::V8::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { i::Isolate* isolate = i::Isolate::Current(); char last_few_messages[Heap::kTraceRingBufferSize + 1]; @@ -249,49 +262,53 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { memset(js_stacktrace, 0, Heap::kStacktraceBufferSize + 1); i::HeapStats heap_stats; - int start_marker; + intptr_t start_marker; heap_stats.start_marker = &start_marker; - int new_space_size; + size_t new_space_size; heap_stats.new_space_size = &new_space_size; - int new_space_capacity; + size_t new_space_capacity; heap_stats.new_space_capacity = &new_space_capacity; - intptr_t old_space_size; + size_t old_space_size; heap_stats.old_space_size = &old_space_size; - intptr_t old_space_capacity; + size_t old_space_capacity; heap_stats.old_space_capacity = &old_space_capacity; - intptr_t code_space_size; + size_t code_space_size; heap_stats.code_space_size = &code_space_size; - intptr_t code_space_capacity; + size_t code_space_capacity; heap_stats.code_space_capacity = &code_space_capacity; - intptr_t map_space_size; + size_t map_space_size; heap_stats.map_space_size = &map_space_size; - intptr_t map_space_capacity; + size_t map_space_capacity; heap_stats.map_space_capacity = &map_space_capacity; - intptr_t lo_space_size; + size_t lo_space_size; heap_stats.lo_space_size = &lo_space_size; - int global_handle_count; + size_t global_handle_count; heap_stats.global_handle_count = &global_handle_count; - int weak_global_handle_count; + size_t weak_global_handle_count; heap_stats.weak_global_handle_count = &weak_global_handle_count; - int pending_global_handle_count; + size_t pending_global_handle_count; heap_stats.pending_global_handle_count = &pending_global_handle_count; - int near_death_global_handle_count; + size_t near_death_global_handle_count; heap_stats.near_death_global_handle_count = &near_death_global_handle_count; - int free_global_handle_count; + size_t free_global_handle_count; heap_stats.free_global_handle_count = &free_global_handle_count; - intptr_t memory_allocator_size; + size_t memory_allocator_size; heap_stats.memory_allocator_size = &memory_allocator_size; - intptr_t memory_allocator_capacity; + size_t memory_allocator_capacity; heap_stats.memory_allocator_capacity = &memory_allocator_capacity; - int objects_per_type[LAST_TYPE + 1] = {0}; + 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; - int size_per_type[LAST_TYPE + 1] = {0}; + 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; - int end_marker; + 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 @@ -303,9 +320,7 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { PrintF("\n<--- Last few GCs --->\n%s\n", first_newline); PrintF("\n<--- JS stacktrace --->\n%s\n", js_stacktrace); } - Utils::ApiCheck(false, location, is_heap_oom - ? "Allocation failed - JavaScript heap out of memory" - : "Allocation failed - process out of memory"); + Utils::ReportOOMFailure(location, is_heap_oom); // If the fatal error handler returns, we stop execution. FATAL("API fatal error handler returned after process out of memory"); } @@ -314,7 +329,7 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { void Utils::ReportApiFailure(const char* location, const char* message) { i::Isolate* isolate = i::Isolate::Current(); FatalErrorCallback callback = isolate->exception_behavior(); - if (callback == NULL) { + if (callback == nullptr) { base::OS::PrintError("\n#\n# Fatal error in %s\n# %s\n#\n\n", location, message); base::OS::Abort(); @@ -324,6 +339,28 @@ void Utils::ReportApiFailure(const char* location, const char* message) { isolate->SignalFatalError(); } +void Utils::ReportOOMFailure(const char* location, bool is_heap_oom) { + i::Isolate* isolate = i::Isolate::Current(); + 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); + base::OS::Abort(); + } 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(); +} static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) { if (isolate->has_scheduled_exception()) { @@ -383,91 +420,159 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context, return true; } -StartupData SerializeIsolateAndContext( - Isolate* isolate, Persistent<Context>* context, - i::Snapshot::Metadata metadata, - i::StartupSerializer::FunctionCodeHandling function_code_handling) { - if (context->IsEmpty()) return {NULL, 0}; +struct SnapshotCreatorData { + explicit SnapshotCreatorData(Isolate* isolate) + : isolate_(isolate), + contexts_(isolate), + templates_(isolate), + created_(false) {} - i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); + static SnapshotCreatorData* cast(void* data) { + return reinterpret_cast<SnapshotCreatorData*>(data); + } + + ArrayBufferAllocator allocator_; + Isolate* isolate_; + PersistentValueVector<Context> contexts_; + PersistentValueVector<Template> templates_; + bool created_; +}; + +} // namespace + +SnapshotCreator::SnapshotCreator(intptr_t* external_references, + StartupData* existing_snapshot) { + i::Isolate* internal_isolate = new i::Isolate(true); + Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate); + SnapshotCreatorData* data = new SnapshotCreatorData(isolate); + data->isolate_ = isolate; + internal_isolate->set_array_buffer_allocator(&data->allocator_); + internal_isolate->set_api_external_references(external_references); + isolate->Enter(); + if (existing_snapshot) { + internal_isolate->set_snapshot_blob(existing_snapshot); + i::Snapshot::Initialize(internal_isolate); + } else { + internal_isolate->Init(nullptr); + } + data_ = data; +} + +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_; +} + +size_t SnapshotCreator::AddContext(Local<Context> context) { + DCHECK(!context.IsEmpty()); + SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); + DCHECK(!data->created_); + Isolate* isolate = data->isolate_; + CHECK_EQ(isolate, context->GetIsolate()); + size_t index = static_cast<int>(data->contexts_.Size()); + data->contexts_.Append(context); + return index; +} + +size_t SnapshotCreator::AddTemplate(Local<Template> template_obj) { + DCHECK(!template_obj.IsEmpty()); + SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); + DCHECK(!data->created_); + DCHECK_EQ(reinterpret_cast<i::Isolate*>(data->isolate_), + Utils::OpenHandle(*template_obj)->GetIsolate()); + size_t index = static_cast<int>(data->templates_.Size()); + data->templates_.Append(template_obj); + return index; +} + +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_); + + { + int num_templates = static_cast<int>(data->templates_.Size()); + i::HandleScope scope(isolate); + i::Handle<i::FixedArray> templates = + isolate->factory()->NewFixedArray(num_templates, i::TENURED); + for (int i = 0; i < num_templates; i++) { + templates->set(i, *v8::Utils::OpenHandle(*data->templates_.Get(i))); + } + isolate->heap()->SetSerializedTemplates(*templates); + data->templates_.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. - internal_isolate->heap()->CollectAllAvailableGarbage("mksnapshot"); - - // GC may have cleared weak cells, so compact any WeakFixedArrays - // found on the heap. - i::HeapIterator iterator(internal_isolate->heap(), - i::HeapIterator::kFilterUnreachable); - for (i::HeapObject* o = iterator.next(); o != NULL; o = iterator.next()) { - if (o->IsPrototypeInfo()) { - i::Object* prototype_users = i::PrototypeInfo::cast(o)->prototype_users(); - if (prototype_users->IsWeakFixedArray()) { - i::WeakFixedArray* array = i::WeakFixedArray::cast(prototype_users); - array->Compact<i::JSObject::PrototypeRegistryCompactionCallback>(); - } - } else if (o->IsScript()) { - i::Object* shared_list = i::Script::cast(o)->shared_function_infos(); - if (shared_list->IsWeakFixedArray()) { - i::WeakFixedArray* array = i::WeakFixedArray::cast(shared_list); - array->Compact<i::WeakFixedArray::NullCallback>(); - } - } + isolate->heap()->CollectAllAvailableGarbage("mksnapshot"); + isolate->heap()->CompactWeakFixedArrays(); + + i::DisallowHeapAllocation no_gc_from_here_on; + + int num_contexts = static_cast<int>(data->contexts_.Size()); + i::List<i::Object*> contexts(num_contexts); + for (int i = 0; i < num_contexts; i++) { + i::HandleScope scope(isolate); + i::Handle<i::Context> context = + v8::Utils::OpenHandle(*data->contexts_.Get(i)); + contexts.Add(*context); } + data->contexts_.Clear(); - i::Object* raw_context = *v8::Utils::OpenPersistent(*context); - context->Reset(); + i::StartupSerializer startup_serializer(isolate, function_code_handling); + startup_serializer.SerializeStrongReferences(); - i::SnapshotByteSink snapshot_sink; - i::StartupSerializer ser(internal_isolate, &snapshot_sink, - function_code_handling); - ser.SerializeStrongReferences(); + // Serialize each context with a new partial serializer. + i::List<i::SnapshotData*> context_snapshots(num_contexts); + for (int i = 0; i < num_contexts; i++) { + i::PartialSerializer partial_serializer(isolate, &startup_serializer); + partial_serializer.Serialize(&contexts[i]); + context_snapshots.Add(new i::SnapshotData(&partial_serializer)); + } - i::SnapshotByteSink context_sink; - i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink); - context_ser.Serialize(&raw_context); - ser.SerializeWeakReferencesAndDeferred(); + startup_serializer.SerializeWeakReferencesAndDeferred(); + i::SnapshotData startup_snapshot(&startup_serializer); + StartupData result = + i::Snapshot::CreateSnapshotBlob(&startup_snapshot, &context_snapshots); - return i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata); + // Delete heap-allocated context snapshot instances. + for (const auto& context_snapshot : context_snapshots) { + delete context_snapshot; + } + data->created_ = true; + return result; } -} // namespace - StartupData V8::CreateSnapshotDataBlob(const char* embedded_source) { // Create a new isolate and a new context from scratch, optionally run // a script to embed, and serialize to create a snapshot blob. - StartupData result = {NULL, 0}; - + StartupData result = {nullptr, 0}; base::ElapsedTimer timer; timer.Start(); - - ArrayBufferAllocator allocator; - i::Isolate* internal_isolate = new i::Isolate(true); - internal_isolate->set_array_buffer_allocator(&allocator); - Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate); - { - Isolate::Scope isolate_scope(isolate); - internal_isolate->Init(NULL); - Persistent<Context> context; + SnapshotCreator snapshot_creator; + Isolate* isolate = snapshot_creator.GetIsolate(); { - HandleScope handle_scope(isolate); - Local<Context> new_context = Context::New(isolate); - context.Reset(isolate, new_context); + HandleScope scope(isolate); + Local<Context> context = Context::New(isolate); if (embedded_source != NULL && - !RunExtraCode(isolate, new_context, embedded_source, "<embedded>")) { - context.Reset(); + !RunExtraCode(isolate, context, embedded_source, "<embedded>")) { + return result; } + snapshot_creator.AddContext(context); } - - i::Snapshot::Metadata metadata; - metadata.set_embeds_script(embedded_source != NULL); - - result = SerializeIsolateAndContext( - isolate, &context, metadata, i::StartupSerializer::CLEAR_FUNCTION_CODE); - DCHECK(context.IsEmpty()); + result = snapshot_creator.CreateBlob( + SnapshotCreator::FunctionCodeHandling::kClear); } - isolate->Dispose(); if (i::FLAG_profile_deserialization) { i::PrintF("Creating snapshot took %0.3f ms\n", @@ -487,42 +592,28 @@ StartupData V8::WarmUpSnapshotDataBlob(StartupData cold_snapshot_blob, // compilation of executed functions. // - Create a new context. This context will be unpolluted. // - Serialize the isolate and the second context into a new snapshot blob. - StartupData result = {NULL, 0}; - + StartupData result = {nullptr, 0}; base::ElapsedTimer timer; timer.Start(); - - ArrayBufferAllocator allocator; - i::Isolate* internal_isolate = new i::Isolate(true); - internal_isolate->set_array_buffer_allocator(&allocator); - internal_isolate->set_snapshot_blob(&cold_snapshot_blob); - Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate); - { - Isolate::Scope isolate_scope(isolate); - i::Snapshot::Initialize(internal_isolate); - Persistent<Context> context; - bool success; + SnapshotCreator snapshot_creator(nullptr, &cold_snapshot_blob); + Isolate* isolate = snapshot_creator.GetIsolate(); { - HandleScope handle_scope(isolate); - Local<Context> new_context = Context::New(isolate); - success = RunExtraCode(isolate, new_context, warmup_source, "<warm-up>"); + HandleScope scope(isolate); + Local<Context> context = Context::New(isolate); + if (!RunExtraCode(isolate, context, warmup_source, "<warm-up>")) { + return result; + } } - if (success) { + { HandleScope handle_scope(isolate); isolate->ContextDisposedNotification(false); - Local<Context> new_context = Context::New(isolate); - context.Reset(isolate, new_context); + Local<Context> context = Context::New(isolate); + snapshot_creator.AddContext(context); } - - i::Snapshot::Metadata metadata; - metadata.set_embeds_script(i::Snapshot::EmbedsScript(internal_isolate)); - - result = SerializeIsolateAndContext( - isolate, &context, metadata, i::StartupSerializer::KEEP_FUNCTION_CODE); - DCHECK(context.IsEmpty()); + result = snapshot_creator.CreateBlob( + SnapshotCreator::FunctionCodeHandling::kKeep); } - isolate->Dispose(); if (i::FLAG_profile_deserialization) { i::PrintF("Warming up snapshot took %0.3f ms\n", @@ -658,7 +749,7 @@ void SetResourceConstraints(i::Isolate* isolate, i::Object** V8::GlobalizeReference(i::Isolate* isolate, i::Object** obj) { - LOG_API(isolate, "Persistent::New"); + LOG_API(isolate, Persistent, New); i::Handle<i::Object> result = isolate->global_handles()->Create(*obj); #ifdef VERIFY_HEAP if (i::FLAG_verify_heap) { @@ -684,13 +775,7 @@ void V8::RegisterExternallyReferencedObject(i::Object** object, isolate->heap()->RegisterExternallyReferencedObject(object); } -void V8::MakeWeak(i::Object** object, void* parameter, - WeakCallback weak_callback) { - i::GlobalHandles::MakeWeak(object, parameter, weak_callback); -} - - -void V8::MakeWeak(i::Object** object, void* parameter, +void V8::MakeWeak(i::Object** location, void* parameter, int internal_field_index1, int internal_field_index2, WeakCallbackInfo<void>::Callback weak_callback) { WeakCallbackType type = WeakCallbackType::kParameter; @@ -705,24 +790,25 @@ void V8::MakeWeak(i::Object** object, void* parameter, DCHECK_EQ(internal_field_index1, -1); DCHECK_EQ(internal_field_index2, -1); } - i::GlobalHandles::MakeWeak(object, parameter, weak_callback, type); + i::GlobalHandles::MakeWeak(location, parameter, weak_callback, type); } - -void V8::MakeWeak(i::Object** object, void* parameter, +void V8::MakeWeak(i::Object** location, void* parameter, WeakCallbackInfo<void>::Callback weak_callback, WeakCallbackType type) { - i::GlobalHandles::MakeWeak(object, parameter, weak_callback, type); + i::GlobalHandles::MakeWeak(location, parameter, weak_callback, type); } - -void* V8::ClearWeak(i::Object** obj) { - return i::GlobalHandles::ClearWeakness(obj); +void V8::MakeWeak(i::Object*** location_addr) { + i::GlobalHandles::MakeWeak(location_addr); } +void* V8::ClearWeak(i::Object** location) { + return i::GlobalHandles::ClearWeakness(location); +} -void V8::DisposeGlobal(i::Object** obj) { - i::GlobalHandles::Destroy(obj); +void V8::DisposeGlobal(i::Object** location) { + i::GlobalHandles::Destroy(location); } @@ -817,9 +903,8 @@ EscapableHandleScope::EscapableHandleScope(Isolate* v8_isolate) { i::Object** EscapableHandleScope::Escape(i::Object** escape_value) { i::Heap* heap = reinterpret_cast<i::Isolate*>(GetIsolate())->heap(); - Utils::ApiCheck(*escape_slot_ == heap->the_hole_value(), - "EscapeableHandleScope::Escape", - "Escape value set twice"); + Utils::ApiCheck((*escape_slot_)->IsTheHole(heap->isolate()), + "EscapableHandleScope::Escape", "Escape value set twice"); if (escape_value == NULL) { *escape_slot_ = heap->undefined_value(); return NULL; @@ -828,12 +913,9 @@ i::Object** EscapableHandleScope::Escape(i::Object** escape_value) { return escape_slot_; } - -SealHandleScope::SealHandleScope(Isolate* isolate) { - i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); - - isolate_ = internal_isolate; - i::HandleScopeData* current = internal_isolate->handle_scope_data(); +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; @@ -950,70 +1032,6 @@ void Context::SetAlignedPointerInEmbedderData(int index, void* value) { } -// --- N e a n d e r --- - - -// A constructor cannot easily return an error value, therefore it is necessary -// to check for a dead VM with ON_BAILOUT before constructing any Neander -// objects. To remind you about this there is no HandleScope in the -// NeanderObject constructor. When you add one to the site calling the -// constructor you should check that you ensured the VM was not dead first. -NeanderObject::NeanderObject(v8::internal::Isolate* isolate, int size) { - ENTER_V8(isolate); - value_ = isolate->factory()->NewNeanderObject(); - i::Handle<i::FixedArray> elements = isolate->factory()->NewFixedArray(size); - value_->set_elements(*elements); -} - - -int NeanderObject::size() { - return i::FixedArray::cast(value_->elements())->length(); -} - - -NeanderArray::NeanderArray(v8::internal::Isolate* isolate) : obj_(isolate, 2) { - obj_.set(0, i::Smi::FromInt(0)); -} - - -int NeanderArray::length() { - return i::Smi::cast(obj_.get(0))->value(); -} - - -i::Object* NeanderArray::get(int offset) { - DCHECK_LE(0, offset); - DCHECK_LT(offset, length()); - return obj_.get(offset + 1); -} - - -// This method cannot easily return an error value, therefore it is necessary -// to check for a dead VM with ON_BAILOUT before calling it. To remind you -// about this there is no HandleScope in this method. When you add one to the -// site calling this method you should check that you ensured the VM was not -// dead first. -void NeanderArray::add(i::Isolate* isolate, i::Handle<i::Object> value) { - int length = this->length(); - int size = obj_.size(); - if (length == size - 1) { - i::Factory* factory = isolate->factory(); - i::Handle<i::FixedArray> new_elms = factory->NewFixedArray(2 * size); - for (int i = 0; i < length; i++) - new_elms->set(i + 1, get(i)); - obj_.value()->set_elements(*new_elms); - } - obj_.set(length + 1, *value); - obj_.set(0, i::Smi::FromInt(length + 1)); -} - - -void NeanderArray::set(int index, i::Object* value) { - if (index < 0 || index >= this->length()) return; - obj_.set(index + 1, value); -} - - // --- T e m p l a t e --- @@ -1030,23 +1048,13 @@ void Template::Set(v8::Local<Name> name, v8::Local<Data> value, ENTER_V8(isolate); i::HandleScope scope(isolate); auto value_obj = Utils::OpenHandle(*value); + CHECK(!value_obj->IsJSReceiver() || value_obj->IsTemplateInfo()); if (value_obj->IsObjectTemplateInfo()) { templ->set_serial_number(i::Smi::FromInt(0)); if (templ->IsFunctionTemplateInfo()) { i::Handle<i::FunctionTemplateInfo>::cast(templ)->set_do_not_cache(true); } } - if (i::FLAG_warn_template_set && - value_obj->IsJSReceiver() && - !value_obj->IsTemplateInfo()) { - base::OS::PrintError( - "(node) v8::%sTemplate::Set() with non-primitive values is deprecated\n" - "(node) and will stop working in the next major release.\n", - templ->IsFunctionTemplateInfo() ? "Function" : "Object"); - isolate->PrintStack(stderr, i::Isolate::kPrintStackConcise); - base::DumpBacktrace(); - } - // TODO(dcarney): split api to allow values of v8::Value or v8::TemplateInfo. i::ApiNatives::AddDataProperty(isolate, templ, Utils::OpenHandle(*name), value_obj, static_cast<i::PropertyAttributes>(attribute)); @@ -1090,7 +1098,7 @@ Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() { ENTER_V8(i_isolate); i::Handle<i::Object> result(Utils::OpenHandle(this)->prototype_template(), i_isolate); - if (result->IsUndefined()) { + if (result->IsUndefined(i_isolate)) { // Do not cache prototype objects. result = Utils::OpenHandle( *ObjectTemplateNew(i_isolate, Local<FunctionTemplate>(), true)); @@ -1128,8 +1136,7 @@ static Local<FunctionTemplate> FunctionTemplateNew( obj->set_do_not_cache(do_not_cache); int next_serial_number = 0; if (!do_not_cache) { - next_serial_number = isolate->next_serial_number() + 1; - isolate->set_next_serial_number(next_serial_number); + next_serial_number = isolate->heap()->GetNextTemplateSerialNumber(); } obj->set_serial_number(i::Smi::FromInt(next_serial_number)); if (callback != 0) { @@ -1147,34 +1154,34 @@ static Local<FunctionTemplate> FunctionTemplateNew( return Utils::ToLocal(obj); } - -Local<FunctionTemplate> FunctionTemplate::New(Isolate* isolate, - FunctionCallback callback, - v8::Local<Value> data, - v8::Local<Signature> signature, - int length) { - return New( - isolate, callback, data, signature, length, ConstructorBehavior::kAllow); -} - -Local<FunctionTemplate> FunctionTemplate::New(Isolate* isolate, - FunctionCallback callback, - v8::Local<Value> data, - v8::Local<Signature> signature, - int length, - ConstructorBehavior behavior) { +Local<FunctionTemplate> FunctionTemplate::New( + Isolate* isolate, FunctionCallback callback, v8::Local<Value> data, + v8::Local<Signature> signature, int length, ConstructorBehavior behavior) { 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. - DCHECK(!i_isolate->serializer_enabled()); - LOG_API(i_isolate, "FunctionTemplate::New"); + LOG_API(i_isolate, FunctionTemplate, New); ENTER_V8(i_isolate); - auto tmpl = FunctionTemplateNew(i_isolate, callback, nullptr, data, signature, - length, false); - if (behavior == ConstructorBehavior::kThrow) tmpl->RemovePrototype(); - return tmpl; + auto templ = FunctionTemplateNew(i_isolate, callback, nullptr, data, + signature, length, false); + if (behavior == ConstructorBehavior::kThrow) templ->RemovePrototype(); + return templ; } +MaybeLocal<FunctionTemplate> FunctionTemplate::FromSnapshot(Isolate* isolate, + size_t index) { + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::FixedArray* templates = i_isolate->heap()->serialized_templates(); + int int_index = static_cast<int>(index); + if (int_index < templates->length()) { + i::Object* info = templates->get(int_index); + if (info->IsFunctionTemplateInfo()) { + return Utils::ToLocal(i::Handle<i::FunctionTemplateInfo>( + i::FunctionTemplateInfo::cast(info))); + } + } + return Local<FunctionTemplate>(); +} Local<FunctionTemplate> FunctionTemplate::NewWithFastHandler( Isolate* isolate, FunctionCallback callback, @@ -1182,7 +1189,7 @@ Local<FunctionTemplate> FunctionTemplate::NewWithFastHandler( v8::Local<Signature> signature, int length) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); DCHECK(!i_isolate->serializer_enabled()); - LOG_API(i_isolate, "FunctionTemplate::NewWithFastHandler"); + LOG_API(i_isolate, FunctionTemplate, NewWithFastHandler); ENTER_V8(i_isolate); return FunctionTemplateNew(i_isolate, callback, fast_handler, data, signature, length, false); @@ -1247,8 +1254,10 @@ static i::Handle<i::AccessorInfo> SetAccessorInfoProperties( return obj; } +namespace { + template <typename Getter, typename Setter> -static i::Handle<i::AccessorInfo> MakeAccessorInfo( +i::Handle<i::AccessorInfo> MakeAccessorInfo( v8::Local<Name> name, Getter getter, Setter setter, v8::Local<Value> data, v8::AccessControl settings, v8::PropertyAttribute attributes, v8::Local<AccessorSignature> signature, bool is_special_data_property) { @@ -1259,6 +1268,8 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo( setter = reinterpret_cast<Setter>(&i::Accessors::ReconfigureToDataProperty); } SET_FIELD_WRAPPED(obj, set_setter, setter); + i::Address redirected = obj->redirected_getter(); + if (redirected != nullptr) SET_FIELD_WRAPPED(obj, set_js_getter, redirected); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); } @@ -1267,6 +1278,7 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo( return SetAccessorInfoProperties(obj, name, settings, attributes, signature); } +} // namespace Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() { i::Handle<i::FunctionTemplateInfo> handle = Utils::OpenHandle(this, true); @@ -1277,7 +1289,7 @@ Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() { } i::Isolate* isolate = handle->GetIsolate(); ENTER_V8(isolate); - if (handle->instance_template()->IsUndefined()) { + if (handle->instance_template()->IsUndefined(isolate)) { Local<ObjectTemplate> templ = ObjectTemplate::New(isolate, ToApiHandle<FunctionTemplate>(handle)); handle->set_instance_template(*Utils::OpenHandle(*templ)); @@ -1358,10 +1370,7 @@ Local<ObjectTemplate> ObjectTemplate::New() { static Local<ObjectTemplate> ObjectTemplateNew( i::Isolate* isolate, v8::Local<FunctionTemplate> constructor, bool do_not_cache) { - // Changes to the environment cannot be captured in the snapshot. Expect no - // object templates when the isolate is created for serialization. - DCHECK(!isolate->serializer_enabled()); - LOG_API(isolate, "ObjectTemplate::New"); + LOG_API(isolate, ObjectTemplate, New); ENTER_V8(isolate); i::Handle<i::Struct> struct_obj = isolate->factory()->NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE); @@ -1370,13 +1379,12 @@ static Local<ObjectTemplate> ObjectTemplateNew( InitializeTemplate(obj, Consts::OBJECT_TEMPLATE); int next_serial_number = 0; if (!do_not_cache) { - next_serial_number = isolate->next_serial_number() + 1; - isolate->set_next_serial_number(next_serial_number); + next_serial_number = isolate->heap()->GetNextTemplateSerialNumber(); } obj->set_serial_number(i::Smi::FromInt(next_serial_number)); if (!constructor.IsEmpty()) obj->set_constructor(*Utils::OpenHandle(*constructor)); - obj->set_internal_field_count(i::Smi::FromInt(0)); + obj->set_data(i::Smi::FromInt(0)); return Utils::ToLocal(obj); } @@ -1385,13 +1393,28 @@ Local<ObjectTemplate> ObjectTemplate::New( return ObjectTemplateNew(isolate, constructor, false); } +MaybeLocal<ObjectTemplate> ObjectTemplate::FromSnapshot(Isolate* isolate, + size_t index) { + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::FixedArray* templates = i_isolate->heap()->serialized_templates(); + int int_index = static_cast<int>(index); + if (int_index < templates->length()) { + i::Object* info = templates->get(int_index); + if (info->IsObjectTemplateInfo()) { + return Utils::ToLocal( + i::Handle<i::ObjectTemplateInfo>(i::ObjectTemplateInfo::cast(info))); + } + } + return Local<ObjectTemplate>(); +} + // 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()) { + if (!obj->IsUndefined(isolate)) { i::FunctionTemplateInfo* info = i::FunctionTemplateInfo::cast(obj); return i::Handle<i::FunctionTemplateInfo>(info, isolate); } @@ -1480,20 +1503,12 @@ void ObjectTemplate::SetAccessor(v8::Local<Name> name, signature, i::FLAG_disable_old_api_accessors); } - template <typename Getter, typename Setter, typename Query, typename Deleter, typename Enumerator> -static void ObjectTemplateSetNamedPropertyHandler(ObjectTemplate* templ, - Getter getter, Setter setter, - Query query, Deleter remover, - Enumerator enumerator, - Local<Value> data, - PropertyHandlerFlags flags) { - i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate(); - ENTER_V8(isolate); - i::HandleScope scope(isolate); - auto cons = EnsureConstructor(isolate, templ); - EnsureNotInstantiated(cons, "ObjectTemplateSetNamedPropertyHandler"); +static i::Handle<i::InterceptorInfo> CreateInterceptorInfo( + i::Isolate* isolate, Getter getter, Setter setter, Query query, + Deleter remover, Enumerator enumerator, Local<Value> data, + PropertyHandlerFlags flags) { auto obj = i::Handle<i::InterceptorInfo>::cast( isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE)); obj->set_flags(0); @@ -1515,6 +1530,24 @@ static void ObjectTemplateSetNamedPropertyHandler(ObjectTemplate* templ, data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); } obj->set_data(*Utils::OpenHandle(*data)); + return obj; +} + +template <typename Getter, typename Setter, typename Query, typename Deleter, + typename Enumerator> +static void ObjectTemplateSetNamedPropertyHandler(ObjectTemplate* templ, + Getter getter, Setter setter, + Query query, Deleter remover, + Enumerator enumerator, + Local<Value> data, + PropertyHandlerFlags flags) { + i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate(); + ENTER_V8(isolate); + i::HandleScope scope(isolate); + auto cons = EnsureConstructor(isolate, templ); + EnsureNotInstantiated(cons, "ObjectTemplateSetNamedPropertyHandler"); + auto obj = CreateInterceptorInfo(isolate, getter, setter, query, remover, + enumerator, data, flags); cons->set_named_property_handler(*obj); } @@ -1561,8 +1594,8 @@ void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback, i::Handle<i::AccessCheckInfo>::cast(struct_info); SET_FIELD_WRAPPED(info, set_callback, callback); - SET_FIELD_WRAPPED(info, set_named_callback, nullptr); - SET_FIELD_WRAPPED(info, set_indexed_callback, nullptr); + info->set_named_interceptor(nullptr); + info->set_indexed_interceptor(nullptr); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); @@ -1573,28 +1606,34 @@ void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback, cons->set_needs_access_check(true); } -void ObjectTemplate::SetAccessCheckCallback( - DeprecatedAccessCheckCallback callback, Local<Value> data) { - SetAccessCheckCallback(reinterpret_cast<AccessCheckCallback>(callback), data); -} - -void ObjectTemplate::SetAccessCheckCallbacks( - NamedSecurityCallback named_callback, - IndexedSecurityCallback indexed_callback, Local<Value> data) { +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(isolate); i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); - EnsureNotInstantiated(cons, "v8::ObjectTemplate::SetAccessCheckCallbacks"); + EnsureNotInstantiated( + cons, "v8::ObjectTemplate::SetAccessCheckCallbackWithHandler"); i::Handle<i::Struct> struct_info = isolate->factory()->NewStruct(i::ACCESS_CHECK_INFO_TYPE); i::Handle<i::AccessCheckInfo> info = i::Handle<i::AccessCheckInfo>::cast(struct_info); - SET_FIELD_WRAPPED(info, set_callback, nullptr); - SET_FIELD_WRAPPED(info, set_named_callback, named_callback); - SET_FIELD_WRAPPED(info, set_indexed_callback, indexed_callback); + SET_FIELD_WRAPPED(info, set_callback, callback); + auto named_interceptor = CreateInterceptorInfo( + isolate, named_handler.getter, named_handler.setter, named_handler.query, + named_handler.deleter, named_handler.enumerator, named_handler.data, + named_handler.flags); + info->set_named_interceptor(*named_interceptor); + auto indexed_interceptor = CreateInterceptorInfo( + isolate, indexed_handler.getter, indexed_handler.setter, + indexed_handler.query, indexed_handler.deleter, + indexed_handler.enumerator, indexed_handler.data, indexed_handler.flags); + info->set_indexed_interceptor(*indexed_interceptor); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); @@ -1605,7 +1644,6 @@ void ObjectTemplate::SetAccessCheckCallbacks( cons->set_needs_access_check(true); } - void ObjectTemplate::SetHandler( const IndexedPropertyHandlerConfiguration& config) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); @@ -1613,25 +1651,9 @@ void ObjectTemplate::SetHandler( i::HandleScope scope(isolate); auto cons = EnsureConstructor(isolate, this); EnsureNotInstantiated(cons, "v8::ObjectTemplate::SetHandler"); - auto obj = i::Handle<i::InterceptorInfo>::cast( - isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE)); - obj->set_flags(0); - - if (config.getter != 0) SET_FIELD_WRAPPED(obj, set_getter, config.getter); - if (config.setter != 0) SET_FIELD_WRAPPED(obj, set_setter, config.setter); - if (config.query != 0) SET_FIELD_WRAPPED(obj, set_query, config.query); - if (config.deleter != 0) SET_FIELD_WRAPPED(obj, set_deleter, config.deleter); - if (config.enumerator != 0) { - SET_FIELD_WRAPPED(obj, set_enumerator, config.enumerator); - } - obj->set_all_can_read(static_cast<int>(config.flags) & - static_cast<int>(PropertyHandlerFlags::kAllCanRead)); - - v8::Local<v8::Value> data = config.data; - if (data.IsEmpty()) { - data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); - } - obj->set_data(*Utils::OpenHandle(*data)); + auto obj = CreateInterceptorInfo( + isolate, config.getter, config.setter, config.query, config.deleter, + config.enumerator, config.data, config.flags); cons->set_indexed_property_handler(*obj); } @@ -1657,7 +1679,7 @@ void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback, int ObjectTemplate::InternalFieldCount() { - return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value(); + return Utils::OpenHandle(this)->internal_field_count(); } @@ -1675,9 +1697,18 @@ void ObjectTemplate::SetInternalFieldCount(int value) { // function to do the setting. EnsureConstructor(isolate, this); } - Utils::OpenHandle(this)->set_internal_field_count(i::Smi::FromInt(value)); + Utils::OpenHandle(this)->set_internal_field_count(value); +} + +bool ObjectTemplate::IsImmutableProto() { + return Utils::OpenHandle(this)->immutable_proto(); } +void ObjectTemplate::SetImmutableProto() { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + ENTER_V8(isolate); + Utils::OpenHandle(this)->set_immutable_proto(true); +} // --- S c r i p t s --- @@ -1723,13 +1754,11 @@ ScriptCompiler::StreamedSource::GetCachedData() const { Local<Script> UnboundScript::BindToCurrentContext() { i::Handle<i::HeapObject> obj = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this)); - i::Handle<i::SharedFunctionInfo> - function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate()); i::Isolate* isolate = obj->GetIsolate(); - - i::Handle<i::JSReceiver> global(isolate->native_context()->global_object()); + i::Handle<i::SharedFunctionInfo> function_info( + i::SharedFunctionInfo::cast(*obj), isolate); i::Handle<i::JSFunction> function = - obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo( + isolate->factory()->NewFunctionFromSharedFunctionInfo( function_info, isolate->native_context()); return ToApiHandle<Script>(function); } @@ -1739,7 +1768,7 @@ int UnboundScript::GetId() { i::Handle<i::HeapObject> obj = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this)); i::Isolate* isolate = obj->GetIsolate(); - LOG_API(isolate, "v8::UnboundScript::GetId"); + LOG_API(isolate, UnboundScript, GetId); i::HandleScope scope(isolate); i::Handle<i::SharedFunctionInfo> function_info( i::SharedFunctionInfo::cast(*obj)); @@ -1752,7 +1781,7 @@ int UnboundScript::GetLineNumber(int code_pos) { i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); i::Isolate* isolate = obj->GetIsolate(); - LOG_API(isolate, "UnboundScript::GetLineNumber"); + LOG_API(isolate, UnboundScript, GetLineNumber); if (obj->script()->IsScript()) { i::Handle<i::Script> script(i::Script::cast(obj->script())); return i::Script::GetLineNumber(script, code_pos); @@ -1766,7 +1795,7 @@ Local<Value> UnboundScript::GetScriptName() { i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); i::Isolate* isolate = obj->GetIsolate(); - LOG_API(isolate, "UnboundScript::GetName"); + 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)); @@ -1780,7 +1809,7 @@ Local<Value> UnboundScript::GetSourceURL() { i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); i::Isolate* isolate = obj->GetIsolate(); - LOG_API(isolate, "UnboundScript::GetSourceURL"); + 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)); @@ -1794,7 +1823,7 @@ 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"); + LOG_API(isolate, UnboundScript, GetSourceMappingURL); if (obj->script()->IsScript()) { i::Object* url = i::Script::cast(obj->script())->source_mapping_url(); return Utils::ToLocal(i::Handle<i::Object>(url, isolate)); @@ -1805,12 +1834,13 @@ Local<Value> UnboundScript::GetSourceMappingURL() { MaybeLocal<Value> Script::Run(Local<Context> context) { - PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Script::Run()", Value) + PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, Script, Run, Value) + i::HistogramTimerScope execute_timer(isolate->counters()->execute(), true); i::AggregatingHistogramTimerScope timer(isolate->counters()->compile_lazy()); i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); - TRACE_EVENT0("v8", "V8.Execute"); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute"); auto fun = i::Handle<i::JSFunction>::cast(Utils::OpenHandle(this)); - i::Handle<i::Object> receiver(isolate->global_proxy(), isolate); + i::Handle<i::Object> receiver = isolate->global_proxy(); Local<Value> result; has_pending_exception = !ToLocal<Value>(i::Execution::Call(isolate, fun, receiver, 0, NULL), @@ -1841,8 +1871,9 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( Isolate* v8_isolate, Source* source, CompileOptions options, bool is_module) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); - PREPARE_FOR_EXECUTION_WITH_ISOLATE( - isolate, "v8::ScriptCompiler::CompileUnbound()", UnboundScript); + PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, ScriptCompiler, CompileUnbound, + UnboundScript); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler"); // Don't try to produce any kind of cache when the debugger is loaded. if (isolate->debug()->is_loaded() && @@ -1862,7 +1893,7 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( i::Handle<i::SharedFunctionInfo> result; { i::HistogramTimerScope total(isolate->counters()->compile_script(), true); - TRACE_EVENT0("v8", "V8.CompileScript"); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileScript"); i::Handle<i::Object> name_obj; i::Handle<i::Object> source_map_url; int line_offset = 0; @@ -2001,8 +2032,9 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext( Local<Context> v8_context, Source* source, size_t arguments_count, Local<String> arguments[], size_t context_extension_count, Local<Object> context_extensions[]) { - PREPARE_FOR_EXECUTION( - v8_context, "v8::ScriptCompiler::CompileFunctionInContext()", Function); + PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext, + Function); + TRACE_EVENT0("v8", "V8.ScriptCompiler"); i::Handle<i::String> source_string; auto factory = isolate->factory(); if (arguments_count) { @@ -2056,6 +2088,8 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext( } i::Handle<i::Object> name_obj; + int eval_scope_position = 0; + int eval_position = i::kNoSourcePosition; int line_offset = 0; int column_offset = 0; if (!source->resource_name.IsEmpty()) { @@ -2068,11 +2102,13 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext( column_offset = static_cast<int>(source->resource_column_offset->Value()); } i::Handle<i::JSFunction> fun; - has_pending_exception = !i::Compiler::GetFunctionFromEval( - source_string, outer_info, context, i::SLOPPY, - i::ONLY_SINGLE_FUNCTION_LITERAL, line_offset, - column_offset - scope_position, name_obj, - source->resource_options).ToHandle(&fun); + has_pending_exception = + !i::Compiler::GetFunctionFromEval( + source_string, outer_info, context, i::SLOPPY, + i::ONLY_SINGLE_FUNCTION_LITERAL, eval_scope_position, eval_position, + line_offset, column_offset - scope_position, name_obj, + source->resource_options) + .ToHandle(&fun); if (has_pending_exception) { isolate->ReportPendingMessages(); } @@ -2112,7 +2148,8 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context, StreamedSource* v8_source, Local<String> full_source_string, const ScriptOrigin& origin) { - PREPARE_FOR_EXECUTION(context, "v8::ScriptCompiler::Compile()", Script); + PREPARE_FOR_EXECUTION(context, ScriptCompiler, Compile, Script); + TRACE_EVENT0("v8", "V8.ScriptCompiler"); i::StreamedSource* source = v8_source->impl(); i::Handle<i::String> str = Utils::OpenHandle(*(full_source_string)); i::Handle<i::Script> script = isolate->factory()->NewScript(str); @@ -2136,6 +2173,11 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context, source->info->set_script(script); source->info->set_context(isolate->native_context()); + // Create a canonical handle scope before internalizing parsed values if + // compiling bytecode. This is required for off-thread bytecode generation. + std::unique_ptr<i::CanonicalHandleScope> canonical; + if (i::FLAG_ignition) canonical.reset(new i::CanonicalHandleScope(isolate)); + // Do the parsing tasks which need to be done on the main thread. This will // also handle parse errors. source->parser->Internalize(isolate, script, @@ -2275,7 +2317,7 @@ v8::TryCatch::~TryCatch() { bool v8::TryCatch::HasCaught() const { - return !reinterpret_cast<i::Object*>(exception_)->IsTheHole(); + return !reinterpret_cast<i::Object*>(exception_)->IsTheHole(isolate_); } @@ -2311,7 +2353,7 @@ MaybeLocal<Value> v8::TryCatch::StackTrace(Local<Context> context) const { if (!HasCaught()) return v8::Local<Value>(); i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_); if (!raw_obj->IsJSObject()) return v8::Local<Value>(); - PREPARE_FOR_EXECUTION(context, "v8::TryCatch::StackTrace", Value); + PREPARE_FOR_EXECUTION(context, TryCatch, StackTrace, Value); i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_); i::Handle<i::String> name = isolate->factory()->stack_string(); Maybe<bool> maybe = i::JSReceiver::HasProperty(obj, name); @@ -2334,8 +2376,8 @@ v8::Local<Value> v8::TryCatch::StackTrace() const { v8::Local<v8::Message> v8::TryCatch::Message() const { i::Object* message = reinterpret_cast<i::Object*>(message_obj_); - DCHECK(message->IsJSMessageObject() || message->IsTheHole()); - if (HasCaught() && !message->IsTheHole()) { + DCHECK(message->IsJSMessageObject() || message->IsTheHole(isolate_)); + if (HasCaught() && !message->IsTheHole(isolate_)) { return v8::Utils::MessageToLocal(i::Handle<i::Object>(message, isolate_)); } else { return v8::Local<v8::Message>(); @@ -2413,16 +2455,12 @@ v8::Local<v8::StackTrace> Message::GetStackTrace() const { Maybe<int> Message::GetLineNumber(Local<Context> context) const { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Message::GetLineNumber()", int); - i::Handle<i::JSFunction> fun = isolate->message_get_line_number(); - i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); - i::Handle<i::Object> args[] = {Utils::OpenHandle(this)}; - i::Handle<i::Object> result; - has_pending_exception = - !i::Execution::Call(isolate, fun, undefined, arraysize(args), args) - .ToHandle(&result); - RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int); - return Just(static_cast<int>(result->Number())); + auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); + ENTER_V8(isolate); + EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate)); + auto msg = i::Handle<i::JSMessageObject>::cast(self); + return Just(msg->GetLineNumber()); } @@ -2445,17 +2483,12 @@ int Message::GetEndPosition() const { Maybe<int> Message::GetStartColumn(Local<Context> context) const { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Message::GetStartColumn()", - int); - i::Handle<i::JSFunction> fun = isolate->message_get_column_number(); - i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); - i::Handle<i::Object> args[] = {Utils::OpenHandle(this)}; - i::Handle<i::Object> result; - has_pending_exception = - !i::Execution::Call(isolate, fun, undefined, arraysize(args), args) - .ToHandle(&result); - RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int); - return Just(static_cast<int>(result->Number())); + auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); + ENTER_V8(isolate); + EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate)); + auto msg = i::Handle<i::JSMessageObject>::cast(self); + return Just(msg->GetColumnNumber()); } @@ -2468,18 +2501,15 @@ int Message::GetStartColumn() const { Maybe<int> Message::GetEndColumn(Local<Context> context) const { auto self = Utils::OpenHandle(this); - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Message::GetEndColumn()", int); - i::Handle<i::JSFunction> fun = isolate->message_get_column_number(); - i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); - i::Handle<i::Object> args[] = {self}; - i::Handle<i::Object> result; - has_pending_exception = - !i::Execution::Call(isolate, fun, undefined, arraysize(args), args) - .ToHandle(&result); - RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int); - int start = self->start_position(); - int end = self->end_position(); - return Just(static_cast<int>(result->Number()) + (end - start)); + i::Isolate* isolate = self->GetIsolate(); + ENTER_V8(isolate); + EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate)); + auto msg = i::Handle<i::JSMessageObject>::cast(self); + const int column_number = msg->GetColumnNumber(); + if (column_number == -1) return Just(-1); + const int start = self->start_position(); + const int end = self->end_position(); + return Just(column_number + (end - start)); } @@ -2512,20 +2542,12 @@ bool Message::IsOpaque() const { MaybeLocal<String> Message::GetSourceLine(Local<Context> context) const { - PREPARE_FOR_EXECUTION(context, "v8::Message::GetSourceLine()", String); - i::Handle<i::JSFunction> fun = isolate->message_get_source_line(); - i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); - i::Handle<i::Object> args[] = {Utils::OpenHandle(this)}; - i::Handle<i::Object> result; - has_pending_exception = - !i::Execution::Call(isolate, fun, undefined, arraysize(args), args) - .ToHandle(&result); - RETURN_ON_FAILED_EXECUTION(String); - Local<String> str; - if (result->IsString()) { - str = Utils::ToLocal(i::Handle<i::String>::cast(result)); - } - RETURN_ESCAPED(str); + auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); + ENTER_V8(isolate); + EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate)); + auto msg = i::Handle<i::JSMessageObject>::cast(self); + RETURN_ESCAPED(Utils::ToLocal(msg->GetSourceLine())); } @@ -2645,7 +2667,7 @@ static bool getBoolProperty(const StackFrame* f, const char* propertyName) { i::Handle<i::JSObject> self = Utils::OpenHandle(f); i::Handle<i::Object> obj = i::JSReceiver::GetProperty(isolate, self, propertyName).ToHandleChecked(); - return obj->IsTrue(); + return obj->IsTrue(isolate); } bool StackFrame::IsEval() const { return getBoolProperty(this, "isEval"); } @@ -2680,7 +2702,7 @@ void NativeWeakMap::Set(Local<Value> v8_key, Local<Value> v8_value) { } i::Handle<i::ObjectHashTable> table( i::ObjectHashTable::cast(weak_collection->table())); - if (!table->IsKey(*key)) { + if (!table->IsKey(isolate, *key)) { DCHECK(false); return; } @@ -2700,12 +2722,12 @@ Local<Value> NativeWeakMap::Get(Local<Value> v8_key) { } i::Handle<i::ObjectHashTable> table( i::ObjectHashTable::cast(weak_collection->table())); - if (!table->IsKey(*key)) { + if (!table->IsKey(isolate, *key)) { DCHECK(false); return v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); } i::Handle<i::Object> lookup(table->Lookup(key), isolate); - if (lookup->IsTheHole()) + if (lookup->IsTheHole(isolate)) return v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); return Utils::ToLocal(lookup); } @@ -2723,12 +2745,12 @@ bool NativeWeakMap::Has(Local<Value> v8_key) { } i::Handle<i::ObjectHashTable> table( i::ObjectHashTable::cast(weak_collection->table())); - if (!table->IsKey(*key)) { + if (!table->IsKey(isolate, *key)) { DCHECK(false); return false; } i::Handle<i::Object> lookup(table->Lookup(key), isolate); - return !lookup->IsTheHole(); + return !lookup->IsTheHole(isolate); } @@ -2744,7 +2766,7 @@ bool NativeWeakMap::Delete(Local<Value> v8_key) { } i::Handle<i::ObjectHashTable> table( i::ObjectHashTable::cast(weak_collection->table())); - if (!table->IsKey(*key)) { + if (!table->IsKey(isolate, *key)) { DCHECK(false); return false; } @@ -2757,49 +2779,94 @@ bool NativeWeakMap::Delete(Local<Value> v8_key) { MaybeLocal<Value> JSON::Parse(Isolate* v8_isolate, Local<String> json_string) { auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate); - PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, "JSON::Parse", Value); + PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, JSON, Parse, Value); i::Handle<i::String> string = Utils::OpenHandle(*json_string); i::Handle<i::String> source = i::String::Flatten(string); + i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); auto maybe = source->IsSeqOneByteString() - ? i::JsonParser<true>::Parse(source) - : i::JsonParser<false>::Parse(source); + ? i::JsonParser<true>::Parse(isolate, source, undefined) + : i::JsonParser<false>::Parse(isolate, source, undefined); Local<Value> result; has_pending_exception = !ToLocal<Value>(maybe, &result); RETURN_ON_FAILED_EXECUTION(Value); RETURN_ESCAPED(result); } +MaybeLocal<Value> JSON::Parse(Local<Context> context, + Local<String> json_string) { + PREPARE_FOR_EXECUTION(context, JSON, Parse, Value); + i::Handle<i::String> string = Utils::OpenHandle(*json_string); + i::Handle<i::String> source = i::String::Flatten(string); + i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); + auto maybe = source->IsSeqOneByteString() + ? i::JsonParser<true>::Parse(isolate, source, undefined) + : i::JsonParser<false>::Parse(isolate, source, undefined); + Local<Value> result; + has_pending_exception = !ToLocal<Value>(maybe, &result); + RETURN_ON_FAILED_EXECUTION(Value); + RETURN_ESCAPED(result); +} Local<Value> JSON::Parse(Local<String> json_string) { - auto isolate = reinterpret_cast<v8::Isolate*>( - Utils::OpenHandle(*json_string)->GetIsolate()); - RETURN_TO_LOCAL_UNCHECKED(Parse(isolate, json_string), Value); + RETURN_TO_LOCAL_UNCHECKED(Parse(Local<Context>(), json_string), Value); +} + +MaybeLocal<String> JSON::Stringify(Local<Context> context, + Local<Object> json_object, + Local<String> gap) { + PREPARE_FOR_EXECUTION(context, JSON, Stringify, String); + i::Handle<i::Object> object = Utils::OpenHandle(*json_object); + i::Handle<i::Object> replacer = isolate->factory()->undefined_value(); + i::Handle<i::String> gap_string = gap.IsEmpty() + ? isolate->factory()->empty_string() + : Utils::OpenHandle(*gap); + i::Handle<i::Object> maybe; + has_pending_exception = !i::JsonStringifier(isolate) + .Stringify(object, replacer, gap_string) + .ToHandle(&maybe); + RETURN_ON_FAILED_EXECUTION(String); + Local<String> result; + has_pending_exception = + !ToLocal<String>(i::Object::ToString(isolate, maybe), &result); + RETURN_ON_FAILED_EXECUTION(String); + RETURN_ESCAPED(result); } - // --- D a t a --- bool Value::FullIsUndefined() const { - bool result = Utils::OpenHandle(this)->IsUndefined(); + i::Handle<i::Object> object = Utils::OpenHandle(this); + bool result = false; + if (!object->IsSmi()) { + result = object->IsUndefined(i::HeapObject::cast(*object)->GetIsolate()); + } DCHECK_EQ(result, QuickIsUndefined()); return result; } bool Value::FullIsNull() const { - bool result = Utils::OpenHandle(this)->IsNull(); + i::Handle<i::Object> object = Utils::OpenHandle(this); + bool result = false; + if (!object->IsSmi()) { + result = object->IsNull(i::HeapObject::cast(*object)->GetIsolate()); + } DCHECK_EQ(result, QuickIsNull()); return result; } bool Value::IsTrue() const { - return Utils::OpenHandle(this)->IsTrue(); + i::Handle<i::Object> object = Utils::OpenHandle(this); + if (object->IsSmi()) return false; + return object->IsTrue(i::HeapObject::cast(*object)->GetIsolate()); } bool Value::IsFalse() const { - return Utils::OpenHandle(this)->IsFalse(); + i::Handle<i::Object> object = Utils::OpenHandle(this); + if (object->IsSmi()) return false; + return object->IsFalse(i::HeapObject::cast(*object)->GetIsolate()); } @@ -2878,6 +2945,13 @@ bool Value::IsNumber() const { bool Value::IsProxy() const { return Utils::OpenHandle(this)->IsJSProxy(); } +bool Value::IsWebAssemblyCompiledModule() const { + i::Handle<i::Object> obj = Utils::OpenHandle(this); + if (!obj->IsJSObject()) return false; + i::Handle<i::JSObject> js_obj = i::Handle<i::JSObject>::cast(obj); + return js_obj->GetIsolate()->native_context()->wasm_module_constructor() == + js_obj->map()->GetConstructor(); +} #define VALUE_IS_SPECIFIC_TYPE(Type, Class) \ bool Value::Is##Type() const { \ @@ -2936,22 +3010,7 @@ bool Value::IsUint32() const { bool Value::IsNativeError() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsJSObject()) return false; - i::Handle<i::JSObject> js_obj = i::Handle<i::JSObject>::cast(obj); - i::Isolate* isolate = js_obj->GetIsolate(); - i::Handle<i::Object> constructor(js_obj->map()->GetConstructor(), isolate); - if (!constructor->IsJSFunction()) return false; - i::Handle<i::JSFunction> function = - i::Handle<i::JSFunction>::cast(constructor); - if (!function->shared()->native()) return false; - return function.is_identical_to(isolate->error_function()) || - function.is_identical_to(isolate->eval_error_function()) || - function.is_identical_to(isolate->range_error_function()) || - function.is_identical_to(isolate->reference_error_function()) || - function.is_identical_to(isolate->syntax_error_function()) || - function.is_identical_to(isolate->type_error_function()) || - function.is_identical_to(isolate->uri_error_function()); + return Utils::OpenHandle(this)->IsJSError(); } @@ -2983,17 +3042,12 @@ bool Value::IsSetIterator() const { return Utils::OpenHandle(this)->IsJSSetIterator(); } - -bool Value::IsPromise() const { - auto self = Utils::OpenHandle(this); - return i::Object::IsPromise(self); -} - +bool Value::IsPromise() const { return Utils::OpenHandle(this)->IsJSPromise(); } MaybeLocal<String> Value::ToString(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsString()) return ToApiHandle<String>(obj); - PREPARE_FOR_EXECUTION(context, "ToString", String); + PREPARE_FOR_EXECUTION(context, Object, ToString, String); Local<String> result; has_pending_exception = !ToLocal<String>(i::Object::ToString(isolate, obj), &result); @@ -3010,14 +3064,9 @@ Local<String> Value::ToString(Isolate* isolate) const { MaybeLocal<String> Value::ToDetailString(Local<Context> context) const { i::Handle<i::Object> obj = Utils::OpenHandle(this); if (obj->IsString()) return ToApiHandle<String>(obj); - PREPARE_FOR_EXECUTION(context, "ToDetailString", String); - Local<String> result; - i::Handle<i::Object> args[] = {obj}; - has_pending_exception = !ToLocal<String>( - i::Execution::TryCall(isolate, isolate->no_side_effects_to_string_fun(), - isolate->factory()->undefined_value(), - arraysize(args), args), - &result); + PREPARE_FOR_EXECUTION(context, Object, ToDetailString, String); + Local<String> result = + Utils::ToLocal(i::Object::NoSideEffectsToString(isolate, obj)); RETURN_ON_FAILED_EXECUTION(String); RETURN_ESCAPED(result); } @@ -3032,7 +3081,7 @@ Local<String> Value::ToDetailString(Isolate* isolate) const { MaybeLocal<Object> Value::ToObject(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsJSReceiver()) return ToApiHandle<Object>(obj); - PREPARE_FOR_EXECUTION(context, "ToObject", Object); + PREPARE_FOR_EXECUTION(context, Object, ToObject, Object); Local<Object> result; has_pending_exception = !ToLocal<Object>(i::Object::ToObject(isolate, obj), &result); @@ -3063,7 +3112,7 @@ Local<Boolean> Value::ToBoolean(Isolate* v8_isolate) const { MaybeLocal<Number> Value::ToNumber(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsNumber()) return ToApiHandle<Number>(obj); - PREPARE_FOR_EXECUTION(context, "ToNumber", Number); + PREPARE_FOR_EXECUTION(context, Object, ToNumber, Number); Local<Number> result; has_pending_exception = !ToLocal<Number>(i::Object::ToNumber(obj), &result); RETURN_ON_FAILED_EXECUTION(Number); @@ -3079,7 +3128,7 @@ Local<Number> Value::ToNumber(Isolate* isolate) const { MaybeLocal<Integer> Value::ToInteger(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsSmi()) return ToApiHandle<Integer>(obj); - PREPARE_FOR_EXECUTION(context, "ToInteger", Integer); + PREPARE_FOR_EXECUTION(context, Object, ToInteger, Integer); Local<Integer> result; has_pending_exception = !ToLocal<Integer>(i::Object::ToInteger(isolate, obj), &result); @@ -3097,7 +3146,7 @@ MaybeLocal<Int32> Value::ToInt32(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsSmi()) return ToApiHandle<Int32>(obj); Local<Int32> result; - PREPARE_FOR_EXECUTION(context, "ToInt32", Int32); + PREPARE_FOR_EXECUTION(context, Object, ToInt32, Int32); has_pending_exception = !ToLocal<Int32>(i::Object::ToInt32(isolate, obj), &result); RETURN_ON_FAILED_EXECUTION(Int32); @@ -3114,7 +3163,7 @@ MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsSmi()) return ToApiHandle<Uint32>(obj); Local<Uint32> result; - PREPARE_FOR_EXECUTION(context, "ToUint32", Uint32); + PREPARE_FOR_EXECUTION(context, Object, ToUint32, Uint32); has_pending_exception = !ToLocal<Uint32>(i::Object::ToUint32(isolate, obj), &result); RETURN_ON_FAILED_EXECUTION(Uint32); @@ -3129,62 +3178,55 @@ Local<Uint32> Value::ToUint32(Isolate* isolate) const { void i::Internals::CheckInitializedImpl(v8::Isolate* external_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate); - Utils::ApiCheck(isolate != NULL && - !isolate->IsDead(), - "v8::internal::Internals::CheckInitialized()", + Utils::ApiCheck(isolate != NULL && !isolate->IsDead(), + "v8::internal::Internals::CheckInitialized", "Isolate is not initialized or V8 has died"); } void External::CheckCast(v8::Value* that) { - Utils::ApiCheck(Utils::OpenHandle(that)->IsExternal(), - "v8::External::Cast()", + Utils::ApiCheck(Utils::OpenHandle(that)->IsExternal(), "v8::External::Cast", "Could not convert to external"); } void v8::Object::CheckCast(Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsJSReceiver(), "v8::Object::Cast()", + Utils::ApiCheck(obj->IsJSReceiver(), "v8::Object::Cast", "Could not convert to object"); } void v8::Function::CheckCast(Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsCallable(), "v8::Function::Cast()", + Utils::ApiCheck(obj->IsCallable(), "v8::Function::Cast", "Could not convert to function"); } void v8::Boolean::CheckCast(v8::Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsBoolean(), - "v8::Boolean::Cast()", + Utils::ApiCheck(obj->IsBoolean(), "v8::Boolean::Cast", "Could not convert to boolean"); } void v8::Name::CheckCast(v8::Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsName(), - "v8::Name::Cast()", - "Could not convert to name"); + Utils::ApiCheck(obj->IsName(), "v8::Name::Cast", "Could not convert to name"); } void v8::String::CheckCast(v8::Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsString(), - "v8::String::Cast()", + Utils::ApiCheck(obj->IsString(), "v8::String::Cast", "Could not convert to string"); } void v8::Symbol::CheckCast(v8::Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsSymbol(), - "v8::Symbol::Cast()", + Utils::ApiCheck(obj->IsSymbol(), "v8::Symbol::Cast", "Could not convert to symbol"); } @@ -3199,65 +3241,64 @@ void v8::Number::CheckCast(v8::Value* that) { void v8::Integer::CheckCast(v8::Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsNumber(), - "v8::Integer::Cast()", + Utils::ApiCheck(obj->IsNumber(), "v8::Integer::Cast", "Could not convert to number"); } void v8::Int32::CheckCast(v8::Value* that) { - Utils::ApiCheck(that->IsInt32(), "v8::Int32::Cast()", + Utils::ApiCheck(that->IsInt32(), "v8::Int32::Cast", "Could not convert to 32-bit signed integer"); } void v8::Uint32::CheckCast(v8::Value* that) { - Utils::ApiCheck(that->IsUint32(), "v8::Uint32::Cast()", + Utils::ApiCheck(that->IsUint32(), "v8::Uint32::Cast", "Could not convert to 32-bit unsigned integer"); } void v8::Array::CheckCast(Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsJSArray(), - "v8::Array::Cast()", + Utils::ApiCheck(obj->IsJSArray(), "v8::Array::Cast", "Could not convert to array"); } void v8::Map::CheckCast(Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsJSMap(), "v8::Map::Cast()", - "Could not convert to Map"); + Utils::ApiCheck(obj->IsJSMap(), "v8::Map::Cast", "Could not convert to Map"); } void v8::Set::CheckCast(Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); - Utils::ApiCheck(obj->IsJSSet(), "v8::Set::Cast()", - "Could not convert to Set"); + Utils::ApiCheck(obj->IsJSSet(), "v8_Set_Cast", "Could not convert to Set"); } void v8::Promise::CheckCast(Value* that) { - Utils::ApiCheck(that->IsPromise(), - "v8::Promise::Cast()", + Utils::ApiCheck(that->IsPromise(), "v8::Promise::Cast", "Could not convert to promise"); } void v8::Promise::Resolver::CheckCast(Value* that) { - Utils::ApiCheck(that->IsPromise(), - "v8::Promise::Resolver::Cast()", + Utils::ApiCheck(that->IsPromise(), "v8::Promise::Resolver::Cast", "Could not convert to promise resolver"); } void v8::Proxy::CheckCast(Value* that) { - Utils::ApiCheck(that->IsProxy(), "v8::Proxy::Cast()", + Utils::ApiCheck(that->IsProxy(), "v8::Proxy::Cast", "Could not convert to proxy"); } +void v8::WasmCompiledModule::CheckCast(Value* that) { + Utils::ApiCheck(that->IsWebAssemblyCompiledModule(), + "v8::WasmCompiledModule::Cast", + "Could not convert to wasm compiled module"); +} void v8::ArrayBuffer::CheckCast(Value* that) { i::Handle<i::Object> obj = Utils::OpenHandle(that); @@ -3391,7 +3432,7 @@ bool Value::BooleanValue() const { Maybe<double> Value::NumberValue(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsNumber()) return Just(obj->Number()); - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "NumberValue", double); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, NumberValue, double); i::Handle<i::Object> num; has_pending_exception = !i::Object::ToNumber(obj).ToHandle(&num); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(double); @@ -3412,7 +3453,7 @@ Maybe<int64_t> Value::IntegerValue(Local<Context> context) const { if (obj->IsNumber()) { return Just(NumberToInt64(*obj)); } - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "IntegerValue", int64_t); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, IntegerValue, int64_t); i::Handle<i::Object> num; has_pending_exception = !i::Object::ToInteger(isolate, obj).ToHandle(&num); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int64_t); @@ -3436,7 +3477,7 @@ int64_t Value::IntegerValue() const { Maybe<int32_t> Value::Int32Value(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsNumber()) return Just(NumberToInt32(*obj)); - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Int32Value", int32_t); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Int32Value, int32_t); i::Handle<i::Object> num; has_pending_exception = !i::Object::ToInt32(isolate, obj).ToHandle(&num); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int32_t); @@ -3455,7 +3496,7 @@ int32_t Value::Int32Value() const { Maybe<uint32_t> Value::Uint32Value(Local<Context> context) const { auto obj = Utils::OpenHandle(this); if (obj->IsNumber()) return Just(NumberToUint32(*obj)); - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Uint32Value", uint32_t); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Uint32Value, uint32_t); i::Handle<i::Object> num; has_pending_exception = !i::Object::ToUint32(isolate, obj).ToHandle(&num); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(uint32_t); @@ -3477,7 +3518,7 @@ MaybeLocal<Uint32> Value::ToArrayIndex(Local<Context> context) const { if (i::Smi::cast(*self)->value() >= 0) return Utils::Uint32ToLocal(self); return Local<Uint32>(); } - PREPARE_FOR_EXECUTION(context, "ToArrayIndex", Uint32); + PREPARE_FOR_EXECUTION(context, Object, ToArrayIndex, Uint32); i::Handle<i::Object> string_obj; has_pending_exception = !i::Object::ToString(isolate, self).ToHandle(&string_obj); @@ -3543,10 +3584,16 @@ bool Value::SameValue(Local<Value> that) const { return self->SameValue(*other); } +Local<String> Value::TypeOf(v8::Isolate* external_isolate) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate); + ENTER_V8(isolate); + LOG_API(isolate, Value, TypeOf); + return Utils::ToLocal(i::Object::TypeOf(isolate, Utils::OpenHandle(this))); +} Maybe<bool> v8::Object::Set(v8::Local<v8::Context> context, v8::Local<Value> key, v8::Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Set()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Set, bool); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); auto value_obj = Utils::OpenHandle(*value); @@ -3566,7 +3613,7 @@ bool v8::Object::Set(v8::Local<Value> key, v8::Local<Value> value) { Maybe<bool> v8::Object::Set(v8::Local<v8::Context> context, uint32_t index, v8::Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Set()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Set, bool); auto self = Utils::OpenHandle(this); auto value_obj = Utils::OpenHandle(*value); has_pending_exception = i::Object::SetElement(isolate, self, index, value_obj, @@ -3585,8 +3632,7 @@ bool v8::Object::Set(uint32_t index, v8::Local<Value> value) { Maybe<bool> v8::Object::CreateDataProperty(v8::Local<v8::Context> context, v8::Local<Name> key, v8::Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::CreateDataProperty()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, CreateDataProperty, bool); i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); i::Handle<i::Name> key_obj = Utils::OpenHandle(*key); i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); @@ -3604,8 +3650,7 @@ Maybe<bool> v8::Object::CreateDataProperty(v8::Local<v8::Context> context, Maybe<bool> v8::Object::CreateDataProperty(v8::Local<v8::Context> context, uint32_t index, v8::Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::CreateDataProperty()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, CreateDataProperty, bool); i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); @@ -3622,8 +3667,7 @@ Maybe<bool> v8::Object::DefineOwnProperty(v8::Local<v8::Context> context, v8::Local<Name> key, v8::Local<Value> value, v8::PropertyAttribute attributes) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::DefineOwnProperty()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, DefineOwnProperty, bool); i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); i::Handle<i::Name> key_obj = Utils::OpenHandle(*key); i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); @@ -3666,7 +3710,7 @@ static i::MaybeHandle<i::Object> DefineObjectProperty( Maybe<bool> v8::Object::ForceSet(v8::Local<v8::Context> context, v8::Local<Value> key, v8::Local<Value> value, v8::PropertyAttribute attribs) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::ForceSet()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, ForceSet, bool); auto self = i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); auto key_obj = Utils::OpenHandle(*key); auto value_obj = Utils::OpenHandle(*value); @@ -3682,9 +3726,8 @@ Maybe<bool> v8::Object::ForceSet(v8::Local<v8::Context> context, bool v8::Object::ForceSet(v8::Local<Value> key, v8::Local<Value> value, v8::PropertyAttribute attribs) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - PREPARE_FOR_EXECUTION_GENERIC(isolate, Local<Context>(), - "v8::Object::ForceSet", false, i::HandleScope, - false); + PREPARE_FOR_EXECUTION_GENERIC(isolate, Local<Context>(), Object, ForceSet, + false, i::HandleScope, false); i::Handle<i::JSObject> self = i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); i::Handle<i::Object> key_obj = Utils::OpenHandle(*key); @@ -3700,7 +3743,7 @@ bool v8::Object::ForceSet(v8::Local<Value> key, v8::Local<Value> value, Maybe<bool> v8::Object::SetPrivate(Local<Context> context, Local<Private> key, Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::SetPrivate()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, SetPrivate, bool); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(reinterpret_cast<Name*>(*key)); auto value_obj = Utils::OpenHandle(*value); @@ -3726,7 +3769,7 @@ Maybe<bool> v8::Object::SetPrivate(Local<Context> context, Local<Private> key, MaybeLocal<Value> v8::Object::Get(Local<v8::Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION(context, "v8::Object::Get()", Value); + PREPARE_FOR_EXECUTION(context, Object, Get, Value); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); i::Handle<i::Object> result; @@ -3744,7 +3787,7 @@ Local<Value> v8::Object::Get(v8::Local<Value> key) { MaybeLocal<Value> v8::Object::Get(Local<Context> context, uint32_t index) { - PREPARE_FOR_EXECUTION(context, "v8::Object::Get()", Value); + PREPARE_FOR_EXECUTION(context, Object, Get, Value); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; has_pending_exception = @@ -3768,8 +3811,8 @@ MaybeLocal<Value> v8::Object::GetPrivate(Local<Context> context, Maybe<PropertyAttribute> v8::Object::GetPropertyAttributes( Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE( - context, "v8::Object::GetPropertyAttributes()", PropertyAttribute); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, GetPropertyAttributes, + PropertyAttribute); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); if (!key_obj->IsName()) { @@ -3797,8 +3840,7 @@ PropertyAttribute v8::Object::GetPropertyAttributes(v8::Local<Value> key) { MaybeLocal<Value> v8::Object::GetOwnPropertyDescriptor(Local<Context> context, Local<String> key) { - PREPARE_FOR_EXECUTION(context, "v8::Object::GetOwnPropertyDescriptor()", - Value); + PREPARE_FOR_EXECUTION(context, Object, GetOwnPropertyDescriptor, Value); i::Handle<i::JSReceiver> obj = Utils::OpenHandle(this); i::Handle<i::String> key_name = Utils::OpenHandle(*key); @@ -3830,7 +3872,7 @@ Local<Value> v8::Object::GetPrototype() { Maybe<bool> v8::Object::SetPrototype(Local<Context> context, Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::SetPrototype()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, SetPrototype, bool); auto self = Utils::OpenHandle(this); auto value_obj = Utils::OpenHandle(*value); // We do not allow exceptions thrown while setting the prototype @@ -3854,27 +3896,38 @@ Local<Object> v8::Object::FindInstanceInPrototypeChain( v8::Local<FunctionTemplate> tmpl) { auto isolate = Utils::OpenHandle(this)->GetIsolate(); i::PrototypeIterator iter(isolate, *Utils::OpenHandle(this), - i::PrototypeIterator::START_AT_RECEIVER); + i::kStartAtReceiver); auto tmpl_info = *Utils::OpenHandle(*tmpl); - while (!tmpl_info->IsTemplateFor(iter.GetCurrent())) { + while (!tmpl_info->IsTemplateFor(iter.GetCurrent<i::JSObject>())) { iter.Advance(); - if (iter.IsAtEnd()) { - return Local<Object>(); - } + if (iter.IsAtEnd()) return Local<Object>(); + if (!iter.GetCurrent()->IsJSObject()) return Local<Object>(); } // IsTemplateFor() ensures that iter.GetCurrent() can't be a Proxy here. return Utils::ToLocal(i::handle(iter.GetCurrent<i::JSObject>(), isolate)); } - MaybeLocal<Array> v8::Object::GetPropertyNames(Local<Context> context) { - PREPARE_FOR_EXECUTION(context, "v8::Object::GetPropertyNames()", Array); + return GetPropertyNames( + context, v8::KeyCollectionMode::kIncludePrototypes, + static_cast<v8::PropertyFilter>(ONLY_ENUMERABLE | SKIP_SYMBOLS), + v8::IndexFilter::kIncludeIndices); +} + +MaybeLocal<Array> v8::Object::GetPropertyNames(Local<Context> context, + KeyCollectionMode mode, + PropertyFilter property_filter, + IndexFilter index_filter) { + PREPARE_FOR_EXECUTION(context, Object, GetPropertyNames, Array); auto self = Utils::OpenHandle(this); i::Handle<i::FixedArray> value; - has_pending_exception = - !i::JSReceiver::GetKeys(self, i::INCLUDE_PROTOS, i::ENUMERABLE_STRINGS) - .ToHandle(&value); + i::KeyAccumulator accumulator( + isolate, static_cast<i::KeyCollectionMode>(mode), + static_cast<i::PropertyFilter>(property_filter)); + accumulator.set_skip_indices(index_filter == IndexFilter::kSkipIndices); + has_pending_exception = accumulator.CollectKeys(self, self).IsNothing(); RETURN_ON_FAILED_EXECUTION(Array); + value = accumulator.GetKeys(i::GetKeysConversion::kKeepNumbers); DCHECK(self->map()->EnumLength() == i::kInvalidEnumCacheSentinel || self->map()->EnumLength() == 0 || self->map()->instance_descriptors()->GetEnumCache() != *value); @@ -3888,31 +3941,24 @@ Local<Array> v8::Object::GetPropertyNames() { RETURN_TO_LOCAL_UNCHECKED(GetPropertyNames(context), Array); } - MaybeLocal<Array> v8::Object::GetOwnPropertyNames(Local<Context> context) { - PREPARE_FOR_EXECUTION(context, "v8::Object::GetOwnPropertyNames()", Array); - auto self = Utils::OpenHandle(this); - i::Handle<i::FixedArray> value; - has_pending_exception = - !i::JSReceiver::GetKeys(self, i::OWN_ONLY, i::ENUMERABLE_STRINGS) - .ToHandle(&value); - RETURN_ON_FAILED_EXECUTION(Array); - DCHECK(self->map()->EnumLength() == i::kInvalidEnumCacheSentinel || - self->map()->EnumLength() == 0 || - self->map()->instance_descriptors()->GetEnumCache() != *value); - auto result = isolate->factory()->NewJSArrayWithElements(value); - RETURN_ESCAPED(Utils::ToLocal(result)); + return GetOwnPropertyNames( + context, static_cast<v8::PropertyFilter>(ONLY_ENUMERABLE | SKIP_SYMBOLS)); } - Local<Array> v8::Object::GetOwnPropertyNames() { auto context = ContextFromHeapObject(Utils::OpenHandle(this)); RETURN_TO_LOCAL_UNCHECKED(GetOwnPropertyNames(context), Array); } +MaybeLocal<Array> v8::Object::GetOwnPropertyNames(Local<Context> context, + PropertyFilter filter) { + return GetPropertyNames(context, KeyCollectionMode::kOwnOnly, filter, + v8::IndexFilter::kIncludeIndices); +} MaybeLocal<String> v8::Object::ObjectProtoToString(Local<Context> context) { - PREPARE_FOR_EXECUTION(context, "v8::Object::ObjectProtoToString", String); + PREPARE_FOR_EXECUTION(context, Object, ObjectProtoToString, String); auto obj = Utils::OpenHandle(this); Local<String> result; has_pending_exception = @@ -3936,8 +3982,7 @@ Local<String> v8::Object::GetConstructorName() { Maybe<bool> v8::Object::SetIntegrityLevel(Local<Context> context, IntegrityLevel level) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::SetIntegrityLevel()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, SetIntegrityLevel, bool); auto self = Utils::OpenHandle(this); i::JSReceiver::IntegrityLevel i_level = level == IntegrityLevel::kFrozen ? i::FROZEN : i::SEALED; @@ -3949,7 +3994,7 @@ Maybe<bool> v8::Object::SetIntegrityLevel(Local<Context> context, } Maybe<bool> v8::Object::Delete(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Delete()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Delete, bool); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); Maybe<bool> result = @@ -3973,7 +4018,7 @@ Maybe<bool> v8::Object::DeletePrivate(Local<Context> context, Maybe<bool> v8::Object::Has(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Get()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Get, bool); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); Maybe<bool> maybe = Nothing<bool>(); @@ -4006,8 +4051,7 @@ Maybe<bool> v8::Object::HasPrivate(Local<Context> context, Local<Private> key) { Maybe<bool> v8::Object::Delete(Local<Context> context, uint32_t index) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::DeleteProperty()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, DeleteProperty, bool); auto self = Utils::OpenHandle(this); Maybe<bool> result = i::JSReceiver::DeleteElement(self, index); has_pending_exception = result.IsNothing(); @@ -4023,7 +4067,7 @@ bool v8::Object::Delete(uint32_t index) { Maybe<bool> v8::Object::Has(Local<Context> context, uint32_t index) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Get()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, Get, bool); auto self = Utils::OpenHandle(this); auto maybe = i::JSReceiver::HasElement(self, index); has_pending_exception = maybe.IsNothing(); @@ -4044,7 +4088,7 @@ static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self, Setter setter, Data data, AccessControl settings, PropertyAttribute attributes) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::SetAccessor()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, SetAccessor, bool); if (!Utils::OpenHandle(self)->IsJSObject()) return Just(false); i::Handle<i::JSObject> obj = i::Handle<i::JSObject>::cast(Utils::OpenHandle(self)); @@ -4057,7 +4101,7 @@ static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self, has_pending_exception = !i::JSObject::SetAccessor(obj, info).ToHandle(&result); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - if (result->IsUndefined()) return Nothing<bool>(); + if (result->IsUndefined(obj->GetIsolate())) return Nothing<bool>(); if (fast) { i::JSObject::MigrateSlowToFast(obj, 0, "APISetAccessor"); } @@ -4116,8 +4160,7 @@ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter, Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context, Local<Name> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::HasOwnProperty()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, HasOwnProperty, bool); auto self = Utils::OpenHandle(this); auto key_val = Utils::OpenHandle(*key); auto result = i::JSReceiver::HasOwnProperty(self, key_val); @@ -4126,6 +4169,14 @@ Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context, return result; } +Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context, uint32_t index) { + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, HasOwnProperty, bool); + auto self = Utils::OpenHandle(this); + auto result = i::JSReceiver::HasOwnProperty(self, index); + has_pending_exception = result.IsNothing(); + RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); + return result; +} bool v8::Object::HasOwnProperty(Local<String> key) { auto context = ContextFromHeapObject(Utils::OpenHandle(this)); @@ -4135,8 +4186,7 @@ bool v8::Object::HasOwnProperty(Local<String> key) { Maybe<bool> v8::Object::HasRealNamedProperty(Local<Context> context, Local<Name> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::HasRealNamedProperty()", - bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, HasRealNamedProperty, bool); auto self = Utils::OpenHandle(this); if (!self->IsJSObject()) return Just(false); auto key_val = Utils::OpenHandle(*key); @@ -4156,8 +4206,8 @@ bool v8::Object::HasRealNamedProperty(Local<String> key) { Maybe<bool> v8::Object::HasRealIndexedProperty(Local<Context> context, uint32_t index) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, - "v8::Object::HasRealIndexedProperty()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, HasRealIndexedProperty, + bool); auto self = Utils::OpenHandle(this); if (!self->IsJSObject()) return Just(false); auto result = i::JSObject::HasRealElementProperty( @@ -4176,8 +4226,8 @@ bool v8::Object::HasRealIndexedProperty(uint32_t index) { Maybe<bool> v8::Object::HasRealNamedCallbackProperty(Local<Context> context, Local<Name> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE( - context, "v8::Object::HasRealNamedCallbackProperty()", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Object, HasRealNamedCallbackProperty, + bool); auto self = Utils::OpenHandle(this); if (!self->IsJSObject()) return Just(false); auto key_val = Utils::OpenHandle(*key); @@ -4211,8 +4261,8 @@ bool v8::Object::HasIndexedLookupInterceptor() { MaybeLocal<Value> v8::Object::GetRealNamedPropertyInPrototypeChain( Local<Context> context, Local<Name> key) { - PREPARE_FOR_EXECUTION( - context, "v8::Object::GetRealNamedPropertyInPrototypeChain()", Value); + PREPARE_FOR_EXECUTION(context, Object, GetRealNamedPropertyInPrototypeChain, + Value); i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); if (!self->IsJSObject()) return MaybeLocal<Value>(); i::Handle<i::Name> key_obj = Utils::OpenHandle(*key); @@ -4243,7 +4293,7 @@ Maybe<PropertyAttribute> v8::Object::GetRealNamedPropertyAttributesInPrototypeChain( Local<Context> context, Local<Name> key) { PREPARE_FOR_EXECUTION_PRIMITIVE( - context, "v8::Object::GetRealNamedPropertyAttributesInPrototypeChain()", + context, Object, GetRealNamedPropertyAttributesInPrototypeChain, PropertyAttribute); i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); if (!self->IsJSObject()) return Nothing<PropertyAttribute>(); @@ -4273,7 +4323,7 @@ v8::Object::GetRealNamedPropertyAttributesInPrototypeChain(Local<String> key) { MaybeLocal<Value> v8::Object::GetRealNamedProperty(Local<Context> context, Local<Name> key) { - PREPARE_FOR_EXECUTION(context, "v8::Object::GetRealNamedProperty()", Value); + PREPARE_FOR_EXECUTION(context, Object, GetRealNamedProperty, Value); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); i::LookupIterator it = i::LookupIterator::PropertyOrElement( @@ -4296,8 +4346,7 @@ Local<Value> v8::Object::GetRealNamedProperty(Local<String> key) { Maybe<PropertyAttribute> v8::Object::GetRealNamedPropertyAttributes( Local<Context> context, Local<Name> key) { PREPARE_FOR_EXECUTION_PRIMITIVE( - context, "v8::Object::GetRealNamedPropertyAttributes()", - PropertyAttribute); + context, Object, GetRealNamedPropertyAttributes, PropertyAttribute); auto self = Utils::OpenHandle(this); auto key_obj = Utils::OpenHandle(*key); i::LookupIterator it = i::LookupIterator::PropertyOrElement( @@ -4342,60 +4391,7 @@ int v8::Object::GetIdentityHash() { auto isolate = Utils::OpenHandle(this)->GetIsolate(); i::HandleScope scope(isolate); auto self = Utils::OpenHandle(this); - return i::JSReceiver::GetOrCreateIdentityHash(self)->value(); -} - - -bool v8::Object::SetHiddenValue(v8::Local<v8::String> key, - v8::Local<v8::Value> value) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8(isolate); - i::HandleScope scope(isolate); - i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); - if (!self->IsJSObject()) return false; - i::Handle<i::String> key_obj = Utils::OpenHandle(*key); - i::Handle<i::String> key_string = - isolate->factory()->InternalizeString(key_obj); - if (value.IsEmpty()) { - i::JSObject::DeleteHiddenProperty(i::Handle<i::JSObject>::cast(self), - key_string); - return true; - } - i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); - i::Handle<i::Object> result = i::JSObject::SetHiddenProperty( - i::Handle<i::JSObject>::cast(self), key_string, value_obj); - return *result == *self; -} - - -v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Local<v8::String> key) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8(isolate); - i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); - if (!self->IsJSObject()) return v8::Local<v8::Value>(); - i::Handle<i::String> key_obj = Utils::OpenHandle(*key); - i::Handle<i::String> key_string = - isolate->factory()->InternalizeString(key_obj); - i::Handle<i::Object> result( - i::Handle<i::JSObject>::cast(self)->GetHiddenProperty(key_string), - isolate); - if (result->IsTheHole()) return v8::Local<v8::Value>(); - return Utils::ToLocal(result); -} - - -bool v8::Object::DeleteHiddenValue(v8::Local<v8::String> key) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8(isolate); - i::HandleScope scope(isolate); - i::Handle<i::JSReceiver> self = Utils::OpenHandle(this); - if (!self->IsJSObject()) return false; - i::Handle<i::String> key_obj = Utils::OpenHandle(*key); - i::Handle<i::String> key_string = - isolate->factory()->InternalizeString(key_obj); - i::JSObject::DeleteHiddenProperty(i::Handle<i::JSObject>::cast(self), - key_string); - return true; + return i::JSReceiver::GetOrCreateIdentityHash(isolate, self)->value(); } @@ -4404,14 +4400,17 @@ bool v8::Object::IsCallable() { return self->IsCallable(); } +bool v8::Object::IsConstructor() { + auto self = Utils::OpenHandle(this); + return self->IsConstructor(); +} MaybeLocal<Value> Object::CallAsFunction(Local<Context> context, Local<Value> recv, int argc, Local<Value> argv[]) { - PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Object::CallAsFunction()", - Value); + PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, Object, CallAsFunction, Value); i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); - TRACE_EVENT0("v8", "V8.Execute"); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute"); auto self = Utils::OpenHandle(this); auto recv_obj = Utils::OpenHandle(*recv); STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**)); @@ -4435,10 +4434,10 @@ Local<v8::Value> Object::CallAsFunction(v8::Local<v8::Value> recv, int argc, MaybeLocal<Value> Object::CallAsConstructor(Local<Context> context, int argc, Local<Value> argv[]) { - PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, - "v8::Object::CallAsConstructor()", Value); + PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, Object, CallAsConstructor, + Value); i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); - TRACE_EVENT0("v8", "V8.Execute"); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute"); auto self = Utils::OpenHandle(this); STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**)); i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv); @@ -4457,28 +4456,23 @@ Local<v8::Value> Object::CallAsConstructor(int argc, RETURN_TO_LOCAL_UNCHECKED(CallAsConstructor(context, argc, argv_cast), Value); } - -MaybeLocal<Function> Function::New(Local<Context> context, - FunctionCallback callback, Local<Value> data, - int length) { - return New(context, callback, data, length, ConstructorBehavior::kAllow); -} - MaybeLocal<Function> Function::New(Local<Context> context, FunctionCallback callback, Local<Value> data, int length, ConstructorBehavior behavior) { i::Isolate* isolate = Utils::OpenHandle(*context)->GetIsolate(); - LOG_API(isolate, "Function::New"); + LOG_API(isolate, Function, New); ENTER_V8(isolate); - auto tmpl = FunctionTemplateNew(isolate, callback, nullptr, data, - Local<Signature>(), length, true); - if (behavior == ConstructorBehavior::kThrow) tmpl->RemovePrototype(); - return tmpl->GetFunction(context); + auto templ = FunctionTemplateNew(isolate, callback, nullptr, data, + Local<Signature>(), length, true); + if (behavior == ConstructorBehavior::kThrow) templ->RemovePrototype(); + return templ->GetFunction(context); } + Local<Function> Function::New(Isolate* v8_isolate, FunctionCallback callback, Local<Value> data, int length) { - return Function::New(v8_isolate->GetCurrentContext(), callback, data, length) + return Function::New(v8_isolate->GetCurrentContext(), callback, data, length, + ConstructorBehavior::kAllow) .FromMaybe(Local<Function>()); } @@ -4491,10 +4485,9 @@ Local<v8::Object> Function::NewInstance() const { MaybeLocal<Object> Function::NewInstance(Local<Context> context, int argc, v8::Local<v8::Value> argv[]) const { - PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Function::NewInstance()", - Object); + PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, Function, NewInstance, Object); i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); - TRACE_EVENT0("v8", "V8.Execute"); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute"); auto self = Utils::OpenHandle(this); STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**)); i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv); @@ -4516,9 +4509,9 @@ Local<v8::Object> Function::NewInstance(int argc, MaybeLocal<v8::Value> Function::Call(Local<Context> context, v8::Local<v8::Value> recv, int argc, v8::Local<v8::Value> argv[]) { - PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Function::Call()", Value); + PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, Function, Call, Value); i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); - TRACE_EVENT0("v8", "V8.Execute"); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute"); auto self = Utils::OpenHandle(this); i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv); STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**)); @@ -4548,16 +4541,20 @@ void Function::SetName(v8::Local<v8::String> name) { Local<Value> Function::GetName() const { auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); if (self->IsJSBoundFunction()) { auto func = i::Handle<i::JSBoundFunction>::cast(self); - return Utils::ToLocal(handle(func->name(), func->GetIsolate())); + i::Handle<i::Object> name; + ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, name, + i::JSBoundFunction::GetName(isolate, func), + Local<Value>()); + return Utils::ToLocal(name); } if (self->IsJSFunction()) { auto func = i::Handle<i::JSFunction>::cast(self); - return Utils::ToLocal(handle(func->shared()->name(), func->GetIsolate())); + return Utils::ToLocal(handle(func->shared()->name(), isolate)); } - return ToApiHandle<Primitive>( - self->GetIsolate()->factory()->undefined_value()); + return ToApiHandle<Primitive>(isolate->factory()->undefined_value()); } @@ -5224,10 +5221,10 @@ int String::WriteUtf8(char* buffer, int capacity, int* nchars_ref, int options) const { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - LOG_API(isolate, "String::WriteUtf8"); - ENTER_V8(isolate); i::Handle<i::String> str = Utils::OpenHandle(this); + i::Isolate* isolate = str->GetIsolate(); + LOG_API(isolate, String, WriteUtf8); + ENTER_V8(isolate); if (options & HINT_MANY_WRITES_EXPECTED) { str = i::String::Flatten(str); // Flatten the string for efficiency. } @@ -5243,7 +5240,7 @@ int String::WriteUtf8(char* buffer, if (success) return writer.CompleteWrite(write_null, nchars_ref); } else if (capacity >= string_length) { // First check that the buffer is large enough. - int utf8_bytes = v8::Utf8Length(*str, str->GetIsolate()); + int utf8_bytes = v8::Utf8Length(*str, isolate); if (utf8_bytes <= capacity) { // one-byte fast path. if (utf8_bytes == string_length) { @@ -5278,7 +5275,7 @@ static inline int WriteHelper(const String* string, int length, int options) { i::Isolate* isolate = Utils::OpenHandle(string)->GetIsolate(); - LOG_API(isolate, "String::Write"); + LOG_API(isolate, String, Write); ENTER_V8(isolate); DCHECK(start >= 0 && length >= -1); i::Handle<i::String> str = Utils::OpenHandle(string); @@ -5399,7 +5396,7 @@ double Number::Value() const { bool Boolean::Value() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); - return obj->IsTrue(); + return obj->IsTrue(i::HeapObject::cast(*obj)->GetIsolate()); } @@ -5477,7 +5474,6 @@ void* v8::Object::SlowGetAlignedPointerFromInternalField(int index) { i::Handle<i::JSObject>::cast(obj)->GetInternalField(index), location); } - void v8::Object::SetAlignedPointerInInternalField(int index, void* value) { i::Handle<i::JSReceiver> obj = Utils::OpenHandle(this); const char* location = "v8::Object::SetAlignedPointerInInternalField()"; @@ -5487,10 +5483,31 @@ void v8::Object::SetAlignedPointerInInternalField(int index, void* value) { DCHECK_EQ(value, GetAlignedPointerFromInternalField(index)); } +void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[], + void* values[]) { + i::Handle<i::JSReceiver> obj = Utils::OpenHandle(this); + const char* location = "v8::Object::SetAlignedPointerInInternalFields()"; + i::DisallowHeapAllocation no_gc; + i::JSObject* object = i::JSObject::cast(*obj); + int nof_internal_fields = object->GetInternalFieldCount(); + for (int i = 0; i < argc; i++) { + int index = indices[i]; + if (!Utils::ApiCheck(index < nof_internal_fields, location, + "Internal field out of bounds")) { + return; + } + void* value = values[i]; + object->SetInternalField(index, EncodeAlignedAsSmi(value, location)); + DCHECK_EQ(value, GetAlignedPointerFromInternalField(index)); + } +} static void* ExternalValue(i::Object* obj) { // Obscure semantics for undefined, but somehow checked in our unit tests... - if (obj->IsUndefined()) return NULL; + if (!obj->IsSmi() && + obj->IsUndefined(i::HeapObject::cast(obj)->GetIsolate())) { + return NULL; + } i::Object* foreign = i::JSObject::cast(obj)->GetInternalField(0); return i::Foreign::cast(foreign)->foreign_address(); } @@ -5544,6 +5561,8 @@ HeapStatistics::HeapStatistics() total_available_size_(0), used_heap_size_(0), heap_size_limit_(0), + malloced_memory_(0), + peak_malloced_memory_(0), does_zap_garbage_(0) {} HeapSpaceStatistics::HeapSpaceStatistics(): space_name_(0), @@ -5559,11 +5578,17 @@ HeapObjectStatistics::HeapObjectStatistics() object_count_(0), object_size_(0) {} +HeapCodeStatistics::HeapCodeStatistics() + : code_and_metadata_size_(0), bytecode_and_metadata_size_(0) {} bool v8::V8::InitializeICU(const char* icu_data_file) { return i::InitializeICU(icu_data_file); } +bool v8::V8::InitializeICUDefaultLocation(const char* exec_path, + const char* icu_data_file) { + return i::InitializeICUDefaultLocation(exec_path, icu_data_file); +} void v8::V8::InitializeExternalStartupData(const char* directory_path) { i::InitializeExternalStartupData(directory_path); @@ -5580,21 +5605,51 @@ const char* v8::V8::GetVersion() { return i::Version::GetVersion(); } +template <typename ObjectType> +struct InvokeBootstrapper; -static i::Handle<i::Context> CreateEnvironment( +template <> +struct InvokeBootstrapper<i::Context> { + i::Handle<i::Context> Invoke( + i::Isolate* isolate, i::MaybeHandle<i::JSGlobalProxy> maybe_global_proxy, + v8::Local<v8::ObjectTemplate> global_object_template, + v8::ExtensionConfiguration* extensions, size_t context_snapshot_index) { + return isolate->bootstrapper()->CreateEnvironment( + maybe_global_proxy, global_object_template, extensions, + context_snapshot_index); + } +}; + +template <> +struct InvokeBootstrapper<i::JSGlobalProxy> { + i::Handle<i::JSGlobalProxy> Invoke( + i::Isolate* isolate, i::MaybeHandle<i::JSGlobalProxy> maybe_global_proxy, + v8::Local<v8::ObjectTemplate> global_object_template, + v8::ExtensionConfiguration* extensions, size_t context_snapshot_index) { + USE(extensions); + USE(context_snapshot_index); + return isolate->bootstrapper()->NewRemoteContext(maybe_global_proxy, + global_object_template); + } +}; + +template <typename ObjectType> +static i::Handle<ObjectType> CreateEnvironment( i::Isolate* isolate, v8::ExtensionConfiguration* extensions, - v8::Local<ObjectTemplate> global_template, - v8::Local<Value> maybe_global_proxy) { - i::Handle<i::Context> env; + v8::MaybeLocal<ObjectTemplate> maybe_global_template, + v8::MaybeLocal<Value> maybe_global_proxy, size_t context_snapshot_index) { + i::Handle<ObjectType> result; // Enter V8 via an ENTER_V8 scope. { ENTER_V8(isolate); - v8::Local<ObjectTemplate> proxy_template = global_template; + v8::Local<ObjectTemplate> proxy_template; i::Handle<i::FunctionTemplateInfo> proxy_constructor; i::Handle<i::FunctionTemplateInfo> global_constructor; - if (!global_template.IsEmpty()) { + if (!maybe_global_template.IsEmpty()) { + v8::Local<v8::ObjectTemplate> global_template = + maybe_global_template.ToLocalChecked(); // Make sure that the global_template has a constructor. global_constructor = EnsureConstructor(isolate, *global_template); @@ -5611,7 +5666,7 @@ static i::Handle<i::Context> CreateEnvironment( // Migrate security handlers from global_template to // proxy_template. Temporarily removing access check // information from the global template. - if (!global_constructor->access_check_info()->IsUndefined()) { + if (!global_constructor->access_check_info()->IsUndefined(isolate)) { proxy_constructor->set_access_check_info( global_constructor->access_check_info()); proxy_constructor->set_needs_access_check( @@ -5622,17 +5677,18 @@ static i::Handle<i::Context> CreateEnvironment( } } - i::Handle<i::Object> proxy = Utils::OpenHandle(*maybe_global_proxy, true); i::MaybeHandle<i::JSGlobalProxy> maybe_proxy; - if (!proxy.is_null()) { - maybe_proxy = i::Handle<i::JSGlobalProxy>::cast(proxy); + if (!maybe_global_proxy.IsEmpty()) { + maybe_proxy = i::Handle<i::JSGlobalProxy>::cast( + Utils::OpenHandle(*maybe_global_proxy.ToLocalChecked())); } // Create the environment. - env = isolate->bootstrapper()->CreateEnvironment( - maybe_proxy, proxy_template, extensions); + InvokeBootstrapper<ObjectType> invoke; + result = invoke.Invoke(isolate, maybe_proxy, proxy_template, extensions, + context_snapshot_index); // Restore the access check info on the global template. - if (!global_template.IsEmpty()) { + if (!maybe_global_template.IsEmpty()) { DCHECK(!global_constructor.is_null()); DCHECK(!proxy_constructor.is_null()); global_constructor->set_access_check_info( @@ -5643,20 +5699,23 @@ static i::Handle<i::Context> CreateEnvironment( } // Leave V8. - return env; + return result; } -Local<Context> v8::Context::New(v8::Isolate* external_isolate, - v8::ExtensionConfiguration* extensions, - v8::Local<ObjectTemplate> global_template, - v8::Local<Value> global_object) { +Local<Context> NewContext(v8::Isolate* external_isolate, + v8::ExtensionConfiguration* extensions, + v8::MaybeLocal<ObjectTemplate> global_template, + v8::MaybeLocal<Value> global_object, + size_t context_snapshot_index) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate); - LOG_API(isolate, "Context::New"); + LOG_API(isolate, Context, New); + TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.NewContext"); i::HandleScope scope(isolate); ExtensionConfiguration no_extensions; if (extensions == NULL) extensions = &no_extensions; i::Handle<i::Context> env = - CreateEnvironment(isolate, extensions, global_template, global_object); + CreateEnvironment<i::Context>(isolate, extensions, global_template, + global_object, context_snapshot_index); if (env.is_null()) { if (isolate->has_pending_exception()) { isolate->OptionalRescheduleException(true); @@ -5666,6 +5725,57 @@ Local<Context> v8::Context::New(v8::Isolate* external_isolate, return Utils::ToLocal(scope.CloseAndEscape(env)); } +Local<Context> v8::Context::New(v8::Isolate* external_isolate, + v8::ExtensionConfiguration* extensions, + v8::MaybeLocal<ObjectTemplate> global_template, + v8::MaybeLocal<Value> global_object) { + return NewContext(external_isolate, extensions, global_template, + global_object, 0); +} + +MaybeLocal<Context> v8::Context::FromSnapshot( + v8::Isolate* external_isolate, size_t context_snapshot_index, + v8::ExtensionConfiguration* extensions, + v8::MaybeLocal<ObjectTemplate> global_template, + v8::MaybeLocal<Value> global_object) { + if (!i::Snapshot::HasContextSnapshot( + reinterpret_cast<i::Isolate*>(external_isolate), + context_snapshot_index)) { + return MaybeLocal<Context>(); + } + return NewContext(external_isolate, extensions, global_template, + global_object, context_snapshot_index); +} + +MaybeLocal<Object> v8::Context::NewRemoteContext( + v8::Isolate* external_isolate, v8::Local<ObjectTemplate> global_template, + v8::MaybeLocal<v8::Value> global_object) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate); + LOG_API(isolate, Context, NewRemoteContext); + i::HandleScope scope(isolate); + i::Handle<i::FunctionTemplateInfo> global_constructor = + EnsureConstructor(isolate, *global_template); + Utils::ApiCheck(global_constructor->needs_access_check(), + "v8::Context::NewRemoteContext", + "Global template needs to have access checks enabled."); + i::Handle<i::AccessCheckInfo> access_check_info = i::handle( + i::AccessCheckInfo::cast(global_constructor->access_check_info()), + isolate); + Utils::ApiCheck(access_check_info->named_interceptor() != nullptr, + "v8::Context::NewRemoteContext", + "Global template needs to have access check handlers."); + i::Handle<i::JSGlobalProxy> global_proxy = + CreateEnvironment<i::JSGlobalProxy>(isolate, nullptr, global_template, + global_object, 0); + if (global_proxy.is_null()) { + if (isolate->has_pending_exception()) { + isolate->OptionalRescheduleException(true); + } + return MaybeLocal<Object>(); + } + return Utils::ToLocal( + scope.CloseAndEscape(i::Handle<i::JSObject>::cast(global_proxy))); +} void v8::Context::SetSecurityToken(Local<Value> token) { i::Handle<i::Context> env = Utils::OpenHandle(this); @@ -5736,7 +5846,8 @@ void Context::AllowCodeGenerationFromStrings(bool allow) { bool Context::IsCodeGenerationFromStringsAllowed() { i::Handle<i::Context> context = Utils::OpenHandle(this); - return !context->allow_code_gen_from_strings()->IsFalse(); + return !context->allow_code_gen_from_strings()->IsFalse( + context->GetIsolate()); } @@ -5754,7 +5865,7 @@ size_t Context::EstimatedSize() { MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) { - PREPARE_FOR_EXECUTION(context, "v8::ObjectTemplate::NewInstance()", Object); + PREPARE_FOR_EXECUTION(context, ObjectTemplate, NewInstance, Object); auto self = Utils::OpenHandle(this); Local<Object> result; has_pending_exception = @@ -5771,8 +5882,7 @@ Local<v8::Object> ObjectTemplate::NewInstance() { MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) { - PREPARE_FOR_EXECUTION(context, "v8::FunctionTemplate::GetFunction()", - Function); + PREPARE_FOR_EXECUTION(context, FunctionTemplate, GetFunction, Function); auto self = Utils::OpenHandle(this); Local<Function> result; has_pending_exception = @@ -5787,18 +5897,44 @@ Local<v8::Function> FunctionTemplate::GetFunction() { RETURN_TO_LOCAL_UNCHECKED(GetFunction(context), Function); } +MaybeLocal<v8::Object> FunctionTemplate::NewRemoteInstance() { + auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); + LOG_API(isolate, FunctionTemplate, NewRemoteInstance); + i::HandleScope scope(isolate); + i::Handle<i::FunctionTemplateInfo> constructor = + EnsureConstructor(isolate, *InstanceTemplate()); + Utils::ApiCheck(constructor->needs_access_check(), + "v8::FunctionTemplate::NewRemoteInstance", + "InstanceTemplate needs to have access checks enabled."); + i::Handle<i::AccessCheckInfo> access_check_info = i::handle( + i::AccessCheckInfo::cast(constructor->access_check_info()), isolate); + Utils::ApiCheck(access_check_info->named_interceptor() != nullptr, + "v8::FunctionTemplate::NewRemoteInstance", + "InstanceTemplate needs to have access check handlers."); + i::Handle<i::JSObject> object; + if (!i::ApiNatives::InstantiateRemoteObject( + Utils::OpenHandle(*InstanceTemplate())) + .ToHandle(&object)) { + if (isolate->has_pending_exception()) { + isolate->OptionalRescheduleException(true); + } + return MaybeLocal<Object>(); + } + return Utils::ToLocal(scope.CloseAndEscape(object)); +} bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) { auto self = Utils::OpenHandle(this); auto obj = Utils::OpenHandle(*value); - return self->IsTemplateFor(*obj); + return obj->IsJSObject() && self->IsTemplateFor(i::JSObject::cast(*obj)); } Local<External> v8::External::New(Isolate* isolate, void* value) { STATIC_ASSERT(sizeof(value) == sizeof(i::Address)); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "External::New"); + LOG_API(i_isolate, External, New); ENTER_V8(i_isolate); i::Handle<i::JSObject> external = i_isolate->factory()->NewExternal(value); return Utils::ExternalToLocal(external); @@ -5866,42 +6002,42 @@ inline i::MaybeHandle<i::String> NewString(i::Factory* factory, STATIC_ASSERT(v8::String::kMaxLength == i::String::kMaxLength); - -template <typename Char> -inline MaybeLocal<String> NewString(Isolate* v8_isolate, const char* location, - const char* env, const Char* data, - v8::NewStringType type, int length) { - i::Isolate* isolate = reinterpret_cast<internal::Isolate*>(v8_isolate); - if (length == 0) return String::Empty(v8_isolate); - // TODO(dcarney): throw a context free exception. - if (length > i::String::kMaxLength) return MaybeLocal<String>(); - ENTER_V8(isolate); - LOG_API(isolate, env); - if (length < 0) length = StringLength(data); - i::Handle<i::String> result = - NewString(isolate->factory(), type, i::Vector<const Char>(data, length)) - .ToHandleChecked(); - return Utils::ToLocal(result); -} - } // anonymous namespace +// TODO(dcarney): throw a context free exception. +#define NEW_STRING(isolate, class_name, function_name, Char, data, type, \ + length) \ + MaybeLocal<String> result; \ + if (length == 0) { \ + result = String::Empty(isolate); \ + } else if (length > i::String::kMaxLength) { \ + result = MaybeLocal<String>(); \ + } else { \ + i::Isolate* i_isolate = reinterpret_cast<internal::Isolate*>(isolate); \ + ENTER_V8(i_isolate); \ + LOG_API(i_isolate, class_name, function_name); \ + if (length < 0) length = StringLength(data); \ + i::Handle<i::String> handle_result = \ + NewString(i_isolate->factory(), type, \ + i::Vector<const Char>(data, length)) \ + .ToHandleChecked(); \ + result = Utils::ToLocal(handle_result); \ + } Local<String> String::NewFromUtf8(Isolate* isolate, const char* data, NewStringType type, int length) { - RETURN_TO_LOCAL_UNCHECKED( - NewString(isolate, "v8::String::NewFromUtf8()", "String::NewFromUtf8", - data, static_cast<v8::NewStringType>(type), length), - String); + NEW_STRING(isolate, String, NewFromUtf8, char, data, + static_cast<v8::NewStringType>(type), length); + RETURN_TO_LOCAL_UNCHECKED(result, String); } MaybeLocal<String> String::NewFromUtf8(Isolate* isolate, const char* data, v8::NewStringType type, int length) { - return NewString(isolate, "v8::String::NewFromUtf8()", "String::NewFromUtf8", - data, type, length); + NEW_STRING(isolate, String, NewFromUtf8, char, data, type, length); + return result; } @@ -5909,18 +6045,16 @@ Local<String> String::NewFromOneByte(Isolate* isolate, const uint8_t* data, NewStringType type, int length) { - RETURN_TO_LOCAL_UNCHECKED( - NewString(isolate, "v8::String::NewFromOneByte()", - "String::NewFromOneByte", data, - static_cast<v8::NewStringType>(type), length), - String); + NEW_STRING(isolate, String, NewFromOneByte, uint8_t, data, + static_cast<v8::NewStringType>(type), length); + RETURN_TO_LOCAL_UNCHECKED(result, String); } MaybeLocal<String> String::NewFromOneByte(Isolate* isolate, const uint8_t* data, v8::NewStringType type, int length) { - return NewString(isolate, "v8::String::NewFromOneByte()", - "String::NewFromOneByte", data, type, length); + NEW_STRING(isolate, String, NewFromOneByte, uint8_t, data, type, length); + return result; } @@ -5928,19 +6062,17 @@ Local<String> String::NewFromTwoByte(Isolate* isolate, const uint16_t* data, NewStringType type, int length) { - RETURN_TO_LOCAL_UNCHECKED( - NewString(isolate, "v8::String::NewFromTwoByte()", - "String::NewFromTwoByte", data, - static_cast<v8::NewStringType>(type), length), - String); + NEW_STRING(isolate, String, NewFromTwoByte, uint16_t, data, + static_cast<v8::NewStringType>(type), length); + RETURN_TO_LOCAL_UNCHECKED(result, String); } MaybeLocal<String> String::NewFromTwoByte(Isolate* isolate, const uint16_t* data, v8::NewStringType type, int length) { - return NewString(isolate, "v8::String::NewFromTwoByte()", - "String::NewFromTwoByte", data, type, length); + NEW_STRING(isolate, String, NewFromTwoByte, uint16_t, data, type, length); + return result; } @@ -5948,7 +6080,7 @@ Local<String> v8::String::Concat(Local<String> left, Local<String> right) { i::Handle<i::String> left_string = Utils::OpenHandle(*left); i::Isolate* isolate = left_string->GetIsolate(); ENTER_V8(isolate); - LOG_API(isolate, "v8::String::Concat"); + LOG_API(isolate, String, Concat); i::Handle<i::String> right_string = Utils::OpenHandle(*right); // If we are steering towards a range error, do not wait for the error to be // thrown, and return the null handle instead. @@ -5970,7 +6102,7 @@ MaybeLocal<String> v8::String::NewExternalTwoByte( } i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); ENTER_V8(i_isolate); - LOG_API(i_isolate, "String::NewExternalTwoByte"); + LOG_API(i_isolate, String, NewExternalTwoByte); i::Handle<i::String> string = i_isolate->factory() ->NewExternalStringFromTwoByte(resource) .ToHandleChecked(); @@ -5994,7 +6126,7 @@ MaybeLocal<String> v8::String::NewExternalOneByte( } i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); ENTER_V8(i_isolate); - LOG_API(i_isolate, "String::NewExternalOneByte"); + LOG_API(i_isolate, String, NewExternalOneByte); i::Handle<i::String> string = i_isolate->factory() ->NewExternalStringFromOneByte(resource) .ToHandleChecked(); @@ -6058,14 +6190,11 @@ bool v8::String::MakeExternal( bool v8::String::CanMakeExternal() { i::Handle<i::String> obj = Utils::OpenHandle(this); - i::Isolate* isolate = obj->GetIsolate(); + if (obj->IsExternalString()) return false; // Old space strings should be externalized. - if (!isolate->heap()->new_space()->Contains(*obj)) return true; - int size = obj->Size(); // Byte size of the original string. - if (size <= i::ExternalString::kShortSize) return false; - i::StringShape shape(*obj); - return !shape.IsExternal(); + i::Isolate* isolate = obj->GetIsolate(); + return !isolate->heap()->new_space()->Contains(*obj); } @@ -6077,7 +6206,7 @@ Isolate* v8::Object::GetIsolate() { Local<v8::Object> v8::Object::New(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Object::New"); + LOG_API(i_isolate, Object, New); ENTER_V8(i_isolate); i::Handle<i::JSObject> obj = i_isolate->factory()->NewJSObject(i_isolate->object_function()); @@ -6087,7 +6216,7 @@ Local<v8::Object> v8::Object::New(Isolate* isolate) { Local<v8::Value> v8::NumberObject::New(Isolate* isolate, double value) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "NumberObject::New"); + LOG_API(i_isolate, NumberObject, New); ENTER_V8(i_isolate); i::Handle<i::Object> number = i_isolate->factory()->NewNumber(value); i::Handle<i::Object> obj = @@ -6100,14 +6229,14 @@ double v8::NumberObject::ValueOf() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj); i::Isolate* isolate = jsvalue->GetIsolate(); - LOG_API(isolate, "NumberObject::NumberValue"); + LOG_API(isolate, NumberObject, NumberValue); return jsvalue->value()->Number(); } Local<v8::Value> v8::BooleanObject::New(Isolate* isolate, bool value) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "BooleanObject::New"); + LOG_API(i_isolate, BooleanObject, New); ENTER_V8(i_isolate); i::Handle<i::Object> boolean(value ? i_isolate->heap()->true_value() : i_isolate->heap()->false_value(), @@ -6127,15 +6256,15 @@ bool v8::BooleanObject::ValueOf() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj); i::Isolate* isolate = jsvalue->GetIsolate(); - LOG_API(isolate, "BooleanObject::BooleanValue"); - return jsvalue->value()->IsTrue(); + LOG_API(isolate, BooleanObject, BooleanValue); + return jsvalue->value()->IsTrue(isolate); } Local<v8::Value> v8::StringObject::New(Local<String> value) { i::Handle<i::String> string = Utils::OpenHandle(*value); i::Isolate* isolate = string->GetIsolate(); - LOG_API(isolate, "StringObject::New"); + LOG_API(isolate, StringObject, New); ENTER_V8(isolate); i::Handle<i::Object> obj = i::Object::ToObject(isolate, string).ToHandleChecked(); @@ -6147,7 +6276,7 @@ Local<v8::String> v8::StringObject::ValueOf() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj); i::Isolate* isolate = jsvalue->GetIsolate(); - LOG_API(isolate, "StringObject::StringValue"); + LOG_API(isolate, StringObject, StringValue); return Utils::ToLocal( i::Handle<i::String>(i::String::cast(jsvalue->value()))); } @@ -6155,7 +6284,7 @@ Local<v8::String> v8::StringObject::ValueOf() const { Local<v8::Value> v8::SymbolObject::New(Isolate* isolate, Local<Symbol> value) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "SymbolObject::New"); + LOG_API(i_isolate, SymbolObject, New); ENTER_V8(i_isolate); i::Handle<i::Object> obj = i::Object::ToObject( i_isolate, Utils::OpenHandle(*value)).ToHandleChecked(); @@ -6167,7 +6296,7 @@ Local<v8::Symbol> v8::SymbolObject::ValueOf() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj); i::Isolate* isolate = jsvalue->GetIsolate(); - LOG_API(isolate, "SymbolObject::SymbolValue"); + LOG_API(isolate, SymbolObject, SymbolValue); return Utils::ToLocal( i::Handle<i::Symbol>(i::Symbol::cast(jsvalue->value()))); } @@ -6178,7 +6307,7 @@ MaybeLocal<v8::Value> v8::Date::New(Local<Context> context, double time) { // Introduce only canonical NaN value into the VM, to avoid signaling NaNs. time = std::numeric_limits<double>::quiet_NaN(); } - PREPARE_FOR_EXECUTION(context, "Date::New", Value); + PREPARE_FOR_EXECUTION(context, Date, New, Value); Local<Value> result; has_pending_exception = !ToLocal<Value>( i::JSDate::New(isolate->date_function(), isolate->date_function(), time), @@ -6198,14 +6327,14 @@ double v8::Date::ValueOf() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::JSDate> jsdate = i::Handle<i::JSDate>::cast(obj); i::Isolate* isolate = jsdate->GetIsolate(); - LOG_API(isolate, "Date::NumberValue"); + LOG_API(isolate, Date, NumberValue); return jsdate->value()->Number(); } void v8::Date::DateTimeConfigurationChangeNotification(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Date::DateTimeConfigurationChangeNotification"); + LOG_API(i_isolate, Date, DateTimeConfigurationChangeNotification); ENTER_V8(i_isolate); i_isolate->date_cache()->ResetDateCache(); if (!i_isolate->eternal_handles()->Exists( @@ -6225,7 +6354,7 @@ void v8::Date::DateTimeConfigurationChangeNotification(Isolate* isolate) { MaybeLocal<v8::RegExp> v8::RegExp::New(Local<Context> context, Local<String> pattern, Flags flags) { - PREPARE_FOR_EXECUTION(context, "RegExp::New", RegExp); + PREPARE_FOR_EXECUTION(context, RegExp, New, RegExp); Local<v8::RegExp> result; has_pending_exception = !ToLocal<RegExp>(i::JSRegExp::New(Utils::OpenHandle(*pattern), @@ -6270,7 +6399,7 @@ v8::RegExp::Flags v8::RegExp::GetFlags() const { Local<v8::Array> v8::Array::New(Isolate* isolate, int length) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Array::New"); + LOG_API(i_isolate, Array, New); ENTER_V8(i_isolate); int real_length = length > 0 ? length : 0; i::Handle<i::JSArray> obj = i_isolate->factory()->NewJSArray(real_length); @@ -6294,7 +6423,7 @@ uint32_t v8::Array::Length() const { MaybeLocal<Object> Array::CloneElementAt(Local<Context> context, uint32_t index) { - PREPARE_FOR_EXECUTION(context, "v8::Array::CloneElementAt()", Object); + PREPARE_FOR_EXECUTION(context, Array, CloneElementAt, Object); auto self = Utils::OpenHandle(this); if (!self->HasFastObjectElements()) return Local<Object>(); i::FixedArray* elms = i::FixedArray::cast(self->elements()); @@ -6315,7 +6444,7 @@ Local<Object> Array::CloneElementAt(uint32_t index) { return Local<Object>(); } Local<v8::Map> v8::Map::New(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Map::New"); + LOG_API(i_isolate, Map, New); ENTER_V8(i_isolate); i::Handle<i::JSMap> obj = i_isolate->factory()->NewJSMap(); return Utils::ToLocal(obj); @@ -6331,14 +6460,14 @@ size_t v8::Map::Size() const { void Map::Clear() { auto self = Utils::OpenHandle(this); i::Isolate* isolate = self->GetIsolate(); - LOG_API(isolate, "Map::Clear"); + LOG_API(isolate, Map, Clear); ENTER_V8(isolate); i::JSMap::Clear(self); } MaybeLocal<Value> Map::Get(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION(context, "Map::Get", Value); + PREPARE_FOR_EXECUTION(context, Map, Get, Value); auto self = Utils::OpenHandle(this); Local<Value> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)}; @@ -6353,7 +6482,7 @@ MaybeLocal<Value> Map::Get(Local<Context> context, Local<Value> key) { MaybeLocal<Map> Map::Set(Local<Context> context, Local<Value> key, Local<Value> value) { - PREPARE_FOR_EXECUTION(context, "Map::Set", Map); + PREPARE_FOR_EXECUTION(context, Map, Set, Map); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key), @@ -6367,7 +6496,7 @@ MaybeLocal<Map> Map::Set(Local<Context> context, Local<Value> key, Maybe<bool> Map::Has(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Map::Has", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Map, Has, bool); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)}; @@ -6375,12 +6504,12 @@ Maybe<bool> Map::Has(Local<Context> context, Local<Value> key) { arraysize(argv), argv) .ToHandle(&result); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - return Just(result->IsTrue()); + return Just(result->IsTrue(isolate)); } Maybe<bool> Map::Delete(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Map::Delete", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Map, Delete, bool); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)}; @@ -6388,7 +6517,7 @@ Maybe<bool> Map::Delete(Local<Context> context, Local<Value> key) { self, arraysize(argv), argv) .ToHandle(&result); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - return Just(result->IsTrue()); + return Just(result->IsTrue(isolate)); } @@ -6396,17 +6525,25 @@ Local<Array> Map::AsArray() const { i::Handle<i::JSMap> obj = Utils::OpenHandle(this); i::Isolate* isolate = obj->GetIsolate(); i::Factory* factory = isolate->factory(); - LOG_API(isolate, "Map::AsArray"); + LOG_API(isolate, Map, AsArray); ENTER_V8(isolate); i::Handle<i::OrderedHashMap> table(i::OrderedHashMap::cast(obj->table())); - int size = table->NumberOfElements(); - int length = size * 2; + int length = table->NumberOfElements() * 2; i::Handle<i::FixedArray> result = factory->NewFixedArray(length); - for (int i = 0; i < size; ++i) { - if (table->KeyAt(i)->IsTheHole()) continue; - result->set(i * 2, table->KeyAt(i)); - result->set(i * 2 + 1, table->ValueAt(i)); + int result_index = 0; + { + i::DisallowHeapAllocation no_gc; + int capacity = table->UsedCapacity(); + i::Oddball* the_hole = isolate->heap()->the_hole_value(); + for (int i = 0; i < capacity; ++i) { + i::Object* key = table->KeyAt(i); + if (key == the_hole) continue; + result->set(result_index++, key); + result->set(result_index++, table->ValueAt(i)); + } } + DCHECK_EQ(result_index, result->length()); + DCHECK_EQ(result_index, length); i::Handle<i::JSArray> result_array = factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length); return Utils::ToLocal(result_array); @@ -6415,7 +6552,7 @@ Local<Array> Map::AsArray() const { Local<v8::Set> v8::Set::New(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Set::New"); + LOG_API(i_isolate, Set, New); ENTER_V8(i_isolate); i::Handle<i::JSSet> obj = i_isolate->factory()->NewJSSet(); return Utils::ToLocal(obj); @@ -6431,14 +6568,14 @@ size_t v8::Set::Size() const { void Set::Clear() { auto self = Utils::OpenHandle(this); i::Isolate* isolate = self->GetIsolate(); - LOG_API(isolate, "Set::Clear"); + LOG_API(isolate, Set, Clear); ENTER_V8(isolate); i::JSSet::Clear(self); } MaybeLocal<Set> Set::Add(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION(context, "Set::Add", Set); + PREPARE_FOR_EXECUTION(context, Set, Add, Set); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)}; @@ -6451,7 +6588,7 @@ MaybeLocal<Set> Set::Add(Local<Context> context, Local<Value> key) { Maybe<bool> Set::Has(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Set::Has", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Set, Has, bool); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)}; @@ -6459,12 +6596,12 @@ Maybe<bool> Set::Has(Local<Context> context, Local<Value> key) { arraysize(argv), argv) .ToHandle(&result); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - return Just(result->IsTrue()); + return Just(result->IsTrue(isolate)); } Maybe<bool> Set::Delete(Local<Context> context, Local<Value> key) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Set::Delete", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Set, Delete, bool); auto self = Utils::OpenHandle(this); i::Handle<i::Object> result; i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)}; @@ -6472,7 +6609,7 @@ Maybe<bool> Set::Delete(Local<Context> context, Local<Value> key) { self, arraysize(argv), argv) .ToHandle(&result); RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - return Just(result->IsTrue()); + return Just(result->IsTrue(isolate)); } @@ -6480,17 +6617,24 @@ Local<Array> Set::AsArray() const { i::Handle<i::JSSet> obj = Utils::OpenHandle(this); i::Isolate* isolate = obj->GetIsolate(); i::Factory* factory = isolate->factory(); - LOG_API(isolate, "Set::AsArray"); + LOG_API(isolate, Set, AsArray); ENTER_V8(isolate); i::Handle<i::OrderedHashSet> table(i::OrderedHashSet::cast(obj->table())); int length = table->NumberOfElements(); i::Handle<i::FixedArray> result = factory->NewFixedArray(length); - for (int i = 0; i < length; ++i) { - i::Object* key = table->KeyAt(i); - if (!key->IsTheHole()) { - result->set(i, key); + int result_index = 0; + { + i::DisallowHeapAllocation no_gc; + int capacity = table->UsedCapacity(); + i::Oddball* the_hole = isolate->heap()->the_hole_value(); + for (int i = 0; i < capacity; ++i) { + i::Object* key = table->KeyAt(i); + if (key == the_hole) continue; + result->set(result_index++, key); } } + DCHECK_EQ(result_index, result->length()); + DCHECK_EQ(result_index, length); i::Handle<i::JSArray> result_array = factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length); return Utils::ToLocal(result_array); @@ -6498,7 +6642,7 @@ Local<Array> Set::AsArray() const { MaybeLocal<Promise::Resolver> Promise::Resolver::New(Local<Context> context) { - PREPARE_FOR_EXECUTION(context, "Promise::Resolver::New", Resolver); + PREPARE_FOR_EXECUTION(context, Promise_Resolver, New, Resolver); i::Handle<i::Object> result; has_pending_exception = !i::Execution::Call(isolate, isolate->promise_create(), @@ -6523,7 +6667,7 @@ Local<Promise> Promise::Resolver::GetPromise() { Maybe<bool> Promise::Resolver::Resolve(Local<Context> context, Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Promise::Resolver::Resolve", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Promise_Resolver, Resolve, bool); auto self = Utils::OpenHandle(this); i::Handle<i::Object> argv[] = {self, Utils::OpenHandle(*value)}; has_pending_exception = @@ -6544,7 +6688,7 @@ void Promise::Resolver::Resolve(Local<Value> value) { Maybe<bool> Promise::Resolver::Reject(Local<Context> context, Local<Value> value) { - PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Promise::Resolver::Resolve", bool); + PREPARE_FOR_EXECUTION_PRIMITIVE(context, Promise_Resolver, Resolve, bool); auto self = Utils::OpenHandle(this); i::Handle<i::Object> argv[] = {self, Utils::OpenHandle(*value)}; has_pending_exception = @@ -6563,39 +6707,9 @@ void Promise::Resolver::Reject(Local<Value> value) { } -namespace { - -MaybeLocal<Promise> DoChain(Value* value, Local<Context> context, - Local<Function> handler) { - PREPARE_FOR_EXECUTION(context, "Promise::Chain", Promise); - auto self = Utils::OpenHandle(value); - i::Handle<i::Object> argv[] = {Utils::OpenHandle(*handler)}; - i::Handle<i::Object> result; - has_pending_exception = !i::Execution::Call(isolate, isolate->promise_chain(), - self, arraysize(argv), argv) - .ToHandle(&result); - RETURN_ON_FAILED_EXECUTION(Promise); - RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result))); -} - -} // namespace - - -MaybeLocal<Promise> Promise::Chain(Local<Context> context, - Local<Function> handler) { - return DoChain(this, context, handler); -} - - -Local<Promise> Promise::Chain(Local<Function> handler) { - auto context = ContextFromHeapObject(Utils::OpenHandle(this)); - RETURN_TO_LOCAL_UNCHECKED(DoChain(this, context, handler), Promise); -} - - MaybeLocal<Promise> Promise::Catch(Local<Context> context, Local<Function> handler) { - PREPARE_FOR_EXECUTION(context, "Promise::Catch", Promise); + PREPARE_FOR_EXECUTION(context, Promise, Catch, Promise); auto self = Utils::OpenHandle(this); i::Handle<i::Object> argv[] = { Utils::OpenHandle(*handler) }; i::Handle<i::Object> result; @@ -6615,7 +6729,7 @@ Local<Promise> Promise::Catch(Local<Function> handler) { MaybeLocal<Promise> Promise::Then(Local<Context> context, Local<Function> handler) { - PREPARE_FOR_EXECUTION(context, "Promise::Then", Promise); + PREPARE_FOR_EXECUTION(context, Promise, Then, Promise); auto self = Utils::OpenHandle(this); i::Handle<i::Object> argv[] = { Utils::OpenHandle(*handler) }; i::Handle<i::Object> result; @@ -6636,10 +6750,10 @@ Local<Promise> Promise::Then(Local<Function> handler) { bool Promise::HasHandler() { i::Handle<i::JSReceiver> promise = Utils::OpenHandle(this); i::Isolate* isolate = promise->GetIsolate(); - LOG_API(isolate, "Promise::HasRejectHandler"); + LOG_API(isolate, Promise, HasRejectHandler); ENTER_V8(isolate); i::Handle<i::Symbol> key = isolate->factory()->promise_has_handler_symbol(); - return i::JSReceiver::GetDataProperty(promise, key)->IsTrue(); + return i::JSReceiver::GetDataProperty(promise, key)->IsTrue(isolate); } @@ -6671,7 +6785,7 @@ void Proxy::Revoke() { MaybeLocal<Proxy> Proxy::New(Local<Context> context, Local<Object> local_target, Local<Object> local_handler) { - PREPARE_FOR_EXECUTION(context, "Proxy::New", Proxy); + PREPARE_FOR_EXECUTION(context, Proxy, New, Proxy); i::Handle<i::JSReceiver> target = Utils::OpenHandle(*local_target); i::Handle<i::JSReceiver> handler = Utils::OpenHandle(*local_handler); Local<Proxy> result; @@ -6681,6 +6795,40 @@ MaybeLocal<Proxy> Proxy::New(Local<Context> context, Local<Object> local_target, RETURN_ESCAPED(result); } +WasmCompiledModule::SerializedModule WasmCompiledModule::Serialize() { + i::Handle<i::JSObject> obj = + i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); + i::Handle<i::FixedArray> compiled_part = + i::handle(i::FixedArray::cast(obj->GetInternalField(0))); + std::unique_ptr<i::ScriptData> script_data = + i::WasmCompiledModuleSerializer::SerializeWasmModule(obj->GetIsolate(), + compiled_part); + script_data->ReleaseDataOwnership(); + size_t size = static_cast<size_t>(script_data->length()); + return {std::unique_ptr<const uint8_t[]>(script_data->data()), size}; +} + +MaybeLocal<WasmCompiledModule> WasmCompiledModule::Deserialize( + Isolate* isolate, + const WasmCompiledModule::SerializedModule& serialized_data) { + int size = static_cast<int>(serialized_data.second); + i::ScriptData sc(serialized_data.first.get(), size); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::MaybeHandle<i::FixedArray> maybe_compiled_part = + i::WasmCompiledModuleSerializer::DeserializeWasmModule(i_isolate, &sc); + i::Handle<i::FixedArray> compiled_part; + if (!maybe_compiled_part.ToHandle(&compiled_part)) { + return MaybeLocal<WasmCompiledModule>(); + } + return Local<WasmCompiledModule>::Cast(Utils::ToLocal( + i::wasm::CreateCompiledModuleObject(i_isolate, compiled_part))); +} + +// static +v8::ArrayBuffer::Allocator* v8::ArrayBuffer::Allocator::NewDefaultAllocator() { + return new ArrayBufferAllocator(); +} + bool v8::ArrayBuffer::IsExternal() const { return Utils::OpenHandle(this)->is_external(); } @@ -6694,7 +6842,7 @@ bool v8::ArrayBuffer::IsNeuterable() const { v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() { i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this); i::Isolate* isolate = self->GetIsolate(); - Utils::ApiCheck(!self->is_external(), "v8::ArrayBuffer::Externalize", + Utils::ApiCheck(!self->is_external(), "v8_ArrayBuffer_Externalize", "ArrayBuffer already externalized"); self->set_is_external(true); isolate->heap()->UnregisterArrayBuffer(*self); @@ -6721,7 +6869,7 @@ void v8::ArrayBuffer::Neuter() { "Only externalized ArrayBuffers can be neutered"); Utils::ApiCheck(obj->is_neuterable(), "v8::ArrayBuffer::Neuter", "Only neuterable ArrayBuffers can be neutered"); - LOG_API(obj->GetIsolate(), "v8::ArrayBuffer::Neuter()"); + LOG_API(isolate, ArrayBuffer, Neuter); ENTER_V8(isolate); obj->Neuter(); } @@ -6735,7 +6883,7 @@ size_t v8::ArrayBuffer::ByteLength() const { Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, size_t byte_length) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "v8::ArrayBuffer::New(size_t)"); + LOG_API(i_isolate, ArrayBuffer, New); ENTER_V8(i_isolate); i::Handle<i::JSArrayBuffer> obj = i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared); @@ -6750,7 +6898,7 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, void* data, // Embedders must guarantee that the external backing store is valid. CHECK(byte_length == 0 || data != NULL); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)"); + LOG_API(i_isolate, ArrayBuffer, New); ENTER_V8(i_isolate); i::Handle<i::JSArrayBuffer> obj = i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared); @@ -6778,10 +6926,9 @@ Local<ArrayBuffer> v8::ArrayBufferView::Buffer() { size_t v8::ArrayBufferView::CopyContents(void* dest, size_t byte_length) { i::Handle<i::JSArrayBufferView> self = Utils::OpenHandle(this); - i::Isolate* isolate = self->GetIsolate(); - size_t byte_offset = i::NumberToSize(isolate, self->byte_offset()); + size_t byte_offset = i::NumberToSize(self->byte_offset()); size_t bytes_to_copy = - i::Min(byte_length, i::NumberToSize(isolate, self->byte_length())); + i::Min(byte_length, i::NumberToSize(self->byte_length())); if (bytes_to_copy) { i::DisallowHeapAllocation no_gc; i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(self->buffer())); @@ -6823,49 +6970,45 @@ size_t v8::TypedArray::Length() { return static_cast<size_t>(obj->length_value()); } - -#define TYPED_ARRAY_NEW(Type, type, TYPE, ctype, size) \ - Local<Type##Array> Type##Array::New(Local<ArrayBuffer> array_buffer, \ - size_t byte_offset, size_t length) { \ - i::Isolate* isolate = Utils::OpenHandle(*array_buffer)->GetIsolate(); \ - LOG_API(isolate, \ - "v8::" #Type "Array::New(Local<ArrayBuffer>, size_t, size_t)"); \ - ENTER_V8(isolate); \ - if (!Utils::ApiCheck(length <= static_cast<size_t>(i::Smi::kMaxValue), \ - "v8::" #Type \ - "Array::New(Local<ArrayBuffer>, size_t, size_t)", \ - "length exceeds max allowed value")) { \ - return Local<Type##Array>(); \ - } \ - i::Handle<i::JSArrayBuffer> buffer = Utils::OpenHandle(*array_buffer); \ - i::Handle<i::JSTypedArray> obj = isolate->factory()->NewJSTypedArray( \ - i::kExternal##Type##Array, buffer, byte_offset, length); \ - return Utils::ToLocal##Type##Array(obj); \ - } \ - Local<Type##Array> Type##Array::New( \ - Local<SharedArrayBuffer> shared_array_buffer, size_t byte_offset, \ - size_t length) { \ - CHECK(i::FLAG_harmony_sharedarraybuffer); \ - i::Isolate* isolate = \ - Utils::OpenHandle(*shared_array_buffer)->GetIsolate(); \ - LOG_API(isolate, "v8::" #Type \ - "Array::New(Local<SharedArrayBuffer>, size_t, size_t)"); \ - ENTER_V8(isolate); \ - if (!Utils::ApiCheck( \ - length <= static_cast<size_t>(i::Smi::kMaxValue), \ - "v8::" #Type \ - "Array::New(Local<SharedArrayBuffer>, size_t, size_t)", \ - "length exceeds max allowed value")) { \ - return Local<Type##Array>(); \ - } \ - i::Handle<i::JSArrayBuffer> buffer = \ - Utils::OpenHandle(*shared_array_buffer); \ - i::Handle<i::JSTypedArray> obj = isolate->factory()->NewJSTypedArray( \ - i::kExternal##Type##Array, buffer, byte_offset, length); \ - return Utils::ToLocal##Type##Array(obj); \ +#define TYPED_ARRAY_NEW(Type, type, TYPE, ctype, size) \ + Local<Type##Array> Type##Array::New(Local<ArrayBuffer> array_buffer, \ + size_t byte_offset, size_t length) { \ + i::Isolate* isolate = Utils::OpenHandle(*array_buffer)->GetIsolate(); \ + LOG_API(isolate, Type##Array, New); \ + ENTER_V8(isolate); \ + if (!Utils::ApiCheck(length <= static_cast<size_t>(i::Smi::kMaxValue), \ + "v8::" #Type \ + "Array::New(Local<ArrayBuffer>, size_t, size_t)", \ + "length exceeds max allowed value")) { \ + return Local<Type##Array>(); \ + } \ + i::Handle<i::JSArrayBuffer> buffer = Utils::OpenHandle(*array_buffer); \ + i::Handle<i::JSTypedArray> obj = isolate->factory()->NewJSTypedArray( \ + i::kExternal##Type##Array, buffer, byte_offset, length); \ + return Utils::ToLocal##Type##Array(obj); \ + } \ + Local<Type##Array> Type##Array::New( \ + Local<SharedArrayBuffer> shared_array_buffer, size_t byte_offset, \ + size_t length) { \ + CHECK(i::FLAG_harmony_sharedarraybuffer); \ + i::Isolate* isolate = \ + Utils::OpenHandle(*shared_array_buffer)->GetIsolate(); \ + LOG_API(isolate, Type##Array, New); \ + ENTER_V8(isolate); \ + if (!Utils::ApiCheck( \ + length <= static_cast<size_t>(i::Smi::kMaxValue), \ + "v8::" #Type \ + "Array::New(Local<SharedArrayBuffer>, size_t, size_t)", \ + "length exceeds max allowed value")) { \ + return Local<Type##Array>(); \ + } \ + i::Handle<i::JSArrayBuffer> buffer = \ + Utils::OpenHandle(*shared_array_buffer); \ + i::Handle<i::JSTypedArray> obj = isolate->factory()->NewJSTypedArray( \ + i::kExternal##Type##Array, buffer, byte_offset, length); \ + return Utils::ToLocal##Type##Array(obj); \ } - TYPED_ARRAYS(TYPED_ARRAY_NEW) #undef TYPED_ARRAY_NEW @@ -6873,7 +7016,7 @@ Local<DataView> DataView::New(Local<ArrayBuffer> array_buffer, size_t byte_offset, size_t byte_length) { i::Handle<i::JSArrayBuffer> buffer = Utils::OpenHandle(*array_buffer); i::Isolate* isolate = buffer->GetIsolate(); - LOG_API(isolate, "v8::DataView::New(Local<ArrayBuffer>, size_t, size_t)"); + LOG_API(isolate, DataView, New); ENTER_V8(isolate); i::Handle<i::JSDataView> obj = isolate->factory()->NewJSDataView(buffer, byte_offset, byte_length); @@ -6886,8 +7029,7 @@ Local<DataView> DataView::New(Local<SharedArrayBuffer> shared_array_buffer, CHECK(i::FLAG_harmony_sharedarraybuffer); i::Handle<i::JSArrayBuffer> buffer = Utils::OpenHandle(*shared_array_buffer); i::Isolate* isolate = buffer->GetIsolate(); - LOG_API(isolate, - "v8::DataView::New(Local<SharedArrayBuffer>, size_t, size_t)"); + LOG_API(isolate, DataView, New); ENTER_V8(isolate); i::Handle<i::JSDataView> obj = isolate->factory()->NewJSDataView(buffer, byte_offset, byte_length); @@ -6903,7 +7045,7 @@ bool v8::SharedArrayBuffer::IsExternal() const { v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::Externalize() { i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this); i::Isolate* isolate = self->GetIsolate(); - Utils::ApiCheck(!self->is_external(), "v8::SharedArrayBuffer::Externalize", + Utils::ApiCheck(!self->is_external(), "v8_SharedArrayBuffer_Externalize", "SharedArrayBuffer already externalized"); self->set_is_external(true); isolate->heap()->UnregisterArrayBuffer(*self); @@ -6931,7 +7073,7 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(Isolate* isolate, size_t byte_length) { CHECK(i::FLAG_harmony_sharedarraybuffer); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "v8::SharedArrayBuffer::New(size_t)"); + LOG_API(i_isolate, SharedArrayBuffer, New); ENTER_V8(i_isolate); i::Handle<i::JSArrayBuffer> obj = i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kShared); @@ -6948,7 +7090,7 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New( // Embedders must guarantee that the external backing store is valid. CHECK(byte_length == 0 || data != NULL); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "v8::SharedArrayBuffer::New(void*, size_t)"); + LOG_API(i_isolate, SharedArrayBuffer, New); ENTER_V8(i_isolate); i::Handle<i::JSArrayBuffer> obj = i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kShared); @@ -6961,7 +7103,7 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New( Local<Symbol> v8::Symbol::New(Isolate* isolate, Local<String> name) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Symbol::New()"); + LOG_API(i_isolate, Symbol, New); ENTER_V8(i_isolate); i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol(); if (!name.IsEmpty()) result->set_name(*Utils::OpenHandle(*name)); @@ -6980,7 +7122,7 @@ static i::Handle<i::Symbol> SymbolFor(i::Isolate* isolate, i::Handle<i::Object> symbol = i::Object::GetPropertyOrElement(symbols, name).ToHandleChecked(); if (!symbol->IsSymbol()) { - DCHECK(symbol->IsUndefined()); + DCHECK(symbol->IsUndefined(isolate)); if (private_symbol) symbol = isolate->factory()->NewPrivateSymbol(); else @@ -7034,7 +7176,7 @@ Local<Symbol> v8::Symbol::GetIsConcatSpreadable(Isolate* isolate) { Local<Private> v8::Private::New(Isolate* isolate, Local<String> name) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - LOG_API(i_isolate, "Private::New()"); + LOG_API(i_isolate, Private, New); ENTER_V8(i_isolate); i::Handle<i::Symbol> symbol = i_isolate->factory()->NewPrivateSymbol(); if (!name.IsEmpty()) symbol->set_name(*Utils::OpenHandle(*name)); @@ -7227,23 +7369,6 @@ void Isolate::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) { isolate->heap()->SetEmbedderHeapTracer(tracer); } -void Isolate::AddMemoryAllocationCallback(MemoryAllocationCallback callback, - ObjectSpace space, - AllocationAction action) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - isolate->memory_allocator()->AddMemoryAllocationCallback( - callback, space, action); -} - - -void Isolate::RemoveMemoryAllocationCallback( - MemoryAllocationCallback callback) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - isolate->memory_allocator()->RemoveMemoryAllocationCallback( - callback); -} - - void Isolate::TerminateExecution() { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); isolate->stack_guard()->RequestTerminateExecution(); @@ -7326,18 +7451,12 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) { v8_isolate->SetAddHistogramSampleFunction( params.add_histogram_sample_callback); } + + isolate->set_api_external_references(params.external_references); SetResourceConstraints(isolate, params.constraints); // TODO(jochen): Once we got rid of Isolate::Current(), we can remove this. Isolate::Scope isolate_scope(v8_isolate); if (params.entry_hook || !i::Snapshot::Initialize(isolate)) { - // If the isolate has a function entry hook, it needs to re-build all its - // code stubs with entry hooks embedded, so don't deserialize a snapshot. - if (i::Snapshot::EmbedsScript(isolate)) { - // If the snapshot embeds a script, we cannot initialize the isolate - // without the snapshot as a fallback. This is unlikely to happen though. - V8_Fatal(__FILE__, __LINE__, - "Initializing isolate from custom startup snapshot failed"); - } isolate->Init(NULL); } return v8_isolate; @@ -7445,6 +7564,10 @@ void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) { heap_statistics->total_available_size_ = heap->Available(); heap_statistics->used_heap_size_ = heap->SizeOfObjects(); heap_statistics->heap_size_limit_ = heap->MaxReserved(); + heap_statistics->malloced_memory_ = + isolate->allocator()->GetCurrentMemoryUsage(); + heap_statistics->peak_malloced_memory_ = + isolate->allocator()->GetMaxMemoryUsage(); heap_statistics->does_zap_garbage_ = heap->ShouldZapGarbage(); } @@ -7507,14 +7630,37 @@ bool Isolate::GetHeapObjectStatisticsAtLastGC( return true; } +bool Isolate::GetHeapCodeAndMetadataStatistics( + HeapCodeStatistics* code_statistics) { + if (!code_statistics) return false; + + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); + isolate->heap()->CollectCodeStatistics(); + + code_statistics->code_and_metadata_size_ = isolate->code_and_metadata_size(); + code_statistics->bytecode_and_metadata_size_ = + isolate->bytecode_and_metadata_size(); + return true; +} void Isolate::GetStackSample(const RegisterState& state, void** frames, size_t frames_limit, SampleInfo* sample_info) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - i::TickSample::GetStackSample(isolate, state, i::TickSample::kSkipCEntryFrame, - frames, frames_limit, sample_info); + RegisterState regs = state; + if (TickSample::GetStackSample(this, ®s, TickSample::kSkipCEntryFrame, + frames, frames_limit, sample_info)) { + return; + } + sample_info->frames_count = 0; + sample_info->vm_state = OTHER; + sample_info->external_callback_entry = nullptr; } +size_t Isolate::NumberOfPhantomHandleResetsSinceLastCall() { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); + size_t result = isolate->global_handles()->NumberOfPhantomHandleResets(); + isolate->global_handles()->ResetNumberOfPhantomHandleResets(); + return result; +} void Isolate::SetEventLogger(LogEventCallback that) { // Do not overwrite the event logger if we want to log explicitly. @@ -7700,13 +7846,13 @@ int Isolate::ContextDisposedNotification(bool dependant_context) { void Isolate::IsolateInForegroundNotification() { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - return isolate->heap()->SetOptimizeForLatency(); + return isolate->IsolateInForegroundNotification(); } void Isolate::IsolateInBackgroundNotification() { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - return isolate->heap()->SetOptimizeForMemoryUsage(); + return isolate->IsolateInBackgroundNotification(); } void Isolate::MemoryPressureNotification(MemoryPressureLevel level) { @@ -7715,6 +7861,11 @@ void Isolate::MemoryPressureNotification(MemoryPressureLevel level) { Locker::IsLocked(this)); } +void Isolate::SetRAILMode(RAILMode rail_mode) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); + return isolate->SetRAILMode(rail_mode); +} + void Isolate::SetJitCodeEventHandler(JitCodeEventOptions options, JitCodeEventHandler event_handler) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); @@ -7733,9 +7884,10 @@ void Isolate::SetStackLimit(uintptr_t stack_limit) { void Isolate::GetCodeRange(void** start, size_t* length_in_bytes) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - if (isolate->code_range()->valid()) { - *start = isolate->code_range()->start(); - *length_in_bytes = isolate->code_range()->size(); + if (isolate->heap()->memory_allocator()->code_range()->valid()) { + *start = isolate->heap()->memory_allocator()->code_range()->start(); + *length_in_bytes = + isolate->heap()->memory_allocator()->code_range()->size(); } else { *start = NULL; *length_in_bytes = 0; @@ -7748,6 +7900,10 @@ void Isolate::SetFatalErrorHandler(FatalErrorCallback that) { isolate->set_exception_behavior(that); } +void Isolate::SetOOMErrorHandler(OOMErrorCallback that) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); + isolate->set_oom_behavior(that); +} void Isolate::SetAllowCodeGenerationFromStringsCallback( AllowCodeGenerationFromStringsCallback callback) { @@ -7766,12 +7922,15 @@ bool Isolate::AddMessageListener(MessageCallback that, Local<Value> data) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); ENTER_V8(isolate); i::HandleScope scope(isolate); - NeanderArray listeners(isolate->factory()->message_listeners()); - NeanderObject obj(isolate, 2); - obj.set(0, *isolate->factory()->NewForeign(FUNCTION_ADDR(that))); - obj.set(1, data.IsEmpty() ? isolate->heap()->undefined_value() - : *Utils::OpenHandle(*data)); - listeners.add(isolate, obj.value()); + i::Handle<i::TemplateList> list = isolate->factory()->message_listeners(); + i::Handle<i::FixedArray> listener = isolate->factory()->NewFixedArray(2); + i::Handle<i::Foreign> foreign = + isolate->factory()->NewForeign(FUNCTION_ADDR(that)); + listener->set(0, *foreign); + listener->set(1, data.IsEmpty() ? isolate->heap()->undefined_value() + : *Utils::OpenHandle(*data)); + list = i::TemplateList::Add(isolate, list, listener); + isolate->heap()->SetMessageListeners(*list); return true; } @@ -7780,14 +7939,14 @@ void Isolate::RemoveMessageListeners(MessageCallback that) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); ENTER_V8(isolate); i::HandleScope scope(isolate); - NeanderArray listeners(isolate->factory()->message_listeners()); - for (int i = 0; i < listeners.length(); i++) { - if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones - - NeanderObject listener(i::JSObject::cast(listeners.get(i))); - i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0))); + i::DisallowHeapAllocation no_gc; + i::TemplateList* listeners = isolate->heap()->message_listeners(); + for (int i = 0; i < listeners->length(); i++) { + if (listeners->get(i)->IsUndefined(isolate)) continue; // skip deleted ones + i::FixedArray* listener = i::FixedArray::cast(listeners->get(i)); + i::Foreign* callback_obj = i::Foreign::cast(listener->get(0)); if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) { - listeners.set(i, isolate->heap()->undefined_value()); + listeners->set(i, isolate->heap()->undefined_value()); } } } @@ -7814,6 +7973,12 @@ void Isolate::VisitExternalResources(ExternalResourceVisitor* visitor) { } +bool Isolate::IsInUse() { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); + return isolate->IsInUse(); +} + + class VisitorAdapter : public i::ObjectVisitor { public: explicit VisitorAdapter(PersistentHandleVisitor* visitor) @@ -7821,6 +7986,7 @@ class VisitorAdapter : public i::ObjectVisitor { void VisitPointers(i::Object** start, i::Object** end) override { UNREACHABLE(); } + DISABLE_CFI_PERF void VisitEmbedderReference(i::Object** p, uint16_t class_id) override { Value* value = ToApi<Value>(i::Handle<i::Object>(p)); visitor_->VisitPersistentHandle( @@ -7901,6 +8067,10 @@ int MicrotasksScope::GetCurrentDepth(Isolate* v8Isolate) { return isolate->handle_scope_implementer()->GetMicrotasksScopeDepth(); } +bool MicrotasksScope::IsRunningMicrotasks(Isolate* v8Isolate) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate); + return isolate->IsRunningMicrotasks(); +} String::Utf8Value::Utf8Value(v8::Local<v8::Value> obj) : str_(NULL), length_(0) { @@ -7945,11 +8115,10 @@ String::Value::~Value() { i::DeleteArray(str_); } - #define DEFINE_ERROR(NAME, name) \ Local<Value> Exception::NAME(v8::Local<v8::String> raw_message) { \ i::Isolate* isolate = i::Isolate::Current(); \ - LOG_API(isolate, #NAME); \ + LOG_API(isolate, NAME, New); \ ENTER_V8(isolate); \ i::Object* error; \ { \ @@ -8016,12 +8185,6 @@ bool Debug::SetDebugEventListener(Isolate* isolate, EventCallback that, } -bool Debug::SetDebugEventListener(EventCallback that, Local<Value> data) { - return SetDebugEventListener( - reinterpret_cast<Isolate*>(i::Isolate::Current()), that, data); -} - - void Debug::DebugBreak(Isolate* isolate) { reinterpret_cast<i::Isolate*>(isolate)->stack_guard()->RequestDebugBreak(); } @@ -8047,11 +8210,6 @@ void Debug::SetMessageHandler(Isolate* isolate, } -void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { - SetMessageHandler(reinterpret_cast<Isolate*>(i::Isolate::Current()), handler); -} - - void Debug::SendCommand(Isolate* isolate, const uint16_t* command, int length, @@ -8065,7 +8223,7 @@ void Debug::SendCommand(Isolate* isolate, MaybeLocal<Value> Debug::Call(Local<Context> context, v8::Local<v8::Function> fun, v8::Local<v8::Value> data) { - PREPARE_FOR_EXECUTION(context, "v8::Debug::Call()", Value); + PREPARE_FOR_EXECUTION(context, Debug, Call, Value); i::Handle<i::Object> data_obj; if (data.IsEmpty()) { data_obj = isolate->factory()->undefined_value(); @@ -8081,16 +8239,9 @@ MaybeLocal<Value> Debug::Call(Local<Context> context, } -Local<Value> Debug::Call(v8::Local<v8::Function> fun, - v8::Local<v8::Value> data) { - auto context = ContextFromHeapObject(Utils::OpenHandle(*fun)); - RETURN_TO_LOCAL_UNCHECKED(Call(context, fun, data), Value); -} - - MaybeLocal<Value> Debug::GetMirror(Local<Context> context, v8::Local<v8::Value> obj) { - PREPARE_FOR_EXECUTION(context, "v8::Debug::GetMirror()", Value); + PREPARE_FOR_EXECUTION(context, Debug, GetMirror, Value); i::Debug* isolate_debug = isolate->debug(); has_pending_exception = !isolate_debug->Load(); RETURN_ON_FAILED_EXECUTION(Value); @@ -8109,21 +8260,11 @@ MaybeLocal<Value> Debug::GetMirror(Local<Context> context, } -Local<Value> Debug::GetMirror(v8::Local<v8::Value> obj) { - RETURN_TO_LOCAL_UNCHECKED(GetMirror(Local<Context>(), obj), Value); -} - - void Debug::ProcessDebugMessages(Isolate* isolate) { reinterpret_cast<i::Isolate*>(isolate)->debug()->ProcessDebugMessages(true); } -void Debug::ProcessDebugMessages() { - ProcessDebugMessages(reinterpret_cast<Isolate*>(i::Isolate::Current())); -} - - Local<Context> Debug::GetDebugContext(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); ENTER_V8(i_isolate); @@ -8131,11 +8272,15 @@ Local<Context> Debug::GetDebugContext(Isolate* isolate) { } -Local<Context> Debug::GetDebugContext() { - return GetDebugContext(reinterpret_cast<Isolate*>(i::Isolate::Current())); +MaybeLocal<Context> Debug::GetDebuggedContext(Isolate* isolate) { + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + ENTER_V8(i_isolate); + if (!i_isolate->debug()->in_debug_scope()) return MaybeLocal<Context>(); + i::Handle<i::Object> calling = i_isolate->GetCallingNativeContext(); + if (calling.is_null()) return MaybeLocal<Context>(); + return Utils::ToLocal(i::Handle<i::Context>::cast(calling)); } - void Debug::SetLiveEditEnabled(Isolate* isolate, bool enable) { i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); internal_isolate->debug()->set_live_edit_enabled(enable); @@ -8261,9 +8406,8 @@ const std::vector<CpuProfileDeoptInfo>& CpuProfileNode::GetDeoptInfos() const { void CpuProfile::Delete() { i::CpuProfile* profile = reinterpret_cast<i::CpuProfile*>(this); - i::Isolate* isolate = profile->top_down()->isolate(); - i::CpuProfiler* profiler = isolate->cpu_profiler(); - DCHECK(profiler != NULL); + i::CpuProfiler* profiler = profile->cpu_profiler(); + DCHECK(profiler != nullptr); profiler->DeleteProfile(profile); } @@ -8311,6 +8455,12 @@ int CpuProfile::GetSamplesCount() const { return reinterpret_cast<const i::CpuProfile*>(this)->samples_count(); } +CpuProfiler* CpuProfiler::New(Isolate* isolate) { + return reinterpret_cast<CpuProfiler*>( + new i::CpuProfiler(reinterpret_cast<i::Isolate*>(isolate))); +} + +void CpuProfiler::Dispose() { delete reinterpret_cast<i::CpuProfiler*>(this); } void CpuProfiler::SetSamplingInterval(int us) { DCHECK_GE(us, 0); @@ -8336,7 +8486,9 @@ CpuProfile* CpuProfiler::StopProfiling(Local<String> title) { void CpuProfiler::SetIdle(bool is_idle) { - i::Isolate* isolate = reinterpret_cast<i::CpuProfiler*>(this)->isolate(); + i::CpuProfiler* profiler = reinterpret_cast<i::CpuProfiler*>(this); + i::Isolate* isolate = profiler->isolate(); + if (!isolate->is_profiling()) return; v8::StateTag state = isolate->current_vm_state(); DCHECK(state == v8::EXTERNAL || state == v8::IDLE); if (isolate->js_entry_sp() != NULL) return; @@ -8548,11 +8700,11 @@ SnapshotObjectId HeapProfiler::GetHeapStats(OutputStream* stream, return heap_profiler->PushHeapObjectsStats(stream, timestamp_us); } - bool HeapProfiler::StartSamplingHeapProfiler(uint64_t sample_interval, - int stack_depth) { - return reinterpret_cast<i::HeapProfiler*>(this) - ->StartSamplingHeapProfiler(sample_interval, stack_depth); + int stack_depth, + SamplingFlags flags) { + return reinterpret_cast<i::HeapProfiler*>(this)->StartSamplingHeapProfiler( + sample_interval, stack_depth, flags); } @@ -8724,6 +8876,10 @@ void HandleScopeImplementer::IterateThis(ObjectVisitor* v) { Object** start = reinterpret_cast<Object**>(&context_lists[i]->first()); v->VisitPointers(start, start + context_lists[i]->length()); } + if (microtask_context_) { + Object** start = reinterpret_cast<Object**>(µtask_context_); + v->VisitPointers(start, start + 1); + } } @@ -8808,6 +8964,11 @@ void InvokeAccessorGetterCallback( v8::AccessorNameGetterCallback getter) { // Leaving JavaScript. Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + RuntimeCallTimerScope timer(isolate, + &RuntimeCallStats::AccessorGetterCallback); + TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED( + isolate, + &internal::tracing::TraceEventStatsTable::AccessorGetterCallback); Address getter_address = reinterpret_cast<Address>(reinterpret_cast<intptr_t>( getter)); VMState<EXTERNAL> state(isolate); @@ -8819,6 +8980,11 @@ void InvokeAccessorGetterCallback( void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info, v8::FunctionCallback callback) { Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + RuntimeCallTimerScope timer(isolate, + &RuntimeCallStats::InvokeFunctionCallback); + TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED( + isolate, + &internal::tracing::TraceEventStatsTable::InvokeFunctionCallback); Address callback_address = reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback)); VMState<EXTERNAL> state(isolate); |