diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 982d0c363..5e6c69bd4 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -498,7 +498,7 @@ public: \ \ static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \ /* Do not call memnew here, we don't want the post-initializer to be called */ \ - return new ("", "") m_class((GodotObject *)p_instance); \ + return new (godot::DefaultAllocator{}) m_class((GodotObject *)p_instance); \ } \ static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ /* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \ diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 7af36d9de..071909fe0 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -119,7 +119,7 @@ class ClassDB { if constexpr (!std::is_abstract_v) { Wrapped::_set_construct_info(); #if GODOT_VERSION_MINOR >= 4 - T *new_object = new ("", "") T; + T *new_object = new (godot::DefaultAllocator{}) T; if (p_notify_postinitialize) { new_object->_postinitialize(); } diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 0e1525dd4..ea3b709a4 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -32,6 +32,7 @@ #include #include +#include // IWYU pragma: keep // `new` operators. #include #include @@ -39,25 +40,7 @@ #include -// 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 -void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory - -_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) { - return p_pointer; -} - -#ifdef _MSC_VER -// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291). -// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete. -void operator delete(void *p_mem, const char *p_dummy, const char *p_description); -void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); -void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); -#endif - namespace godot { - class Wrapped; namespace Memory { @@ -92,6 +75,35 @@ void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); void free_static(void *p_ptr, bool p_pad_align = false); }; //namespace Memory +class DefaultAllocator { +public: + _ALWAYS_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory); } + _ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); } +}; + +} // namespace godot + +// Overload of `new` operator to use the `Memory::alloc_static()` function. +// The `DefaultAllocator` parameter is just a tag to select this overload. +// NOTE: do not inline `new` operators due to GCC+LTO compiler bug (see GH-119752). +void *operator new(size_t p_size, godot::DefaultAllocator p_allocator); + +// Overload of `new` operator to use a custom allocation function. +// p_allocator 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, godot::DefaultAllocator p_allocator, void *(*p_allocfunc)(size_t p_size)); + +#if defined(_MSC_VER) && !defined(__clang__) +// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291). +// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete. +inline void operator delete(void *p_mem, godot::DefaultAllocator p_allocator) { + CRASH_NOW_MSG("Call to placement delete should not happen."); +} +inline void operator delete(void *p_mem, godot::DefaultAllocator, void *(*p_allocfunc)(size_t p_size)) { + CRASH_NOW_MSG("Call to placement delete should not happen."); +} +#endif // defined(_MSC_VER) && !defined(__clang__) + +namespace godot { template ::value, bool> = true> _ALWAYS_INLINE_ void _pre_initialize() {} @@ -117,10 +129,10 @@ _ALWAYS_INLINE_ memnew_result_t _post_initialize(T *p_obj) { #define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size) #define memfree(m_mem) ::godot::Memory::free_static(m_mem) -#define memnew(m_class) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", "") m_class)) +#define memnew(m_class) (::godot::_pre_initialize>(), ::godot::_post_initialize(new (godot::DefaultAllocator{}) m_class)) -#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)) -#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)) +#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize>(), ::godot::_post_initialize(new (godot::DefaultAllocator{}, m_allocator::alloc) m_class)) +#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize>(), ::godot::_post_initialize(new (m_placement) m_class)) template void memdelete(T *p_class, typename std::enable_if>::type * = nullptr) { @@ -145,12 +157,6 @@ void memdelete_allocator(T *p_class) { A::free(p_class); } -class DefaultAllocator { -public: - _ALWAYS_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory); } - _ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); } -}; - template class DefaultTypedAllocator { public: @@ -166,7 +172,7 @@ _FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) { } template -T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { +T *memnew_arr_template(size_t p_elements) { if (p_elements == 0) { return nullptr; } @@ -186,7 +192,7 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { /* call operator new */ for (size_t i = 0; i < p_elements; i++) { - new ("", &elems[i], sizeof(T), p_descr) T; + new (&elems[i]) T; } } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index e24f98a89..4995adb0e 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -95,31 +95,10 @@ _GlobalNil _GlobalNilClass::_nil; } // namespace godot -// 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) { +void *operator new(size_t p_size, godot::DefaultAllocator p_allocator) { return godot::Memory::alloc_static(p_size); } -void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)) { +void *operator new(size_t p_size, godot::DefaultAllocator p_allocator, void *(*p_allocfunc)(size_t p_size)) { return p_allocfunc(p_size); } - -using namespace godot; - -#ifdef _MSC_VER -void operator delete(void *p_mem, const char *p_dummy, const char *p_description) { - ERR_PRINT("Call to placement delete should not happen."); - CRASH_NOW(); -} - -void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)) { - ERR_PRINT("Call to placement delete should not happen."); - CRASH_NOW(); -} - -void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) { - ERR_PRINT("Call to placement delete should not happen."); - CRASH_NOW(); -} - -#endif