浏览代码

backup

backup

backup

...
blueloveTH 1 年之前
父节点
当前提交
723407dafe

+ 2 - 2
README.md

@@ -37,7 +37,7 @@ Please see https://pocketpy.dev for details and try the following resources.
 pkpy should work on any platform with a C11 compiler.
 These platforms are officially tested.
 
-> C99 compilers also work currently according to users' feedback.
+> C99 compilers may also work currently according to users' feedback.
 
 + Windows 64-bit
 + Linux 64-bit / 32-bit
@@ -74,7 +74,7 @@ It is safe to use `main` branch in production if CI badge is green.
 
 To compile it with your project, these flags must be set:
 
-+ `--std=c11` flag must be set (`--std=c99` may also work)
++ `--std=c11` flag must be set
 + For MSVC, `/utf-8` flag must be set
 + `NDEBUG` macro should be defined for release build, or you will get poor performance
 

+ 1 - 1
docs/index.md

@@ -32,7 +32,7 @@ print(primes)
 pkpy should work on any platform with a C11 compiler.
 These platforms are officially tested.
 
-> C99 compilers also work currently according to users' feedback.
+> C99 compilers may also work currently according to users' feedback.
 
 + Windows 64-bit
 + Linux 64-bit / 32-bit

+ 1 - 1
docs/quick-start.md

@@ -29,7 +29,7 @@ It is safe to use `main` branch in production if CI badge is green.
 
 To compile it with your project, these flags must be set:
 
-+ `--std=c11` flag must be set (`--std=c99` may also work)
++ `--std=c11` flag must be set
 + For MSVC, `/utf-8` flag must be set
 + `NDEBUG` macro should be defined for release build, or you will get poor performance
 

+ 1 - 1
docs/retype.yml

@@ -3,7 +3,7 @@ output: .retype
 url: https://pocketpy.dev
 branding:
   title: pocketpy
-  label: v2.0.5
+  label: v2.0.6
   logo: "./static/logo.png"
 favicon: "./static/logo.png"
 meta:

+ 0 - 10
include/pocketpy/common/memorypool.h

@@ -2,10 +2,6 @@
 
 #define kPoolExprBlockSize      128
 #define kPoolFrameBlockSize     80
-#define kPoolObjectBlockSize    80
-
-#define kPoolObjectArenaSize    (256*1024)
-#define kPoolObjectMaxBlocks    (kPoolObjectArenaSize / kPoolObjectBlockSize)
 
 void MemoryPools__initialize();
 void MemoryPools__finalize();
@@ -14,9 +10,3 @@ void* PoolExpr_alloc();
 void PoolExpr_dealloc(void*);
 void* PoolFrame_alloc();
 void PoolFrame_dealloc(void*);
-
-void* PoolObject_alloc();
-void PoolObject_dealloc(void* p);
-void PoolObject_shrink_to_fit();
-
-void Pools_debug_info(char* buffer, int size);

+ 1 - 0
include/pocketpy/common/vector.h

@@ -22,6 +22,7 @@ void c11_vector__clear(c11_vector* self);
 void* c11_vector__emplace(c11_vector* self);
 bool c11_vector__contains(const c11_vector* self, void* elem);
 void* c11_vector__submit(c11_vector* self, int* length);
+void c11_vector__swap(c11_vector* self, c11_vector* other);
 
 #define c11__getitem(T, self, index) (((T*)(self)->data)[index])
 #define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;

+ 2 - 2
include/pocketpy/config.h

@@ -1,10 +1,10 @@
 #pragma once
 // clang-format off
 
-#define PK_VERSION				"2.0.5"
+#define PK_VERSION				"2.0.6"
 #define PK_VERSION_MAJOR            2
 #define PK_VERSION_MINOR            0
-#define PK_VERSION_PATCH            5
+#define PK_VERSION_PATCH            6
 
 /*************** feature settings ***************/
 

+ 10 - 9
include/pocketpy/interpreter/heap.h

@@ -1,24 +1,25 @@
 #include "pocketpy/objects/object.h"
+#include "pocketpy/interpreter/objectpool.h"
 
