LCOV - code coverage report
Current view: top level - core/core/memory - SPMemAlloc.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 122 93.4 %
Date: 2024-05-12 00:16:13 Functions: 1909 2446 78.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_CORE_MEMORY_SPMEMALLOC_H_
      25             : #define STAPPLER_CORE_MEMORY_SPMEMALLOC_H_
      26             : 
      27             : #include "SPMemPoolApi.h"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler::memory {
      30             : 
      31             : struct AllocBase {
      32     8876438 :         void * operator new (size_t size) noexcept { return ::operator new(size); }
      33             :         void * operator new (size_t size, const std::nothrow_t& tag) noexcept { return ::operator new(size); }
      34          42 :         void * operator new (size_t size, void* ptr) noexcept { return ::operator new(size, ptr); }
      35     8877253 :         void operator delete(void *ptr) noexcept { return ::operator delete(ptr); }
      36             : };
      37             : 
      38             : // Root class for pool allocated objects
      39             : // Use with care
      40             : struct AllocPool {
      41    11223895 :         void *operator new(size_t size) noexcept {
      42    11223895 :                 return pool::alloc(pool::acquire(), size);
      43             :         }
      44      842355 :         void *operator new(size_t size, pool_t *pool) noexcept {
      45      842355 :                 return pool::alloc(pool, size);
      46             :         }
      47     3858796 :         void *operator new(size_t size, void *mem) noexcept {
      48     3858796 :                 return mem;
      49             :         }
      50      796325 :         void operator delete(void *) noexcept {
      51             :                 // APR doesn't require to free object's memory
      52      796325 :         }
      53             : 
      54          50 :         static pool_t *getCurrentPool() {
      55          50 :                 return pool::acquire();
      56             :         }
      57             : 
      58             :         static bool isCustomPool(pool_t *);
      59             : 
      60             :         template <typename T>
      61             :         static status_t cleanupObjectFromPool(void *data);
      62             : 
      63             :         template <typename T>
      64             :         static void registerCleanupDestructor(T *obj, pool_t *pool);
      65             : };
      66             : 
      67             : namespace {
      68             : template< class...Args> struct Allocator_SelectFirst;
      69             : template< class A, class ...Args> struct Allocator_SelectFirst<A,Args...>{ using type = A; };
      70             : }
      71             : 
      72             : template <typename Type>
      73             : struct Allocator_protect_construct {
      74             :         static constexpr bool value = false; // !std::is_scalar<Type>::value;
      75             : };
      76             : 
      77             : template <class T>
      78             : class Allocator {
      79             : public:
      80             :         using pointer = T *;
      81             :         using const_pointer = const T *;
      82             : 
      83             :         using void_pointer = void *;
      84             :         using const_void_pointer = const void *;
      85             : 
      86             :         using reference = T &;
      87             :         using const_reference = const T &;
      88             : 
      89             :         using value_type = T;
      90             : 
      91             :         using size_type = size_t;
      92             :         using difference_type = ptrdiff_t;
      93             : 
      94             :     template <class U> struct rebind { using other = Allocator<U>; };
      95             : 
      96             :         // default alignment for pool_t is 8-bit, so, we can store up to 3 flags in pool pointer
      97             : 
      98             :     enum AllocFlag : uintptr_t {
      99             :         FirstFlag = 1,
     100             :         SecondFlag = 2,
     101             :                 ThirdFlag = 4,
     102             :         BitMask = 7,
     103             :     };
     104             : 
     105             : private:
     106    37281728 :     static pool_t *pool_ptr(pool_t *p) {
     107    37281728 :         return (pool_t *)(uintptr_t(p) & ~toInt(BitMask));
     108             :     }
     109             : 
     110             : public:
     111             :     // Default allocator uses pool from top of thread's AllocStack
     112    30627348 :     Allocator() noexcept : pool(pool::acquire()) { }
     113      258856 :     Allocator(pool_t *p) noexcept : pool(p) { }
     114             : 
     115     6547975 :         template<class B> Allocator(const Allocator<B> &a) noexcept : pool(a.getPool()) { }
     116             :         template<class B> Allocator(Allocator<B> &&a) noexcept : pool(a.getPool()) { }
     117             : 
     118             :         template<class B> Allocator<T> & operator = (const Allocator<B> &a) noexcept { pool = pool_ptr(a.pool); return *this; }
     119             :         template<class B> Allocator<T> & operator = (Allocator<B> &&a) noexcept { pool = pool_ptr(a.pool); return *this; }
     120             : 
     121        1704 :         T * allocate(size_t n) {
     122        1704 :                 size_t size = sizeof(T) * n;
     123        3408 :                 return (T *)pool::alloc(pool_ptr(pool), size);
     124             :         }
     125             : 
     126             :         T * __allocate(size_t &n) {
     127             :                 size_t size = sizeof(T) * n;
     128             :                 auto ptr = (T *)pool::alloc(pool_ptr(pool), size);
     129             :                 n = size / sizeof(T);
     130             :                 return ptr;
     131             :         }
     132             : 
     133    10351859 :         T * __allocate(size_t n, size_t &bytes) {
     134    10351859 :                 size_t size = sizeof(T) * n;
     135    10351859 :                 auto ptr = (T *)pool::alloc(pool_ptr(pool), size);
     136    10351485 :                 bytes = size;
     137    10351485 :                 return ptr;
     138             :         }
     139             : 
     140     2195846 :         void deallocate(T *t, size_t n) {
     141     2195846 :                 pool::free(pool_ptr(pool), t, n * sizeof(T));
     142     2196052 :         }
     143             : 
     144     1277247 :         void __deallocate(T *t, size_t n, size_t bytes) {
     145     1277247 :                 pool::free(pool_ptr(pool), t, bytes);
     146     1277204 :         }
     147             : 
     148     8423228 :         template<class B> inline bool operator == (const Allocator<B> &p) const noexcept { return pool_ptr(p.pool) == pool_ptr(pool); }
     149             :         template<class B> inline bool operator != (const Allocator<B> &p) const noexcept { return pool_ptr(p.pool) != pool_ptr(pool); }
     150             : 
     151             :         inline pointer address(reference r) const noexcept { return &r; }
     152             :         inline const_pointer address(const_reference r) const noexcept { return &r; }
     153             : 
     154             :         size_type max_size() const noexcept { return maxOf<size_type>(); }
     155             : 
     156             :         template <typename ...Args>
     157  1731787987 :         void construct(pointer p, Args &&...args) {
     158             :                 static_assert(std::is_constructible<T, Args...>::value, "Invalid arguments for constructor");
     159             :                 if constexpr (std::is_constructible<T, Args...>::value) {
     160             :                         if constexpr (sizeof...(Args) == 1) {
     161             :                                 if constexpr (std::is_trivially_copyable<T>::value && std::is_convertible_v<typename Allocator_SelectFirst<Args...>::type, const T &>) {
     162   558179498 :                                         auto construct_memcpy = [] (pointer p, const T &source) {
     163   558179498 :                                                 memcpy(p, &source, sizeof(T));
     164             :                                         };
     165             : 
     166   558173413 :                                         construct_memcpy(p, std::forward<Args>(args)...);
     167   558209684 :                                         return;
     168             :                                 }
     169             :                         }
     170             : 
     171             :                         if constexpr (Allocator_protect_construct<T>::value) {
     172             :                                 auto selfP = pool_ptr(pool);
     173             :                                 auto p = memory::pool::acquire();
     174             :                                 if (p != selfP) {
     175             :                                         memory::pool::push(selfP);
     176             :                                         new ((T*)p) T(std::forward<Args>(args)...);
     177             :                                         memory::pool::pop();
     178             :                                         return;
     179             :                                 }
     180             :                         }
     181  1173614574 :                         new ((T*)p) T(std::forward<Args>(args)...);
     182             :                 }
     183  1173614565 :         }
     184             : 
     185    15142178 :         void destroy(pointer p) {
     186             :                 if constexpr (!std::is_destructible<T>::value || std::is_scalar<T>::value) {
     187             :                         // do nothing
     188             :                 } else {
     189             :                         if constexpr (Allocator_protect_construct<T>::value) {
     190             :                                 auto selfP = pool_ptr(pool);
     191             :                                 auto pool = memory::pool::acquire();
     192             :                                 if (pool != selfP) {
     193             :                                         memory::pool::push(selfP);
     194             :                                         do { p->~T(); } while (0);
     195             :                                         memory::pool::pop();
     196             :                                         return;
     197             :                                 }
     198             :                         }
     199             : 
     200    13083407 :                         do { p->~T(); } while (0);
     201             :                 }
     202    15142181 :         }
     203             : 
     204    16920616 :         void destroy(pointer p, size_t size) {
     205             :                 if constexpr (!std::is_destructible<T>::value || std::is_scalar<T>::value) {
     206             :                         // do nothing
     207             :                 } else {
     208             :                         if constexpr (Allocator_protect_construct<T>::value) {
     209             :                                 auto selfP = pool_ptr(pool);
     210             :                                 auto pool = memory::pool::acquire();
     211             :                                 if (pool != selfP) {
     212             :                                         memory::pool::push(selfP);
     213             :                                         for (size_t i = 0; i < size; ++i) {
     214             :                                                 (p + i)->~T();
     215             :                                         }
     216             :                                         memory::pool::pop();
     217             :                                         return;
     218             :                                 }
     219             :                         }
     220             : 
     221     2232890 :                         for (size_t i = 0; i < size; ++i) {
     222     2023743 :                                 (p + i)->~T();
     223             :                         }
     224             :                 }
     225    16920617 :         }
     226             : 
     227       24644 :         operator pool_t * () const noexcept { return pool_ptr(pool); }
     228     6552792 :         pool_t *getPool() const noexcept { return pool_ptr(pool); }
     229             : 
     230   494137574 :         void copy(T *dest, const T *source, size_t count) noexcept {
     231             :                 if constexpr (std::is_trivially_copyable<T>::value) {
     232   494137574 :                         memmove(dest, source, count * sizeof(T));
     233             :                 } else {
     234             :                         if (dest == source) {
     235             :                                 return;
     236             :                         } else if (uintptr_t(dest) > uintptr_t(source)) {
     237             :                                 for (size_t i = count; i > 0; i--) {
     238             :                                         construct(dest + i - 1, *(source + i - 1));
     239             :                                 }
     240             :                         } else {
     241             :                                 for (size_t i = 0; i < count; i++) {
     242             :                                         construct(dest + i, *(source + i));
     243             :                                 }
     244             :                         }
     245             :                 }
     246   494137574 :         }
     247             : 
     248    19463712 :         void copy_rewrite(T *dest, size_t dcount, const T *source, size_t count) noexcept {
     249             :                 if constexpr (std::is_trivially_copyable<T>::value) {
     250    19077812 :                         memmove(dest, source, count * sizeof(T));
     251             :                 } else {
     252      385900 :                         if (dest == source) {
     253        3475 :                                 return;
     254      382425 :                         } else if (uintptr_t(dest) > uintptr_t(source)) {
     255      201423 :                                 size_t i = count;
     256      201423 :                                 size_t m = std::min(count, dcount);
     257      850935 :                                 for (; i > m; i--) {
     258      649512 :                                         construct(dest + i - 1, *(source + i - 1));
     259             :                                 }
     260      316814 :                                 for (; i > 0; i--) {
     261      115391 :                                         destroy(dest + i - 1);
     262      115391 :                                         construct(dest + i - 1, *(source + i - 1));
     263             :                                 }
     264             :                         } else {
     265      181002 :                                 size_t i = 0;
     266      181002 :                                 size_t m = std::min(count, dcount);
     267      327236 :                                 for (; i < m; ++ i) {
     268      146234 :                                         destroy(dest + i);
     269      146234 :                                         construct(dest + i, *(source + i));
     270             :                                 }
     271      539740 :                                 for (; i < count; ++ i) {
     272      358738 :                                         construct(dest + i, *(source + i));
     273             :                                 }
     274             :                         }
     275             :                 }
     276    19077812 :         }
     277             : 
     278     1406419 :         void move(T *dest, T *source, size_t count) noexcept {
     279             :                 if constexpr (std::is_trivially_copyable<T>::value) {
     280     1218948 :                         memmove(dest, source, count * sizeof(T));
     281             :                 } else {
     282      187471 :                         if (dest == source) {
     283           0 :                                 return;
     284      187471 :                         } else if (uintptr_t(dest) > uintptr_t(source)) {
     285      872600 :                                 for (size_t i = count; i > 0; i--) {
     286      713787 :                                         construct(dest + i - 1, std::move(*(source + i - 1)));
     287      713787 :                                         destroy(source + i - 1);
     288             :                                 }
     289             :                         } else {
     290      293998 :                                 for (size_t i = 0; i < count; i++) {
     291      265340 :                                         construct(dest + i, std::move(*(source + i)));
     292      265340 :                                         destroy(source + i);
     293             :                                 }
     294             :                         }
     295             :                 }
     296     1218948 :         }
     297     7699551 :         void move_rewrite(T *dest, size_t dcount, T *source, size_t count) noexcept {
     298             :                 if constexpr (std::is_trivially_copyable<T>::value) {
     299     7633026 :                         memmove(dest, source, count * sizeof(T));
     300             :                 } else {
     301       66525 :                         if (dest == source) {
     302           0 :                                 return;
     303       66525 :                         } else if (uintptr_t(dest) > uintptr_t(source)) {
     304       64386 :                                 size_t i = count;
     305       64386 :                                 size_t m = std::min(count, dcount);
     306      128772 :                                 for (; i > m; i--) {
     307       64386 :                                         construct(dest + i - 1, std::move(*(source + i - 1)));
     308       64386 :                                         destroy(source + i - 1);
     309             :                                 }
     310       64386 :                                 for (; i > 0; i--) {
     311           0 :                                         destroy(dest + i - 1);
     312           0 :                                         construct(dest + i - 1, std::move(*(source + i - 1)));
     313           0 :                                         destroy(source + i - 1);
     314             :                                 }
     315             :                         } else {
     316        2139 :                                 size_t i = 0;
     317        2139 :                                 size_t m = std::min(count, dcount);
     318        2139 :                                 for (; i < m; ++ i) {
     319           0 :                                         destroy(dest + i);
     320           0 :                                         construct(dest + i, std::move(*(source + i)));
     321           0 :                                         destroy(source + i);
     322             :                                 }
     323        4278 :                                 for (; i < count; ++ i) {
     324        2139 :                                         construct(dest + i, std::move(*(source + i)));
     325        2139 :                                         destroy(source + i);
     326             :                                 }
     327             :                         }
     328             :                 }
     329     7633026 :         }
     330             : 
     331  4748088222 :         bool test(AllocFlag f) const { return (uintptr_t(pool) & toInt(f)) != uintptr_t(0); }
     332    25340335 :         void set(AllocFlag f) { pool = (pool_t *)(uintptr_t(pool) | toInt(f)); }
     333    39729088 :         void reset(AllocFlag f) {pool = (pool_t *)(uintptr_t(pool) & ~toInt(f)); }
     334             :         void flip(AllocFlag f) { pool = (pool_t *)(uintptr_t(pool) ^ toInt(f)); }
     335             : 
     336             : private:
     337             :         pool_t *pool = nullptr;
     338             : };
     339             : 
     340             : template <typename Value>
     341             : struct Storage {
     342             :         struct Image { Value _value; };
     343             : 
     344             :         alignas(__alignof__(Image::_value)) uint8_t _storage[sizeof(Value)];
     345             : 
     346             :         Storage()  noexcept { }
     347             :         Storage(nullptr_t)  noexcept {}
     348             : 
     349    45385754 :         void * addr() noexcept { return static_cast<void *>(&_storage); }
     350   457560155 :         const void * addr() const noexcept { return static_cast<const void *>(&_storage); }
     351             : 
     352    45383177 :         Value * ptr() noexcept { return static_cast<Value *>(addr()); }
     353   457654595 :         const Value * ptr() const noexcept { return static_cast<const Value *>(addr()); }
     354             : 
     355             :         Value & ref() noexcept { return *ptr(); }
     356   138303636 :         const Value & ref() const noexcept { return *ptr(); }
     357             : };
     358             : 
     359             : template <typename T>
     360         125 : inline status_t AllocPool::cleanupObjectFromPool(void *data) {
     361         125 :         delete ((T *)data);
     362         125 :         return SUCCESS;
     363             : }
     364             : 
     365             : template <typename T>
     366         150 : inline void AllocPool::registerCleanupDestructor(T *obj, pool_t *pool) {
     367         150 :         pool::pre_cleanup_register(pool, (void *)obj, &(cleanupObjectFromPool<T>));
     368         150 : }
     369             : 
     370             : }
     371             : 
     372             : #endif /* STAPPLER_CORE_MEMORY_SPMEMALLOC_H_ */

Generated by: LCOV version 1.14