Inline GetFlag fast path and guard AssertValidType with op_ pointer check. In non-LTO builds, `absl::GetFlag` and `Flag<T>::Get` / `Flag<T>::Set` incur out-of-line calls across `GetFlag` -> `FlagImplPeer::InvokeGet` -> `Flag<T>::Get` -> `FlagValue<T>::Get`, and in `!NDEBUG` builds unconditionally call `FlagImpl::AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>)` on every flag read. PiperOrigin-RevId: 988739302
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index 8baff43..c12c924 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h
@@ -378,11 +378,11 @@ MaskedPointer(const MaskedPointer& rhs) = default; MaskedPointer& operator=(const MaskedPointer& rhs) = default; - void* Ptr() const { + ABSL_ATTRIBUTE_ALWAYS_INLINE void* Ptr() const { return reinterpret_cast<void*>(reinterpret_cast<mask_t>(ptr_) & kPtrValueMask); } - bool AllowsUnprotectedRead() const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool AllowsUnprotectedRead() const { return (reinterpret_cast<mask_t>(ptr_) & kAllowsUnprotectedRead) == kAllowsUnprotectedRead; } @@ -437,7 +437,7 @@ template <typename T> struct FlagValue<T, FlagValueStorageKind::kValueAndInitBit> : FlagOneWordValue { constexpr FlagValue() : FlagOneWordValue(0) {} - bool Get(const SequenceLock&, T& dst) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool Get(const SequenceLock&, T& dst) const { int64_t storage = value.load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(storage == 0)) { // This assert is to ensure that the initialization inside FlagImpl::Init @@ -458,7 +458,7 @@ template <typename T> struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue { constexpr FlagValue() : FlagOneWordValue() {} - bool Get(const SequenceLock&, T& dst) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool Get(const SequenceLock&, T& dst) const { int64_t one_word_val = value.load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(one_word_val == FlagOneWordValue::Uninitialized())) { return false; @@ -476,7 +476,8 @@ // value once it is initialized. template <typename T> struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> { - bool Get(const SequenceLock& lock, T& dst) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool Get(const SequenceLock& lock, + T& dst) const { return lock.TryRead(&dst, value_words, sizeof(T)); } @@ -531,7 +532,7 @@ // ensure Init is done before any access to the flag value. constexpr FlagValue() : FlagMaskedPointerValue(&buffer[0]) {} - bool Get(const SequenceLock&, T& dst) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool Get(const SequenceLock&, T& dst) const { MaskedPointer ptr_value = value.load(std::memory_order_acquire); if (ABSL_PREDICT_TRUE(ptr_value.AllowsUnprotectedRead())) { @@ -792,6 +793,14 @@ // flag reflection handle interface. template <typename T> +struct IsSupportedFlagType : std::false_type {}; +#define ABSL_FLAGS_INTERNAL_IS_SUPPORTED_TYPE(T, name) \ + template <> \ + struct IsSupportedFlagType<T> : std::true_type {}; +ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IS_SUPPORTED_TYPE) +#undef ABSL_FLAGS_INTERNAL_IS_SUPPORTED_TYPE + +template <typename T> class Flag { public: constexpr Flag(const char* name, const char* type_name, const char* filename, @@ -816,7 +825,7 @@ friend class FlagRegistrar; friend class FlagImplPeer; - T Get() const { + ABSL_ATTRIBUTE_ALWAYS_INLINE T Get() const { // See implementation notes in CommandLineFlag::Get(). union U { T value; @@ -826,7 +835,13 @@ U u; #if !defined(NDEBUG) - impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>); + if constexpr (IsSupportedFlagType<T>::value) { + if (ABSL_PREDICT_FALSE(impl_.op_ != &FlagOps<T>)) { + impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>); + } + } else { + impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>); + } #endif if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) { @@ -835,7 +850,13 @@ return std::move(u.value); } void Set(const T& v) { - impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>); + if constexpr (IsSupportedFlagType<T>::value) { + if (ABSL_PREDICT_FALSE(impl_.op_ != &FlagOps<T>)) { + impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>); + } + } else { + impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>); + } impl_.Write(&v); } @@ -856,7 +877,7 @@ class FlagImplPeer { public: template <typename T, typename FlagType> - static T InvokeGet(const FlagType& flag) { + ABSL_ATTRIBUTE_ALWAYS_INLINE static T InvokeGet(const FlagType& flag) { return flag.Get(); } template <typename FlagType, typename T>