%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/api/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/api/api-inl.h |
// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_API_API_INL_H_ #define V8_API_API_INL_H_ #include "include/v8-fast-api-calls.h" #include "src/api/api.h" #include "src/common/assert-scope.h" #include "src/execution/interrupts-scope.h" #include "src/execution/microtask-queue.h" #include "src/flags/flags.h" #include "src/handles/handles-inl.h" #include "src/heap/heap-inl.h" #include "src/objects/foreign-inl.h" #include "src/objects/objects-inl.h" namespace v8 { template <typename T> inline T ToCData(v8::internal::Tagged<v8::internal::Object> obj) { static_assert(sizeof(T) == sizeof(v8::internal::Address)); if (obj == v8::internal::Smi::zero()) return nullptr; return reinterpret_cast<T>( v8::internal::Foreign::cast(obj)->foreign_address()); } template <> inline v8::internal::Address ToCData( v8::internal::Tagged<v8::internal::Object> obj) { if (obj == v8::internal::Smi::zero()) return v8::internal::kNullAddress; return v8::internal::Foreign::cast(obj)->foreign_address(); } template <typename T> inline v8::internal::Handle<v8::internal::Object> FromCData( v8::internal::Isolate* isolate, T obj) { static_assert(sizeof(T) == sizeof(v8::internal::Address)); if (obj == nullptr) return handle(v8::internal::Smi::zero(), isolate); return isolate->factory()->NewForeign( reinterpret_cast<v8::internal::Address>(obj)); } template <> inline v8::internal::Handle<v8::internal::Object> FromCData( v8::internal::Isolate* isolate, v8::internal::Address obj) { if (obj == v8::internal::kNullAddress) { return handle(v8::internal::Smi::zero(), isolate); } return isolate->factory()->NewForeign(obj); } template <class From, class To> inline Local<To> Utils::Convert(v8::internal::Handle<From> obj) { DCHECK(obj.is_null() || (IsSmi(*obj) || !IsTheHole(*obj))); #ifdef V8_ENABLE_DIRECT_LOCAL if (obj.is_null()) return Local<To>(); #endif return Local<To>::FromSlot(obj.location()); } template <class From, class To> inline Local<To> Utils::Convert(v8::internal::DirectHandle<From> obj, v8::internal::Isolate* isolate) { #if defined(V8_ENABLE_DIRECT_LOCAL) DCHECK(obj.is_null() || (IsSmi(*obj) || !IsTheHole(*obj))); return Local<To>::FromAddress(obj.address()); #elif defined(V8_ENABLE_DIRECT_HANDLE) return Convert<From, To>(v8::internal::Handle<From>(*obj, isolate)); #else return Convert<From, To>(obj); #endif } // Implementations of ToLocal #define MAKE_TO_LOCAL(Name, From, To) \ Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \ return Convert<v8::internal::From, v8::To>(obj); \ } \ \ Local<v8::To> Utils::Name( \ v8::internal::DirectHandle<v8::internal::From> obj, \ i::Isolate* isolate) { \ return Convert<v8::internal::From, v8::To>(obj, isolate); \ } TO_LOCAL_LIST(MAKE_TO_LOCAL) #define MAKE_TO_LOCAL_TYPED_ARRAY(Type, typeName, TYPE, ctype) \ Local<v8::Type##Array> Utils::ToLocal##Type##Array( \ v8::internal::Handle<v8::internal::JSTypedArray> obj) { \ DCHECK(obj->type() == v8::internal::kExternal##Type##Array); \ return Convert<v8::internal::JSTypedArray, v8::Type##Array>(obj); \ } \ \ Local<v8::Type##Array> Utils::ToLocal##Type##Array( \ v8::internal::DirectHandle<v8::internal::JSTypedArray> obj, \ v8::internal::Isolate* isolate) { \ DCHECK(obj->type() == v8::internal::kExternal##Type##Array); \ return Convert<v8::internal::JSTypedArray, v8::Type##Array>(obj, isolate); \ } TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY) #undef MAKE_TO_LOCAL_TYPED_ARRAY #undef MAKE_TO_LOCAL #undef TO_LOCAL_LIST // Implementations of OpenHandle #ifdef V8_ENABLE_DIRECT_LOCAL #define MAKE_OPEN_HANDLE(From, To) \ v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \ const v8::From* that, bool allow_empty_handle) { \ DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \ DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \ Is##To(v8::internal::Tagged<v8::internal::Object>( \ v8::internal::ValueHelper::ValueAsAddress(that)))); \ if (v8::internal::ValueHelper::IsEmpty(that)) { \ return v8::internal::Handle<v8::internal::To>::null(); \ } \ return v8::internal::Handle<v8::internal::To>( \ v8::HandleScope::CreateHandleForCurrentIsolate( \ v8::internal::ValueHelper::ValueAsAddress(that))); \ } \ \ v8::internal::DirectHandle<v8::internal::To> Utils::OpenDirectHandle( \ const v8::From* that, bool allow_empty_handle) { \ DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \ DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \ Is##To(v8::internal::Tagged<v8::internal::Object>( \ v8::internal::ValueHelper::ValueAsAddress(that)))); \ return v8::internal::DirectHandle<v8::internal::To>( \ v8::internal::ValueHelper::ValueAsAddress(that)); \ } \ \ v8::internal::IndirectHandle<v8::internal::To> Utils::OpenIndirectHandle( \ const v8::From* that, bool allow_empty_handle) { \ return Utils::OpenHandle(that, allow_empty_handle); \ } #else // !V8_ENABLE_DIRECT_LOCAL #define MAKE_OPEN_HANDLE(From, To) \ v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \ const v8::From* that, bool allow_empty_handle) { \ DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \ DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \ Is##To(v8::internal::Tagged<v8::internal::Object>( \ v8::internal::ValueHelper::ValueAsAddress(that)))); \ return v8::internal::Handle<v8::internal::To>( \ reinterpret_cast<v8::internal::Address*>( \ const_cast<v8::From*>(that))); \ } \ \ v8::internal::DirectHandle<v8::internal::To> Utils::OpenDirectHandle( \ const v8::From* that, bool allow_empty_handle) { \ return Utils::OpenHandle(that, allow_empty_handle); \ } \ \ v8::internal::IndirectHandle<v8::internal::To> Utils::OpenIndirectHandle( \ const v8::From* that, bool allow_empty_handle) { \ return Utils::OpenHandle(that, allow_empty_handle); \ } #endif // V8_ENABLE_DIRECT_LOCAL OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE) #undef MAKE_OPEN_HANDLE #undef OPEN_HANDLE_LIST template <bool do_callback> class V8_NODISCARD CallDepthScope { public: CallDepthScope(i::Isolate* isolate, Local<Context> context) : isolate_(isolate), context_(context), did_enter_context_(false), escaped_(false), safe_for_termination_(isolate->next_v8_call_is_safe_for_termination()), interrupts_scope_(isolate_, i::StackGuard::TERMINATE_EXECUTION, isolate_->only_terminate_in_safe_scope() ? (safe_for_termination_ ? i::InterruptsScope::kRunInterrupts : i::InterruptsScope::kPostponeInterrupts) : i::InterruptsScope::kNoop) { isolate_->thread_local_top()->IncrementCallDepth(this); isolate_->set_next_v8_call_is_safe_for_termination(false); if (!context.IsEmpty()) { i::DisallowGarbageCollection no_gc; i::Tagged<i::Context> env = *Utils::OpenHandle(*context); i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); if (isolate->context().is_null() || isolate->context()->native_context() != env->native_context()) { impl->SaveContext(isolate->context()); isolate->set_context(env); did_enter_context_ = true; } } if (do_callback) isolate_->FireBeforeCallEnteredCallback(); } ~CallDepthScope() { i::MicrotaskQueue* microtask_queue = isolate_->default_microtask_queue(); if (!context_.IsEmpty()) { if (did_enter_context_) { i::HandleScopeImplementer* impl = isolate_->handle_scope_implementer(); isolate_->set_context(impl->RestoreContext()); } i::Handle<i::Context> env = Utils::OpenHandle(*context_); microtask_queue = env->native_context()->microtask_queue(); } if (!escaped_) isolate_->thread_local_top()->DecrementCallDepth(this); if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue); #ifdef DEBUG if (do_callback) { if (microtask_queue && microtask_queue->microtasks_policy() == v8::MicrotasksPolicy::kScoped) { DCHECK(microtask_queue->GetMicrotasksScopeDepth() || !microtask_queue->DebugMicrotasksScopeDepthIsZero()); } } DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue)); #endif isolate_->set_next_v8_call_is_safe_for_termination(safe_for_termination_); } CallDepthScope(const CallDepthScope&) = delete; CallDepthScope& operator=(const CallDepthScope&) = delete; void Escape() { DCHECK(!escaped_); escaped_ = true; auto thread_local_top = isolate_->thread_local_top(); thread_local_top->DecrementCallDepth(this); bool clear_exception = thread_local_top->CallDepthIsZero() && thread_local_top->try_catch_handler_ == nullptr; isolate_->OptionalRescheduleException(clear_exception); } private: #ifdef DEBUG bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint( i::MicrotaskQueue* microtask_queue) { bool did_perform_microtask_checkpoint = isolate_->thread_local_top()->CallDepthIsZero() && do_callback && microtask_queue && microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto && !isolate_->is_execution_terminating(); return !did_perform_microtask_checkpoint || IsUndefined(isolate_->heap()->weak_refs_keep_during_job(), isolate_); } #endif i::Isolate* const isolate_; Local<Context> context_; bool did_enter_context_ : 1; bool escaped_ : 1; bool safe_for_termination_ : 1; i::InterruptsScope interrupts_scope_; i::Address previous_stack_height_; friend class i::ThreadLocalTop; DISALLOW_NEW_AND_DELETE() }; class V8_NODISCARD InternalEscapableScope : public EscapableHandleScope { public: explicit inline InternalEscapableScope(i::Isolate* isolate) : EscapableHandleScope(reinterpret_cast<v8::Isolate*>(isolate)) {} }; template <typename T> void CopySmiElementsToTypedBuffer(T* dst, uint32_t length, i::Tagged<i::FixedArray> elements) { for (uint32_t i = 0; i < length; ++i) { double value = i::Object::Number(elements->get(static_cast<int>(i))); // TODO(mslekova): Avoid converting back-and-forth when possible, e.g // avoid int->double->int conversions to boost performance. dst[i] = i::ConvertDouble<T>(value); } } template <typename T> void CopyDoubleElementsToTypedBuffer(T* dst, uint32_t length, i::Tagged<i::FixedDoubleArray> elements) { for (uint32_t i = 0; i < length; ++i) { double value = elements->get_scalar(static_cast<int>(i)); // TODO(mslekova): There are certain cases, e.g. double->double, in which // we could do a memcpy directly. dst[i] = i::ConvertDouble<T>(value); } } template <CTypeInfo::Identifier type_info_id, typename T> bool CopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst, uint32_t max_length) { static_assert( std::is_same<T, typename i::CTypeInfoTraits< CTypeInfo(type_info_id).GetType()>::ctype>::value, "Type mismatch between the expected CTypeInfo::Type and the destination " "array"); uint32_t length = src->Length(); if (length > max_length) { return false; } i::DisallowGarbageCollection no_gc; i::Tagged<i::JSArray> obj = *Utils::OpenHandle(*src); if (i::Object::IterationHasObservableEffects(obj)) { // The array has a custom iterator. return false; } i::Tagged<i::FixedArrayBase> elements = obj->elements(); switch (obj->GetElementsKind()) { case i::PACKED_SMI_ELEMENTS: CopySmiElementsToTypedBuffer(dst, length, i::FixedArray::cast(elements)); return true; case i::PACKED_DOUBLE_ELEMENTS: CopyDoubleElementsToTypedBuffer(dst, length, i::FixedDoubleArray::cast(elements)); return true; default: return false; } } // Deprecated; to be removed. template <const CTypeInfo* type_info, typename T> inline bool V8_EXPORT TryCopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst, uint32_t max_length) { return CopyAndConvertArrayToCppBuffer<type_info->GetId(), T>(src, dst, max_length); } template <CTypeInfo::Identifier type_info_id, typename T> inline bool V8_EXPORT TryToCopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst, uint32_t max_length) { return CopyAndConvertArrayToCppBuffer<type_info_id, T>(src, dst, max_length); } namespace internal { void HandleScopeImplementer::EnterContext(Tagged<NativeContext> context) { DCHECK_EQ(entered_contexts_.capacity(), is_microtask_context_.capacity()); DCHECK_EQ(entered_contexts_.size(), is_microtask_context_.size()); entered_contexts_.push_back(context); is_microtask_context_.push_back(0); } void HandleScopeImplementer::EnterMicrotaskContext( Tagged<NativeContext> context) { DCHECK_EQ(entered_contexts_.capacity(), is_microtask_context_.capacity()); DCHECK_EQ(entered_contexts_.size(), is_microtask_context_.size()); entered_contexts_.push_back(context); is_microtask_context_.push_back(1); } Handle<NativeContext> HandleScopeImplementer::LastEnteredContext() { DCHECK_EQ(entered_contexts_.capacity(), is_microtask_context_.capacity()); DCHECK_EQ(entered_contexts_.size(), is_microtask_context_.size()); for (size_t i = 0; i < entered_contexts_.size(); ++i) { size_t j = entered_contexts_.size() - i - 1; if (!is_microtask_context_.at(j)) { return handle(entered_contexts_.at(j), isolate_); } } return {}; } Handle<NativeContext> HandleScopeImplementer::LastEnteredOrMicrotaskContext() { if (entered_contexts_.empty()) return {}; return handle(entered_contexts_.back(), isolate_); } } // namespace internal } // namespace v8 #endif // V8_API_API_INL_H_