blueloveTH 2 лет назад
Родитель
Сommit
9e9cbcdffd
11 измененных файлов с 298 добавлено и 274 удалено
  1. 2 2
      include/pocketpy/gc.h
  2. 12 241
      include/pocketpy/memory.h
  3. 4 4
      include/pocketpy/namedict.h
  4. 1 1
      include/pocketpy/obj.h
  5. 7 7
      include/pocketpy/vector.h
  6. 10 10
      src/dict.cpp
  7. 3 3
      src/gc.cpp
  8. 253 0
      src/memory.cpp
  9. 1 1
      src/obj.cpp
  10. 3 3
      src/str.cpp
  11. 2 2
      src/tuplelist.cpp

+ 2 - 2
include/pocketpy/gc.h

@@ -41,7 +41,7 @@ struct ManagedHeap{
     PyObject* gcnew(Type type, Args&&... args){
         using __T = Py_<std::decay_t<T>>;
         // https://github.com/blueloveTH/pocketpy/issues/94#issuecomment-1594784476
-        PyObject* obj = new(pool64.alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
+        PyObject* obj = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
         gen.push_back(obj);
         gc_counter++;
         return obj;
@@ -51,7 +51,7 @@ struct ManagedHeap{
     PyObject* _new(Type type, Args&&... args){
         using __T = Py_<std::decay_t<T>>;
         // https://github.com/blueloveTH/pocketpy/issues/94#issuecomment-1594784476
-        PyObject* obj = new(pool64.alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
+        PyObject* obj = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
         obj->gc.enabled = false;
         _no_gc.push_back(obj);
         return obj;

+ 12 - 241
include/pocketpy/memory.h

@@ -4,249 +4,20 @@
 
 namespace pkpy{
 
-struct LinkedListNode{
-    LinkedListNode* prev;
-    LinkedListNode* next;
-};
+void* pool64_alloc(size_t);
+void pool64_dealloc(void*);
 
-template<typename T>
-struct DoubleLinkedList{
-    static_assert(std::is_base_of_v<LinkedListNode, T>);
-    int _size;
-    LinkedListNode head;
-    LinkedListNode tail;
-    
-    DoubleLinkedList(): _size(0){
-        head.prev = nullptr;
-        head.next = &tail;
-        tail.prev = &head;
-        tail.next = nullptr;
-    }
-
-    void push_back(T* node){
-        node->prev = tail.prev;
-        node->next = &tail;
-        tail.prev->next = node;
-        tail.prev = node;
-        _size++;
-    }
-
-    void push_front(T* node){
-        node->prev = &head;
-        node->next = head.next;
-        head.next->prev = node;
-        head.next = node;
-        _size++;
-    }
-
-    void pop_back(){
-#if PK_DEBUG_MEMORY_POOL
-        if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list");
-#endif
-        tail.prev->prev->next = &tail;
-        tail.prev = tail.prev->prev;
-        _size--;
-    }
-
-    void pop_front(){
-#if PK_DEBUG_MEMORY_POOL
-        if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list");
-#endif
-        head.next->next->prev = &head;
-        head.next = head.next->next;
-        _size--;
-    }
-
-    T* back() const {
-#if PK_DEBUG_MEMORY_POOL
-        if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list");
-#endif
-        return static_cast<T*>(tail.prev);
-    }
-
-    T* front() const {
-#if PK_DEBUG_MEMORY_POOL
-        if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list");
-#endif
-        return static_cast<T*>(head.next);
-    }
-
-    void erase(T* node){
-#if PK_DEBUG_MEMORY_POOL
-        if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list");
-        LinkedListNode* n = head.next;
-        while(n != &tail){
-            if(n == node) break;
-            n = n->next;
-        }
-        if(n != node) throw std::runtime_error("DoubleLinkedList::erase() called on node not in the list");
-#endif
-        node->prev->next = node->next;
-        node->next->prev = node->prev;
-        _size--;
-    }
-
-    // void move_all_back(DoubleLinkedList<T>& other){
-    //     if(other.empty()) return;
-    //     other.tail.prev->next = &tail;
-    //     tail.prev->next = other.head.next;
-    //     other.head.next->prev = tail.prev;
-    //     tail.prev = other.tail.prev;
-    //     _size += other._size;
-    //     other.head.next = &other.tail;
-    //     other.tail.prev = &other.head;
-    //     other._size = 0;
-    // }
-
-    bool empty() const {
-#if PK_DEBUG_MEMORY_POOL
-        if(size() == 0){
-            if(head.next != &tail || tail.prev != &head){
-                throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty");
-            }
-            return true;
-        }
-#endif
-        return _size == 0;
-    }
-
-    int size() const { return _size; }
-
-    template<typename Func>
-    void apply(Func func){
-        LinkedListNode* p = head.next;
-        while(p != &tail){
-            LinkedListNode* next = p->next;
-            func(static_cast<T*>(p));
-            p = next;
-        }
-    }
-};
-
-template<int __BlockSize=128>
-struct MemoryPool{
-    static const size_t __MaxBlocks = 256*1024 / __BlockSize;
-    struct Block{
-        void* arena;
-        char data[__BlockSize];
-    };
-
-    struct Arena: LinkedListNode{
-        Block _blocks[__MaxBlocks];
-        Block* _free_list[__MaxBlocks];
-        int _free_list_size;
-        bool dirty;
-        
-        Arena(): _free_list_size(__MaxBlocks), dirty(false){
-            for(int i=0; i<__MaxBlocks; i++){
-                _blocks[i].arena = this;
-                _free_list[i] = &_blocks[i];
-            }
-        }
+void* pool128_alloc(size_t);
+void pool128_dealloc(void*);
 
-        bool empty() const { return _free_list_size == 0; }
-        bool full() const { return _free_list_size == __MaxBlocks; }
-
-        size_t allocated_size() const{
-            return __BlockSize * (__MaxBlocks - _free_list_size);
-        }
-
-        Block* alloc(){
-#if PK_DEBUG_MEMORY_POOL
-            if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena");
-#endif
-            _free_list_size--;
-            return _free_list[_free_list_size];
-        }
-
-        void dealloc(Block* block){
-#if PK_DEBUG_MEMORY_POOL
-            if(full()) throw std::runtime_error("Arena::dealloc() called on full arena");
-#endif
-            _free_list[_free_list_size] = block;
-            _free_list_size++;
-        }
-    };
-
-    MemoryPool() = default;
-    MemoryPool(const MemoryPool&) = delete;
-    MemoryPool& operator=(const MemoryPool&) = delete;
-    MemoryPool(MemoryPool&&) = delete;
-    MemoryPool& operator=(MemoryPool&&) = delete;
-
-    DoubleLinkedList<Arena> _arenas;
-    DoubleLinkedList<Arena> _empty_arenas;
-
-    template<typename __T>
-    void* alloc() { return alloc(sizeof(__T)); }
-
-    void* alloc(size_t size){
-        PK_GLOBAL_SCOPE_LOCK();
-#if PK_DEBUG_NO_MEMORY_POOL
-        return malloc(size);
-#endif
-        if(size > __BlockSize){
-            void* p = malloc(sizeof(void*) + size);
-            memset(p, 0, sizeof(void*));
-            return (char*)p + sizeof(void*);
-        }
-
-        if(_arenas.empty()){
-            // std::cout << _arenas.size() << ',' << _empty_arenas.size() << ',' << _full_arenas.size() << std::endl;
-            _arenas.push_back(new Arena());
-        }
-        Arena* arena = _arenas.back();
-        void* p = arena->alloc()->data;
-        if(arena->empty()){
-            _arenas.pop_back();
-            arena->dirty = true;
-            _empty_arenas.push_back(arena);
-        }
-        return p;
-    }
-
-    void dealloc(void* p){
-        PK_GLOBAL_SCOPE_LOCK();
-#if PK_DEBUG_NO_MEMORY_POOL
-        free(p);
-        return;
-#endif
-#if PK_DEBUG_MEMORY_POOL
-        if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr");
-#endif
-        Block* block = (Block*)((char*)p - sizeof(void*));
-        if(block->arena == nullptr){
-            free(block);
-        }else{
-            Arena* arena = (Arena*)block->arena;
-            if(arena->empty()){
-                _empty_arenas.erase(arena);
-                _arenas.push_front(arena);
-                arena->dealloc(block);
-            }else{
-                arena->dealloc(block);
-                if(arena->full() && arena->dirty){
-                    _arenas.erase(arena);
-                    delete arena;
-                }
-            }
-        }
-    }
-
-    size_t allocated_size() {
-        size_t n = 0;
-        _arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); });
-        _empty_arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); });
-        return n;
-    }
-
-    ~MemoryPool(){
-        _arenas.apply([](Arena* arena){ delete arena; });
-        _empty_arenas.apply([](Arena* arena){ delete arena; });
-    }
-};
+template<typename T>
+void* pool64_alloc(){
+    return pool64_alloc(sizeof(T));
+}
 
-inline MemoryPool<64> pool64;
-inline MemoryPool<128> pool128;
+template<typename T>
+void* pool128_alloc(){
+    return pool128_alloc(sizeof(T));
+}
 
 };  // namespace pkpy

