mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
backup
backup backup ...
This commit is contained in:
parent
3c18e736c4
commit
723407dafe
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 ***************/
|
||||
|
||||
|
@ -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
include/pocketpy/interpreter/objectpool.h
Normal file
30
include/pocketpy/interpreter/objectpool.h
Normal file
@ -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);
|
@ -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,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
|
||||
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
// 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);
|
||||
}
|
||||
for(int i = 0; i < self->no_gc.length; i++) {
|
||||
PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
|
||||
PyObject__delete(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
src/interpreter/objectpool.c
Normal file
174
src/interpreter/objectpool.c
Normal file
@ -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(¬_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, ¬_free_arenas);
|
||||
}
|
||||
c11_vector__dtor(&arenas);
|
||||
c11_vector__dtor(¬_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]);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user