From b173a4d93551bbaabd3c4c26104f3c098055efae Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 5 Feb 2024 19:26:45 +0200 Subject: [Core] Improve `CowData` and `Memory` metadata alignment. --- include/godot_cpp/core/memory.hpp | 46 +++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'include/godot_cpp/core') diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 97a2b13..6775cf7 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -40,10 +40,6 @@ #include -#ifndef PAD_ALIGN -#define PAD_ALIGN 16 //must always be greater than this at much -#endif - // p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS. void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool @@ -69,6 +65,18 @@ class Memory { Memory(); public: + // Alignment: ↓ max_align_t ↓ uint64_t ↓ max_align_t + // ┌─────────────────┬──┬────────────────┬──┬───────────... + // │ uint64_t │░░│ uint64_t │░░│ T[] + // │ alloc size │░░│ element count │░░│ data + // └─────────────────┴──┴────────────────┴──┴───────────... + // Offset: ↑ SIZE_OFFSET ↑ ELEMENT_OFFSET ↑ DATA_OFFSET + // Note: "alloc size" is used and set by the engine and is never accessed or changed for the extension. + + static constexpr size_t SIZE_OFFSET = 0; + static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t))); + static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t))); + static void *alloc_static(size_t p_bytes, bool p_pad_align = false); static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); static void free_static(void *p_ptr, bool p_pad_align = false); @@ -99,7 +107,7 @@ struct Comparator { template void memdelete(T *p_class, typename std::enable_if>::type * = nullptr) { - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { p_class->~T(); } @@ -113,7 +121,7 @@ void memdelete(T *p_class) { template void memdelete_allocator(T *p_class) { - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { p_class->~T(); } @@ -136,6 +144,10 @@ public: #define memnew_arr(m_class, m_count) memnew_arr_template(m_count) +_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) { + return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET); +} + template T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { if (p_elements == 0) { @@ -145,12 +157,14 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { same strategy used by std::vector, and the Vector class, so it should be safe.*/ size_t len = sizeof(T) * p_elements; - uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true); + uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true); T *failptr = nullptr; // Get rid of a warning. ERR_FAIL_NULL_V(mem, failptr); - *(mem - 1) = p_elements; - if (!std::is_trivially_destructible::value) { + uint64_t *_elem_count_ptr = _get_element_count_ptr(mem); + *(_elem_count_ptr) = p_elements; + + if constexpr (!std::is_trivially_destructible_v) { T *elems = (T *)mem; /* call operator new */ @@ -162,12 +176,20 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { return (T *)mem; } +template +size_t memarr_len(const T *p_class) { + uint8_t *ptr = (uint8_t *)p_class; + uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr); + return *(_elem_count_ptr); +} + template void memdelete_arr(T *p_class) { - uint64_t *ptr = (uint64_t *)p_class; + uint8_t *ptr = (uint8_t *)p_class; - if (!std::is_trivially_destructible::value) { - uint64_t elem_count = *(ptr - 1); + if constexpr (!std::is_trivially_destructible_v) { + uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr); + uint64_t elem_count = *(_elem_count_ptr); for (uint64_t i = 0; i < elem_count; i++) { p_class[i].~T(); -- cgit v1.2.3