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
253
263
272
273 private:
274 template <typename U>
276 friend class MacroAssembler;
280
281 static constexpr int kPropertyKeyIndex = 0;
282 static constexpr int kShouldThrowOnErrorIndex = 1;
283 // TODO(http://crbug.com/333672197): drop this in favor of HolderV2.
284 static constexpr int kHolderIndex = 2;
285 static constexpr int kIsolateIndex = 3;
286 static constexpr int kHolderV2Index = 4;
287 static constexpr int kReturnValueIndex = 5;
288 static constexpr int kDataIndex = 6;
289 static constexpr int kThisIndex = 7;
290 static constexpr int kArgsLength = 8;
291
292 static constexpr int kSize = kArgsLength * internal::kApiSystemPointerSize;
293
294 PropertyCallbackInfo() = default;
295
296 mutable internal::Address args_[kArgsLength];
297};
298
299using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
300
301// --- Implementation ---
302
303template <typename T>
304ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
305
306template <typename T>
307void ReturnValue<T>::SetInternal(internal::Address value) {
308#if V8_STATIC_ROOTS_BOOL
309 using I = internal::Internals;
310 // Ensure that the upper 32-bits are not modified. Compiler should be
311 // able to optimize this to a store of a lower 32-bits of the value.
312 // This is fine since the callback can return only JavaScript values which
313 // are either Smis or heap objects allocated in the main cage.
314 *value_ = I::DecompressTaggedField(*value_, I::CompressTagged(value));
315#else
316 *value_ = value;
317#endif // V8_STATIC_ROOTS_BOOL
318}
319
320template <typename T>
321template <typename S>
322void ReturnValue<T>::Set(const Global<S>& handle) {
323 static_assert(std::is_base_of_v<T, S>, "type check");
324 if (V8_UNLIKELY(handle.IsEmpty())) {
325 SetDefaultValue();
326 } else {
327 SetInternal(handle.ptr());
328 }
329}
330
331template <typename T>
332template <typename S>
334 static_assert(std::is_base_of_v<T, S>, "type check");
335#ifdef V8_ENABLE_CHECKS
336 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
337#endif // V8_ENABLE_CHECKS
338 SetInternal(handle.ptr());
339}
340
341template <typename T>
342template <typename S>
344 static_assert(std::is_base_of_v<T, S>, "type check");
345 if (V8_UNLIKELY(handle.IsEmpty())) {
346 SetDefaultValue();
347 } else {
348 SetInternal(handle.ptr());
349 }
350}
351
352template <typename T>
353template <typename S>
355 static_assert(std::is_base_of_v<T, S>, "type check");
356#ifdef V8_ENABLE_CHECKS
357 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
358#endif // V8_ENABLE_CHECKS
359 SetInternal(handle.ptr());
360}
361
362template <typename T>
363template <typename S>
364void ReturnValue<T>::Set(const Local<S> handle) {
365 // "V8_DEPRECATE_SOON" this method if |T| is |void|.
366#ifdef V8_IMMINENT_DEPRECATION_WARNINGS
367 static constexpr bool is_allowed_void = false;
368 static_assert(!std::is_void_v<T>,
369 "ReturnValue<void>::Set(const Local<S>) is deprecated. "
370 "Do nothing to indicate that the operation succeeded or use "
371 "SetFalse() to indicate that the operation failed (don't "
372 "forget to handle info.ShouldThrowOnError()). "
373 "See http://crbug.com/348660658 for details.");
374#else
375 static constexpr bool is_allowed_void = std::is_void_v<T>;
376#endif // V8_IMMINENT_DEPRECATION_WARNINGS
377 static_assert(is_allowed_void || std::is_base_of_v<T, S>, "type check");
378 if (V8_UNLIKELY(handle.IsEmpty())) {
379 SetDefaultValue();
380 } else if constexpr (is_allowed_void) {
381 // Simulate old behaviour for "v8::AccessorSetterCallback" for which
382 // it was possible to set the return value even for ReturnValue<void>.
383 Set(handle->BooleanValue(GetIsolate()));
384 } else {
385 SetInternal(handle.ptr());
386 }
387}
388
389template <typename T>
390template <typename S>
392 // "V8_DEPRECATE_SOON" this method if |T| is |void|.
393#ifdef V8_IMMINENT_DEPRECATION_WARNINGS
394 static constexpr bool is_allowed_void = false;
395 static_assert(!std::is_void_v<T>,
396 "ReturnValue<void>::SetNonEmpty(const Local<S>) is deprecated. "
397 "Do nothing to indicate that the operation succeeded or use "
398 "SetFalse() to indicate that the operation failed (don't "
399 "forget to handle info.ShouldThrowOnError()). "
400 "See http://crbug.com/348660658 for details.");
401#else
402 static constexpr bool is_allowed_void = std::is_void_v<T>;
403#endif // V8_IMMINENT_DEPRECATION_WARNINGS
404 static_assert(is_allowed_void || std::is_base_of_v<T, S>, "type check");
405#ifdef V8_ENABLE_CHECKS
406 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
407#endif // V8_ENABLE_CHECKS
408 if constexpr (is_allowed_void) {
409 // Simulate old behaviour for "v8::AccessorSetterCallback" for which
410 // it was possible to set the return value even for ReturnValue<void>.
411 Set(handle->BooleanValue(GetIsolate()));
412 } else {
413 SetInternal(handle.ptr());
414 }
415}
416
417template <typename T>
418void ReturnValue<T>::Set(double i) {
419 static_assert(std::is_base_of_v<T, Number>, "type check");
420 SetNonEmpty(Number::New(GetIsolate(), i));
421}
422
423template <typename T>
424void ReturnValue<T>::Set(int16_t i) {
425 static_assert(std::is_base_of_v<T, Integer>, "type check");
426 using I = internal::Internals;
427 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::min()));
428 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::max()));
429 SetInternal(I::IntegralToSmi(i));
430}
431
432template <typename T>
433void ReturnValue<T>::Set(int32_t i) {
434 static_assert(std::is_base_of_v<T, Integer>, "type check");
435 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
436 SetInternal(*result);
437 return;
438 }
439 SetNonEmpty(Integer::New(GetIsolate(), i));
440}
441
442template <typename T>
443void ReturnValue<T>::Set(int64_t i) {
444 static_assert(std::is_base_of_v<T, Integer>, "type check");
445 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
446 SetInternal(*result);
447 return;
448 }
449 SetNonEmpty(Number::New(GetIsolate(), static_cast<double>(i)));
450}
451
452template <typename T>
453void ReturnValue<T>::Set(uint16_t i) {
454 static_assert(std::is_base_of_v<T, Integer>, "type check");
455 using I = internal::Internals;
456 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::min()));
457 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::max()));
458 SetInternal(I::IntegralToSmi(i));
459}
460
461template <typename T>
462void ReturnValue<T>::Set(uint32_t i) {
463 static_assert(std::is_base_of_v<T, Integer>, "type check");
464 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
465 SetInternal(*result);
466 return;
467 }
468 SetNonEmpty(Integer::NewFromUnsigned(GetIsolate(), i));
469}
470
471template <typename T>
472void ReturnValue<T>::Set(uint64_t i) {
473 static_assert(std::is_base_of_v<T, Integer>, "type check");
474 if (const auto result = internal::Internals::TryIntegralToSmi(i)) {
475 SetInternal(*result);
476 return;
477 }
478 SetNonEmpty(Number::New(GetIsolate(), static_cast<double>(i)));
479}
480
481template <typename T>
482void ReturnValue<T>::Set(bool value) {
483 static_assert(std::is_void_v<T> || std::is_base_of_v<T, Boolean>,
484 "type check");
485 using I = internal::Internals;
486#if V8_STATIC_ROOTS_BOOL
487#ifdef V8_ENABLE_CHECKS
488 internal::PerformCastCheck(
489 internal::ValueHelper::SlotAsValue<Value, true>(value_));
490#endif // V8_ENABLE_CHECKS
491 SetInternal(value ? I::StaticReadOnlyRoot::kTrueValue
492 : I::StaticReadOnlyRoot::kFalseValue);
493#else
494 int root_index;
495 if (value) {
496 root_index = I::kTrueValueRootIndex;
497 } else {
498 root_index = I::kFalseValueRootIndex;
499 }
500 *value_ = I::GetRoot(GetIsolate(), root_index);
501#endif // V8_STATIC_ROOTS_BOOL
502}
503
504template <typename T>
506 using I = internal::Internals;
507 if constexpr (std::is_same_v<void, T> || std::is_same_v<v8::Boolean, T>) {
508 Set(true);
509 } else if constexpr (std::is_same_v<v8::Integer, T>) {
510 SetInternal(I::IntegralToSmi(0));
511 } else {
512 static_assert(std::is_same_v<v8::Value, T> || std::is_same_v<v8::Array, T>);
513#if V8_STATIC_ROOTS_BOOL
514 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
515#else
516 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
517#endif // V8_STATIC_ROOTS_BOOL
518 }
519}
520
521template <typename T>
523 static_assert(std::is_base_of_v<T, Primitive>, "type check");
524 using I = internal::Internals;
525#if V8_STATIC_ROOTS_BOOL
526#ifdef V8_ENABLE_CHECKS
527 internal::PerformCastCheck(
528 internal::ValueHelper::SlotAsValue<Value, true>(value_));
529#endif // V8_ENABLE_CHECKS
530 SetInternal(I::StaticReadOnlyRoot::kNullValue);
531#else
532 *value_ = I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
533#endif // V8_STATIC_ROOTS_BOOL
534}
535
536template <typename T>
538 static_assert(std::is_base_of_v<T, Primitive>, "type check");
539 using I = internal::Internals;
540#if V8_STATIC_ROOTS_BOOL
541#ifdef V8_ENABLE_CHECKS
542 internal::PerformCastCheck(
543 internal::ValueHelper::SlotAsValue<Value, true>(value_));
544#endif // V8_ENABLE_CHECKS
545 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
546#else
547 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
548#endif // V8_STATIC_ROOTS_BOOL
549}
550
551template <typename T>
553 static_assert(std::is_void_v<T> || std::is_base_of_v<T, Boolean>,
554 "type check");
555 using I = internal::Internals;
556#if V8_STATIC_ROOTS_BOOL
557#ifdef V8_ENABLE_CHECKS
558 internal::PerformCastCheck(
559 internal::ValueHelper::SlotAsValue<Value, true>(value_));
560#endif // V8_ENABLE_CHECKS
561 SetInternal(I::StaticReadOnlyRoot::kFalseValue);
562#else
563 *value_ = I::GetRoot(GetIsolate(), I::kFalseValueRootIndex);
564#endif // V8_STATIC_ROOTS_BOOL
565}
566
567template <typename T>
569 static_assert(std::is_base_of_v<T, String>, "type check");
570 using I = internal::Internals;
571#if V8_STATIC_ROOTS_BOOL
572#ifdef V8_ENABLE_CHECKS
573 internal::PerformCastCheck(
574 internal::ValueHelper::SlotAsValue<Value, true>(value_));
575#endif // V8_ENABLE_CHECKS
576 SetInternal(I::StaticReadOnlyRoot::kEmptyString);
577#else
578 *value_ = I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
579#endif // V8_STATIC_ROOTS_BOOL
580}
581
582template <typename T>
584 return *reinterpret_cast<Isolate**>(&value_[kIsolateValueIndex]);
585}
586
587template <typename T>
589 return Local<Value>::New(GetIsolate(),
590 internal::ValueHelper::SlotAsValue<Value>(value_));
591}
592
593template <typename T>
594template <typename S>
595void ReturnValue<T>::Set(S* whatever) {
596 static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
597}
598
599template <typename T>
601 internal::Address* values,
602 int length)
603 : implicit_args_(implicit_args), values_(values), length_(length) {}
604
605template <typename T>
607 // values_ points to the first argument (not the receiver).
608 if (i < 0 || Length() <= i) return Undefined(GetIsolate());
609 return Local<Value>::FromSlot(values_ + i);
610}
611
612template <typename T>
614 // values_ points to the first argument (not the receiver).
615 return Local<Object>::FromSlot(values_ + kThisValuesIndex);
616}
617
618template <typename T>
620 return Local<Value>::FromSlot(&implicit_args_[kNewTargetIndex]);
621}
622
623template <typename T>
625 auto target = Local<v8::Data>::FromSlot(&implicit_args_[kTargetIndex]);
626 return api_internal::GetFunctionTemplateData(GetIsolate(), target);
627}
628
629template <typename T>
631 return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
632}
633
634template <typename T>
636 return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
637}
638
639template <typename T>
641 return !NewTarget()->IsUndefined();
642}
643
644template <typename T>
646 return static_cast<int>(length_);
647}
648
649template <typename T>
651 return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
652}
653
654template <typename T>
656 return Local<Value>::FromSlot(&args_[kDataIndex]);
657}
658
659template <typename T>
661 return Local<Object>::FromSlot(&args_[kThisIndex]);
662}
663
664namespace api_internal {
665// Returns JSGlobalProxy if holder is JSGlobalObject or unmodified holder
666// otherwise.
668 internal::Address holder);
669} // namespace api_internal
670
671template <typename T>
673 using I = internal::Internals;
674 if (!I::HasHeapObjectTag(args_[kHolderV2Index])) {
675 args_[kHolderV2Index] =
677 }
678 return Local<Object>::FromSlot(&args_[kHolderV2Index]);
679}
680
681template <typename T>
683 return ReturnValue<T>(&args_[kReturnValueIndex]);
684}
685
686template <typename T>
688 using I = internal::Internals;
689 if (args_[kShouldThrowOnErrorIndex] !=
690 I::IntegralToSmi(I::kInferShouldThrowMode)) {
691 return args_[kShouldThrowOnErrorIndex] != I::IntegralToSmi(I::kDontThrow);
692 }
694 reinterpret_cast<v8::internal::Isolate*>(GetIsolate()));
695}
696
697} // namespace v8
698
699#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:635
Local< Object > This() const
Definition: v8-function-callback.h:613
Local< Value > operator[](int i) const
Definition: v8-function-callback.h:606
Isolate * GetIsolate() const
Definition: v8-function-callback.h:630
Local< Value > NewTarget() const
Definition: v8-function-callback.h:619
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:624
bool IsConstructCall() const
Definition: v8-function-callback.h:640
int Length() const
Definition: v8-function-callback.h:645
Definition: v8-persistent-handle.h:349
Definition: v8-isolate.h:291
Definition: v8-local-handle.h:366
Definition: v8-util.h:166
Definition: v8-function-callback.h:187
Local< Value > Data() const
Definition: v8-function-callback.h:655
friend class internal::PropertyCallbackArguments
Definition: v8-function-callback.h:277
friend class PropertyCallbackInfo
Definition: v8-function-callback.h:275
bool ShouldThrowOnError() const
Definition: v8-function-callback.h:687
ReturnValue< T > GetReturnValue() const
Definition: v8-function-callback.h:682
Local< Object > HolderV2() const
Definition: v8-function-callback.h:672
friend class MacroAssembler
Definition: v8-function-callback.h:276
Local< Object > This() const
Definition: v8-function-callback.h:660
Isolate * GetIsolate() const
Definition: v8-function-callback.h:650
Definition: v8-function-callback.h:41
void SetFalse()
Definition: v8-function-callback.h:552
void SetEmptyString()
Definition: v8-function-callback.h:568
friend class ReturnValue
Definition: v8-function-callback.h:88
ReturnValue(const ReturnValue< S > &that)
Definition: v8-function-callback.h:44
void SetNonEmpty(const Global< S > &handle)
Definition: v8-function-callback.h:333
Local< Value > Get() const
Definition: v8-function-callback.h:588
void SetNull()
Definition: v8-function-callback.h:522
Isolate * GetIsolate() const
Definition: v8-function-callback.h:583
void SetUndefined()
Definition: v8-function-callback.h:537
Definition: v8-container.h:148
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
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 PrintPropertyCallbackInfo(void *property_callback_info)
bool ShouldThrowOnError(internal::Isolate *isolate)
uintptr_t Address
Definition: v8-internal.h:38
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:299
#define V8_EXPORT
Definition: v8config.h:855
#define V8_INLINE
Definition: v8config.h:508
#define V8_UNLIKELY(condition)
Definition: v8config.h:668