v8 12.4.254 (node 22.4.1)
V8 is Google's open source JavaScript engine
Loading...
Searching...
No Matches
v8-function-callback.h
Go to the documentation of this file.
1// Copyright 2021 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 INCLUDE_V8_FUNCTION_CALLBACK_H_
6#define INCLUDE_V8_FUNCTION_CALLBACK_H_
7
8#include <cstdint>
9#include <limits>
10
11#include "v8-local-handle.h" // NOLINT(build/include_directory)
12#include "v8-primitive.h" // NOLINT(build/include_directory)
13#include "v8config.h" // NOLINT(build/include_directory)
14
15namespace v8 {
16
17template <typename T>
18class BasicTracedReference;
19template <typename T>
20class Global;
21class Object;
22class Value;
23
24namespace internal {
25class FunctionCallbackArguments;
26class PropertyCallbackArguments;
27class Builtins;
28} // namespace internal
29
30namespace debug {
31class ConsoleCallArguments;
32} // namespace debug
33
34template <typename T>
36 public:
37 template <class S>
38 V8_INLINE ReturnValue(const ReturnValue<S>& that) : value_(that.value_) {
39 static_assert(std::is_base_of<T, S>::value, "type check");
40 }
41 // Local setters
42 template <typename S>
43 V8_INLINE void Set(const Global<S>& handle);
44 template <typename S>
45 V8_INLINE void SetNonEmpty(const Global<S>& handle);
46 template <typename S>
48 template <typename S>
50 template <typename S>
51 V8_INLINE void Set(const Local<S> handle);
52 template <typename S>
53 V8_INLINE void SetNonEmpty(const Local<S> handle);
54 // Fast primitive setters
55 V8_INLINE void Set(bool value);
56 V8_INLINE void Set(double i);
57 V8_INLINE void Set(int32_t i);
58 V8_INLINE void Set(uint32_t i);
59 V8_INLINE void Set(uint16_t);
60 // Fast JS primitive setters
61 V8_INLINE void SetNull();
64 // Convenience getter for Isolate
66
67 // Pointer setter: Uncompilable to prevent inadvertent misuse.
68 template <typename S>
69 V8_INLINE void Set(S* whatever);
70
71 // Getter. Creates a new Local<> so it comes with a certain performance
72 // hit. If the ReturnValue was not yet set, this will return the undefined
73 // value.
75
76 private:
77 template <class F>
78 friend class ReturnValue;
79 template <class F>
81 template <class F>
83 template <class F, class G, class H>
85 V8_INLINE void SetInternal(internal::Address value);
86 // Setting the hole value has different meanings depending on the usage:
87 // - for function template callbacks it means that the callback returns
88 // the undefined value,
89 // - for property getter callbacks is means that the callback returns
90 // the undefined value (for property setter callbacks the value returned
91 // is ignored),
92 // - for interceptor callbacks it means that the request was not handled.
93 V8_INLINE void SetTheHole();
95
96 // See FunctionCallbackInfo.
97 static constexpr int kIsolateValueIndex = -2;
98
99 internal::Address* value_;
100};
101
108template <typename T>
110 public:
112 V8_INLINE int Length() const;
117 V8_INLINE Local<Value> operator[](int i) const;
134 V8_INLINE bool IsConstructCall() const;
141
142 private:
146
147 static constexpr int kHolderIndex = 0;
148 static constexpr int kIsolateIndex = 1;
149 static constexpr int kUnusedIndex = 2;
150 static constexpr int kReturnValueIndex = 3;
151 static constexpr int kDataIndex = 4;
152 static constexpr int kNewTargetIndex = 5;
153 static constexpr int kArgsLength = 6;
154
155 static constexpr int kArgsLengthWithReceiver = kArgsLength + 1;
156
157 // Codegen constants:
158 static constexpr int kSize = 3 * internal::kApiSystemPointerSize;
159 static constexpr int kImplicitArgsOffset = 0;
160 static constexpr int kValuesOffset =
161 kImplicitArgsOffset + internal::kApiSystemPointerSize;
162 static constexpr int kLengthOffset =
163 kValuesOffset + internal::kApiSystemPointerSize;
164
165 static constexpr int kThisValuesIndex = -1;
167 kIsolateIndex - kReturnValueIndex);
168
170 internal::Address* values, int length);
171 internal::Address* implicit_args_;
172 internal::Address* values_;
173 int length_;
174};
175
180template <typename T>
182 public:
187
194
237
248
258
267
268 private:
269 friend class MacroAssembler;
272 static constexpr int kShouldThrowOnErrorIndex = 0;
273 static constexpr int kHolderIndex = 1;
274 static constexpr int kIsolateIndex = 2;
275 static constexpr int kUnusedIndex = 3;
276 static constexpr int kReturnValueIndex = 4;
277 static constexpr int kDataIndex = 5;
278 static constexpr int kThisIndex = 6;
279 static constexpr int kArgsLength = 7;
280
281 static constexpr int kSize = 1 * internal::kApiSystemPointerSize;
282
284 : args_(args) {}
285
286 internal::Address* args_;
287};
288
289using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
290
291// --- Implementation ---
292
293template <typename T>
294ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
295
296template <typename T>
297void ReturnValue<T>::SetInternal(internal::Address value) {
298#if V8_STATIC_ROOTS_BOOL
299 using I = internal::Internals;
300 // Ensure that the upper 32-bits are not modified. Compiler should be
301 // able to optimize this to a store of a lower 32-bits of the value.
302 // This is fine since the callback can return only JavaScript values which
303 // are either Smis or heap objects allocated in the main cage.
304 *value_ = I::DecompressTaggedField(*value_, I::CompressTagged(value));
305#else
306 *value_ = value;
307#endif // V8_STATIC_ROOTS_BOOL
308}
309
310template <typename T>
311template <typename S>
312void ReturnValue<T>::Set(const Global<S>& handle) {
313 static_assert(std::is_base_of<T, S>::value, "type check");
314 if (V8_UNLIKELY(handle.IsEmpty())) {
315 SetTheHole();
316 } else {
317 SetInternal(handle.ptr());
318 }
319}
320
321template <typename T>
322template <typename S>
324 static_assert(std::is_base_of<T, S>::value, "type check");
325#ifdef V8_ENABLE_CHECKS
326 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
327#endif // V8_ENABLE_CHECKS
328 SetInternal(handle.ptr());
329}
330
331template <typename T>
332template <typename S>
334 static_assert(std::is_base_of<T, S>::value, "type check");
335 if (V8_UNLIKELY(handle.IsEmpty())) {
336 SetTheHole();
337 } else {
338 SetInternal(handle.ptr());
339 }
340}
341
342template <typename T>
343template <typename S>
345 static_assert(std::is_base_of<T, S>::value, "type check");
346#ifdef V8_ENABLE_CHECKS
347 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
348#endif // V8_ENABLE_CHECKS
349 SetInternal(handle.ptr());
350}
351
352template <typename T>
353template <typename S>
354void ReturnValue<T>::Set(const Local<S> handle) {
355 static_assert(std::is_void<T>::value || std::is_base_of<T, S>::value,
356 "type check");
357 if (V8_UNLIKELY(handle.IsEmpty())) {
358 SetTheHole();
359 } else {
360 SetInternal(handle.ptr());
361 }
362}
363
364template <typename T>
365template <typename S>
367 static_assert(std::is_void<T>::value || std::is_base_of<T, S>::value,
368 "type check");
369#ifdef V8_ENABLE_CHECKS
370 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
371#endif // V8_ENABLE_CHECKS
372 SetInternal(handle.ptr());
373}
374
375template <typename T>
376void ReturnValue<T>::Set(double i) {
377 static_assert(std::is_base_of<T, Number>::value, "type check");
378 SetNonEmpty(Number::New(GetIsolate(), i));
379}
380
381template <typename T>
382void ReturnValue<T>::Set(int32_t i) {
383 static_assert(std::is_base_of<T, Integer>::value, "type check");
384 using I = internal::Internals;
385 if (V8_LIKELY(I::IsValidSmi(i))) {
386 SetInternal(I::IntToSmi(i));
387 return;
388 }
389 SetNonEmpty(Integer::New(GetIsolate(), i));
390}
391
392template <typename T>
393void ReturnValue<T>::Set(uint32_t i) {
394 static_assert(std::is_base_of<T, Integer>::value, "type check");
395 // Can't simply use INT32_MAX here for whatever reason.
396 bool fits_into_int32_t = (i & (1U << 31)) == 0;
397 if (V8_LIKELY(fits_into_int32_t)) {
398 Set(static_cast<int32_t>(i));
399 return;
400 }
401 SetNonEmpty(Integer::NewFromUnsigned(GetIsolate(), i));
402}
403
404template <typename T>
405void ReturnValue<T>::Set(uint16_t i) {
406 static_assert(std::is_base_of<T, Integer>::value, "type check");
407 using I = internal::Internals;
408 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::min()));
409 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::max()));
410 SetInternal(I::IntToSmi(i));
411}
412
413template <typename T>
414void ReturnValue<T>::Set(bool value) {
415 static_assert(std::is_base_of<T, Boolean>::value, "type check");
416 using I = internal::Internals;
417#if V8_STATIC_ROOTS_BOOL
418#ifdef V8_ENABLE_CHECKS
419 internal::PerformCastCheck(
420 internal::ValueHelper::SlotAsValue<Value, true>(value_));
421#endif // V8_ENABLE_CHECKS
422 SetInternal(value ? I::StaticReadOnlyRoot::kTrueValue
423 : I::StaticReadOnlyRoot::kFalseValue);
424#else
425 int root_index;
426 if (value) {
427 root_index = I::kTrueValueRootIndex;
428 } else {
429 root_index = I::kFalseValueRootIndex;
430 }
431 *value_ = I::GetRoot(GetIsolate(), root_index);
432#endif // V8_STATIC_ROOTS_BOOL
433}
434
435template <typename T>
437 using I = internal::Internals;
438#if V8_STATIC_ROOTS_BOOL
439 SetInternal(I::StaticReadOnlyRoot::kTheHoleValue);
440#else
441 *value_ = I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex);
442#endif // V8_STATIC_ROOTS_BOOL
443}
444
445template <typename T>
447 static_assert(std::is_base_of<T, Primitive>::value, "type check");
448 using I = internal::Internals;
449#if V8_STATIC_ROOTS_BOOL
450#ifdef V8_ENABLE_CHECKS
451 internal::PerformCastCheck(
452 internal::ValueHelper::SlotAsValue<Value, true>(value_));
453#endif // V8_ENABLE_CHECKS
454 SetInternal(I::StaticReadOnlyRoot::kNullValue);
455#else
456 *value_ = I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
457#endif // V8_STATIC_ROOTS_BOOL
458}
459
460template <typename T>
462 static_assert(std::is_base_of<T, Primitive>::value, "type check");
463 using I = internal::Internals;
464#if V8_STATIC_ROOTS_BOOL
465#ifdef V8_ENABLE_CHECKS
466 internal::PerformCastCheck(
467 internal::ValueHelper::SlotAsValue<Value, true>(value_));
468#endif // V8_ENABLE_CHECKS
469 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
470#else
471 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
472#endif // V8_STATIC_ROOTS_BOOL
473}
474
475template <typename T>
477 static_assert(std::is_base_of<T, String>::value, "type check");
478 using I = internal::Internals;
479#if V8_STATIC_ROOTS_BOOL
480#ifdef V8_ENABLE_CHECKS
481 internal::PerformCastCheck(
482 internal::ValueHelper::SlotAsValue<Value, true>(value_));
483#endif // V8_ENABLE_CHECKS
484 SetInternal(I::StaticReadOnlyRoot::kEmptyString);
485#else
486 *value_ = I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
487#endif // V8_STATIC_ROOTS_BOOL
488}
489
490template <typename T>
492 return *reinterpret_cast<Isolate**>(&value_[kIsolateValueIndex]);
493}
494
495template <typename T>
497 using I = internal::Internals;
498#if V8_STATIC_ROOTS_BOOL
499 if (I::is_identical(*value_, I::StaticReadOnlyRoot::kTheHoleValue)) {
500#else
501 if (*value_ == I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex)) {
502#endif // V8_STATIC_ROOTS_BOOL
503 return Undefined(GetIsolate());
504 }
505 return Local<Value>::New(GetIsolate(),
506 internal::ValueHelper::SlotAsValue<Value>(value_));
507}
508
509template <typename T>
510template <typename S>
511void ReturnValue<T>::Set(S* whatever) {
512 static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
513}
514
515template <typename T>
517 internal::Address* values,
518 int length)
519 : implicit_args_(implicit_args), values_(values), length_(length) {}
520
521template <typename T>
523 // values_ points to the first argument (not the receiver).
524 if (i < 0 || length_ <= i) return Undefined(GetIsolate());
525 return Local<Value>::FromSlot(values_ + i);
526}
527
528template <typename T>
530 // values_ points to the first argument (not the receiver).
531 return Local<Object>::FromSlot(values_ + kThisValuesIndex);
532}
533
534template <typename T>
536 return Local<Object>::FromSlot(&implicit_args_[kHolderIndex]);
537}
538
539template <typename T>
541 return Local<Value>::FromSlot(&implicit_args_[kNewTargetIndex]);
542}
543
544template <typename T>
546 return Local<Value>::FromSlot(&implicit_args_[kDataIndex]);
547}
548
549template <typename T>
551 return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
552}
553
554template <typename T>
556 return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
557}
558
559template <typename T>
561 return !NewTarget()->IsUndefined();
562}
563
564template <typename T>
566 return length_;
567}
568
569template <typename T>
571 return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
572}
573
574template <typename T>
576 return Local<Value>::FromSlot(&args_[kDataIndex]);
577}
578
579template <typename T>
581 return Local<Object>::FromSlot(&args_[kThisIndex]);
582}
583
584template <typename T>
586 return Local<Object>::FromSlot(&args_[kHolderIndex]);
587}
588
589template <typename T>
591 return ReturnValue<T>(&args_[kReturnValueIndex]);
592}
593
594template <typename T>
596 using I = internal::Internals;
597 if (args_[kShouldThrowOnErrorIndex] !=
598 I::IntToSmi(I::kInferShouldThrowMode)) {
599 return args_[kShouldThrowOnErrorIndex] != I::IntToSmi(I::kDontThrow);
600 }
602 reinterpret_cast<v8::internal::Isolate*>(GetIsolate()));
603}
604
605} // namespace v8
606
607#endif // INCLUDE_V8_FUNCTION_CALLBACK_H_
V8_INLINE ReturnValue< T > GetReturnValue() const
V8_INLINE bool IsConstructCall() const
V8_INLINE Local< Object > This() const
V8_INLINE Local< Object > Holder() const
V8_INLINE Isolate * GetIsolate() const
V8_INLINE Local< Value > Data() const
V8_INLINE int Length() const
friend class debug::ConsoleCallArguments
V8_INLINE Local< Value > NewTarget() const
friend class internal::FunctionCallbackArguments
V8_INLINE Local< Value > operator[](int i) const
V8_INLINE ReturnValue< T > GetReturnValue() const
friend class internal::PropertyCallbackArguments
V8_INLINE Local< Object > This() const
V8_INLINE Local< Object > Holder() const
V8_INLINE Isolate * GetIsolate() const
V8_INLINE Local< Value > Data() const
V8_INLINE bool ShouldThrowOnError() const
V8_INLINE ReturnValue(const ReturnValue< S > &that)
V8_INLINE Isolate * GetIsolate() const
V8_INLINE void SetNonEmpty(const Local< S > handle)
V8_INLINE void Set(const BasicTracedReference< S > &handle)
V8_INLINE void SetNull()
V8_INLINE void SetUndefined()
V8_INLINE void SetNonEmpty(const Global< S > &handle)
V8_INLINE void Set(const Global< S > &handle)
V8_INLINE void SetEmptyString()
V8_INLINE void SetNonEmpty(const BasicTracedReference< S > &handle)
V8_INLINE void Set(const Local< S > handle)
V8_INLINE void Set(S *whatever)
V8_INLINE Local< Value > Get() const
V8_INLINE internal::Address ptr() const
const int kApiSystemPointerSize
Definition v8-internal.h:44
uintptr_t Address
Definition v8-internal.h:31
V8_EXPORT bool ShouldThrowOnError(internal::Isolate *isolate)
void(*)(const FunctionCallbackInfo< Value > &info) FunctionCallback
V8_INLINE Local< Primitive > Undefined(Isolate *isolate)
#define V8_INLINE
Definition v8config.h:477
#define V8_LIKELY(condition)
Definition v8config.h:618
#define V8_UNLIKELY(condition)
Definition v8config.h:617