File Coverage

src/panda/memory.h
Criterion Covered Total %
statement 7 10 70.0
branch 2 4 50.0
condition n/a
subroutine n/a
pod n/a
total 9 14 64.2


line stmt bran cond sub pod time code
1             #pragma once
2             #include
3             #include
4             #include
5             #include
6              
7             namespace panda {
8              
9             namespace detail {
10             void* __get_global_ptr (const std::type_info& ti, const char* name, void* val);
11             void* __get_global_tls_ptr (const std::type_info& ti, const char* name, void* val);
12             }
13              
14             template
15             inline T* get_global_ptr (T* val, const char* name = NULL) {
16             return reinterpret_cast(detail::__get_global_ptr(typeid(CLASS), name, reinterpret_cast(val)));
17             }
18              
19             template
20             inline T* get_global_tls_ptr (T* val, const char* name = NULL) {
21             return reinterpret_cast(detail::__get_global_tls_ptr(typeid(CLASS), name, reinterpret_cast(val)));
22             }
23              
24             #define PANDA_GLOBAL_MEMBER_PTR(CLASS, TYPE, accessor, defval) \
25             static TYPE accessor () { \
26             static TYPE ptr; \
27             if (!ptr) ptr = panda::get_global_ptr(defval, #accessor); \
28             return ptr; \
29             }
30              
31             #define PANDA_GLOBAL_MEMBER(CLASS, TYPE, accessor, defval) \
32             static TYPE& accessor () { \
33             static TYPE* ptr; \
34             if (!ptr) { \
35             static TYPE val = defval; \
36             ptr = panda::get_global_ptr(&val, #accessor); \
37             } \
38             return *ptr; \
39             }
40              
41             #define PANDA_GLOBAL_MEMBER_AS_PTR(CLASS, TYPE, accessor, defval) \
42             static TYPE* accessor () { \
43             static TYPE* ptr; \
44             if (!ptr) { \
45             static TYPE val = defval; \
46             ptr = panda::get_global_ptr(&val, #accessor); \
47             } \
48             return ptr; \
49             }
50              
51             #define PANDA_TLS_MEMBER_PTR(CLASS, TYPE, accessor, defval) \
52             static TYPE accessor () { \
53             static thread_local TYPE _ptr; \
54             TYPE ptr = _ptr; \
55             if (!ptr) ptr = _ptr = panda::get_global_tls_ptr(defval, #accessor); \
56             return ptr; \
57             }
58              
59             #define PANDA_TLS_MEMBER(CLASS, TYPE, accessor, defval) \
60             static TYPE& accessor () { \
61             static thread_local TYPE* _ptr; \
62             TYPE* ptr = _ptr; \
63             if (!ptr) { \
64             static thread_local TYPE val = defval; \
65             ptr = _ptr = panda::get_global_tls_ptr(&val, #accessor); \
66             } \
67             return *ptr; \
68             }
69              
70             #define PANDA_TLS_MEMBER_AS_PTR(CLASS, TYPE, accessor, defval) \
71             static TYPE* accessor () { \
72             static thread_local TYPE* _ptr; \
73             TYPE* ptr = _ptr; \
74             if (!ptr) { \
75             static thread_local TYPE val = defval; \
76             ptr = _ptr = panda::get_global_tls_ptr(&val, #accessor); \
77             } \
78             return ptr; \
79             }
80              
81             struct MemoryPool {
82 52           MemoryPool (size_t blocksize) : first_free(NULL) {
83 26           this->blocksize = round_up(blocksize);
84 26           }
85              
86             void* allocate () {
87             if (!first_free) grow();
88             void* ret = first_free;
89             first_free = *((void**)ret);
90             return ret;
91             }
92              
93             void deallocate (void* elem) {
94             #ifdef TEST_FULL
95             if(!is_mine(elem)) abort(); // protection for debugging, normally you MUST NEVER pass a pointer that wasn't created via current mempool
96             #endif
97             *((void**)elem) = first_free;
98             first_free = elem;
99             }
100              
101             ~MemoryPool ();
102              
103             private:
104             struct Pool {
105             char* list;
106             size_t size;
107             size_t len;
108             };
109             size_t blocksize;
110             std::vector pools;
111             void* first_free;
112              
113             void grow ();
114             bool is_mine (void* elem);
115              
116 26           inline static size_t round_up (size_t size) {
117 26 50         assert(size > 0);
118 26           const size_t factor = sizeof(void*);
119 26 50         if ((size & (factor-1)) == 0) return size;
120 0           size += factor;
121 0           size &= ~((size_t)(factor-1));
122 0           return size;
123             }
124             };
125              
126             template
127             struct StaticMemoryPool {
128             PANDA_GLOBAL_MEMBER_PTR(StaticMemoryPool, MemoryPool*, global_instance, new MemoryPool(BLOCKSIZE));
129             PANDA_TLS_MEMBER_PTR (StaticMemoryPool, MemoryPool*, instance, new MemoryPool(BLOCKSIZE));
130              
131             static void* allocate () { return instance()->allocate(); }
132             static void deallocate (void* p) { instance()->deallocate(p); }
133             };
134              
135             template <> struct StaticMemoryPool<7> : StaticMemoryPool<8> {};
136             template <> struct StaticMemoryPool<6> : StaticMemoryPool<8> {};
137             template <> struct StaticMemoryPool<5> : StaticMemoryPool<8> {};
138             template <> struct StaticMemoryPool<4> : StaticMemoryPool<8> {};
139             template <> struct StaticMemoryPool<3> : StaticMemoryPool<8> {};
140             template <> struct StaticMemoryPool<2> : StaticMemoryPool<8> {};
141             template <> struct StaticMemoryPool<1> : StaticMemoryPool<8> {};
142              
143              
144             struct DynamicMemoryPool {
145             static DynamicMemoryPool* global_instance () { return _global_instance; }
146              
147             PANDA_TLS_MEMBER_PTR(DynamicMemoryPool, DynamicMemoryPool*, instance, new DynamicMemoryPool());
148              
149             DynamicMemoryPool ();
150              
151             void* allocate (size_t size) {
152             if (size == 0) return NULL;
153             MemoryPool* pool;
154             if (size <= 1024) {
155             pool = small_pools[(size-1)>>2];
156             if (!pool) pool = small_pools[(size-1)>>2] = new MemoryPool((((size-1)>>2) + 1)<<2);
157             }
158             else if (size <= 16384) {
159             pool = medium_pools[(size-1)>>6];
160             if (!pool) pool = medium_pools[(size-1)>>6] = new MemoryPool((((size-1)>>6) + 1)<<6);
161             }
162             else if (size <= 262144) {
163             pool = big_pools[(size-1)>>10];
164             if (!pool) pool = big_pools[(size-1)>>10] = new MemoryPool((((size-1)>>10) + 1)<<10);
165             }
166             else throw std::invalid_argument("ObjectAllocator: object size cannot exceed 256k");
167              
168             return pool->allocate();
169             }
170              
171             void deallocate (void* ptr, size_t size) {
172             if (ptr == NULL || size == 0) return;
173             MemoryPool* pool;
174             if (size <= 1024) pool = small_pools[(size-1)>>2];
175             else if (size <= 16384) pool = medium_pools[(size-1)>>6];
176             else if (size <= 262144) pool = big_pools[(size-1)>>10];
177             else throw std::invalid_argument("ObjectAllocator: object size cannot exceed 256k");
178             pool->deallocate(ptr);
179             }
180              
181             ~DynamicMemoryPool ();
182              
183             private:
184             static constexpr const int POOLS_CNT = 256;
185             static DynamicMemoryPool* _global_instance;
186             MemoryPool* small_pools[POOLS_CNT];
187             MemoryPool* medium_pools[POOLS_CNT];
188             MemoryPool* big_pools[POOLS_CNT];
189              
190             };
191              
192             template
193             struct AllocatedObject {
194             static void* operator new (size_t, void* p) { return p; }
195              
196             static void* operator new (size_t size) {
197             if (size == sizeof(TARGET)) return StaticMemoryPool::allocate();
198             else return DynamicMemoryPool::instance()->allocate(size);
199             }
200              
201             static void operator delete (void* p, size_t size) {
202             if (size == sizeof(TARGET)) StaticMemoryPool::deallocate(p);
203             else DynamicMemoryPool::instance()->deallocate(p, size);
204             }
205             };
206              
207             template
208             struct AllocatedObject {
209             static void* operator new (size_t, void* p) { return p; }
210              
211             static void* operator new (size_t size) {
212             if (size == sizeof(TARGET)) return StaticMemoryPool::global_instance()->allocate();
213             else return DynamicMemoryPool::global_instance()->allocate(size);
214             }
215              
216             static void operator delete (void* p, size_t size) {
217             if (size == sizeof(TARGET)) StaticMemoryPool::global_instance()->deallocate(p);
218             else DynamicMemoryPool::global_instance()->deallocate(p, size);
219             }
220             };
221              
222             }