v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
api-inl.h
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_API_API_INL_H_
6#define V8_API_API_INL_H_
7
8#include "src/api/api.h"
9// Include the non-inl header before the rest of the headers.
10
14#include "src/flags/flags.h"
16#include "src/heap/heap-inl.h"
19
20namespace v8 {
21
22template <typename T, internal::ExternalPointerTag tag>
23inline T ToCData(i::Isolate* isolate,
25 static_assert(sizeof(T) == sizeof(v8::internal::Address));
26 if (obj == v8::internal::Smi::zero()) return nullptr;
27 return reinterpret_cast<T>(
28 v8::internal::Cast<v8::internal::Foreign>(obj)->foreign_address<tag>(
29 isolate));
30}
31
32template <internal::ExternalPointerTag tag>
39
40template <internal::ExternalPointerTag tag, typename T>
42 v8::internal::Isolate* isolate, T obj) {
43 static_assert(sizeof(T) == sizeof(v8::internal::Address));
44 if (obj == nullptr) return direct_handle(v8::internal::Smi::zero(), isolate);
45 return isolate->factory()->NewForeign<tag>(
46 reinterpret_cast<v8::internal::Address>(obj));
47}
48
49template <internal::ExternalPointerTag tag>
52 if (obj == v8::internal::kNullAddress) {
53 return direct_handle(v8::internal::Smi::zero(), isolate);
54 }
55 return isolate->factory()->NewForeign<tag>(obj);
56}
57
58template <class From, class To>
60 DCHECK(obj.is_null() || IsSmi(*obj) || !IsTheHole(*obj));
61#ifdef V8_ENABLE_DIRECT_HANDLE
62 if (obj.is_null()) return Local<To>();
63 return Local<To>::FromAddress(obj.address());
64#else
65 // This simply uses the location of the indirect handle wrapped inside a
66 // "fake" direct handle.
67 return Local<To>::FromSlot(indirect_handle(obj).location());
68#endif
69}
70
71// Implementations of ToLocal
72
73#define MAKE_TO_LOCAL(Name) \
74 template <template <typename> typename HandleType, typename T, typename> \
75 inline auto Utils::Name(HandleType<T> obj) { \
76 return Utils::Name##_helper(v8::internal::DirectHandle<T>(obj)); \
77 }
78
80
81#define MAKE_TO_LOCAL_PRIVATE(Name, From, To) \
82 inline Local<v8::To> Utils::Name##_helper( \
83 v8::internal::DirectHandle<v8::internal::From> obj) { \
84 return Convert<v8::internal::From, v8::To>(obj); \
85 }
86
88
89#define MAKE_TO_LOCAL_TYPED_ARRAY(Type, typeName, TYPE, ctype) \
90 Local<v8::Type##Array> Utils::ToLocal##Type##Array( \
91 v8::internal::DirectHandle<v8::internal::JSTypedArray> obj) { \
92 DCHECK(obj->type() == v8::internal::kExternal##Type##Array); \
93 return Convert<v8::internal::JSTypedArray, v8::Type##Array>(obj); \
94 }
95
97
98#undef MAKE_TO_LOCAL_TYPED_ARRAY
99#undef MAKE_TO_LOCAL
100#undef MAKE_TO_LOCAL_PRIVATE
101#undef TO_LOCAL_LIST
102
103// Implementations of OpenHandle
104
105#ifdef V8_ENABLE_DIRECT_HANDLE
106
107#define MAKE_OPEN_HANDLE(From, To) \
108 v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \
109 const v8::From* that, bool allow_empty_handle) { \
110 DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \
111 DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \
112 Is##To(v8::internal::Tagged<v8::internal::Object>( \
113 v8::internal::ValueHelper::ValueAsAddress(that)))); \
114 if (v8::internal::ValueHelper::IsEmpty(that)) { \
115 return v8::internal::Handle<v8::internal::To>::null(); \
116 } \
117 return v8::internal::Handle<v8::internal::To>( \
118 v8::HandleScope::CreateHandleForCurrentIsolate( \
119 v8::internal::ValueHelper::ValueAsAddress(that))); \
120 } \
121 \
122 v8::internal::DirectHandle<v8::internal::To> Utils::OpenDirectHandle( \
123 const v8::From* that, bool allow_empty_handle) { \
124 DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \
125 DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \
126 Is##To(v8::internal::Tagged<v8::internal::Object>( \
127 v8::internal::ValueHelper::ValueAsAddress(that)))); \
128 return v8::internal::DirectHandle<v8::internal::To>::FromAddress( \
129 v8::internal::ValueHelper::ValueAsAddress(that)); \
130 } \
131 \
132 v8::internal::IndirectHandle<v8::internal::To> Utils::OpenIndirectHandle( \
133 const v8::From* that, bool allow_empty_handle) { \
134 return Utils::OpenHandle(that, allow_empty_handle); \
135 }
136
137#else // !V8_ENABLE_DIRECT_HANDLE
138
139#define MAKE_OPEN_HANDLE(From, To) \
140 v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \
141 const v8::From* that, bool allow_empty_handle) { \
142 DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \
143 DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \
144 Is##To(v8::internal::Tagged<v8::internal::Object>( \
145 v8::internal::ValueHelper::ValueAsAddress(that)))); \
146 return v8::internal::Handle<v8::internal::To>( \
147 reinterpret_cast<v8::internal::Address*>( \
148 const_cast<v8::From*>(that))); \
149 } \
150 \
151 v8::internal::DirectHandle<v8::internal::To> Utils::OpenDirectHandle( \
152 const v8::From* that, bool allow_empty_handle) { \
153 return Utils::OpenHandle(that, allow_empty_handle); \
154 } \
155 \
156 v8::internal::IndirectHandle<v8::internal::To> Utils::OpenIndirectHandle( \
157 const v8::From* that, bool allow_empty_handle) { \
158 return Utils::OpenHandle(that, allow_empty_handle); \
159 }
160
161#endif // V8_ENABLE_DIRECT_HANDLE
162
164
165#undef MAKE_OPEN_HANDLE
166#undef OPEN_HANDLE_LIST
167
168template <bool do_callback>
170 public:
172 : isolate_(isolate), saved_context_(isolate->context(), isolate_) {
173 isolate_->thread_local_top()->IncrementCallDepth<do_callback>(this);
174 i::Tagged<i::NativeContext> env = *Utils::OpenDirectHandle(*context);
175 isolate->set_context(env);
176
177 if (do_callback) isolate_->FireBeforeCallEnteredCallback();
178 }
182 ->microtask_queue(isolate_);
183
184 isolate_->thread_local_top()->DecrementCallDepth(this);
185 // Clear the exception when exiting V8 to avoid memory leaks.
186 // Also clear termination exceptions iff there's no TryCatch handler.
187 // TODO(verwaest): Drop this once we propagate exceptions to external
188 // TryCatch on Throw. This should be debug-only.
189 if (isolate_->thread_local_top()->CallDepthIsZero() &&
190 (isolate_->thread_local_top()->try_catch_handler_ == nullptr ||
191 !isolate_->is_execution_terminating())) {
192 isolate_->clear_internal_exception();
193 }
194 if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue);
195#ifdef DEBUG
196 if (do_callback) {
197 if (microtask_queue && microtask_queue->microtasks_policy() ==
199 DCHECK(microtask_queue->GetMicrotasksScopeDepth() ||
200 !microtask_queue->DebugMicrotasksScopeDepthIsZero());
201 }
202 }
203 DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue));
204#endif
205
206 isolate_->set_context(*saved_context_);
207 }
208
211
212 private:
213#ifdef DEBUG
214 bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint(
216 bool did_perform_microtask_checkpoint =
217 isolate_->thread_local_top()->CallDepthIsZero() && do_callback &&
219 microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto &&
220 !isolate_->is_execution_terminating();
221 return !did_perform_microtask_checkpoint ||
222 IsUndefined(isolate_->heap()->weak_refs_keep_during_job(), isolate_);
223 }
224#endif
225
228
230
231 friend class i::ThreadLocalTop;
232
234};
235
237 public:
238 explicit inline InternalEscapableScope(i::Isolate* isolate)
239 : EscapableHandleScopeBase(reinterpret_cast<v8::Isolate*>(isolate)) {}
240
245 template <class T>
247#ifdef V8_ENABLE_DIRECT_HANDLE
248 return value;
249#else
250 DCHECK(!value.IsEmpty());
251 return Local<T>::FromSlot(EscapeSlot(value.slot()));
252#endif
253 }
254
255 template <class T>
258 if (!maybe_value.ToLocal(&value)) return maybe_value;
259 return Escape(value);
260 }
261};
262
263template <typename T>
264void CopySmiElementsToTypedBuffer(T* dst, uint32_t length,
265 i::Tagged<i::FixedArray> elements) {
266 for (uint32_t i = 0; i < length; ++i) {
267 double value = i::Object::NumberValue(
268 i::Cast<i::Smi>(elements->get(static_cast<int>(i))));
269 // TODO(mslekova): Avoid converting back-and-forth when possible, e.g
270 // avoid int->double->int conversions to boost performance.
271 dst[i] = i::ConvertDouble<T>(value);
272 }
273}
274
275template <typename T>
276void CopyDoubleElementsToTypedBuffer(T* dst, uint32_t length,
278 for (uint32_t i = 0; i < length; ++i) {
279 double value = elements->get_scalar(static_cast<int>(i));
280 // TODO(mslekova): There are certain cases, e.g. double->double, in which
281 // we could do a memcpy directly.
282 dst[i] = i::ConvertDouble<T>(value);
283 }
284}
285
286template <CTypeInfo::Identifier type_info_id, typename T>
288 uint32_t max_length) {
289 static_assert(
290 std::is_same<T, typename i::CTypeInfoTraits<
291 CTypeInfo(type_info_id).GetType()>::ctype>::value,
292 "Type mismatch between the expected CTypeInfo::Type and the destination "
293 "array");
294
295 uint32_t length = src->Length();
296 if (length == 0) {
297 // Early return here to avoid a cast error below, as the EmptyFixedArray
298 // cannot be cast to a FixedDoubleArray.
299 return true;
300 }
301 if (length > max_length) {
302 return false;
303 }
304
307 if (i::Object::IterationHasObservableEffects(obj)) {
308 // The array has a custom iterator.
309 return false;
310 }
311
312 i::Tagged<i::FixedArrayBase> elements = obj->elements();
313 switch (obj->GetElementsKind()) {
316 i::Cast<i::FixedArray>(elements));
317 return true;
321 return true;
322 default:
323 return false;
324 }
325}
326
327// Deprecated; to be removed.
328template <const CTypeInfo* type_info, typename T>
330 T* dst,
331 uint32_t max_length) {
332 return CopyAndConvertArrayToCppBuffer<type_info->GetId(), T>(src, dst,
333 max_length);
334}
335
336template <CTypeInfo::Identifier type_info_id, typename T>
338 T* dst,
339 uint32_t max_length) {
340 return CopyAndConvertArrayToCppBuffer<type_info_id, T>(src, dst, max_length);
341}
342
343namespace internal {
344
348
353
354} // namespace internal
355} // namespace v8
356
357#endif // V8_API_API_INL_H_
#define MAKE_TO_LOCAL_PRIVATE(Name, From, To)
Definition api-inl.h:81
#define MAKE_OPEN_HANDLE(From, To)
Definition api-inl.h:139
#define MAKE_TO_LOCAL_TYPED_ARRAY(Type, typeName, TYPE, ctype)
Definition api-inl.h:89
#define MAKE_TO_LOCAL(Name)
Definition api-inl.h:73
Isolate * isolate_
#define TO_LOCAL_NAME_LIST(V)
Definition api.h:137
#define OPEN_HANDLE_LIST(V)
Definition api.h:154
#define TO_LOCAL_LIST(V)
Definition api.h:94
#define T
constexpr Type GetType() const
i::Address previous_stack_height_
Definition api-inl.h:229
i::Isolate *const isolate_
Definition api-inl.h:226
CallDepthScope(i::Isolate *isolate, Local< Context > context)
Definition api-inl.h:171
i::Handle< i::Context > saved_context_
Definition api-inl.h:227
CallDepthScope & operator=(const CallDepthScope &)=delete
CallDepthScope(const CallDepthScope &)=delete
InternalEscapableScope(i::Isolate *isolate)
Definition api-inl.h:238
V8_INLINE MaybeLocal< T > EscapeMaybe(MaybeLocal< T > maybe_value)
Definition api-inl.h:256
V8_INLINE Local< T > Escape(Local< T > value)
Definition api-inl.h:246
static V8_INLINE Local< T > FromSlot(internal::Address *slot)
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local< S > *out) const
static Local< To > Convert(v8::internal::DirectHandle< From > obj)
Definition api-inl.h:59
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
V8_INLINE bool is_null() const
Definition handles.h:693
V8_INLINE Address address() const
Definition handles.h:695
DetachableVector< Tagged< NativeContext > > entered_contexts_
Definition api.h:427
DirectHandle< NativeContext > LastEnteredContext()
Definition api-inl.h:349
void EnterContext(Tagged< NativeContext > context)
Definition api-inl.h:345
static constexpr Tagged< Smi > zero()
Definition smi.h:99
#define TYPED_ARRAYS(V)
MicrotaskQueue * microtask_queue
Definition execution.cc:77
Isolate * isolate
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
int32_t ConvertDouble(double d)
Definition api.cc:12211
static constexpr Address kNullAddress
Definition v8-internal.h:53
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
void CopyDoubleElementsToTypedBuffer(T *dst, uint32_t length, i::Tagged< i::FixedDoubleArray > elements)
Definition api-inl.h:276
bool V8_EXPORT TryCopyAndConvertArrayToCppBuffer(Local< Array > src, T *dst, uint32_t max_length)
Definition api-inl.h:329
v8::internal::DirectHandle< i::UnionOf< i::Smi, i::Foreign > > FromCData(v8::internal::Isolate *isolate, T obj)
Definition api-inl.h:41
void CopySmiElementsToTypedBuffer(T *dst, uint32_t length, i::Tagged< i::FixedArray > elements)
Definition api-inl.h:264
T ToCData(i::Isolate *isolate, v8::internal::Tagged< v8::internal::Object > obj)
Definition api-inl.h:23
bool CopyAndConvertArrayToCppBuffer(Local< Array > src, T *dst, uint32_t max_length)
Definition api-inl.h:287
bool V8_EXPORT TryToCopyAndConvertArrayToCppBuffer(Local< Array > src, T *dst, uint32_t max_length)
Definition api-inl.h:337
#define DCHECK(condition)
Definition logging.h:482
#define DISALLOW_NEW_AND_DELETE()
Definition macros.h:155
#define V8_EXPORT
Definition v8config.h:800
#define V8_INLINE
Definition v8config.h:500
#define V8_NODISCARD
Definition v8config.h:693
std::unique_ptr< ValueMirror > value