From 1b2007cc7f02ccb043abf39adbfa8276089bfa00 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Thu, 14 Sep 2023 15:45:10 +0330 Subject: [PATCH] AK: Use outline Function storage if alignment requirements are not met Instead of ballooning the size of the Function object, simply place the callable on the heap with a properly aligned address. This brings the alignment of Function down from ridiculous sizes like 64 bytes down to a manageable 8 bytes. --- AK/Function.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/AK/Function.h b/AK/Function.h index d295843b77..bb3319d4d2 100644 --- a/AK/Function.h +++ b/AK/Function.h @@ -56,6 +56,14 @@ public: using FunctionType = Out(In...); using ReturnType = Out; +#ifdef KERNEL + constexpr static auto AccommodateExcessiveAlignmentRequirements = false; + constexpr static size_t ExcessiveAlignmentThreshold = alignof(void*); +#else + constexpr static auto AccommodateExcessiveAlignmentRequirements = true; + constexpr static size_t ExcessiveAlignmentThreshold = 16; +#endif + Function() = default; Function(nullptr_t) { @@ -234,10 +242,17 @@ private: template void init_with_callable(Callable&& callable, CallableKind callable_kind) { + if constexpr (alignof(Callable) > ExcessiveAlignmentThreshold && !AccommodateExcessiveAlignmentRequirements) { + static_assert( + alignof(Callable) <= ExcessiveAlignmentThreshold, + "This callable object has a very large alignment requirement, " + "check your capture list if it is a lambda expression, " + "and make sure your callable object is not excessively aligned."); + } VERIFY(m_call_nesting_level == 0); using WrapperType = CallableWrapper; #ifndef KERNEL - if constexpr (sizeof(WrapperType) > inline_capacity) { + if constexpr (alignof(Callable) > inline_alignment || sizeof(WrapperType) > inline_capacity) { *bit_cast(&m_storage) = new WrapperType(forward(callable)); m_kind = FunctionKind::Outline; } else { @@ -281,6 +296,7 @@ private: bool m_deferred_clear { false }; mutable Atomic m_call_nesting_level { 0 }; + static constexpr size_t inline_alignment = max(alignof(CallableWrapperBase), alignof(CallableWrapperBase*)); #ifndef KERNEL // Empirically determined to fit most lambdas and functions. static constexpr size_t inline_capacity = 4 * sizeof(void*); @@ -288,7 +304,8 @@ private: // FIXME: Try to decrease this. static constexpr size_t inline_capacity = 6 * sizeof(void*); #endif - alignas(max(alignof(CallableWrapperBase), alignof(CallableWrapperBase*))) u8 m_storage[inline_capacity]; + + alignas(inline_alignment) u8 m_storage[inline_capacity]; }; }