-typedef struct ManagedHeap{
-    c11_vector no_gc;
-    c11_vector gen;
+typedef struct ManagedHeap {
+    MultiPool small_objects;
+    c11_vector large_objects;
 
-    int gc_threshold;
-    int gc_counter;
+    int freed_ma[3];
+    int gc_threshold;  // threshold for gc_counter
+    int gc_counter;    // objects created since last gc
     bool gc_enabled;
-    
-    VM* vm;
 } ManagedHeap;
 
-void ManagedHeap__ctor(ManagedHeap* self, VM* vm);
+void ManagedHeap__ctor(ManagedHeap* self);
 void ManagedHeap__dtor(ManagedHeap* self);
 
 void ManagedHeap__collect_if_needed(ManagedHeap* self);
 int ManagedHeap__collect(ManagedHeap* self);
 int ManagedHeap__sweep(ManagedHeap* self);
 
-PyObject* ManagedHeap__new(ManagedHeap* self, py_Type type, int slots, int udsize);
+#define ManagedHeap__new(self, type, slots, udsize)                                                \
+    ManagedHeap__gcnew((self), (type), (slots), (udsize))
 PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize);
 
 // external implementation

+ 30 - 0
include/pocketpy/interpreter/objectpool.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "pocketpy/common/vector.h"
+
+#define kPoolArenaSize (120 * 1024)
+#define kMultiPoolCount 5
+#define kPoolMaxBlockSize (32*kMultiPoolCount)
+
+typedef struct PoolArena {
+    int block_size;
+    int block_count;
+    int unused_count;
+    int* unused;
+    char data[kPoolArenaSize];
+} PoolArena;
+
+typedef struct Pool {
+    c11_vector /* PoolArena* */ arenas;
+    c11_vector /* PoolArena* */ not_free_arenas;
+    int block_size;
+} Pool;
+
+typedef struct MultiPool {
+    Pool pools[kMultiPoolCount];
+} MultiPool;
+
+void* MultiPool__alloc(MultiPool* self, int size);
+int MultiPool__sweep_dealloc(MultiPool* self);
+void MultiPool__ctor(MultiPool* self);
+void MultiPool__dtor(MultiPool* self);

+ 2 - 3
include/pocketpy/objects/object.h

