v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
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>
41class ReturnValue {
42 public:
43 template <class S>
45 static_assert(std::is_base_of<T, S>::value, "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>
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 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>
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.
104
105 // See FunctionCallbackInfo.
106 static constexpr int kIsolateValueIndex = -2;
107
109};
110
117template <typename T>
119 public:
121 V8_INLINE int Length() 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 =
164 static constexpr int kLengthOffset =
166
167 static constexpr int kThisValuesIndex = -1;
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.
180};
181
186template <typename T>
188 public:
193
200
243
254 "V8 will stop providing access to hidden prototype (i.e. "
255 "JSGlobalObject). Use HolderV2() instead. \n"
256 "DO NOT try to workaround this by accessing JSGlobalObject via "
257 "v8::Object::GetPrototype() - it'll be deprecated soon too. \n"
258 "See http://crbug.com/333672197. ")
259 V8_INLINE Local<Object> Holder() const;
260
269
279
287 V8_INLINE bool ShouldThrowOnError() const;
288
289 private:
290 template <typename U>
292 friend class MacroAssembler;
293 friend class internal::PropertyCallbackArguments;
294 friend class internal::CustomArguments<PropertyCallbackInfo>;
295 friend void internal::PrintPropertyCallbackInfo(void*);
296
297 static constexpr int kPropertyKeyIndex = 0;
298 static constexpr int kShouldThrowOnErrorIndex = 1;
299 static constexpr int kHolderIndex = 2;
300 static constexpr int kIsolateIndex = 3;
301 static constexpr int kHolderV2Index = 4;
302 static constexpr int kReturnValueIndex = 5;
303 static constexpr int kDataIndex = 6;
304 static constexpr int kThisIndex = 7;
305 static constexpr int kArgsLength = 8;
306
307 static constexpr int kSize = kArgsLength * internal::kApiSystemPointerSize;
308
310
311 mutable internal::Address args_[kArgsLength];
312};
313
314using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
315
316// --- Implementation ---
317
318template <typename T>
319ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
320
321template <typename T>
323#if V8_STATIC_ROOTS_BOOL
324 using I = internal::Internals;
325 // Ensure that the upper 32-bits are not modified. Compiler should be
326 // able to optimize this to a store of a lower 32-bits of the value.
327 // This is fine since the callback can return only JavaScript values which
328 // are either Smis or heap objects allocated in the main cage.
329 *value_ = I::DecompressTaggedField(*value_, I::CompressTagged(value));
330#else
331 *value_ = value;
332#endif // V8_STATIC_ROOTS_BOOL
333}
334
335template <typename T>
336template <typename S>
337void ReturnValue<T>::Set(const Global<S>& handle) {
338 static_assert(std::is_base_of<T, S>::value, "type check");
339 if (V8_UNLIKELY(handle.IsEmpty())) {
340 SetDefaultValue();
341 } else {
342 SetInternal(handle.ptr());
343 }
344}
345
346template <typename T>
347template <typename S>
349 static_assert(std::is_base_of<T, S>::value, "type check");
350#ifdef V8_ENABLE_CHECKS
351 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
352#endif // V8_ENABLE_CHECKS
353 SetInternal(handle.ptr());
354}
355
356template <typename T>
357template <typename S>
359 static_assert(std::is_base_of<T, S>::value, "type check");
360 if (V8_UNLIKELY(handle.IsEmpty())) {
361 SetDefaultValue();
362 } else {
363 SetInternal(handle.ptr());
364 }
365}
366
367template <typename T>
368template <typename S>
370 static_assert(std::is_base_of<T, S>::value, "type check");
371#ifdef V8_ENABLE_CHECKS
372 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
373#endif // V8_ENABLE_CHECKS
374 SetInternal(handle.ptr());
375}
376
377template <typename T>
378template <typename S>
379void ReturnValue<T>::Set(const Local<S> handle) {
380 // "V8_DEPRECATE_SOON" this method if |T| is |void|.
381#ifdef V8_IMMINENT_DEPRECATION_WARNINGS
382 static constexpr bool is_allowed_void = false;
383 static_assert(!std::is_void<T>::value,
384 "ReturnValue<void>::Set(const Local<S>) is deprecated. "
385 "Do nothing to indicate that the operation succeeded or use "
386 "SetFalse() to indicate that the operation failed (don't "
387 "forget to handle info.ShouldThrowOnError()). "
388 "See http://crbug.com/348660658 for details.");
389#else
390 static constexpr bool is_allowed_void = std::is_void<T>::value;
391#endif // V8_IMMINENT_DEPRECATION_WARNINGS
392 static_assert(is_allowed_void || std::is_base_of<T, S>::value, "type check");
393 if (V8_UNLIKELY(handle.IsEmpty())) {
394 SetDefaultValue();
395 } else if constexpr (is_allowed_void) {
396 // Simulate old behaviour for "v8::AccessorSetterCallback" for which
397 // it was possible to set the return value even for ReturnValue<void>.
398 Set(handle->BooleanValue(GetIsolate()));
399 } else {
400 SetInternal(handle.ptr());
401 }
402}
403
404template <typename T>
405template <typename S>
407 // "V8_DEPRECATE_SOON" this method if |T| is |void|.
408#ifdef V8_IMMINENT_DEPRECATION_WARNINGS
409 static constexpr bool is_allowed_void = false;
410 static_assert(!std::is_void<T>::value,
411 "ReturnValue<void>::SetNonEmpty(const Local<S>) is deprecated. "
412 "Do nothing to indicate that the operation succeeded or use "
413 "SetFalse() to indicate that the operation failed (don't "
414 "forget to handle info.ShouldThrowOnError()). "
415 "See http://crbug.com/348660658 for details.");
416#else
417 static constexpr bool is_allowed_void = std::is_void<T>::value;
418#endif // V8_IMMINENT_DEPRECATION_WARNINGS
419 static_assert(is_allowed_void || std::is_base_of<T, S>::value, "type check");
420#ifdef V8_ENABLE_CHECKS
421 internal::VerifyHandleIsNonEmpty(handle.IsEmpty());
422#endif // V8_ENABLE_CHECKS
423 if constexpr (is_allowed_void) {
424 // Simulate old behaviour for "v8::AccessorSetterCallback" for which
425 // it was possible to set the return value even for ReturnValue<void>.
426 Set(handle->BooleanValue(GetIsolate()));
427 } else {
428 SetInternal(handle.ptr());
429 }
430}
431
432template <typename T>
433void ReturnValue<T>::Set(double i) {
434 static_assert(std::is_base_of<T, Number>::value, "type check");
435 SetNonEmpty(Number::New(GetIsolate(), i));
436}
437
438template <typename T>
439void ReturnValue<T>::Set(int16_t i) {
440 static_assert(std::is_base_of<T, Integer>::value, "type check");
441 using I = internal::Internals;
442 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::min()));
443 static_assert(I::IsValidSmi(std::numeric_limits<int16_t>::max()));
444 SetInternal(I::IntegralToSmi(i));
445}
446
447template <typename T>
448void ReturnValue<T>::Set(int32_t i) {
449 static_assert(std::is_base_of<T, Integer>::value, "type check");
451 SetInternal(*result);
452 return;
453 }
454 SetNonEmpty(Integer::New(GetIsolate(), i));
455}
456
457template <typename T>
458void ReturnValue<T>::Set(int64_t i) {
459 static_assert(std::is_base_of<T, Integer>::value, "type check");
461 SetInternal(*result);
462 return;
463 }
464 SetNonEmpty(Number::New(GetIsolate(), static_cast<double>(i)));
465}
466
467template <typename T>
468void ReturnValue<T>::Set(uint16_t i) {
469 static_assert(std::is_base_of<T, Integer>::value, "type check");
470 using I = internal::Internals;
471 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::min()));
472 static_assert(I::IsValidSmi(std::numeric_limits<uint16_t>::max()));
473 SetInternal(I::IntegralToSmi(i));
474}
475
476template <typename T>
477void ReturnValue<T>::Set(uint32_t i) {
478 static_assert(std::is_base_of<T, Integer>::value, "type check");
480 SetInternal(*result);
481 return;
482 }
483 SetNonEmpty(Integer::NewFromUnsigned(GetIsolate(), i));
484}
485
486template <typename T>
487void ReturnValue<T>::Set(uint64_t i) {
488 static_assert(std::is_base_of<T, Integer>::value, "type check");
490 SetInternal(*result);
491 return;
492 }
493 SetNonEmpty(Number::New(GetIsolate(), static_cast<double>(i)));
494}
495
496template <typename T>
497void ReturnValue<T>::Set(bool value) {
498 static_assert(std::is_void<T>::value || std::is_base_of<T, Boolean>::value,
499 "type check");
500 using I = internal::Internals;
501#if V8_STATIC_ROOTS_BOOL
502#ifdef V8_ENABLE_CHECKS
505#endif // V8_ENABLE_CHECKS
506 SetInternal(value ? I::StaticReadOnlyRoot::kTrueValue
507 : I::StaticReadOnlyRoot::kFalseValue);
508#else
509 int root_index;
510 if (value) {
511 root_index = I::kTrueValueRootIndex;
512 } else {
513 root_index = I::kFalseValueRootIndex;
514 }
515 *value_ = I::GetRoot(GetIsolate(), root_index);
516#endif // V8_STATIC_ROOTS_BOOL
517}
518
519template <typename T>
521 using I = internal::Internals;
522 if constexpr (std::is_same_v<void, T> || std::is_same_v<v8::Boolean, T>) {
523 Set(true);
524 } else if constexpr (std::is_same_v<v8::Integer, T>) {
525 SetInternal(I::IntegralToSmi(0));
526 } else {
527 static_assert(std::is_same_v<v8::Value, T> || std::is_same_v<v8::Array, T>);
528#if V8_STATIC_ROOTS_BOOL
529 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
530#else
531 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
532#endif // V8_STATIC_ROOTS_BOOL
533 }
534}
535
536template <typename T>
538 static_assert(std::is_base_of<T, Primitive>::value, "type check");
539 using I = internal::Internals;
540#if V8_STATIC_ROOTS_BOOL
541#ifdef V8_ENABLE_CHECKS
544#endif // V8_ENABLE_CHECKS
545 SetInternal(I::StaticReadOnlyRoot::kNullValue);
546#else
547 *value_ = I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
548#endif // V8_STATIC_ROOTS_BOOL
549}
550
551template <typename T>
553 static_assert(std::is_base_of<T, Primitive>::value, "type check");
554 using I = internal::Internals;
555#if V8_STATIC_ROOTS_BOOL
556#ifdef V8_ENABLE_CHECKS
559#endif // V8_ENABLE_CHECKS
560 SetInternal(I::StaticReadOnlyRoot::kUndefinedValue);
561#else
562 *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
563#endif // V8_STATIC_ROOTS_BOOL
564}
565
566template <typename T>
568 static_assert(std::is_void<T>::value || std::is_base_of<T, Boolean>::value,
569 "type check");
570 using I = internal::Internals;
571#if V8_STATIC_ROOTS_BOOL
572#ifdef V8_ENABLE_CHECKS
575#endif // V8_ENABLE_CHECKS
576 SetInternal(I::StaticReadOnlyRoot::kFalseValue);
577#else
578 *value_ = I::GetRoot(GetIsolate(), I::kFalseValueRootIndex);
579#endif // V8_STATIC_ROOTS_BOOL
580}
581
582template <typename T>
584 static_assert(std::is_base_of<T, String>::value, "type check");
585 using I = internal::Internals;
586#if V8_STATIC_ROOTS_BOOL
587#ifdef V8_ENABLE_CHECKS
590#endif // V8_ENABLE_CHECKS
591 SetInternal(I::StaticReadOnlyRoot::kEmptyString);
592#else
593 *value_ = I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
594#endif // V8_STATIC_ROOTS_BOOL
595}
596
597template <typename T>
599 return *reinterpret_cast<Isolate**>(&value_[kIsolateValueIndex]);
600}
601
602template <typename T>
607
608template <typename T>
609template <typename S>
610void ReturnValue<T>::Set(S* whatever) {
611 static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
612}
613
614template <typename T>
616 internal::Address* values,
617 int length)
618 : implicit_args_(implicit_args), values_(values), length_(length) {}
619
620template <typename T>
622 // values_ points to the first argument (not the receiver).
623 if (i < 0 || Length() <= i) return Undefined(GetIsolate());
624 return Local<Value>::FromSlot(values_ + i);
625}
626
627template <typename T>
629 // values_ points to the first argument (not the receiver).
630 return Local<Object>::FromSlot(values_ + kThisValuesIndex);
631}
632
633template <typename T>
635 return Local<Value>::FromSlot(&implicit_args_[kNewTargetIndex]);
636}
637
638template <typename T>
640 auto target = Local<v8::Data>::FromSlot(&implicit_args_[kTargetIndex]);
641 return api_internal::GetFunctionTemplateData(GetIsolate(), target);
642}
643
644template <typename T>
646 return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
647}
648
649template <typename T>
651 return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
652}
653
654template <typename T>
656 return !NewTarget()->IsUndefined();
657}
658
659template <typename T>
661 return static_cast<int>(length_);
662}
663
664template <typename T>
666 return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
667}
668
669template <typename T>
671 return Local<Value>::FromSlot(&args_[kDataIndex]);
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
684namespace api_internal {
685// Returns JSGlobalProxy if holder is JSGlobalObject or unmodified holder
686// otherwise.
688 internal::Address holder);
689} // namespace api_internal
690
691template <typename T>
693 using I = internal::Internals;
694 if (!I::HasHeapObjectTag(args_[kHolderV2Index])) {
695 args_[kHolderV2Index] =
697 }
698 return Local<Object>::FromSlot(&args_[kHolderV2Index]);
699}
700
701template <typename T>
703 return ReturnValue<T>(&args_[kReturnValueIndex]);
704}
705
706template <typename T>
708 using I = internal::Internals;
709 if (args_[kShouldThrowOnErrorIndex] !=
710 I::IntegralToSmi(I::kInferShouldThrowMode)) {
711 return args_[kShouldThrowOnErrorIndex] != I::IntegralToSmi(I::kDontThrow);
712 }
714 reinterpret_cast<v8::internal::Isolate*>(GetIsolate()));
715}
716
717} // namespace v8
718
719#endif // INCLUDE_V8_FUNCTION_CALLBACK_H_
static constexpr int kReturnValueIndex
static constexpr int kArgsLength
internal::Address * implicit_args_
V8_INLINE ReturnValue< T > GetReturnValue() const
V8_INLINE FunctionCallbackInfo(internal::Address *implicit_args, internal::Address *values, int length)
static constexpr int kContextIndex
static constexpr int kTargetIndex
static constexpr int kUnusedIndex
V8_INLINE Local< Object > This() const
static constexpr int kIsolateIndex
static constexpr int kThisValuesIndex
V8_INLINE Local< Value > operator[](int i) const
V8_INLINE Isolate * GetIsolate() const
static constexpr int kLengthOffset
V8_INLINE Local< Value > NewTarget() const
static constexpr int kValuesOffset
V8_INLINE Local< Value > Data() const
static constexpr int kNewTargetIndex
V8_INLINE bool IsConstructCall() const
static constexpr int kArgsLengthWithReceiver
static constexpr int kImplicitArgsOffset
V8_INLINE int Length() const
static Local< Integer > New(Isolate *isolate, int32_t value)
Definition api.cc:9568
static Local< Integer > NewFromUnsigned(Isolate *isolate, uint32_t value)
Definition api.cc:9579
static V8_INLINE Local< T > New(Isolate *isolate, Local< T > that)
static V8_INLINE Local< T > FromSlot(internal::Address *slot)
static Local< Number > New(Isolate *isolate, double value)
Definition api.cc:9557
V8_INLINE Local< Value > Data() const
static constexpr int kReturnValueIndex
friend class internal::PropertyCallbackArguments
static constexpr int kIsolateIndex
static constexpr int kDataIndex
static constexpr int kArgsLength
static constexpr int kShouldThrowOnErrorIndex
static constexpr int kHolderV2Index
V8_INLINE bool ShouldThrowOnError() const
static constexpr int kThisIndex
static constexpr int kHolderIndex
static constexpr int kPropertyKeyIndex
V8_DEPRECATE_SOON("V8 will stop providing access to hidden prototype (i.e. " "JSGlobalObject). Use HolderV2() instead. \n" "DO NOT try to workaround this by accessing JSGlobalObject via " "v8::Object::GetPrototype() - it'll be deprecated soon too. \n" "See http://crbug.com/333672197. ") V8_INLINE Local< Object > Holder() const
V8_INLINE ReturnValue< T > GetReturnValue() const
V8_INLINE Local< Object > HolderV2() const
internal::Address args_[kArgsLength]
friend void internal::PrintPropertyCallbackInfo(void *)
V8_INLINE Local< Object > This() const
V8_INLINE Isolate * GetIsolate() const
V8_INLINE void Set(const BasicTracedReference< S > &handle)
V8_INLINE void SetNonEmpty(const Global< S > &handle)
V8_INLINE void SetDefaultValue()
V8_INLINE void SetFalse()
V8_INLINE void SetEmptyString()
V8_INLINE void SetNonEmpty(const Local< S > handle)
V8_INLINE void SetInternal(internal::Address value)
static constexpr int kIsolateValueIndex
V8_INLINE void Set(const Global< S > &handle)
V8_INLINE Local< Value > Get() const
V8_INLINE void Set(const Local< S > handle)
internal::Address * value_
V8_INLINE void SetNonEmpty(const BasicTracedReference< S > &handle)
V8_INLINE void SetNull()
V8_INLINE Isolate * GetIsolate() const
V8_INLINE ReturnValue(const ReturnValue< S > &that)
V8_INLINE void Set(S *whatever)
V8_INLINE void SetUndefined()
static constexpr std::optional< Address > TryIntegralToSmi(T value)
static V8_INLINE T * SlotAsValue(S *slot)
Register const value_
ZoneVector< RpoNumber > & result
const int length_
Definition mul-fft.cc:473
i::Address ConvertToJSGlobalProxyIfNecessary(i::Address holder_ptr)
Definition api.cc:3821
V8_EXPORT v8::Local< v8::Value > GetFunctionTemplateData(v8::Isolate *isolate, v8::Local< v8::Data > raw_target)
Definition api.cc:11880
const int kApiSystemPointerSize
Definition v8-internal.h:65
void VerifyHandleIsNonEmpty(bool is_empty)
Definition api.cc:557
V8_INLINE void PerformCastCheck(T *data)
void PrintFunctionCallbackInfo(void *function_callback_info)
V8_EXPORT bool ShouldThrowOnError(internal::Isolate *isolate)
V8_INLINE Local< Primitive > Undefined(Isolate *isolate)
void(*)(const FunctionCallbackInfo< Value > &info) FunctionCallback
#define I(name, number_of_args, result_size)
Definition runtime.cc:36
#define V8_EXPORT
Definition v8config.h:800
#define V8_INLINE
Definition v8config.h:500
#define V8_UNLIKELY(condition)
Definition v8config.h:660
std::unique_ptr< ValueMirror > value