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-internal.h" // NOLINT(build/include_directory)
12#include "v8-local-handle.h" // NOLINT(build/include_directory)
13#include "v8-primitive.h" // NOLINT(build/include_directory)
14#include "v8config.h" // NOLINT(build/include_directory)
15
16namespace v8 {
17
18template <typename T>
19class BasicTracedReference;
20template <typename T>
21class Global;
22class Object;
23class Value;
24
25namespace internal {
26class FunctionCallbackArguments;
27class PropertyCallbackArguments;
28class Builtins;
29} // namespace internal
30
31namespace debug {
32class ConsoleCallArguments;
33} // namespace debug
34
35namespace api_internal {
37 v8::Isolate* isolate, v8::Local<v8::Data> raw_target);
38} // namespace api_internal
39
40template <typename T>
42 public:
43 template <class S>
44 V8_INLINE ReturnValue(const ReturnValue<S>& that) : value_(that.value_) {
45 static_assert(std::is_base_of_v<T, S>, "type check");
46 }
47 // Handle-based setters.
48 template <typename S>
49 V8_INLINE void Set(const Global<S>& handle);
50 template <typename S>
51 V8_INLINE void SetNonEmpty(const Global<S>& handle);
52 template <typename S>
53 V8_INLINE void Set(const BasicTracedReference<S>& handle);
54 template <typename S>
56 template <typename S>
57 V8_INLINE void Set(const Local<S> handle);
58 template <typename S>
59 V8_INLINE void SetNonEmpty(const Local<S> handle);
60
61 // Fast primitive number setters.
62 V8_INLINE void Set(bool value);
63 V8_INLINE void Set(double i);
64 V8_INLINE void Set(int16_t i);
65 V8_INLINE void Set(int32_t i);
66 V8_INLINE void Set(int64_t i);
67 V8_INLINE void Set(uint16_t i);
68 V8_INLINE void Set(uint32_t i);
69 V8_INLINE void Set(uint64_t i);
70
71 // Fast JS primitive setters.
72 V8_INLINE void SetNull();
74 V8_INLINE void SetFalse();
76
77 // Convenience getter for the Isolate.
79
80 // Pointer setter: Uncompilable to prevent inadvertent misuse.
81 template <typename S>
82 V8_INLINE void Set(S* whatever);
83
84 // Getter. Creates a new Local<> so it comes with a certain performance
85 // hit. If the ReturnValue was not yet set, this will return the undefined
86 // value.
88
89 private:
90 template <class F>
91 friend class ReturnValue;
92 template <class F>
94 template <class F>
96 template <class F, class G, class H>
98 V8_INLINE void SetInternal(internal::Address value);
99 // Default value depends on <T>:
100 // - <void> -> true_value,
101 // - <v8::Boolean> -> true_value,
102 // - <v8::Integer> -> 0,
103 // - <v8::Value> -> undefined_value,
104 // - <v8::Array> -> undefined_value.
105 V8_INLINE void SetDefaultValue();
107
108 // See FunctionCallbackInfo.
109 static constexpr int kIsolateValueIndex = -2;
110
111 internal::Address* value_;
112};
113
120template <typename T>
122 public:
124 V8_INLINE int Length() const;
129 V8_INLINE Local<Value> operator[](int i) const;
135 V8_INLINE bool IsConstructCall() const;
142
143 private:
148 using I = internal::Internals;
149
150 // Frame block, matches the layout of ApiCallbackExitFrame.
151 // See ApiCallbackExitFrameConstants.
152 enum {
153 //
154 // Optional frame arguments block (exists only for API_CONSTRUCT_EXIT
155 // frame).
156
157 // Frame arguments block.
158 kNewTargetIndex = -1,
159
160 //
161 // Mandatory part, exists for both API_CALLBACK_EXIT and API_CONSTRUCT_EXIT
162 // frames.
163 //
164
165 // Frame arguments block.
166 kArgcIndex,
167
168 // Regular ExitFrame structure.
169 kFrameSPIndex,
170 kFrameTypeIndex,
171 kFrameConstantPoolIndex, // Optional, see I::kFrameCPSlotCount.
172 kFrameFPIndex = kFrameConstantPoolIndex + I::kFrameCPSlotCount,
173 kFramePCIndex,
174
175 // Api arguments block, starts at kFirstArgumentIndex.
176 kFirstApiArgumentIndex,
177 kIsolateIndex = kFirstApiArgumentIndex,
178 kContextIndex,
179 kReturnValueIndex,
180 kTargetIndex,
181
182 // JS args block, starts at kFrameFirstImplicitArgsIndex.
183 kReceiverIndex,
184 kFirstJSArgumentIndex,
185
186 // Mandatory part includes receiver.
187 kArgsLength = kReceiverIndex + 1,
188 // Optional part size (exists only for API_CONSTRUCT_EXIT frame).
189 kOptionalArgsLength = 1,
190
191 // The length of just Api arguments part.
192 kApiArgsLength = kReceiverIndex - kFirstApiArgumentIndex,
193 };
194
195 static_assert(kArgcIndex == 0);
197 kIsolateIndex - kReturnValueIndex);
198
199 internal::Address* address_of_first_argument() const {
200 return &values_[kFirstJSArgumentIndex];
201 }
202
203 V8_INLINE FunctionCallbackInfo() = default;
204
205 // FunctionCallbackInfo object provides a view of the stack area where the
206 // data is stored and thus it's not supposed to be copyable/movable.
207 FunctionCallbackInfo(const FunctionCallbackInfo&) = delete;
208 FunctionCallbackInfo& operator=(const FunctionCallbackInfo&) = delete;
209 FunctionCallbackInfo(FunctionCallbackInfo&&) = delete;
210 FunctionCallbackInfo& operator=(FunctionCallbackInfo&&) = delete;
211
212 // Declare as mutable to let GC modify the contents of the slots even though
213 // it's not possible to change values via this class.
214 // Define the array size as 1 to make it clear that we are going to access
215 // it out-of-bounds from both sides anyway.
216 mutable internal::Address values_[1];
217};
218
223template <typename T>
225 public:
230
237
280 "Access to receiver will be deprecated soon. Use HolderV2() instead. \n"
281 "See http://crbug.com/455600234. ")
283
293
303
319
320 private:
321 template <typename U>
323 friend class MacroAssembler;
324 friend class internal::PropertyCallbackArguments;
325 friend class internal::CustomArguments<PropertyCallbackInfo>;
326 friend void internal::PrintPropertyCallbackInfo(void*);
327
328 static constexpr int kPropertyKeyIndex = 0;
329 static constexpr int kShouldThrowOnErrorIndex = 1;
330 static constexpr int kHolderIndex = 2;
331 static constexpr int kIsolateIndex = 3;
332 // TODO(http://crbug.com/333672197): drop this parameter.
333 static constexpr int kUnusedIndex = 4;
334 static constexpr int kReturnValueIndex = 5;
335 static constexpr int kCallbackInfoIndex = 6;
336 static constexpr int kThisIndex = 7;
337 static constexpr int kArgsLength = 8;
338
339 static constexpr int kSize = kArgsLength * internal::kApiSystemPointerSize;
340
341 PropertyCallbackInfo() = default;
342
343 mutable internal::Address args_[kArgsLength];
344};
345
346using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
347
348// --- Implementation ---
349
350template <typename T>
351ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
352
353template <typename T>
354void ReturnValue<T>::SetInternal(internal::Address value) {
355#if V8_STATIC_ROOTS_BOOL
356 using I = internal::Internals;
357 // Ensure that the upper 32-bits are not modified. Compiler should be
358 // able to optimize this to a store of a lower 32-bits of the value.
359 // This is fine since the callback can return only JavaScript values which
360 // are either Smis or heap objects allocated in the main cage.
361 *value_ = I::DecompressTaggedField(*value_, I::CompressTagged(value));
362#else
363 *value_ = value;
364#endif // V8_STATIC_ROOTS_BOOL
365}
366
367template <typename T>
368template <typename S>
369void ReturnValue<T>::Set(const Global<S>& handle) {
370 static_assert(std::is_base_of_v<T, S>, "type check");
371 if (V8_UNLIKELY(handle.IsEmpty())) {
372 SetDefaultValue();
373 } else {
374 SetInternal(handle.ptr());
375 }
376}
377
378template <typename T>
379template <typename S>
381 static_assert(std::is_base_of_v<T, S>, "type check");
382#ifdef V8_ENABLE_CHECKS
384#endif // V8_ENABLE_CHECKS
385 SetInternal(handle.ptr());
386}
387
388template <typename T>
389template <typename S>
391 static_assert(std::is_base_of_v<T, S>, "type check");
392 if (V8_UNLIKELY(handle.IsEmpty())) {
393 SetDefaultValue();
394 } else {
395 SetInternal(handle.ptr());
396 }
397}
398
399template <typename T>
400template <typename S>
402 static_assert(std::is_base_of_v<T, S>, "type check");
403#ifdef V8_ENABLE_CHECKS
405#endif // V8_ENABLE_CHECKS
406 SetInternal(handle.ptr());
407}
408
409template <typename T>
410template <typename S>
411void ReturnValue<T>::Set(const Local<S> handle) {
412 static_assert(std::is_base_of_v<T, S>, "type check");
413 if (V8_UNLIKELY(handle.IsEmpty())) {
414 SetDefaultValue();
415 } else {
416 SetInternal(handle.ptr());
417 }
418}
419
420template <typename T>
421template <typename S>
423 static_assert(std::is_base_of_v<T, S>, "type check");
424#ifdef V8_ENABLE_CHECKS
426#endif // V8_ENABLE_CHECKS
427 SetInternal(handle.ptr());
428}
429
430template <typename T>
431void ReturnValue<T>::Set(double i) {
432 static_assert(std::is_base_of_v<T, Number>, "type check");
433 SetNonEmpty(Number::New(GetIsolate(), i));
434}
435
436template <typename T>
437void ReturnValue<T>::Set(int16_t i) {
438 static_assert(std::is_base_of_v<T, Integer>, "type check");
439 using I = internal::Internals;
440 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::min()));
441 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::max()));
442 SetInternal(I::IntegralToSmi(i));
443}
444
445template <typename T>
446void ReturnValue<T>::Set(int32_t i) {
447 static_assert(std::is_base_of_v<T, Integer>, "type check");
448 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
449 SetInternal(*result);
450 return;
451 }
452 SetNonEmpty(Integer::New(GetIsolate(), i));
453}
454
455template <typename T>
456void ReturnValue<T>::Set(int64_t i) {
457 static_assert(std::is_base_of_v<T, Integer>, "type check");
458 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
459 SetInternal(*result);
460 return;
461 }
462 SetNonEmpty(Number::New(GetIsolate(), static_cast<double>(i)));
463}
464
465template <typename T>
466void ReturnValue<T>::Set(uint16_t i) {
467 static_assert(std::is_base_of_v<T, Integer>, "type check");
468 using I = internal::Internals;
469 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::min()));
470 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::max()));
471 SetInternal(I::IntegralToSmi(i));
472}
473
474template <typename T>
475void ReturnValue<T>::Set(uint32_t i) {
476 static_assert(std::is_base_of_v<T, Integer>, "type check");
477 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
478 SetInternal(*result);
479 return;
480 }
481 SetNonEmpty(Integer::NewFromUnsigned(GetIsolate(), i));
482}
483
484template <typename T>
485void ReturnValue<T>::Set(uint64_t i) {
486 static_assert(std::is_base_of_v<T, Integer>, "type check");
487 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
488 SetInternal(*result);
489 return;
490 }
491 SetNonEmpty(Number::New(GetIsolate(), static_cast<double>(i)));
492}
493
494template <typename T>
495void ReturnValue<T>::Set(bool value) {
496 static_assert(std::is_void_v<T> || std::is_base_of_v<T, Boolean>,
497 "type check");
498 using I = internal::Internals;
499#if V8_STATIC_ROOTS_BOOL
500#ifdef V8_ENABLE_CHECKS
502 internal::ValueHelper::SlotAsValue<Value, true>(value_));
503#endif // V8_ENABLE_CHECKS
504 SetInternal(value ? I::StaticReadOnlyRoot::kTrueValue
505 : I::StaticReadOnlyRoot::kFalseValue);
506#else
507 int root_index;
508 if (value) {
509 root_index = I::kTrueValueRootIndex;
510 } else {
511 root_index = I::kFalseValueRootIndex;
512 }
513 *value_ = I::GetRoot(GetIsolate(), root_index);
514#endif // V8_STATIC_ROOTS_BOOL
515}
516
517template <typename T>
519 using I = internal::Internals;
520 if constexpr (std::is_same_v<void, T> || std::is_same_v<v8::Boolean, T>) {
521 Set(true);
522 } else if constexpr (std::is_same_v<v8::Integer, T>) {
523 SetInternal(I::IntegralToSmi(0));
524 } else {
525 static_assert(std::is_same_v<v8::Value, T> || std::is_same_v<v8::Array, T>);
526#if V8_STATIC_ROOTS_BOOL
527 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
528#else
529 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
530#endif // V8_STATIC_ROOTS_BOOL
531 }
532}
533
534template <typename T>
536 static_assert(std::is_base_of_v<T, Primitive>, "type check");
537 using I = internal::Internals;
538#if V8_STATIC_ROOTS_BOOL
539#ifdef V8_ENABLE_CHECKS
541 internal::ValueHelper::SlotAsValue<Value, true>(value_));
542#endif // V8_ENABLE_CHECKS
543 SetInternal(I::StaticReadOnlyRoot::kNullValue);
544#else
545 *value_ = I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
546#endif // V8_STATIC_ROOTS_BOOL
547}
548
549template <typename T>
551 static_assert(std::is_base_of_v<T, Primitive>, "type check");
552 using I = internal::Internals;
553#if V8_STATIC_ROOTS_BOOL
554#ifdef V8_ENABLE_CHECKS
556 internal::ValueHelper::SlotAsValue<Value, true>(value_));
557#endif // V8_ENABLE_CHECKS
558 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
559#else
560 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
561#endif // V8_STATIC_ROOTS_BOOL
562}
563
564template <typename T>
566 static_assert(std::is_void_v<T> || std::is_base_of_v<T, Boolean>,
567 "type check");
568 using I = internal::Internals;
569#if V8_STATIC_ROOTS_BOOL
570#ifdef V8_ENABLE_CHECKS
572 internal::ValueHelper::SlotAsValue<Value, true>(value_));
573#endif // V8_ENABLE_CHECKS
574 SetInternal(I::StaticReadOnlyRoot::kFalseValue);
575#else
576 *value_ = I::GetRoot(GetIsolate(), I::kFalseValueRootIndex);
577#endif // V8_STATIC_ROOTS_BOOL
578}
579
580template <typename T>
582 static_assert(std::is_base_of_v<T, String>, "type check");
583 using I = internal::Internals;
584#if V8_STATIC_ROOTS_BOOL
585#ifdef V8_ENABLE_CHECKS
587 internal::ValueHelper::SlotAsValue<Value, true>(value_));
588#endif // V8_ENABLE_CHECKS
589 SetInternal(I::StaticReadOnlyRoot::kEmptyString);
590#else
591 *value_ = I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
592#endif // V8_STATIC_ROOTS_BOOL
593}
594
595template <typename T>
597 return *reinterpret_cast<Isolate**>(&value_[kIsolateValueIndex]);
598}
599
600template <typename T>
603 internal::ValueHelper::SlotAsValue<Value>(value_));
604}
605
606template <typename T>
607template <typename S>
608void ReturnValue<T>::Set(S* whatever) {
609 static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
610}
611
612template <typename T>
614 if (i < 0 || Length() <= i) return Undefined(GetIsolate());
615 return Local<Value>::FromSlot(&values_[kFirstJSArgumentIndex + i]);
616}
617
618template <typename T>
620 return Local<Object>::FromSlot(&values_[kReceiverIndex]);
621}
622
623template <typename T>
625 if (IsConstructCall()) {
626 // Can't use &values_[kNewTargetIndex] because of "array index -1 is
627 // before the beginning of the array" error.
628 internal::Address* values = &values_[0];
629 return Local<Value>::FromSlot(values + kNewTargetIndex);
630 }
631 return Undefined(GetIsolate());
632}
633
634template <typename T>
636 auto target = Local<v8::Data>::FromSlot(&values_[kTargetIndex]);
638}
639
640template <typename T>
642 return reinterpret_cast<Isolate*>(values_[kIsolateIndex]);
643}
644
645template <typename T>
647 return ReturnValue<T>(&values_[kReturnValueIndex]);
648}
649
650template <typename T>
652 return I::SmiValue(values_[kFrameTypeIndex]) == I::kFrameTypeApiConstructExit;
653}
654
655template <typename T>
657 return static_cast<int>(values_[kArgcIndex]);
658}
659
660template <typename T>
662 return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
663}
664
665template <typename T>
667 using I = internal::Internals;
668 internal::Address callback_info = args_[kCallbackInfoIndex];
669 internal::Address data =
670 I::ReadTaggedPointerField(callback_info, I::kCallbackInfoDataOffset);
671 return Local<Value>::New(GetIsolate(), data);
672}
673
674template <typename T>
676 return Local<Object>::FromSlot(&args_[kThisIndex]);
677}
678
679template <typename T>
681 return Local<Object>::FromSlot(&args_[kHolderIndex]);
682}
683
684template <typename T>
686 return ReturnValue<T>(&args_[kReturnValueIndex]);
687}
688
689template <typename T>
691 using I = internal::Internals;
692 if (args_[kShouldThrowOnErrorIndex] !=
693 I::IntegralToSmi(I::kInferShouldThrowMode)) {
694 return args_[kShouldThrowOnErrorIndex] != I::IntegralToSmi(I::kDontThrow);
695 }
697 reinterpret_cast<v8::internal::Isolate*>(GetIsolate()));
698}
699
700} // namespace v8
701
702#endif // INCLUDE_V8_FUNCTION_CALLBACK_H_
Definition: v8-traced-handle.h:124
Definition: v8-function-callback.h:121
ReturnValue< T > GetReturnValue() const
Definition: v8-function-callback.h:646
Local< Object > This() const
Definition: v8-function-callback.h:619
Local< Value > operator[](int i) const
Definition: v8-function-callback.h:613
Isolate * GetIsolate() const
Definition: v8-function-callback.h:641
Local< Value > NewTarget() const
Definition: v8-function-callback.h:624
friend class debug::ConsoleCallArguments
Definition: v8-function-callback.h:146
friend class internal::FunctionCallbackArguments
Definition: v8-function-callback.h:144
Local< Value > Data() const
Definition: v8-function-callback.h:635
bool IsConstructCall() const
Definition: v8-function-callback.h:651
int Length() const
Definition: v8-function-callback.h:656
Definition: v8-persistent-handle.h:349
static Local< Integer > New(Isolate *isolate, int32_t value)
static Local< Integer > NewFromUnsigned(Isolate *isolate, uint32_t value)
Definition: v8-isolate.h:291
Definition: v8-local-handle.h:366
static Local< T > New(Isolate *isolate, Local< T > that)
Definition: v8-local-handle.h:448
static Local< Number > New(Isolate *isolate, double value)
Definition: v8-object.h:262
Definition: v8-util.h:166
Definition: v8-function-callback.h:224
Local< Value > Data() const
Definition: v8-function-callback.h:666
friend class internal::PropertyCallbackArguments
Definition: v8-function-callback.h:324
bool ShouldThrowOnError() const
Definition: v8-function-callback.h:690
ReturnValue< T > GetReturnValue() const
Definition: v8-function-callback.h:685
Local< Object > HolderV2() const
Definition: v8-function-callback.h:680
friend void internal::PrintPropertyCallbackInfo(void *)
friend class MacroAssembler
Definition: v8-function-callback.h:323
Local< Object > This() const
Definition: v8-function-callback.h:675
Isolate * GetIsolate() const
Definition: v8-function-callback.h:661
Definition: v8-function-callback.h:41
void SetFalse()
Definition: v8-function-callback.h:565
void SetEmptyString()
Definition: v8-function-callback.h:581
friend class ReturnValue
Definition: v8-function-callback.h:91
void Set(const Global< S > &handle)
Definition: v8-function-callback.h:369
ReturnValue(const ReturnValue< S > &that)
Definition: v8-function-callback.h:44
void SetNonEmpty(const Global< S > &handle)
Definition: v8-function-callback.h:380
Local< Value > Get() const
Definition: v8-function-callback.h:601
void SetNull()
Definition: v8-function-callback.h:535
Isolate * GetIsolate() const
Definition: v8-function-callback.h:596
void SetUndefined()
Definition: v8-function-callback.h:550
Definition: v8-container.h:148
Definition: v8-value.h:32
internal::Address ptr() const
Definition: v8-handle-base.h:80
bool IsEmpty() const
Definition: v8-handle-base.h:60
Definition: v8-local-handle.h:75
Definition: v8-internal.h:885
static constexpr int kFrameCPSlotCount
Definition: v8-internal.h:1029
static constexpr std::optional< Address > TryIntegralToSmi(T value)
Definition: v8-internal.h:1162
v8::Local< v8::Value > GetFunctionTemplateData(v8::Isolate *isolate, v8::Local< v8::Data > raw_target)
void VerifyHandleIsNonEmpty(bool is_empty)
bool ShouldThrowOnError(internal::Isolate *isolate)
uintptr_t Address
Definition: v8-internal.h:38
void PerformCastCheck(T *data)
Definition: v8-internal.h:1457
void PrintFunctionCallbackInfo(void *function_callback_info)
Definition: libplatform.h:15
Local< Primitive > Undefined(Isolate *isolate)
Definition: v8-primitive.h:1018
void(*)(const FunctionCallbackInfo< Value > &info) FunctionCallback
Definition: v8-function-callback.h:346
#define V8_EXPORT
Definition: v8config.h:855
#define V8_INLINE
Definition: v8config.h:508
#define V8_DEPRECATED(message)
Definition: v8config.h:614
#define V8_UNLIKELY(condition)
Definition: v8config.h:668