@@ -5,7 +5,7 @@
 
 typedef struct PyObject {
     py_Type type;  // we have a duplicated type here for convenience
-    bool gc_is_large;
+    // bool _;
     bool gc_marked;
     int slots;  // number of slots in the object
     char flex[];
@@ -23,5 +23,4 @@ void* PyObject__userdata(PyObject* self);
 
 #define PK_OBJ_SLOTS_SIZE(slots) ((slots) >= 0 ? sizeof(py_TValue) * (slots) : sizeof(NameDict))
 
-PyObject* PyObject__new(py_Type type, int slots, int size);
-void PyObject__delete(PyObject* self);
+void PyObject__dtor(PyObject* self);

+ 1 - 1
plugins/flutter/pocketpy/pubspec.yaml

@@ -1,6 +1,6 @@
 name: pocketpy
 description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS.
-version: 2.0.5
+version: 2.0.6
 homepage: https://pocketpy.dev
 repository: https://github.com/pocketpy/pocketpy
 

+ 0 - 232
src/common/memorypool.c

@@ -2,183 +2,8 @@
 #include "pocketpy/pocketpy.h"
 
 #include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
 #include <stdbool.h>
 
-typedef struct LinkedListNode {
-    struct LinkedListNode* prev;
-    struct LinkedListNode* next;
-} LinkedListNode;
-
-typedef struct LinkedList {
-    int length;
-    LinkedListNode head;
-    LinkedListNode tail;
-} LinkedList;
-
-static void LinkedList__ctor(LinkedList* self) {
-    self->length = 0;
-    self->head.prev = NULL;
-    self->head.next = &self->tail;
-    self->tail.prev = &self->head;
-    self->tail.next = NULL;
-}
-
-static void LinkedList__push_back(LinkedList* self, LinkedListNode* node) {
-    node->prev = self->tail.prev;
-    node->next = &self->tail;
-    self->tail.prev->next = node;
-    self->tail.prev = node;
-    self->length++;
-}
-
-static void LinkedList__push_front(LinkedList* self, LinkedListNode* node) {
-    node->prev = &self->head;
-    node->next = self->head.next;
-    self->head.next->prev = node;
-    self->head.next = node;
-    self->length++;
-}
-
-static void LinkedList__pop_back(LinkedList* self) {
-    assert(self->length > 0);
-    self->tail.prev->prev->next = &self->tail;
-    self->tail.prev = self->tail.prev->prev;
-    self->length--;
-}
-
-static LinkedListNode* LinkedList__back(LinkedList* self) {
-    assert(self->length > 0);
-    return self->tail.prev;
-}
-
-static void LinkedList__erase(LinkedList* self, LinkedListNode* node) {
-    node->prev->next = node->next;
-    node->next->prev = node->prev;
-    self->length--;
-}
-
-#define LinkedList__apply(self, __STATEMENTS__) \
-    do { \
-        LinkedListNode* node = (self)->head.next; \
-        while(node != &(self)->tail) { \
-            LinkedListNode* next = node->next; \
-            __STATEMENTS__ \
-            node = next; \
-        } \
-    } while(0)
-
-typedef struct MemoryPoolBlock{
-    void* arena;
-    char data[kPoolObjectBlockSize];
-} MemoryPoolBlock;
-
-typedef struct MemoryPoolArena{
-    /* LinkedListNode */
-    LinkedListNode* prev;
-    LinkedListNode* next;
-    /* Arena */
-    MemoryPoolBlock _blocks[kPoolObjectMaxBlocks];
-    MemoryPoolBlock* _free_list[kPoolObjectMaxBlocks];
-    int _free_list_size;
-} MemoryPoolArena;
-
-typedef struct MemoryPool{
-    LinkedList _arenas;
-    LinkedList _empty_arenas;
-} MemoryPool;
-
-static void MemoryPoolArena__ctor(MemoryPoolArena* self) {
-    self->prev = NULL;
-    self->next = NULL;
-    self->_free_list_size = kPoolObjectMaxBlocks;
-    for(int i = 0; i < kPoolObjectMaxBlocks; i++) {
-        self->_blocks[i].arena = self;
-        self->_free_list[i] = &self->_blocks[i];
-    }
-}
-
-static bool MemoryPoolArena__empty(MemoryPoolArena* self) {
-    return self->_free_list_size == 0;
-}
-
-static bool MemoryPoolArena__full(MemoryPoolArena* self) {
-    return self->_free_list_size == kPoolObjectMaxBlocks;
-}
-
-static int MemoryPoolArena__total_bytes(MemoryPoolArena* self) {
-    return kPoolObjectArenaSize;
-}
-
-static int MemoryPoolArena__used_bytes(MemoryPoolArena* self) {
-    return kPoolObjectBlockSize * (kPoolObjectMaxBlocks - self->_free_list_size);
-}
-
-static MemoryPoolBlock* MemoryPoolArena__alloc(MemoryPoolArena* self) {
-    assert(!MemoryPoolArena__empty(self));
-    self->_free_list_size--;
-    return self->_free_list[self->_free_list_size];
-}
-
-static void MemoryPoolArena__dealloc(MemoryPoolArena* self, MemoryPoolBlock* block) {
-    assert(!MemoryPoolArena__full(self));
-    self->_free_list[self->_free_list_size] = block;
-    self->_free_list_size++;
-}
-
-static void MemoryPool__ctor(MemoryPool* self) {
-    LinkedList__ctor(&self->_arenas);
-    LinkedList__ctor(&self->_empty_arenas);
-}
-
-static void* MemoryPool__alloc(MemoryPool* self) {
-    MemoryPoolArena* arena;
-    if(self->_arenas.length == 0){
-        arena = PK_MALLOC(sizeof(MemoryPoolArena));
-        MemoryPoolArena__ctor(arena);
-        LinkedList__push_back(&self->_arenas, (LinkedListNode*)arena);
-    } else {
-        arena = (MemoryPoolArena*)LinkedList__back(&self->_arenas);
-    }
-    void* p = MemoryPoolArena__alloc(arena)->data;
-    if(MemoryPoolArena__empty(arena)) {
-        LinkedList__pop_back(&self->_arenas);
-        LinkedList__push_back(&self->_empty_arenas, (LinkedListNode*)arena);
-    }
-    return p;
-}
-
-static void MemoryPool__dealloc(MemoryPool* self, void* p) {
-    assert(p != NULL);
-    MemoryPoolBlock* block = (MemoryPoolBlock*)((char*)p - sizeof(void*));
-    assert(block->arena != NULL);
-    MemoryPoolArena* arena = (MemoryPoolArena*)block->arena;
-    if(MemoryPoolArena__empty(arena)) {
-        LinkedList__erase(&self->_empty_arenas, (LinkedListNode*)arena);
-        LinkedList__push_front(&self->_arenas, (LinkedListNode*)arena);
-    }
-    MemoryPoolArena__dealloc(arena, block);
-}
-
-static void MemoryPool__shrink_to_fit(MemoryPool* self) {
-    const int MIN_ARENA_COUNT = PK_GC_MIN_THRESHOLD * 100 / (kPoolObjectArenaSize);
-    if(self->_arenas.length < MIN_ARENA_COUNT) return;
-    LinkedList__apply(&self->_arenas,
-            MemoryPoolArena* arena = (MemoryPoolArena*)node;
-            if(MemoryPoolArena__full(arena)) {
-                LinkedList__erase(&self->_arenas, node);
-                PK_FREE(arena);
-            });
-}
-
-
-static void MemoryPool__dtor(MemoryPool* self) {
-    LinkedList__apply(&self->_arenas, PK_FREE(node););
-    LinkedList__apply(&self->_empty_arenas, PK_FREE(node););
-}
-
 typedef struct FixedMemoryPool {
     int BlockSize;
     int BlockCount;
@@ -240,18 +65,15 @@ static int FixedMemoryPool__total_bytes(FixedMemoryPool* self) {
 
 static FixedMemoryPool PoolExpr;
 static FixedMemoryPool PoolFrame;
-static MemoryPool PoolObject;
 
 void MemoryPools__initialize(){
     FixedMemoryPool__ctor(&PoolExpr, kPoolExprBlockSize, 64);
     FixedMemoryPool__ctor(&PoolFrame, kPoolFrameBlockSize, 128);
-    MemoryPool__ctor(&PoolObject);
 }
 
 void MemoryPools__finalize(){
     FixedMemoryPool__dtor(&PoolExpr);
     FixedMemoryPool__dtor(&PoolFrame);
-    MemoryPool__dtor(&PoolObject);
 }
 
 void* PoolExpr_alloc() {
@@ -269,57 +91,3 @@ void* PoolFrame_alloc() {
 void PoolFrame_dealloc(void* p) {
     FixedMemoryPool__dealloc(&PoolFrame, p);
 }
-
-void* PoolObject_alloc() {
-    return MemoryPool__alloc(&PoolObject);
-}
-
-void PoolObject_dealloc(void* p) {
-    MemoryPool__dealloc(&PoolObject, p);
-}
-
-void PoolObject_shrink_to_fit() {
-    MemoryPool__shrink_to_fit(&PoolObject);
-}
-
-void Pools_debug_info(char* buffer, int size) {
-    double BYTES_PER_MB = 1024.0f * 1024.0f;
-    double BYTES_PER_KB = 1024.0f;
-    int n = 0;
-    n = snprintf(
-        buffer, size,  "PoolExpr: %.2f KB (used) / %.2f KB (total) - %.2f KB (exceeded)\n",
-        FixedMemoryPool__used_bytes(&PoolExpr) / BYTES_PER_KB,
-        FixedMemoryPool__total_bytes(&PoolExpr) / BYTES_PER_KB,
-        PoolExpr.exceeded_bytes / BYTES_PER_KB
-    );
-    buffer += n; size -= n;
-    n = snprintf(
-        buffer, size, "PoolFrame: %.2f KB (used) / %.2f KB (total) - %.2f KB (exceeded)\n",
-        FixedMemoryPool__used_bytes(&PoolFrame) / BYTES_PER_KB,
-        FixedMemoryPool__total_bytes(&PoolFrame) / BYTES_PER_KB,
-        PoolFrame.exceeded_bytes / BYTES_PER_KB
-    );
-    buffer += n; size -= n;
-    // PoolObject
-    int empty_arenas = PoolObject._empty_arenas.length;
-    int arenas = PoolObject._arenas.length;
-    // print empty arenas count
-    n = snprintf(
-        buffer, size, "PoolObject: %d empty arenas, %d arenas\n",
-        empty_arenas, arenas
-    );
-    buffer += n; size -= n;
-    // log each non-empty arena
-    LinkedList__apply(&PoolObject._arenas,
-        MemoryPoolArena* arena = (MemoryPoolArena*)node;
-        n = snprintf(
-            buffer, size, "  - %p: %.2f MB (used) / %.2f MB (total)\n",
-            (void*)arena,
-            MemoryPoolArena__used_bytes(arena) / BYTES_PER_MB,
-            MemoryPoolArena__total_bytes(arena) / BYTES_PER_MB
-        );
-        buffer += n; size -= n;
-    );
-}
-
-#undef LinkedList__apply

+ 6 - 0
src/common/vector.c

@@ -62,3 +62,9 @@ void* c11_vector__submit(c11_vector* self, int* length) {
     self->capacity = 0;
     return retval;
 }
+
+void c11_vector__swap(c11_vector *self, c11_vector *other){
+    c11_vector tmp = *self;
+    *self = *other;
+    *other = tmp;
+}

+ 57 - 69
src/interpreter/heap.c

@@ -1,39 +1,46 @@
 #include "pocketpy/interpreter/heap.h"
-#include "pocketpy/common/memorypool.h"
 #include "pocketpy/config.h"
+#include "pocketpy/interpreter/objectpool.h"
 #include "pocketpy/objects/base.h"
+#include "pocketpy/pocketpy.h"
 
-void ManagedHeap__ctor(ManagedHeap* self, VM* vm) {
-    c11_vector__ctor(&self->no_gc, sizeof(PyObject*));
-    c11_vector__ctor(&self->gen, sizeof(PyObject*));
+void ManagedHeap__ctor(ManagedHeap* self) {
+    MultiPool__ctor(&self->small_objects);
+    c11_vector__ctor(&self->large_objects, sizeof(PyObject*));
 
+    for(int i = 0; i < c11__count_array(self->freed_ma); i++) {
+        self->freed_ma[i] = PK_GC_MIN_THRESHOLD;
+    }
     self->gc_threshold = PK_GC_MIN_THRESHOLD;
     self->gc_counter = 0;
     self->gc_enabled = true;
-
-    self->vm = vm;
 }
 
 void ManagedHeap__dtor(ManagedHeap* self) {
-    for(int i = 0; i < self->gen.length; i++) {
-        PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
-        PyObject__delete(obj);
-    }
-    for(int i = 0; i < self->no_gc.length; i++) {
-        PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
-        PyObject__delete(obj);
+    // small_objects
+    MultiPool__dtor(&self->small_objects);
+    // large_objects
+    for(int i = 0; i < self->large_objects.length; i++) {
+        PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
+        PyObject__dtor(obj);
+        PK_FREE(obj);
     }
-    c11_vector__dtor(&self->no_gc);
-    c11_vector__dtor(&self->gen);
+    c11_vector__dtor(&self->large_objects);
 }
 
 void ManagedHeap__collect_if_needed(ManagedHeap* self) {
     if(!self->gc_enabled) return;
     if(self->gc_counter < self->gc_threshold) return;
     self->gc_counter = 0;
-    ManagedHeap__collect(self);
-    self->gc_threshold = self->gen.length * 2;
-    if(self->gc_threshold < PK_GC_MIN_THRESHOLD) { self->gc_threshold = PK_GC_MIN_THRESHOLD; }
+    int freed = ManagedHeap__collect(self);
+    // adjust `gc_threshold` based on `freed_ma`
+    self->freed_ma[0] = self->freed_ma[1];
+    self->freed_ma[1] = self->freed_ma[2];
+    self->freed_ma[2] = freed;
+    int avg_freed = (self->freed_ma[0] + self->freed_ma[1] + self->freed_ma[2]) / 3;
+    int upper = self->gc_threshold * 2;
+    int lower = c11__max(PK_GC_MIN_THRESHOLD, self->gc_threshold / 2 + 1);
+    self->gc_threshold = c11__min(c11__max(avg_freed, lower), upper);
 }
 
 int ManagedHeap__collect(ManagedHeap* self) {
@@ -43,71 +50,52 @@ int ManagedHeap__collect(ManagedHeap* self) {
 }
 
 int ManagedHeap__sweep(ManagedHeap* self) {
-    c11_vector alive;
-    c11_vector__ctor(&alive, sizeof(PyObject*));
-    c11_vector__reserve(&alive, self->gen.length / 2);
-
-    for(int i = 0; i < self->gen.length; i++) {
-        PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
+    // small_objects
+    int small_freed = MultiPool__sweep_dealloc(&self->small_objects);
+    // large_objects
+    int large_living_count = 0;
+    for(int i = 0; i < self->large_objects.length; i++) {
+        PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
         if(obj->gc_marked) {
             obj->gc_marked = false;
-            c11_vector__push(PyObject*, &alive, obj);
+            c11__setitem(PyObject*, &self->large_objects, large_living_count, obj);
+            large_living_count++;
         } else {
-            PyObject__delete(obj);
+            PyObject__dtor(obj);
+            PK_FREE(obj);
+            // type and module objects are perpectual
+            assert(obj->type != tp_type);
+            assert(obj->type != tp_module);
         }
     }
-
-    // clear _no_gc marked flag
-    for(int i = 0; i < self->no_gc.length; i++) {
-        PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
-        obj->gc_marked = false;
-    }
-
-    int freed = self->gen.length - alive.length;
-
-    // destroy old gen
-    c11_vector__dtor(&self->gen);
-    // move alive to gen
-    self->gen = alive;
-
-    PoolObject_shrink_to_fit();
-    return freed;
-}
-
-PyObject* ManagedHeap__new(ManagedHeap* self, py_Type type, int slots, int udsize) {
-    PyObject* obj = PyObject__new(type, slots, udsize);
-    c11_vector__push(PyObject*, &self->no_gc, obj);
-    return obj;
+    // shrink `self->large_objects`
+    int large_freed = self->large_objects.length - large_living_count;
+    self->large_objects.length = large_living_count;
+    return small_freed + large_freed;
 }
 
 PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize) {
-    PyObject* obj = PyObject__new(type, slots, udsize);
-    c11_vector__push(PyObject*, &self->gen, obj);
-    self->gc_counter++;
-    return obj;
-}
-
-PyObject* PyObject__new(py_Type type, int slots, int size) {
     assert(slots >= 0 || slots == -1);
-    PyObject* self;
+    PyObject* obj;
     // header + slots + udsize
-    size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + size;
-    if(!PK_LOW_MEMORY_MODE && size <= kPoolObjectBlockSize) {
-        self = PoolObject_alloc();
-        self->gc_is_large = false;
+    int size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + udsize;
+    if(!PK_LOW_MEMORY_MODE && size <= kPoolMaxBlockSize) {
+        obj = MultiPool__alloc(&self->small_objects, size);
     } else {
-        self = PK_MALLOC(size);
-        self->gc_is_large = true;
+        obj = PK_MALLOC(size);
+        c11_vector__push(PyObject*, &self->large_objects, obj);
     }
-    self->type = type;
-    self->gc_marked = false;
-    self->slots = slots;
+    obj->type = type;
+    obj->gc_marked = false;
+    obj->slots = slots;
 
     // initialize slots or dict
     if(slots >= 0) {
-        memset(self->flex, 0, slots * sizeof(py_TValue));
+        memset(obj->flex, 0, slots * sizeof(py_TValue));
     } else {
-        NameDict__ctor((void*)self->flex);
+        NameDict__ctor((void*)obj->flex);
     }
-    return self;
-}
+
+    self->gc_counter++;
+    return obj;
+}

+ 174 - 0
src/interpreter/objectpool.c

@@ -0,0 +1,174 @@
+#include "pocketpy/interpreter/objectpool.h"
+
+#include "pocketpy/config.h"
+#include "pocketpy/objects/object.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+static PoolArena* PoolArena__new(int block_size) {
+    assert(kPoolArenaSize % block_size == 0);
+    int block_count = kPoolArenaSize / block_size;
+    int total_size = sizeof(PoolArena) + sizeof(int) * block_count;
+    PoolArena* self = PK_MALLOC(total_size);
+    self->block_size = block_size;
+    self->block_count = block_count;
+    self->unused_count = block_count;
+    self->unused = PK_MALLOC(sizeof(int) * block_count);
+    for(int i = 0; i < block_count; i++) {
+        self->unused[i] = i;
+    }
+    memset(self->data, 0, kPoolArenaSize);
+    return self;
+}
+
+static void PoolArena__delete(PoolArena* self) {
+    for(int i = 0; i < self->block_count; i++) {
+        PyObject* obj = (PyObject*)(self->data + i * self->block_size);
+        if(obj->type != 0) PyObject__dtor(obj);
+    }
+    PK_FREE(self->unused);
+    PK_FREE(self);
+}
+
+static void* PoolArena__alloc(PoolArena* self) {
+    assert(self->unused_count > 0);
+    int index = self->unused[self->unused_count - 1];
+    self->unused_count--;
+    return self->data + index * self->block_size;
+}
+
+static int PoolArena__sweep_dealloc(PoolArena* self) {
+    int freed = 0;
+    self->unused_count = 0;
+    for(int i = 0; i < self->block_count; i++) {
+        PyObject* obj = (PyObject*)(self->data + i * self->block_size);
+        if(obj->type == 0) {
+            self->unused[self->unused_count] = i;
+            self->unused_count++;
+        } else {
+            if(!obj->gc_marked) {
+                obj->type = 0;
+                freed++;
+                self->unused[self->unused_count] = i;
+                self->unused_count++;
+            } else {
+                obj->gc_marked = false;
+            }
+        }
+    }
+    return freed;
+}
+
+static void Pool__ctor(Pool* self, int block_size) {
+    c11_vector__ctor(&self->arenas, sizeof(PoolArena*));
+    c11_vector__ctor(&self->not_free_arenas, sizeof(PoolArena*));
+    self->block_size = block_size;
+}
+
+static void Pool__dtor(Pool* self) {
+    c11__foreach(PoolArena*, &self->arenas, arena) { PoolArena__delete(*arena); }
+    c11__foreach(PoolArena*, &self->not_free_arenas, arena) { PoolArena__delete(*arena); }
+    c11_vector__dtor(&self->arenas);
+    c11_vector__dtor(&self->not_free_arenas);
+}
+
+static void* Pool__alloc(Pool* self) {
+    PoolArena* arena;
+    if(self->arenas.length == 0) {
+        arena = PoolArena__new(self->block_size);
+        c11_vector__push(PoolArena*, &self->arenas, arena);
+    } else {
+        arena = c11_vector__back(PoolArena*, &self->arenas);
+    }
+    void* ptr = PoolArena__alloc(arena);
+    if(arena->unused_count == 0) {
+        c11_vector__pop(&self->arenas);
+        c11_vector__push(PoolArena*, &self->not_free_arenas, arena);
+    }
+    return ptr;
+}
+
+static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* not_free_arenas) {
+    c11_vector__clear(arenas);
+    c11_vector__clear(not_free_arenas);
+
+    int freed = 0;
+    for(int i = 0; i < self->arenas.length; i++) {
+        PoolArena* item = c11__getitem(PoolArena*, &self->arenas, i);
+        assert(item->unused_count > 0);
+        freed += PoolArena__sweep_dealloc(item);
+        if(item->unused_count == item->block_count) {
+            // all free
+            if(self->arenas.length > 0) {
+                // at least one arena
+                PoolArena__delete(item);
+            } else {
+                // no arena
+                c11_vector__push(PoolArena*, arenas, item);
+            }
+        } else {
+            // some free
+            c11_vector__push(PoolArena*, arenas, item);
+        }
+    }
+    for(int i = 0; i < self->not_free_arenas.length; i++) {
+        PoolArena* item = c11__getitem(PoolArena*, &self->not_free_arenas, i);
+        freed += PoolArena__sweep_dealloc(item);
+        if(item->unused_count == 0) {
+            // still not free
+            c11_vector__push(PoolArena*, not_free_arenas, item);
+        } else {
+            if(item->unused_count == item->block_count) {
+                // all free
+                PoolArena__delete(item);
+            } else {
+                // some free
+                c11_vector__push(PoolArena*, arenas, item);
+            }
+        }
+    }
+
+    c11_vector__swap(&self->arenas, arenas);
+    c11_vector__swap(&self->not_free_arenas, not_free_arenas);
+    return freed;
+}
+
+void* MultiPool__alloc(MultiPool* self, int size) {
+    if(size == 0) return NULL;
+    int index = (size - 1) >> 5;
+    if(index < kMultiPoolCount) {
+        Pool* pool = &self->pools[index];
+        return Pool__alloc(pool);
+    }
+    return NULL;
+}
+
+int MultiPool__sweep_dealloc(MultiPool* self) {
+    c11_vector arenas;
+    c11_vector not_free_arenas;
+    c11_vector__ctor(&arenas, sizeof(PoolArena*));
+    c11_vector__ctor(&not_free_arenas, sizeof(PoolArena*));
+    int freed = 0;
+    for(int i = 0; i < kMultiPoolCount; i++) {
+        Pool* item = &self->pools[i];
+        freed += Pool__sweep_dealloc(item, &arenas, &not_free_arenas);
+    }
+    c11_vector__dtor(&arenas);
+    c11_vector__dtor(&not_free_arenas);
+    return freed;
+}
+
+void MultiPool__ctor(MultiPool* self) {
+    for(int i = 0; i < kMultiPoolCount; i++) {
+        Pool__ctor(&self->pools[i], 32 * (i + 1));
+    }
+}
+
+void MultiPool__dtor(MultiPool* self) {
+    for(int i = 0; i < kMultiPoolCount; i++) {
+        Pool__dtor(&self->pools[i]);
+    }
+}

+ 6 - 12
src/interpreter/vm.c

@@ -1,5 +1,4 @@
 #include "pocketpy/interpreter/vm.h"
-#include "pocketpy/common/memorypool.h"
 #include "pocketpy/common/sstream.h"
 #include "pocketpy/common/utils.h"
 #include "pocketpy/interpreter/generator.h"
@@ -76,7 +75,7 @@ void VM__ctor(VM* self) {
     self->__curr_class = NULL;
     self->__curr_function = NULL;
 
-    ManagedHeap__ctor(&self->heap, self);
+    ManagedHeap__ctor(&self->heap);
     ValueStack__ctor(&self->stack);
 
     /* Init Builtin Types */
@@ -569,15 +568,10 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
 }
 
 /****************************************/
-void PyObject__delete(PyObject* self) {
+void PyObject__dtor(PyObject* self) {
     py_TypeInfo* ti = pk__type_info(self->type);
     if(ti->dtor) ti->dtor(PyObject__userdata(self));
     if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
-    if(self->gc_is_large) {
-        PK_FREE(self);
-    } else {
-        PoolObject_dealloc(self);
-    }
 }
 
 static void mark_object(PyObject* obj);
@@ -636,10 +630,10 @@ void CodeObject__gc_mark(const CodeObject* self) {
 }
 
 void ManagedHeap__mark(ManagedHeap* self) {
-    VM* vm = self->vm;
-    // mark heap objects
-    for(int i = 0; i < self->no_gc.length; i++) {
-        PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
+    VM* vm = pk_current_vm;
+    // mark large objects
+    for(int i = 0; i < self->large_objects.length; i++) {
+        PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
         mark_object(obj);
     }
     // mark value stack