+ 4 - 4
include/pocketpy/namedict.h

@@ -38,7 +38,7 @@ while(!_items[i].first.empty()) {       \
 }
 
 #define NAMEDICT_ALLOC()                \
-    _items = (Item*)pool128.alloc(_capacity * sizeof(Item));    \
+    _items = (Item*)pool128_alloc(_capacity * sizeof(Item));    \
     memset(_items, 0, _capacity * sizeof(Item));                \
 
     NameDictImpl(float load_factor=0.67f):
@@ -54,14 +54,14 @@ while(!_items[i].first.empty()) {       \
     }
 
     NameDictImpl& operator=(const NameDictImpl& other) {
-        pool128.dealloc(_items);
+        pool128_dealloc(_items);
         memcpy(this, &other, sizeof(NameDictImpl));
         NAMEDICT_ALLOC()
         for(int i=0; i<_capacity; i++) _items[i] = other._items[i];
         return *this;
     }
     
-    ~NameDictImpl(){ pool128.dealloc(_items); }
+    ~NameDictImpl(){ pool128_dealloc(_items); }
 
     NameDictImpl(NameDictImpl&&) = delete;
     NameDictImpl& operator=(NameDictImpl&&) = delete;
@@ -103,7 +103,7 @@ while(!_items[i].first.empty()) {       \
             if(ok) FATAL_ERROR();
             _items[j] = old_items[i];
         }
