v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
v8-fast-api-calls.h
Go to the documentation of this file.
1// Copyright 2020 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_FAST_API_CALLS_H_
6#define INCLUDE_V8_FAST_API_CALLS_H_
7
222#include <stddef.h>
223#include <stdint.h>
224
225#include <tuple>
226#include <type_traits>
227
228#include "v8-internal.h" // NOLINT(build/include_directory)
229#include "v8-local-handle.h" // NOLINT(build/include_directory)
230#include "v8-typed-array.h" // NOLINT(build/include_directory)
231#include "v8-value.h" // NOLINT(build/include_directory)
232#include "v8config.h" // NOLINT(build/include_directory)
233
234namespace v8 {
235
236class Isolate;
237
240 public:
241 enum class Type : uint8_t {
242 kVoid,
243 kBool,
244 kUint8,
245 kInt32,
246 kUint32,
247 kInt64,
248 kUint64,
249 kFloat32,
250 kFloat64,
251 kPointer,
252 kV8Value,
253 kSeqOneByteString,
254 kApiObject, // This will be deprecated once all users have
255 // migrated from v8::ApiObject to v8::Local<v8::Value>.
256 kAny, // This is added to enable untyped representation of fast
257 // call arguments for test purposes. It can represent any of
258 // the other types stored in the same memory as a union
259 // (see AnyCType declared below). This allows for
260 // uniform passing of arguments w.r.t. their location
261 // (in a register or on the stack), independent of their
262 // actual type. It's currently used by the arm64 simulator
263 // and can be added to the other simulators as well when fast
264 // calls having both GP and FP params need to be supported.
265 };
266
267 // kCallbackOptionsType is not part of the Type enum
268 // because it is only used internally. Use value 255 that is larger
269 // than any valid Type enum.
270 static constexpr Type kCallbackOptionsType = Type(255);
271
272 enum class V8_DEPRECATE_SOON(
273 "There is no special support in V8 anymore, there is no need to"
274 "use a SequenceType") SequenceType : uint8_t {
275 kScalar,
276 kIsSequence, // sequence<T>
277 kIsArrayBuffer // ArrayBuffer
278 };
279
280 enum class Flags : uint8_t {
281 kNone = 0,
282 kAllowSharedBit = 1 << 0, // Must be an ArrayBuffer or TypedArray
283 kEnforceRangeBit = 1 << 1, // T must be integral
284 kClampBit = 1 << 2, // T must be integral
285 kIsRestrictedBit = 1 << 3, // T must be float or double
286 };
287
288 explicit constexpr CTypeInfo(Type type, Flags flags = Flags::kNone)
289 : type_(type), sequence_type_(SequenceType::kScalar), flags_(flags) {}
290
291 V8_DEPRECATE_SOON("Use CTypeInfo(Type, Flags) instead")
292 constexpr CTypeInfo(Type type, SequenceType sequence_type,
293 Flags flags = Flags::kNone)
294 : type_(type), sequence_type_(sequence_type), flags_(flags) {}
295
296 typedef uint32_t Identifier;
297 explicit constexpr CTypeInfo(Identifier identifier)
298 : CTypeInfo(static_cast<Type>(identifier >> 16),
299 static_cast<SequenceType>((identifier >> 8) & 255),
300 static_cast<Flags>(identifier & 255)) {}
301 constexpr Identifier GetId() const {
302 return static_cast<uint8_t>(type_) << 16 |
303 static_cast<uint8_t>(sequence_type_) << 8 |
304 static_cast<uint8_t>(flags_);
305 }
306
307 constexpr Type GetType() const { return type_; }
308 V8_DEPRECATE_SOON("Use the constant SequenceType::kScalar instead")
309 constexpr SequenceType GetSequenceType() const { return sequence_type_; }
310 constexpr Flags GetFlags() const { return flags_; }
311
312 static constexpr bool IsIntegralType(Type type) {
313 return type == Type::kUint8 || type == Type::kInt32 ||
314 type == Type::kUint32 || type == Type::kInt64 ||
315 type == Type::kUint64;
316 }
317
318 static constexpr bool IsFloatingPointType(Type type) {
319 return type == Type::kFloat32 || type == Type::kFloat64;
320 }
321
322 static constexpr bool IsPrimitive(Type type) {
323 return IsIntegralType(type) || IsFloatingPointType(type) ||
324 type == Type::kBool;
325 }
326
327 private:
329 SequenceType sequence_type_;
331};
333
335 const char* data;
336 uint32_t length;
337};
338
340 public:
341 enum class Int64Representation : uint8_t {
342 kNumber = 0, // Use numbers to represent 64 bit integers.
343 kBigInt = 1, // Use BigInts to represent 64 bit integers.
344 };
345
346 // Construct a struct to hold a CFunction's type information.
347 // |return_info| describes the function's return type.
348 // |arg_info| is an array of |arg_count| CTypeInfos describing the
349 // arguments. Only the last argument may be of the special type
350 // CTypeInfo::kCallbackOptionsType.
351 CFunctionInfo(const CTypeInfo& return_info, unsigned int arg_count,
352 const CTypeInfo* arg_info,
353 Int64Representation repr = Int64Representation::kNumber);
354
355 const CTypeInfo& ReturnInfo() const { return return_info_; }
356
357 // The argument count, not including the v8::FastApiCallbackOptions
358 // if present.
359 unsigned int ArgumentCount() const {
360 return HasOptions() ? arg_count_ - 1 : arg_count_;
361 }
362
364
365 // |index| must be less than ArgumentCount().
366 // Note: if the last argument passed on construction of CFunctionInfo
367 // has type CTypeInfo::kCallbackOptionsType, it is not included in
368 // ArgumentCount().
369 const CTypeInfo& ArgumentInfo(unsigned int index) const;
370
371 bool HasOptions() const {
372 // The options arg is always the last one.
373 return arg_count_ > 0 && arg_info_[arg_count_ - 1].GetType() ==
374 CTypeInfo::kCallbackOptionsType;
375 }
376
377 private:
380 const unsigned int arg_count_;
382};
383
385
386// Provided for testing.
388 AnyCType() : int64_value(0) {}
389
390#if defined(V8_ENABLE_LOCAL_OFF_STACK_CHECK) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
391 // In this case, Local<T> is not trivially copyable and the implicit
392 // copy constructor and copy assignment for the union are deleted.
393 AnyCType(const AnyCType& other) : int64_value(other.int64_value) {}
394 AnyCType& operator=(const AnyCType& other) {
395 int64_value = other.int64_value;
396 return *this;
397 }
398#endif
399
401 int32_t int32_value;
402 uint32_t uint32_value;
403 int64_t int64_value;
404 uint64_t uint64_value;
412};
413
414static_assert(
415 sizeof(AnyCType) == 8,
416 "The union AnyCType should have size == 64 bits, as this is assumed "
417 "by EffectControlLinearizer.");
418
420 public:
421 constexpr CFunction() : address_(nullptr), type_info_(nullptr) {}
422
423 const CTypeInfo& ReturnInfo() const { return type_info_->ReturnInfo(); }
424
425 const CTypeInfo& ArgumentInfo(unsigned int index) const {
426 return type_info_->ArgumentInfo(index);
427 }
428
429 unsigned int ArgumentCount() const { return type_info_->ArgumentCount(); }
430
431 const void* GetAddress() const { return address_; }
433 return type_info_->GetInt64Representation();
434 }
435 const CFunctionInfo* GetTypeInfo() const { return type_info_; }
436
437 enum class OverloadResolution { kImpossible, kAtRuntime, kAtCompileTime };
438
439 template <typename F>
440 static CFunction Make(F* func,
442 CFunctionInfo::Int64Representation::kNumber) {
443 CFunction result = ArgUnwrap<F*>::Make(func, int64_rep);
444 result.GetInt64Representation();
445 return result;
446 }
447
448 // Provided for testing purposes.
449 template <typename R, typename... Args, typename R_Patch,
450 typename... Args_Patch>
451 static CFunction Make(R (*func)(Args...),
452 R_Patch (*patching_func)(Args_Patch...),
454 CFunctionInfo::Int64Representation::kNumber) {
455 CFunction c_func = ArgUnwrap<R (*)(Args...)>::Make(func, int64_rep);
456 static_assert(
457 sizeof...(Args_Patch) == sizeof...(Args),
458 "The patching function must have the same number of arguments.");
459 c_func.address_ = reinterpret_cast<void*>(patching_func);
460 return c_func;
461 }
462
463 CFunction(const void* address, const CFunctionInfo* type_info);
464
465 private:
466 const void* address_;
468
469 template <typename F>
470 class ArgUnwrap {
471 static_assert(sizeof(F) != sizeof(F),
472 "CFunction must be created from a function pointer.");
473 };
474
475 template <typename R, typename... Args>
476 class ArgUnwrap<R (*)(Args...)> {
477 public:
478 static CFunction Make(R (*func)(Args...),
480 CFunctionInfo::Int64Representation::kNumber);
481 };
482};
483
496 return {};
497 }
498
499 v8::Isolate* isolate = nullptr;
500
505};
506
507namespace internal {
508
509// Helper to count the number of occurances of `T` in `List`
510template <typename T, typename... List>
511struct count : std::integral_constant<int, 0> {};
512template <typename T, typename... Args>
513struct count<T, T, Args...>
514 : std::integral_constant<std::size_t, 1 + count<T, Args...>::value> {};
515template <typename T, typename U, typename... Args>
516struct count<T, U, Args...> : count<T, Args...> {};
517
519 typename RetBuilder, typename... ArgBuilders>
521 static constexpr int kOptionsArgCount =
522 count<FastApiCallbackOptions&, ArgBuilders...>();
523 static constexpr int kReceiverCount = 1;
524
525 static_assert(kOptionsArgCount == 0 || kOptionsArgCount == 1,
526 "Only one options parameter is supported.");
527
528 static_assert(sizeof...(ArgBuilders) >= kOptionsArgCount + kReceiverCount,
529 "The receiver or the options argument is missing.");
530
531 public:
533 : CFunctionInfo(RetBuilder::Build(), sizeof...(ArgBuilders),
535 arg_info_storage_{ArgBuilders::Build()...} {
536 constexpr CTypeInfo::Type kReturnType = RetBuilder::Build().GetType();
537 static_assert(kReturnType == CTypeInfo::Type::kVoid ||
538 kReturnType == CTypeInfo::Type::kBool ||
539 kReturnType == CTypeInfo::Type::kInt32 ||
540 kReturnType == CTypeInfo::Type::kUint32 ||
541 kReturnType == CTypeInfo::Type::kInt64 ||
542 kReturnType == CTypeInfo::Type::kUint64 ||
543 kReturnType == CTypeInfo::Type::kFloat32 ||
544 kReturnType == CTypeInfo::Type::kFloat64 ||
545 kReturnType == CTypeInfo::Type::kPointer ||
546 kReturnType == CTypeInfo::Type::kAny,
547 "String and api object values are not currently "
548 "supported return types.");
549 }
550
551 private:
552 const CTypeInfo arg_info_storage_[sizeof...(ArgBuilders)];
553};
554
555template <typename T>
557 static_assert(sizeof(T) != sizeof(T), "This type is not supported");
558};
559
560#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR(T, Enum) \
561 template <> \
562 struct TypeInfoHelper<T> { \
563 static constexpr CTypeInfo::Flags Flags() { \
564 return CTypeInfo::Flags::kNone; \
565 } \
566 \
567 static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \
568 };
569
570template <CTypeInfo::Type type>
572
573#define DEFINE_TYPE_INFO_TRAITS(CType, Enum) \
574 template <> \
575 struct CTypeInfoTraits<CTypeInfo::Type::Enum> { \
576 using ctype = CType; \
577 };
578
579#define PRIMITIVE_C_TYPES(V) \
580 V(bool, kBool) \
581 V(uint8_t, kUint8) \
582 V(int32_t, kInt32) \
583 V(uint32_t, kUint32) \
584 V(int64_t, kInt64) \
585 V(uint64_t, kUint64) \
586 V(float, kFloat32) \
587 V(double, kFloat64) \
588 V(void*, kPointer)
589
590// Same as above, but includes deprecated types for compatibility.
591#define ALL_C_TYPES(V) \
592 PRIMITIVE_C_TYPES(V) \
593 V(void, kVoid) \
594 V(v8::Local<v8::Value>, kV8Value) \
595 V(v8::Local<v8::Object>, kV8Value) \
596 V(v8::Local<v8::Array>, kV8Value) \
597 V(AnyCType, kAny)
598
599// ApiObject was a temporary solution to wrap the pointer to the v8::Value.
600// Please use v8::Local<v8::Value> in new code for the arguments and
601// v8::Local<v8::Object> for the receiver, as ApiObject will be deprecated.
602
605
606#undef PRIMITIVE_C_TYPES
607#undef ALL_C_TYPES
608
609#undef TYPED_ARRAY_C_TYPES
610
611template <>
613 static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; }
614
615 static constexpr CTypeInfo::Type Type() {
617 }
618};
619
620template <>
622 static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; }
623
624 static constexpr CTypeInfo::Type Type() {
626 }
627};
628
629#define STATIC_ASSERT_IMPLIES(COND, ASSERTION, MSG) \
630 static_assert(((COND) == 0) || (ASSERTION), MSG)
631
632} // namespace internal
633
634template <typename T, CTypeInfo::Flags... Flags>
636 public:
637 using BaseType = T;
638
639 static constexpr CTypeInfo Build() {
640 constexpr CTypeInfo::Flags kFlags =
641 MergeFlags(internal::TypeInfoHelper<T>::Flags(), Flags...);
643
645 uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kEnforceRangeBit),
646 CTypeInfo::IsIntegralType(kType),
647 "kEnforceRangeBit is only allowed for integral types.");
649 uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kClampBit),
650 CTypeInfo::IsIntegralType(kType),
651 "kClampBit is only allowed for integral types.");
653 uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kIsRestrictedBit),
654 CTypeInfo::IsFloatingPointType(kType),
655 "kIsRestrictedBit is only allowed for floating point types.");
656
657 // Return the same type with the merged flags.
659 }
660
661 private:
662 template <typename... Rest>
664 Rest... rest) {
665 return CTypeInfo::Flags(uint8_t(flags) | uint8_t(MergeFlags(rest...)));
666 }
667 static constexpr CTypeInfo::Flags MergeFlags() { return CTypeInfo::Flags(0); }
668};
669
670namespace internal {
671template <typename RetBuilder, typename... ArgBuilders>
673 public:
674 explicit constexpr CFunctionBuilderWithFunction(const void* fn) : fn_(fn) {}
675
676 template <CTypeInfo::Flags... Flags>
677 constexpr auto Ret() {
679 CTypeInfoBuilder<typename RetBuilder::BaseType, Flags...>,
680 ArgBuilders...>(fn_);
681 }
682
683 template <unsigned int N, CTypeInfo::Flags... Flags>
684 constexpr auto Arg() {
685 // Return a copy of the builder with the Nth arg builder merged with
686 // template parameter pack Flags.
687 return ArgImpl<N, Flags...>(
688 std::make_index_sequence<sizeof...(ArgBuilders)>());
689 }
690
691 // Provided for testing purposes.
692 template <typename Ret, typename... Args>
693 auto Patch(Ret (*patching_func)(Args...)) {
694 static_assert(
695 sizeof...(Args) == sizeof...(ArgBuilders),
696 "The patching function must have the same number of arguments.");
697 fn_ = reinterpret_cast<void*>(patching_func);
698 return *this;
699 }
700
703 auto Build() {
704 static CFunctionInfoImpl<Representation, RetBuilder, ArgBuilders...>
705 instance;
706 return CFunction(fn_, &instance);
707 }
708
709 private:
710 template <bool Merge, unsigned int N, CTypeInfo::Flags... Flags>
712
713 // Returns the same ArgBuilder as the one at index N, including its flags.
714 // Flags in the template parameter pack are ignored.
715 template <unsigned int N, CTypeInfo::Flags... Flags>
716 struct GetArgBuilder<false, N, Flags...> {
717 using type =
718 typename std::tuple_element<N, std::tuple<ArgBuilders...>>::type;
719 };
720
721 // Returns an ArgBuilder with the same base type as the one at index N,
722 // but merges the flags with the flags in the template parameter pack.
723 template <unsigned int N, CTypeInfo::Flags... Flags>
724 struct GetArgBuilder<true, N, Flags...> {
726 typename std::tuple_element<N,
727 std::tuple<ArgBuilders...>>::type::BaseType,
728 std::tuple_element<N, std::tuple<ArgBuilders...>>::type::Build()
729 .GetFlags(),
730 Flags...>;
731 };
732
733 // Return a copy of the CFunctionBuilder, but merges the Flags on
734 // ArgBuilder index N with the new Flags passed in the template parameter
735 // pack.
736 template <unsigned int N, CTypeInfo::Flags... Flags, size_t... I>
737 constexpr auto ArgImpl(std::index_sequence<I...>) {
739 RetBuilder, typename GetArgBuilder<N == I, I, Flags...>::type...>(fn_);
740 }
741
742 const void* fn_;
743};
744
746 public:
747 constexpr CFunctionBuilder() {}
748
749 template <typename R, typename... Args>
750 constexpr auto Fn(R (*fn)(Args...)) {
753 reinterpret_cast<const void*>(fn));
754 }
755};
756
757} // namespace internal
758
759// static
760template <typename R, typename... Args>
761CFunction CFunction::ArgUnwrap<R (*)(Args...)>::Make(
762 R (*func)(Args...), CFunctionInfo::Int64Representation int64_rep) {
764 return internal::CFunctionBuilder().Fn(func).Build();
765 }
767 .Fn(func)
768 .template Build<CFunctionInfo::Int64Representation::kBigInt>();
769}
770
772
774static constexpr CTypeInfo kTypeInfoFloat64 =
776
789template <CTypeInfo::Identifier type_info_id, typename T>
791 Local<Array> src, T* dst, uint32_t max_length);
792
793template <>
795TryToCopyAndConvertArrayToCppBuffer<CTypeInfoBuilder<int32_t>::Build().GetId(),
796 int32_t>(Local<Array> src, int32_t* dst,
797 uint32_t max_length);
798
799template <>
801TryToCopyAndConvertArrayToCppBuffer<CTypeInfoBuilder<uint32_t>::Build().GetId(),
802 uint32_t>(Local<Array> src, uint32_t* dst,
803 uint32_t max_length);
804
805template <>
807TryToCopyAndConvertArrayToCppBuffer<CTypeInfoBuilder<float>::Build().GetId(),
808 float>(Local<Array> src, float* dst,
809 uint32_t max_length);
810
811template <>
813TryToCopyAndConvertArrayToCppBuffer<CTypeInfoBuilder<double>::Build().GetId(),
814 double>(Local<Array> src, double* dst,
815 uint32_t max_length);
816
817} // namespace v8
818
819#endif // INCLUDE_V8_FAST_API_CALLS_H_
#define F(name, str)
#define T
Int64Representation GetInt64Representation() const
const CTypeInfo * arg_info_
const CTypeInfo & ReturnInfo() const
const Int64Representation repr_
const CTypeInfo return_info_
const unsigned int arg_count_
unsigned int ArgumentCount() const
const CTypeInfo & ReturnInfo() const
constexpr CFunction()
const CTypeInfo & ArgumentInfo(unsigned int index) const
unsigned int ArgumentCount() const
CFunctionInfo::Int64Representation GetInt64Representation() const
static CFunction Make(R(*func)(Args...), R_Patch(*patching_func)(Args_Patch...), CFunctionInfo::Int64Representation int64_rep=CFunctionInfo::Int64Representation::kNumber)
const void * GetAddress() const
const CFunctionInfo * GetTypeInfo() const
const void * address_
static CFunction Make(F *func, CFunctionInfo::Int64Representation int64_rep=CFunctionInfo::Int64Representation::kNumber)
const CFunctionInfo * type_info_
static constexpr CTypeInfo Build()
static constexpr CTypeInfo::Flags MergeFlags(CTypeInfo::Flags flags, Rest... rest)
static constexpr CTypeInfo::Flags MergeFlags()
SequenceType sequence_type_
constexpr CTypeInfo(Type type, Flags flags=Flags::kNone)
static constexpr bool IsFloatingPointType(Type type)
static constexpr bool IsPrimitive(Type type)
static constexpr Type kCallbackOptionsType
static constexpr bool IsIntegralType(Type type)
constexpr Identifier GetId() const
constexpr Type GetType() const
constexpr Flags GetFlags() const
constexpr CTypeInfo(Identifier identifier)
constexpr CFunctionBuilderWithFunction(const void *fn)
constexpr auto ArgImpl(std::index_sequence< I... >)
auto Patch(Ret(*patching_func)(Args...))
constexpr auto Fn(R(*fn)(Args...))
const CTypeInfo arg_info_storage_[sizeof...(ArgBuilders)]
static constexpr int kOptionsArgCount
JSRegExp::Flags flags_
const ObjectRef type_
ZoneVector< RpoNumber > & result
EmitFn fn
V8_EXPORT_PRIVATE base::Vector< Flag > Flags()
Definition flags.cc:300
constexpr int N
constexpr int I
constexpr int U
static constexpr CTypeInfo kTypeInfoFloat64
static constexpr CTypeInfo kTypeInfoInt32
bool V8_EXPORT TryToCopyAndConvertArrayToCppBuffer(Local< Array > src, T *dst, uint32_t max_length)
Definition api-inl.h:337
v8::Local< v8::Value > data
static FastApiCallbackOptions CreateForTesting(Isolate *isolate)
typename std::tuple_element< N, std::tuple< ArgBuilders... > >::type type
Symbol identifier
FastApiCallbackOptions * options_value
const FastOneByteString * string_value
Local< Array > sequence_value
Local< Object > object_value
#define DEFINE_TYPE_INFO_TRAITS(CType, Enum)
#define PRIMITIVE_C_TYPES(V)
#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR(T, Enum)
#define ALL_C_TYPES(V)
#define STATIC_ASSERT_IMPLIES(COND, ASSERTION, MSG)
#define V8_EXPORT
Definition v8config.h:800
#define V8_DEPRECATE_SOON(message)
Definition v8config.h:614
#define END_ALLOW_USE_DEPRECATED()
Definition v8config.h:634
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_TRIVIAL_ABI
Definition v8config.h:754
#define START_ALLOW_USE_DEPRECATED()
Definition v8config.h:633
wasm::ValueType type