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.
This commit is contained in:
Ali Mohammad Pur 2023-09-14 15:45:10 +03:30 committed by Ali Mohammad Pur
parent 5e0a28c947
commit 1b2007cc7f
Notes: sideshowbarker 2024-07-17 09:56:35 +09:00

View file

@ -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<typename Callable>
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<Callable>;
#ifndef KERNEL
if constexpr (sizeof(WrapperType) > inline_capacity) {
if constexpr (alignof(Callable) > inline_alignment || sizeof(WrapperType) > inline_capacity) {
*bit_cast<CallableWrapperBase**>(&m_storage) = new WrapperType(forward<Callable>(callable));
m_kind = FunctionKind::Outline;
} else {
@ -281,6 +296,7 @@ private:
bool m_deferred_clear { false };
mutable Atomic<u16> 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];
};
}