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 // Fast primitive number setters.
61 V8_INLINE void Set(bool value);
62 V8_INLINE void Set(double i);
63 V8_INLINE void Set(int16_t i);
64 V8_INLINE void Set(int32_t i);
65 V8_INLINE void Set(int64_t i);
66 V8_INLINE void Set(uint16_t i);
67 V8_INLINE void Set(uint32_t i);
68 V8_INLINE void Set(uint64_t i);
69 // Fast JS primitive setters.
70 V8_INLINE void SetNull();
72 V8_INLINE void SetFalse();
74 // Convenience getter for the Isolate.
76
77 // Pointer setter: Uncompilable to prevent inadvertent misuse.
78 template <typename S>
79 V8_INLINE void Set(S* whatever);
80
81 // Getter. Creates a new Local<> so it comes with a certain performance
82 // hit. If the ReturnValue was not yet set, this will return the undefined
83 // value.
85
86 private:
87 template <class F>
88 friend class ReturnValue;
89 template <class F>
91 template <class F>
93 template <class F, class G, class H>
95 V8_INLINE void SetInternal(internal::Address value);
96 // Default value depends on <T>:
97 // - <void> -> true_value,
98 // - <v8::Boolean> -> true_value,
99 // - <v8::Integer> -> 0,
100 // - <v8::Value> -> undefined_value,
101 // - <v8::Array> -> undefined_value.
102 V8_INLINE void SetDefaultValue();
104
105 // See FunctionCallbackInfo.
106 static constexpr int kIsolateValueIndex = -2;
107
108 internal::Address* value_;
109};
110
117template <typename T>
119 public:
121 V8_INLINE int Length() const;
126 V8_INLINE Local<Value> operator[](int i) const;
132 V8_INLINE bool IsConstructCall() const;
139
140 private:
145
146 // TODO(ishell, http://crbug.com/326505377): in case of non-constructor
147 // call, don't pass kNewTarget and kUnused. Add IsConstructCall flag to
148 // kIsolate field.
149 static constexpr int kUnusedIndex = 0;
150 static constexpr int kIsolateIndex = 1;
151 static constexpr int kContextIndex = 2;
152 static constexpr int kReturnValueIndex = 3;
153 static constexpr int kTargetIndex = 4;
154 static constexpr int kNewTargetIndex = 5;
155 static constexpr int kArgsLength = 6;
156
157 static constexpr int kArgsLengthWithReceiver = kArgsLength + 1;
158
159 // Codegen constants:
160 static constexpr int kSize = 3 * internal::kApiSystemPointerSize;
161 static constexpr int kImplicitArgsOffset = 0;
162 static constexpr int kValuesOffset =
163 kImplicitArgsOffset + internal::kApiSystemPointerSize;
164 static constexpr int kLengthOffset =
165 kValuesOffset + internal::kApiSystemPointerSize;
166
167 static constexpr int kThisValuesIndex = -1;
169 kIsolateIndex - kReturnValueIndex);
170
172 internal::Address* values, int length);
173
174 // TODO(https://crbug.com/326505377): flatten the v8::FunctionCallbackInfo
175 // object to avoid indirect loads through values_ and implicit_args_ and
176 // reduce the number of instructions in the CallApiCallback builtin.
177 internal::Address* implicit_args_;
178 internal::Address* values_;
179 internal::Address length_;
180};
181
186template <typename T>
188 public:
193
200
243 "Access to receiver will be deprecated soon. Use HolderV2() instead. \n"
244 "See http://crbug.com/455600234. ")
246
256
266
275
276 private:
277 template <typename U>
279 friend class MacroAssembler;
280 friend class internal::PropertyCallbackArguments;
281 friend class internal::CustomArguments<PropertyCallbackInfo>;
282 friend void internal::PrintPropertyCallbackInfo(void*);
283
284 static constexpr int kPropertyKeyIndex = 0;
285 static constexpr int kShouldThrowOnErrorIndex = 1;
286 // TODO(http://crbug.com/333672197): drop this in favor of HolderV2.
287 static constexpr int kHolderIndex = 2;
288 static constexpr int kIsolateIndex = 3;
289 static constexpr int kHolderV2Index = 4;
290 static constexpr int kReturnValueIndex = 5;
291 static constexpr int kDataIndex = 6;
292 static constexpr int kThisIndex = 7;
293 static constexpr int kArgsLength = 8;
294
295 static constexpr int kSize = kArgsLength * internal::kApiSystemPointerSize;
296
297 PropertyCallbackInfo() = default;
298
299 mutable internal::Address args_[kArgsLength];
300};
301
302using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
303
304// --- Implementation ---
305
306template <typename T>
307ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
308
309template <typename T>
310void ReturnValue<T>::SetInternal(internal::Address value) {
311#if V8_STATIC_ROOTS_BOOL
312 using I = internal::Internals;
313 // Ensure that the upper 32-bits are not modified. Compiler should be
314 // able to optimize this to a store of a lower 32-bits of the value.
315 // This is fine since the callback can return only JavaScript values which
316 // are either Smis or heap objects allocated in the main cage.
317 *value_ = I::DecompressTaggedField(*value_, I::CompressTagged(value));
318#else
319 *value_ = value;
320#endif // V8_STATIC_ROOTS_BOOL
321}
322
323template <typename T>
324template <typename S>
325void ReturnValue<T>::Set(const Global<S>& handle) {
326 static_assert(std::is_base_of_v<T, S>, "type check");
327 if (V8_UNLIKELY(handle.IsEmpty())) {
328 SetDefaultValue();
329 } else {
330 SetInternal(handle.ptr());
331 }
332}
333
334template <typename T>
335template <typename S>
337 static_assert(std::is_base_of_v<T, S>, "type check");
338#ifdef V8_ENABLE_CHECKS
340#endif // V8_ENABLE_CHECKS
341 SetInternal(handle.ptr());
342}
343
344template <typename T>
345template <typename S>
347 static_assert(std::is_base_of_v<T, S>, "type check");
348 if (V8_UNLIKELY(handle.IsEmpty())) {
349 SetDefaultValue();
350 } else {
351 SetInternal(handle.ptr());
352 }
353}
354
355template <typename T>
356template <typename S>
358 static_assert(std::is_base_of_v<T, S>, "type check");
359#ifdef V8_ENABLE_CHECKS
361#endif // V8_ENABLE_CHECKS
362 SetInternal(handle.ptr());
363}
364
365template <typename T>
366template <typename S>
367void ReturnValue<T>::Set(const Local<S> handle) {
368 // "V8_DEPRECATE_SOON" this method if |T| is |void|.
369#ifdef V8_IMMINENT_DEPRECATION_WARNINGS
370 static constexpr bool is_allowed_void = false;
371 static_assert(!std::is_void_v<T>,
372 "ReturnValue<void>::Set(const Local<S>) is deprecated. "
373 "Do nothing to indicate that the operation succeeded or use "
374 "SetFalse() to indicate that the operation failed (don't "
375 "forget to handle info.ShouldThrowOnError()). "
376 "See http://crbug.com/348660658 for details.");
377#else
378 static constexpr bool is_allowed_void = std::is_void_v<T>;
379#endif // V8_IMMINENT_DEPRECATION_WARNINGS
380 static_assert(is_allowed_void || std::is_base_of_v<T, S>, "type check");
381 if (V8_UNLIKELY(handle.IsEmpty())) {
382 SetDefaultValue();
383 } else if constexpr (is_allowed_void) {
384 // Simulate old behaviour for "v8::AccessorSetterCallback" for which
385 // it was possible to set the return value even for ReturnValue<void>.
386 Set(handle->BooleanValue(GetIsolate()));
387 } else {
388 SetInternal(handle.ptr());
389 }
390}
391
392template <typename T>
393template <typename S>
395 // "V8_DEPRECATE_SOON" this method if |T| is |void|.
396#ifdef V8_IMMINENT_DEPRECATION_WARNINGS
397 static constexpr bool is_allowed_void = false;
398 static_assert(!std::is_void_v<T>,
399 "ReturnValue<void>::SetNonEmpty(const Local<S>) is deprecated. "
400 "Do nothing to indicate that the operation succeeded or use "
401 "SetFalse() to indicate that the operation failed (don't "
402 "forget to handle info.ShouldThrowOnError()). "
403 "See http://crbug.com/348660658 for details.");
404#else
405 static constexpr bool is_allowed_void = std::is_void_v<T>;
406#endif // V8_IMMINENT_DEPRECATION_WARNINGS
407 static_assert(is_allowed_void || std::is_base_of_v<T, S>, "type check");
408#ifdef V8_ENABLE_CHECKS
410#endif // V8_ENABLE_CHECKS
411 if constexpr (is_allowed_void) {
412 // Simulate old behaviour for "v8::AccessorSetterCallback" for which
413 // it was possible to set the return value even for ReturnValue<void>.
414 Set(handle->BooleanValue(GetIsolate()));
415 } else {
416 SetInternal(handle.ptr());
417 }
418}
419
420template <typename T>
421void ReturnValue<T>::Set(double i) {
422 static_assert(std::is_base_of_v<T, Number>, "type check");
423 SetNonEmpty(Number::New(GetIsolate(), i));
424}
425
426template <typename T>
427void ReturnValue<T>::Set(int16_t i) {
428 static_assert(std::is_base_of_v<T, Integer>, "type check");
429 using I = internal::Internals;
430 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::min()));
431 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::max()));
432 SetInternal(I::IntegralToSmi(i));
433}
434
435template <typename T>
436void ReturnValue<T>::Set(int32_t i) {
437 static_assert(std::is_base_of_v<T, Integer>, "type check");
438 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
439 SetInternal(*result);
440 return;
441 }
442 SetNonEmpty(Integer::New(GetIsolate(), i));
443}
444
445template <typename T>
446void ReturnValue<T>::Set(int64_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(Number::New(GetIsolate(), static_cast<double>(i)));
453}
454
455template <typename T>
456void ReturnValue<T>::Set(uint16_t i) {
457 static_assert(std::is_base_of_v<T, Integer>, "type check");
458 using I = internal::Internals;
459 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::min()));
460 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::max()));
461 SetInternal(I::IntegralToSmi(i));
462}
463
464template <typename T>
465void ReturnValue<T>::Set(uint32_t i) {
466 static_assert(std::is_base_of_v<T, Integer>, "type check");
467 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
468 SetInternal(*result);
469 return;
470 }
471 SetNonEmpty(Integer::NewFromUnsigned(GetIsolate(), i));
472}
473
474template <typename T>
475void ReturnValue<T>::Set(uint64_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(Number::New(GetIsolate(), static_cast<double>(i)));
482}
483
484template <typename T>
485void ReturnValue<T>::Set(bool value) {
486 static_assert(std::is_void_v<T> || std::is_base_of_v<T, Boolean>,
487 "type check");
488 using I = internal::Internals;
489#if V8_STATIC_ROOTS_BOOL
490#ifdef V8_ENABLE_CHECKS
492 internal::ValueHelper::SlotAsValue<Value, true>(value_));
493#endif // V8_ENABLE_CHECKS
494 SetInternal(value ? I::StaticReadOnlyRoot::kTrueValue
495 : I::StaticReadOnlyRoot::kFalseValue);
496#else
497 int root_index;
498 if (value) {
499 root_index = I::kTrueValueRootIndex;
500 } else {
501 root_index = I::kFalseValueRootIndex;
502 }
503 *value_ = I::GetRoot(GetIsolate(), root_index);
504#endif // V8_STATIC_ROOTS_BOOL
505}
506
507template <typename T>
509 using I = internal::Internals;
510 if constexpr (std::is_same_v<void, T> || std::is_same_v<v8::Boolean, T>) {
511 Set(true);
512 } else if constexpr (std::is_same_v<v8::Integer, T>) {
513 SetInternal(I::IntegralToSmi(0));
514 } else {
515 static_assert(std::is_same_v<v8::Value, T> || std::is_same_v<v8::Array, T>);
516#if V8_STATIC_ROOTS_BOOL
517 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
518#else
519 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
520#endif // V8_STATIC_ROOTS_BOOL
521 }
522}
523
524template <typename T>
526 static_assert(std::is_base_of_v<T, Primitive>, "type check");
527 using I = internal::Internals;
528#if V8_STATIC_ROOTS_BOOL
529#ifdef V8_ENABLE_CHECKS
531 internal::ValueHelper::SlotAsValue<Value, true>(value_));
532#endif // V8_ENABLE_CHECKS
533 SetInternal(I::StaticReadOnlyRoot::kNullValue);
534#else
535 *value_ = I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
536#endif // V8_STATIC_ROOTS_BOOL
537}
538
539template <typename T>
541 static_assert(std::is_base_of_v<T, Primitive>, "type check");
542 using I = internal::Internals;
543#if V8_STATIC_ROOTS_BOOL
544#ifdef V8_ENABLE_CHECKS
546 internal::ValueHelper::SlotAsValue<Value, true>(value_));
547#endif // V8_ENABLE_CHECKS
548 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
549#else
550 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
551#endif // V8_STATIC_ROOTS_BOOL
552}
553
554template <typename T>
556 static_assert(std::is_void_v<T> || std::is_base_of_v<T, Boolean>,
557 "type check");
558 using I = internal::Internals;
559#if V8_STATIC_ROOTS_BOOL
560#ifdef V8_ENABLE_CHECKS
562 internal::ValueHelper::SlotAsValue<Value, true>(value_));
563#endif // V8_ENABLE_CHECKS
564 SetInternal(I::StaticReadOnlyRoot::kFalseValue);
565#else
566 *value_ = I::GetRoot(GetIsolate(), I::kFalseValueRootIndex);
567#endif // V8_STATIC_ROOTS_BOOL
568}
569
570template <typename T>
572 static_assert(std::is_base_of_v<T, String>, "type check");
573 using I = internal::Internals;
574#if V8_STATIC_ROOTS_BOOL
575#ifdef V8_ENABLE_CHECKS
577 internal::ValueHelper::SlotAsValue<Value, true>(value_));
578#endif // V8_ENABLE_CHECKS
579 SetInternal(I::StaticReadOnlyRoot::kEmptyString);
580#else
581 *value_ = I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
582#endif // V8_STATIC_ROOTS_BOOL
583}
584
585template <typename T>
587 return *reinterpret_cast<Isolate**>(&value_[kIsolateValueIndex]);
588}
589
590template <typename T>
593 internal::ValueHelper::SlotAsValue<Value>(value_));
594}
595
596template <typename T>
597template <typename S>
598void ReturnValue<T>::Set(S* whatever) {
599 static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
600}
601
602template <typename T>
604 internal::Address* values,
605 int length)
606 : implicit_args_(implicit_args), values_(values), length_(length) {}
607
608template <typename T>
610 // values_ points to the first argument (not the receiver).
611 if (i < 0 || Length() <= i) return Undefined(GetIsolate());
612 return Local<Value>::FromSlot(values_ + i);
613}
614
615template <typename T>
617 // values_ points to the first argument (not the receiver).
618 return Local<Object>::FromSlot(values_ + kThisValuesIndex);
619}
620
621template <typename T>
623 return Local<Value>::FromSlot(&implicit_args_[kNewTargetIndex]);
624}
625
626template <typename T>
628 auto target = Local<v8::Data>::FromSlot(&implicit_args_[kTargetIndex]);
629 return api_internal::GetFunctionTemplateData(GetIsolate(), target);
630}
631
632template <typename T>
634 return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
635}
636
637template <typename T>
639 return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
640}
641
642template <typename T>
644 return !NewTarget()->IsUndefined();
645}
646
647template <typename T>
649 return static_cast<int>(length_);
650}
651
652template <typename T>
654 return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
655}
656
657template <typename T>
659 return Local<Value>::FromSlot(&args_[kDataIndex]);
660}
661
662template <typename T>
664 return Local<Object>::FromSlot(&args_[kThisIndex]);
665}
666
667namespace api_internal {
668// Returns JSGlobalProxy if holder is JSGlobalObject or unmodified holder
669// otherwise.
671 internal::Address holder);
672} // namespace api_internal
673
674template <typename T>
676 using I = internal::Internals;
677 if (!I::HasHeapObjectTag(args_[kHolderV2Index])) {
678 args_[kHolderV2Index] =
680 }
681 return Local<Object>::FromSlot(&args_[kHolderV2Index]);
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:118
ReturnValue< T > GetReturnValue() const
Definition: v8-function-callback.h:638
Local< Object > This() const
Definition: v8-function-callback.h:616
Local< Value > operator[](int i) const
Definition: v8-function-callback.h:609
Isolate * GetIsolate() const
Definition: v8-function-callback.h:633
Local< Value > NewTarget() const
Definition: v8-function-callback.h:622
friend class debug::ConsoleCallArguments
Definition: v8-function-callback.h:143
friend class internal::FunctionCallbackArguments
Definition: v8-function-callback.h:141
Local< Value > Data() const
Definition: v8-function-callback.h:627
bool IsConstructCall() const
Definition: v8-function-callback.h:643
int Length() const
Definition: v8-function-callback.h:648
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:234
Definition: v8-util.h:166
Definition: v8-function-callback.h:187
Local< Value > Data() const
Definition: v8-function-callback.h:658
friend class internal::PropertyCallbackArguments
Definition: v8-function-callback.h:280
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:675
friend void internal::PrintPropertyCallbackInfo(void *)
friend class MacroAssembler
Definition: v8-function-callback.h:279
Local< Object > This() const
Definition: v8-function-callback.h:663
Isolate * GetIsolate() const
Definition: v8-function-callback.h:653
Definition: v8-function-callback.h:41
void SetFalse()
Definition: v8-function-callback.h:555
void SetEmptyString()
Definition: v8-function-callback.h:571
friend class ReturnValue
Definition: v8-function-callback.h:88
void Set(const Global< S > &handle)
Definition: v8-function-callback.h:325
ReturnValue(const ReturnValue< S > &that)
Definition: v8-function-callback.h:44
void SetNonEmpty(const Global< S > &handle)
Definition: v8-function-callback.h:336
Local< Value > Get() const
Definition: v8-function-callback.h:591
void SetNull()
Definition: v8-function-callback.h:525
Isolate * GetIsolate() const
Definition: v8-function-callback.h:586
void SetUndefined()
Definition: v8-function-callback.h:540
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:878
static constexpr std::optional< Address > TryIntegralToSmi(T value)
Definition: v8-internal.h:1148
v8::Local< v8::Value > GetFunctionTemplateData(v8::Isolate *isolate, v8::Local< v8::Data > raw_target)
internal::Address ConvertToJSGlobalProxyIfNecessary(internal::Address holder)
const int kApiSystemPointerSize
Definition: v8-internal.h:51
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:1443
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:302
#define V8_EXPORT
Definition: v8config.h:855
#define V8_INLINE
Definition: v8config.h:508
#define V8_DEPRECATE_SOON(message)
Definition: v8config.h:622
#define V8_UNLIKELY(condition)
Definition: v8config.h:668