From 53adec5e968941d9149beecc451981ae03ddd04b Mon Sep 17 00:00:00 2001 From: FranklinDM Date: Fri, 17 Mar 2023 19:05:09 +0800 Subject: [PATCH] Issue #2166 - Part 4: Use alignas/alignof to define Variant's internal raw storage Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1338374 --- mfbt/Variant.h | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/mfbt/Variant.h b/mfbt/Variant.h index 6220cd9aa0..86b70a2244 100644 --- a/mfbt/Variant.h +++ b/mfbt/Variant.h @@ -8,9 +8,9 @@ #include #include -#include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" #ifndef mozilla_Variant_h @@ -23,22 +23,6 @@ class Variant; namespace detail { -// MaxSizeOf computes the maximum sizeof(T) for each T in Ts. - -template -struct MaxSizeOf -{ - static const size_t size = sizeof(T) > MaxSizeOf::size - ? sizeof(T) - : MaxSizeOf::size; -}; - -template -struct MaxSizeOf -{ - static const size_t size = sizeof(T); -}; - // The `IsVariant` helper is used in conjunction with static_assert and // `mozilla::EnableIf` to catch passing non-variant types to `Variant::is()` // and friends at compile time, rather than at runtime. It ensures that the @@ -429,23 +413,35 @@ struct AsVariantTemporary * * ... * }; + * + * Because Variant must be aligned suitable to hold any value stored within it, + * and because |alignas| requirements don't affect platform ABI with respect to + * how parameters are laid out in memory, Variant can't be used as the type of a + * function parameter. Pass Variant to functions by pointer or reference + * instead. */ template -class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant { using Tag = typename detail::VariantTag::Type; using Impl = detail::VariantImplementation; - using RawData = AlignedStorage::size>; + + static const size_t RawDataAlignment = tl::Max::value; + static const size_t RawDataSize = tl::Max::value; // Raw storage for the contained variant value. - RawData raw; + alignas(RawDataAlignment) unsigned char rawData[RawDataSize]; // Each type is given a unique tag value that lets us keep track of the // contained variant value's type. Tag tag; void* ptr() { - return reinterpret_cast(&raw); + return rawData; + } + + const void* ptr() const { + return rawData; } public: @@ -552,7 +548,7 @@ public: static_assert(detail::IsVariant::value, "provided a type not found in this Variant's type list"); MOZ_ASSERT(is()); - return *reinterpret_cast(&raw); + return *static_cast(ptr()); } /** Immutable const reference. */ @@ -561,7 +557,7 @@ public: static_assert(detail::IsVariant::value, "provided a type not found in this Variant's type list"); MOZ_ASSERT(is()); - return *reinterpret_cast(&raw); + return *static_cast(ptr()); } /**