-        pool128.dealloc(old_items);
+        pool128_dealloc(old_items);
     }
 
     void _try_perfect_rehash(){

+ 1 - 1
include/pocketpy/obj.h

@@ -119,7 +119,7 @@ struct PyObject{
     virtual ~PyObject();
 
     void enable_instance_dict(float lf=kInstAttrLoadFactor) {
-        _attr = new(pool64.alloc<NameDict>()) NameDict(lf);
+        _attr = new(pool64_alloc<NameDict>()) NameDict(lf);
     }
 };
 

+ 7 - 7
include/pocketpy/vector.h

@@ -16,15 +16,15 @@ struct pod_vector{
     T* _data;
 
     pod_vector(): _size(0), _capacity(N) {
-        _data = (T*)pool64.alloc(_capacity * sizeof(T));
+        _data = (T*)pool64_alloc(_capacity * sizeof(T));
     }
 
     pod_vector(int size): _size(size), _capacity(std::max(N, size)) {
-        _data = (T*)pool64.alloc(_capacity * sizeof(T));
+        _data = (T*)pool64_alloc(_capacity * sizeof(T));
     }
 
     pod_vector(const pod_vector& other): _size(other._size), _capacity(other._capacity) {
-        _data = (T*)pool64.alloc(_capacity * sizeof(T));
+        _data = (T*)pool64_alloc(_capacity * sizeof(T));
         memcpy(_data, other._data, sizeof(T) * _size);
     }
 
@@ -36,7 +36,7 @@ struct pod_vector{
     }
 
     pod_vector& operator=(pod_vector&& other) noexcept {
-        if(_data!=nullptr) pool64.dealloc(_data);
+        if(_data!=nullptr) pool64_dealloc(_data);
         _size = other._size;
         _capacity = other._capacity;
         _data = other._data;
@@ -63,10 +63,10 @@ struct pod_vector{
         if(cap <= _capacity) return;
         _capacity = cap;
         T* old_data = _data;
-        _data = (T*)pool64.alloc(_capacity * sizeof(T));
+        _data = (T*)pool64_alloc(_capacity * sizeof(T));
         if(old_data!=nullptr){
             memcpy(_data, old_data, sizeof(T) * _size);
-            pool64.dealloc(old_data);
+            pool64_dealloc(old_data);
         }
     }
 
@@ -115,7 +115,7 @@ struct pod_vector{
     }
 
     ~pod_vector() {
-        if(_data!=nullptr) pool64.dealloc(_data);
+        if(_data!=nullptr) pool64_dealloc(_data);
     }
 };
 

+ 10 - 10
src/dict.cpp

@@ -5,9 +5,9 @@ namespace pkpy{
     Dict::Dict(VM* vm): vm(vm), _capacity(__Capacity),
             _mask(__Capacity-1),
             _size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _head_idx(-1), _tail_idx(-1){
-        _items = (Item*)pool128.alloc(_capacity * sizeof(Item));
+        _items = (Item*)pool128_alloc(_capacity * sizeof(Item));
         memset(_items, 0, _capacity * sizeof(Item));
-        _nodes = (ItemNode*)pool64.alloc(_capacity * sizeof(ItemNode));
+        _nodes = (ItemNode*)pool64_alloc(_capacity * sizeof(ItemNode));
         memset(_nodes, -1, _capacity * sizeof(ItemNode));
     }
 
@@ -33,9 +33,9 @@ namespace pkpy{
         _critical_size = other._critical_size;
         _head_idx = other._head_idx;
         _tail_idx = other._tail_idx;
-        _items = (Item*)pool128.alloc(_capacity * sizeof(Item));
+        _items = (Item*)pool128_alloc(_capacity * sizeof(Item));
         memcpy(_items, other._items, _capacity * sizeof(Item));
-        _nodes = (ItemNode*)pool64.alloc(_capacity * sizeof(ItemNode));
+        _nodes = (ItemNode*)pool64_alloc(_capacity * sizeof(ItemNode));
         memcpy(_nodes, other._nodes, _capacity * sizeof(ItemNode));
     }
 
@@ -73,9 +73,9 @@ namespace pkpy{
         _head_idx = -1;
         _tail_idx = -1;
         
-        _items = (Item*)pool128.alloc(_capacity * sizeof(Item));
+        _items = (Item*)pool128_alloc(_capacity * sizeof(Item));
         memset(_items, 0, _capacity * sizeof(Item));
-        _nodes = (ItemNode*)pool64.alloc(_capacity * sizeof(ItemNode));
+        _nodes = (ItemNode*)pool64_alloc(_capacity * sizeof(ItemNode));
         memset(_nodes, -1, _capacity * sizeof(ItemNode));
 
         // copy old items to new dict
@@ -84,8 +84,8 @@ namespace pkpy{
             set(old_items[i].first, old_items[i].second);
             i = old_nodes[i].next;
         }
-        pool128.dealloc(old_items);
-        pool64.dealloc(old_nodes);
+        pool128_dealloc(old_items);
+        pool64_dealloc(old_nodes);
     }
 
 
@@ -167,8 +167,8 @@ namespace pkpy{
 
     Dict::~Dict(){
         if(_items==nullptr) return;
-        pool128.dealloc(_items);
-        pool64.dealloc(_nodes);
+        pool128_dealloc(_items);
+        pool64_dealloc(_nodes);
     }
 
     void Dict::_gc_mark() const{

+ 3 - 3
src/gc.cpp

@@ -14,7 +14,7 @@ namespace pkpy{
 #endif
                 if(_gc_on_delete) _gc_on_delete(vm, obj);
                 obj->~PyObject();
-                pool64.dealloc(obj);
+                pool64_dealloc(obj);
             }
         }
 
@@ -47,8 +47,8 @@ namespace pkpy{
     }
 
     ManagedHeap::~ManagedHeap(){
-        for(PyObject* obj: _no_gc) { obj->~PyObject(); pool64.dealloc(obj); }
-        for(PyObject* obj: gen) { obj->~PyObject(); pool64.dealloc(obj); }
+        for(PyObject* obj: _no_gc) { obj->~PyObject(); pool64_dealloc(obj); }
+        for(PyObject* obj: gen) { obj->~PyObject(); pool64_dealloc(obj); }
 #if PK_DEBUG_GC_STATS
         for(auto& [type, count]: deleted){
             std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl;

+ 253 - 0
src/memory.cpp

@@ -0,0 +1,253 @@
+#include "pocketpy/memory.h"
+
+namespace pkpy{
+
+struct LinkedListNode{
+    LinkedListNode* prev;
+    LinkedListNode* next;
+};
+
+template<typename T>
+struct DoubleLinkedList{
+    static_assert(std::is_base_of_v<LinkedListNode, T>);
+    int _size;
+    LinkedListNode head;
+    LinkedListNode tail;
+    
+    DoubleLinkedList(): _size(0){
+        head.prev = nullptr;
+        head.next = &tail;
+        tail.prev = &head;
+        tail.next = nullptr;
+    }
+
+    void push_back(T* node){
+        node->prev = tail.prev;
+        node->next = &tail;
+        tail.prev->next = node;
+        tail.prev = node;
+        _size++;
+    }
+
+    void push_front(T* node){
+        node->prev = &head;
+        node->next = head.next;
+        head.next->prev = node;
+        head.next = node;
+        _size++;
+    }
+
+    void pop_back(){
+#if PK_DEBUG_MEMORY_POOL
+        if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list");
+#endif
+        tail.prev->prev->next = &tail;
+        tail.prev = tail.prev->prev;
+        _size--;
+    }
+
+    void pop_front(){
+#if PK_DEBUG_MEMORY_POOL
+        if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list");
+#endif
+        head.next->next->prev = &head;
+        head.next = head.next->next;
+        _size--;
+    }
+
+    T* back() const {
+#if PK_DEBUG_MEMORY_POOL
+        if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list");
+#endif
+        return static_cast<T*>(tail.prev);
+    }
+
+    T* front() const {
+#if PK_DEBUG_MEMORY_POOL
+        if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list");
+#endif
+        return static_cast<T*>(head.next);
+    }
+
+    void erase(T* node){
+#if PK_DEBUG_MEMORY_POOL
+        if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list");
+        LinkedListNode* n = head.next;
+        while(n != &tail){
+            if(n == node) break;
+            n = n->next;
+        }
+        if(n != node) throw std::runtime_error("DoubleLinkedList::erase() called on node not in the list");
+#endif
+        node->prev->next = node->next;
+        node->next->prev = node->prev;
+        _size--;
+    }
+
+    // void move_all_back(DoubleLinkedList<T>& other){
+    //     if(other.empty()) return;
+    //     other.tail.prev->next = &tail;
+    //     tail.prev->next = other.head.next;
+    //     other.head.next->prev = tail.prev;
+    //     tail.prev = other.tail.prev;
+    //     _size += other._size;
+    //     other.head.next = &other.tail;
+    //     other.tail.prev = &other.head;
+    //     other._size = 0;
+    // }
+
+    bool empty() const {
+#if PK_DEBUG_MEMORY_POOL
+        if(size() == 0){
+            if(head.next != &tail || tail.prev != &head){
+                throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty");
+            }
+            return true;
+        }
+#endif
+        return _size == 0;
+    }
+
+    int size() const { return _size; }
+
+    template<typename Func>
+    void apply(Func func){
+        LinkedListNode* p = head.next;
+        while(p != &tail){
+            LinkedListNode* next = p->next;
+            func(static_cast<T*>(p));
+            p = next;
+        }
+    }
+};
+
+template<int __BlockSize=128>
+struct MemoryPool{
+    static const size_t __MaxBlocks = 256*1024 / __BlockSize;
+    struct Block{
+        void* arena;
+        char data[__BlockSize];
+    };
+
+    struct Arena: LinkedListNode{
+        Block _blocks[__MaxBlocks];
+        Block* _free_list[__MaxBlocks];
+        int _free_list_size;
+        bool dirty;
+        
+        Arena(): _free_list_size(__MaxBlocks), dirty(false){
+            for(int i=0; i<__MaxBlocks; i++){
+                _blocks[i].arena = this;
+                _free_list[i] = &_blocks[i];
+            }
+        }
+
+        bool empty() const { return _free_list_size == 0; }
+        bool full() const { return _free_list_size == __MaxBlocks; }
+
+        size_t allocated_size() const{
+            return __BlockSize * (__MaxBlocks - _free_list_size);
+        }
+
+        Block* alloc(){
+#if PK_DEBUG_MEMORY_POOL
+            if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena");
+#endif
+            _free_list_size--;
+            return _free_list[_free_list_size];
+        }
+
+        void dealloc(Block* block){
+#if PK_DEBUG_MEMORY_POOL
+            if(full()) throw std::runtime_error("Arena::dealloc() called on full arena");
+#endif
+            _free_list[_free_list_size] = block;
+            _free_list_size++;
+        }
+    };
+
+    MemoryPool() = default;
+    MemoryPool(const MemoryPool&) = delete;
+    MemoryPool& operator=(const MemoryPool&) = delete;
+    MemoryPool(MemoryPool&&) = delete;
+    MemoryPool& operator=(MemoryPool&&) = delete;
+
+    DoubleLinkedList<Arena> _arenas;
+    DoubleLinkedList<Arena> _empty_arenas;
+
+    void* alloc(size_t size){
+        PK_GLOBAL_SCOPE_LOCK();
+#if PK_DEBUG_NO_MEMORY_POOL
+        return malloc(size);
+#endif
+        if(size > __BlockSize){
+            void* p = malloc(sizeof(void*) + size);
+            memset(p, 0, sizeof(void*));
+            return (char*)p + sizeof(void*);
+        }
+
+        if(_arenas.empty()){
+            // std::cout << _arenas.size() << ',' << _empty_arenas.size() << ',' << _full_arenas.size() << std::endl;
+            _arenas.push_back(new Arena());
+        }
+        Arena* arena = _arenas.back();
+        void* p = arena->alloc()->data;
+        if(arena->empty()){
+            _arenas.pop_back();
+            arena->dirty = true;
+            _empty_arenas.push_back(arena);
+        }
+        return p;
+    }
+
+    void dealloc(void* p){
+        PK_GLOBAL_SCOPE_LOCK();
+#if PK_DEBUG_NO_MEMORY_POOL
+        free(p);
+        return;
+#endif
+#if PK_DEBUG_MEMORY_POOL
+        if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr");
+#endif
+        Block* block = (Block*)((char*)p - sizeof(void*));
+        if(block->arena == nullptr){
+            free(block);
+        }else{
+            Arena* arena = (Arena*)block->arena;
+            if(arena->empty()){
+                _empty_arenas.erase(arena);
+                _arenas.push_front(arena);
+                arena->dealloc(block);
+            }else{
+                arena->dealloc(block);
+                if(arena->full() && arena->dirty){
+                    _arenas.erase(arena);
+                    delete arena;
+                }
+            }
+        }
+    }
+
+    // size_t allocated_size() {
+    //     size_t n = 0;
+    //     _arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); });
+    //     _empty_arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); });
+    //     return n;
+    // }
+
+    ~MemoryPool(){
+        _arenas.apply([](Arena* arena){ delete arena; });
+        _empty_arenas.apply([](Arena* arena){ delete arena; });
+    }
+};
+
+static MemoryPool<64> pool64;
+static MemoryPool<128> pool128;
+
+void* pool64_alloc(size_t size){ return pool64.alloc(size); }
+void pool64_dealloc(void* p){ pool64.dealloc(p); }
+
+void* pool128_alloc(size_t size){ return pool128.alloc(size); }
+void pool128_dealloc(void* p){ pool128.dealloc(p); }
+
+}

+ 1 - 1
src/obj.cpp

@@ -4,6 +4,6 @@ namespace pkpy{
     PyObject::~PyObject() {
         if(_attr == nullptr) return;
         _attr->~NameDict();
-        pool64.dealloc(_attr);
+        pool64_dealloc(_attr);
     }
 }   // namespace pkpy

+ 3 - 3
src/str.cpp

@@ -75,12 +75,12 @@ int utf8len(unsigned char c, bool suppress){
         if(size <= 16){
             this->data = _inlined;
         }else{
-            this->data = (char*)pool64.alloc(size);
+            this->data = (char*)pool64_alloc(size);
         }
     }
 
     Str& Str::operator=(const Str& other){
-        if(!is_inlined()) pool64.dealloc(data);
+        if(!is_inlined()) pool64_dealloc(data);
         size = other.size;
         is_ascii = other.is_ascii;
         _cached_c_str = nullptr;
@@ -150,7 +150,7 @@ int utf8len(unsigned char c, bool suppress){
     }
 
     Str::~Str(){
-        if(!is_inlined()) pool64.dealloc(data);
+        if(!is_inlined()) pool64_dealloc(data);
         if(_cached_c_str != nullptr) free((void*)_cached_c_str);
     }
 

+ 2 - 2
src/tuplelist.cpp

@@ -6,7 +6,7 @@ Tuple::Tuple(int n){
     if(n <= 3){
         this->_args = _inlined;
     }else{
-        this->_args = (PyObject**)pool64.alloc(n * sizeof(void*));
+        this->_args = (PyObject**)pool64_alloc(n * sizeof(void*));
     }
     this->_size = n;
 }
@@ -38,7 +38,7 @@ Tuple::Tuple(std::initializer_list<PyObject*> list): Tuple(list.size()){
     for(PyObject* obj: list) _args[i++] = obj;
 }
 
-Tuple::~Tuple(){ if(!is_inlined()) pool64.dealloc(_args); }
+Tuple::~Tuple(){ if(!is_inlined()) pool64_dealloc(_args); }
 
 List ArgsView::to_list() const{
     List ret(size());