diff --git a/include/cppgc/internal/member-storage.h b/include/cppgc/internal/member-storage.h index 98389b8cd3..0eb6382070 100644 --- a/include/cppgc/internal/member-storage.h +++ b/include/cppgc/internal/member-storage.h @@ -61,7 +61,7 @@ class CageBaseGlobal final { #undef CPPGC_REQUIRE_CONSTANT_INIT #undef CPPGC_CONST -class CompressedPointer final { +class V8_TRIVIAL_ABI CompressedPointer final { public: using IntegralType = uint32_t; @@ -170,7 +170,7 @@ class CompressedPointer final { #endif // defined(CPPGC_POINTER_COMPRESSION) -class RawPointer final { +class V8_TRIVIAL_ABI RawPointer final { public: using IntegralType = uintptr_t; diff --git a/include/cppgc/member.h b/include/cppgc/member.h index 71f9cab652..077b715db8 100644 --- a/include/cppgc/member.h +++ b/include/cppgc/member.h @@ -28,7 +28,7 @@ namespace internal { // MemberBase always refers to the object as const object and defers to // BasicMember on casting to the right type as needed. -class MemberBase { +class V8_TRIVIAL_ABI MemberBase { public: #if defined(CPPGC_POINTER_COMPRESSION) using RawStorage = CompressedPointer; @@ -74,7 +74,8 @@ class MemberBase { // The basic class from which all Member classes are 'generated'. template -class BasicMember final : private MemberBase, private CheckingPolicy { +class V8_TRIVIAL_ABI BasicMember final : private MemberBase, + private CheckingPolicy { public: using PointeeType = T; diff --git a/include/v8config.h b/include/v8config.h index 207afac8b0..a959be130d 100644 --- a/include/v8config.h +++ b/include/v8config.h @@ -579,6 +579,37 @@ path. Add it with -I to the command line #define V8_NO_UNIQUE_ADDRESS /* NOT SUPPORTED */ #endif +// Marks a type as being eligible for the "trivial" ABI despite having a +// non-trivial destructor or copy/move constructor. Such types can be relocated +// after construction by simply copying their memory, which makes them eligible +// to be passed in registers. The canonical example is std::unique_ptr. +// +// Use with caution; this has some subtle effects on constructor/destructor +// ordering and will be very incorrect if the type relies on its address +// remaining constant. When used as a function argument (by value), the value +// may be constructed in the caller's stack frame, passed in a register, and +// then used and destructed in the callee's stack frame. A similar thing can +// occur when values are returned. +// +// TRIVIAL_ABI is not needed for types which have a trivial destructor and +// copy/move constructors, since those are automatically trivial by the ABI +// spec. +// +// It is also not likely to be effective on types too large to be passed in one +// or two registers on typical target ABIs. +// +// See also: +// https://clang.llvm.org/docs/AttributeReference.html#trivial-abi +// https://libcxx.llvm.org/docs/DesignDocs/UniquePtrTrivialAbi.html +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(trivial_abi) +#define V8_TRIVIAL_ABI [[clang::trivial_abi]] +#endif // __has_attribute(trivial_abi) +#endif // defined(__clang__) && defined(__has_attribute) +#if !defined(V8_TRIVIAL_ABI) +#define V8_TRIVIAL_ABI +#endif //!defined(V8_TRIVIAL_ABI) + // Helper macro to define no_sanitize attributes only with clang. #if defined(__clang__) && defined(__has_attribute) #if __has_attribute(no_sanitize)