mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
Merge pull request #327 from pocketpy/mem-v2
Improve memory managements (mem-v2)
This commit is contained in:
commit
e1e5de396f
@ -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.
|
pkpy should work on any platform with a C11 compiler.
|
||||||
These platforms are officially tested.
|
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
|
+ Windows 64-bit
|
||||||
+ Linux 64-bit / 32-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:
|
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
|
+ For MSVC, `/utf-8` flag must be set
|
||||||
+ `NDEBUG` macro should be defined for release build, or you will get poor performance
|
+ `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.
|
pkpy should work on any platform with a C11 compiler.
|
||||||
These platforms are officially tested.
|
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
|
+ Windows 64-bit
|
||||||
+ Linux 64-bit / 32-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:
|
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
|
+ For MSVC, `/utf-8` flag must be set
|
||||||
+ `NDEBUG` macro should be defined for release build, or you will get poor performance
|
+ `NDEBUG` macro should be defined for release build, or you will get poor performance
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ output: .retype
|
|||||||
url: https://pocketpy.dev
|
url: https://pocketpy.dev
|
||||||
branding:
|
branding:
|
||||||
title: pocketpy
|
title: pocketpy
|
||||||
label: v2.0.5
|
label: v2.0.6
|
||||||
logo: "./static/logo.png"
|
logo: "./static/logo.png"
|
||||||
favicon: "./static/logo.png"
|
favicon: "./static/logo.png"
|
||||||
meta:
|
meta:
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define kPoolExprBlockSize 128
|
typedef struct FixedMemoryPool {
|
||||||
#define kPoolFrameBlockSize 80
|
int BlockSize;
|
||||||
#define kPoolObjectBlockSize 80
|
int BlockCount;
|
||||||
|
|
||||||
#define kPoolObjectArenaSize (256*1024)
|
char* data;
|
||||||
#define kPoolObjectMaxBlocks (kPoolObjectArenaSize / kPoolObjectBlockSize)
|
char* data_end;
|
||||||
|
int exceeded_bytes;
|
||||||
|
|
||||||
void MemoryPools__initialize();
|
char** _free_list;
|
||||||
void MemoryPools__finalize();
|
char** _free_list_end;
|
||||||
|
} FixedMemoryPool;
|
||||||
|
|
||||||
void* PoolExpr_alloc();
|
void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount);
|
||||||
void PoolExpr_dealloc(void*);
|
void FixedMemoryPool__dtor(FixedMemoryPool* self);
|
||||||
void* PoolFrame_alloc();
|
void* FixedMemoryPool__alloc(FixedMemoryPool* self);
|
||||||
void PoolFrame_dealloc(void*);
|
void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p);
|
||||||
|
|
||||||
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);
|
void* c11_vector__emplace(c11_vector* self);
|
||||||
bool c11_vector__contains(const c11_vector* self, void* elem);
|
bool c11_vector__contains(const c11_vector* self, void* elem);
|
||||||
void* c11_vector__submit(c11_vector* self, int* length);
|
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__getitem(T, self, index) (((T*)(self)->data)[index])
|
||||||
#define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;
|
#define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
#define PK_VERSION "2.0.5"
|
#define PK_VERSION "2.0.6"
|
||||||
#define PK_VERSION_MAJOR 2
|
#define PK_VERSION_MAJOR 2
|
||||||
#define PK_VERSION_MINOR 0
|
#define PK_VERSION_MINOR 0
|
||||||
#define PK_VERSION_PATCH 5
|
#define PK_VERSION_PATCH 6
|
||||||
|
|
||||||
/*************** feature settings ***************/
|
/*************** feature settings ***************/
|
||||||
|
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
|
#include "pocketpy/interpreter/objectpool.h"
|
||||||
|
|
||||||
typedef struct ManagedHeap{
|
typedef struct ManagedHeap {
|
||||||
c11_vector no_gc;
|
MultiPool small_objects;
|
||||||
c11_vector gen;
|
c11_vector large_objects;
|
||||||
|
|
||||||
int gc_threshold;
|
int freed_ma[3];
|
||||||
int gc_counter;
|
int gc_threshold; // threshold for gc_counter
|
||||||
|
int gc_counter; // objects created since last gc
|
||||||
bool gc_enabled;
|
bool gc_enabled;
|
||||||
|
|
||||||
VM* vm;
|
|
||||||
} ManagedHeap;
|
} ManagedHeap;
|
||||||
|
|
||||||
void ManagedHeap__ctor(ManagedHeap* self, VM* vm);
|
void ManagedHeap__ctor(ManagedHeap* self);
|
||||||
void ManagedHeap__dtor(ManagedHeap* self);
|
void ManagedHeap__dtor(ManagedHeap* self);
|
||||||
|
|
||||||
void ManagedHeap__collect_if_needed(ManagedHeap* self);
|
void ManagedHeap__collect_if_needed(ManagedHeap* self);
|
||||||
int ManagedHeap__collect(ManagedHeap* self);
|
int ManagedHeap__collect(ManagedHeap* self);
|
||||||
int ManagedHeap__sweep(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);
|
PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize);
|
||||||
|
|
||||||
// external implementation
|
// external implementation
|
||||||
|
32
include/pocketpy/interpreter/objectpool.h
Normal file
32
include/pocketpy/interpreter/objectpool.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pocketpy/common/vector.h"
|
||||||
|
#include "pocketpy/common/str.h"
|
||||||
|
|
||||||
|
#define kPoolArenaSize (120 * 1024)
|
||||||
|
#define kMultiPoolCount 5
|
||||||
|
#define kPoolMaxBlockSize (32*kMultiPoolCount)
|
||||||
|
|
||||||
|
typedef struct PoolArena {
|
||||||
|
int block_size;
|
||||||
|
int block_count;
|
||||||
|
int unused_length;
|
||||||
|
int* unused;
|
||||||
|
char data[kPoolArenaSize];
|
||||||
|
} PoolArena;
|
||||||
|
|
||||||
|
typedef struct Pool {
|
||||||
|
c11_vector /* PoolArena* */ arenas;
|
||||||
|
c11_vector /* PoolArena* */ no_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);
|
||||||
|
c11_string* MultiPool__summary(MultiPool* self);
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "pocketpy/common/memorypool.h"
|
||||||
#include "pocketpy/objects/codeobject.h"
|
#include "pocketpy/objects/codeobject.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
#include "pocketpy/interpreter/heap.h"
|
#include "pocketpy/interpreter/heap.h"
|
||||||
@ -38,6 +39,7 @@ typedef struct VM {
|
|||||||
py_StackRef __curr_function;
|
py_StackRef __curr_function;
|
||||||
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||||
|
|
||||||
|
FixedMemoryPool pool_frame;
|
||||||
ManagedHeap heap;
|
ManagedHeap heap;
|
||||||
ValueStack stack; // put `stack` at the end for better cache locality
|
ValueStack stack; // put `stack` at the end for better cache locality
|
||||||
} VM;
|
} VM;
|
||||||
@ -58,7 +60,6 @@ bool pk__object_new(int argc, py_Ref argv);
|
|||||||
py_TypeInfo* pk__type_info(py_Type type);
|
py_TypeInfo* pk__type_info(py_Type type);
|
||||||
|
|
||||||
bool pk_wrapper__self(int argc, py_Ref argv);
|
bool pk_wrapper__self(int argc, py_Ref argv);
|
||||||
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv);
|
|
||||||
|
|
||||||
const char* pk_op2str(py_Name op);
|
const char* pk_op2str(py_Name op);
|
||||||
|
|
||||||
|
@ -25,3 +25,4 @@ void ModuleDict__dtor(ModuleDict* self);
|
|||||||
void ModuleDict__set(ModuleDict* self, const char* key, py_TValue val);
|
void ModuleDict__set(ModuleDict* self, const char* key, py_TValue val);
|
||||||
py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path);
|
py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path);
|
||||||
bool ModuleDict__contains(ModuleDict* self, const char* path);
|
bool ModuleDict__contains(ModuleDict* self, const char* path);
|
||||||
|
void ModuleDict__apply_mark(ModuleDict* self, void (*marker)(PyObject*));
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
typedef struct PyObject {
|
typedef struct PyObject {
|
||||||
py_Type type; // we have a duplicated type here for convenience
|
py_Type type; // we have a duplicated type here for convenience
|
||||||
bool gc_is_large;
|
// bool _;
|
||||||
bool gc_marked;
|
bool gc_marked;
|
||||||
int slots; // number of slots in the object
|
int slots; // number of slots in the object
|
||||||
char flex[];
|
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))
|
#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__dtor(PyObject* self);
|
||||||
void PyObject__delete(PyObject* self);
|
|
||||||
|
@ -40,6 +40,8 @@ typedef struct py_Callbacks {
|
|||||||
char* (*importfile)(const char*);
|
char* (*importfile)(const char*);
|
||||||
/// Used by `print` to output a string.
|
/// Used by `print` to output a string.
|
||||||
void (*print)(const char*);
|
void (*print)(const char*);
|
||||||
|
/// Used by `input` to get a character.
|
||||||
|
int (*getchar)();
|
||||||
} py_Callbacks;
|
} py_Callbacks;
|
||||||
|
|
||||||
#define PY_RAISE
|
#define PY_RAISE
|
||||||
|
@ -11,3 +11,6 @@ class TValue[T]:
|
|||||||
# TValue_float = TValue[float]
|
# TValue_float = TValue[float]
|
||||||
# TValue_vec2i = TValue[vec2i]
|
# TValue_vec2i = TValue[vec2i]
|
||||||
# TValue_vec2 = TValue[vec2]
|
# TValue_vec2 = TValue[vec2]
|
||||||
|
|
||||||
|
def memory_usage() -> str:
|
||||||
|
"""Return a summary of the memory usage."""
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
name: pocketpy
|
name: pocketpy
|
||||||
description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS.
|
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
|
homepage: https://pocketpy.dev
|
||||||
repository: https://github.com/pocketpy/pocketpy
|
repository: https://github.com/pocketpy/pocketpy
|
||||||
|
|
||||||
|
@ -2,196 +2,9 @@
|
|||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef struct LinkedListNode {
|
void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount) {
|
||||||
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;
|
|
||||||
|
|
||||||
char* data;
|
|
||||||
char* data_end;
|
|
||||||
int exceeded_bytes;
|
|
||||||
|
|
||||||
char** _free_list;
|
|
||||||
char** _free_list_end;
|
|
||||||
} FixedMemoryPool;
|
|
||||||
|
|
||||||
static void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount) {
|
|
||||||
self->BlockSize = BlockSize;
|
self->BlockSize = BlockSize;
|
||||||
self->BlockCount = BlockCount;
|
self->BlockCount = BlockCount;
|
||||||
self->exceeded_bytes = 0;
|
self->exceeded_bytes = 0;
|
||||||
@ -204,12 +17,12 @@ static void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int Bloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FixedMemoryPool__dtor(FixedMemoryPool* self) {
|
void FixedMemoryPool__dtor(FixedMemoryPool* self) {
|
||||||
PK_FREE(self->_free_list);
|
PK_FREE(self->_free_list);
|
||||||
PK_FREE(self->data);
|
PK_FREE(self->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
|
void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
|
||||||
if(self->_free_list_end != self->_free_list) {
|
if(self->_free_list_end != self->_free_list) {
|
||||||
self->_free_list_end--;
|
self->_free_list_end--;
|
||||||
return *self->_free_list_end;
|
return *self->_free_list_end;
|
||||||
@ -219,7 +32,7 @@ static void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) {
|
void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) {
|
||||||
bool is_valid = (char*)p >= self->data && (char*)p < self->data_end;
|
bool is_valid = (char*)p >= self->data && (char*)p < self->data_end;
|
||||||
if(is_valid) {
|
if(is_valid) {
|
||||||
*self->_free_list_end = p;
|
*self->_free_list_end = p;
|
||||||
@ -230,96 +43,10 @@ static void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int FixedMemoryPool__used_bytes(FixedMemoryPool* self) {
|
// static int FixedMemoryPool__used_bytes(FixedMemoryPool* self) {
|
||||||
return (self->_free_list_end - self->_free_list) * self->BlockSize;
|
// return (self->_free_list_end - self->_free_list) * self->BlockSize;
|
||||||
}
|
// }
|
||||||
|
|
||||||
static int FixedMemoryPool__total_bytes(FixedMemoryPool* self) {
|
// static int FixedMemoryPool__total_bytes(FixedMemoryPool* self) {
|
||||||
return self->BlockCount * self->BlockSize;
|
// return self->BlockCount * self->BlockSize;
|
||||||
}
|
// }
|
||||||
|
|
||||||
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() {
|
|
||||||
return FixedMemoryPool__alloc(&PoolExpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PoolExpr_dealloc(void* p) {
|
|
||||||
FixedMemoryPool__dealloc(&PoolExpr, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* PoolFrame_alloc() {
|
|
||||||
return FixedMemoryPool__alloc(&PoolFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
@ -244,45 +244,3 @@ void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) {
|
|||||||
pk_vsprintf(ss, fmt, args);
|
pk_vsprintf(ss, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int py_replinput(char* buf, int max_size) {
|
|
||||||
buf[0] = '\0'; // reset first char because we check '@' at the beginning
|
|
||||||
|
|
||||||
int size = 0;
|
|
||||||
bool multiline = false;
|
|
||||||
printf(">>> ");
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
int c = getchar();
|
|
||||||
if(c == EOF) return -1;
|
|
||||||
|
|
||||||
if(c == '\n') {
|
|
||||||
char last = '\0';
|
|
||||||
if(size > 0) last = buf[size - 1];
|
|
||||||
if(multiline) {
|
|
||||||
if(last == '\n') {
|
|
||||||
break; // 2 consecutive newlines to end multiline input
|
|
||||||
} else {
|
|
||||||
printf("... ");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') {
|
|
||||||
printf("... ");
|
|
||||||
multiline = true;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(size == max_size - 1) {
|
|
||||||
buf[size] = '\0';
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[size++] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[size] = '\0';
|
|
||||||
return size;
|
|
||||||
}
|
|
@ -62,3 +62,9 @@ void* c11_vector__submit(c11_vector* self, int* length) {
|
|||||||
self->capacity = 0;
|
self->capacity = 0;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void c11_vector__swap(c11_vector *self, c11_vector *other){
|
||||||
|
c11_vector tmp = *self;
|
||||||
|
*self = *other;
|
||||||
|
*other = tmp;
|
||||||
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#include "pocketpy/compiler/compiler.h"
|
#include "pocketpy/compiler/compiler.h"
|
||||||
#include "pocketpy/compiler/lexer.h"
|
#include "pocketpy/compiler/lexer.h"
|
||||||
|
#include "pocketpy/objects/base.h"
|
||||||
#include "pocketpy/objects/codeobject.h"
|
#include "pocketpy/objects/codeobject.h"
|
||||||
#include "pocketpy/objects/sourcedata.h"
|
#include "pocketpy/objects/sourcedata.h"
|
||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
#include "pocketpy/common/sstream.h"
|
#include "pocketpy/common/sstream.h"
|
||||||
#include "pocketpy/common/memorypool.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -30,8 +30,6 @@ typedef struct ExprVt {
|
|||||||
void (*dtor)(Expr*);
|
void (*dtor)(Expr*);
|
||||||
} ExprVt;
|
} ExprVt;
|
||||||
|
|
||||||
#define static_assert_expr_size(T) static_assert(sizeof(T) <= kPoolExprBlockSize, "")
|
|
||||||
|
|
||||||
#define vtcall(f, self, ctx) ((self)->vt->f((self), (ctx)))
|
#define vtcall(f, self, ctx) ((self)->vt->f((self), (ctx)))
|
||||||
#define vtemit_(self, ctx) vtcall(emit_, (self), (ctx))
|
#define vtemit_(self, ctx) vtcall(emit_, (self), (ctx))
|
||||||
#define vtemit_del(self, ctx) ((self)->vt->emit_del ? vtcall(emit_del, self, ctx) : false)
|
#define vtemit_del(self, ctx) ((self)->vt->emit_del ? vtcall(emit_del, self, ctx) : false)
|
||||||
@ -44,7 +42,7 @@ typedef struct ExprVt {
|
|||||||
do { \
|
do { \
|
||||||
if(self) { \
|
if(self) { \
|
||||||
if((self)->vt->dtor) (self)->vt->dtor(self); \
|
if((self)->vt->dtor) (self)->vt->dtor(self); \
|
||||||
PoolExpr_dealloc(self); \
|
PK_FREE(self); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
@ -148,8 +146,7 @@ NameExpr* NameExpr__new(int line, py_Name name, NameScope scope) {
|
|||||||
.emit_del = NameExpr__emit_del,
|
.emit_del = NameExpr__emit_del,
|
||||||
.emit_store = NameExpr__emit_store,
|
.emit_store = NameExpr__emit_store,
|
||||||
.is_name = true};
|
.is_name = true};
|
||||||
static_assert_expr_size(NameExpr);
|
NameExpr* self = PK_MALLOC(sizeof(NameExpr));
|
||||||
NameExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->name = name;
|
self->name = name;
|
||||||
@ -186,8 +183,7 @@ StarredExpr* StarredExpr__new(int line, Expr* child, int level) {
|
|||||||
.emit_store = StarredExpr__emit_store,
|
.emit_store = StarredExpr__emit_store,
|
||||||
.is_starred = true,
|
.is_starred = true,
|
||||||
.dtor = StarredExpr__dtor};
|
.dtor = StarredExpr__dtor};
|
||||||
static_assert_expr_size(StarredExpr);
|
StarredExpr* self = PK_MALLOC(sizeof(StarredExpr));
|
||||||
StarredExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->child = child;
|
self->child = child;
|
||||||
@ -216,8 +212,7 @@ static void UnaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
UnaryExpr* UnaryExpr__new(int line, Expr* child, Opcode opcode) {
|
UnaryExpr* UnaryExpr__new(int line, Expr* child, Opcode opcode) {
|
||||||
const static ExprVt Vt = {.emit_ = UnaryExpr__emit_, .dtor = UnaryExpr__dtor};
|
const static ExprVt Vt = {.emit_ = UnaryExpr__emit_, .dtor = UnaryExpr__dtor};
|
||||||
static_assert_expr_size(UnaryExpr);
|
UnaryExpr* self = PK_MALLOC(sizeof(UnaryExpr));
|
||||||
UnaryExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->child = child;
|
self->child = child;
|
||||||
@ -240,8 +235,7 @@ void FStringSpecExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
FStringSpecExpr* FStringSpecExpr__new(int line, Expr* child, c11_sv spec) {
|
FStringSpecExpr* FStringSpecExpr__new(int line, Expr* child, c11_sv spec) {
|
||||||
const static ExprVt Vt = {.emit_ = FStringSpecExpr__emit_, .dtor = UnaryExpr__dtor};
|
const static ExprVt Vt = {.emit_ = FStringSpecExpr__emit_, .dtor = UnaryExpr__dtor};
|
||||||
static_assert_expr_size(FStringSpecExpr);
|
FStringSpecExpr* self = PK_MALLOC(sizeof(FStringSpecExpr));
|
||||||
FStringSpecExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->child = child;
|
self->child = child;
|
||||||
@ -263,8 +257,7 @@ void RawStringExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
RawStringExpr* RawStringExpr__new(int line, c11_sv value, Opcode opcode) {
|
RawStringExpr* RawStringExpr__new(int line, c11_sv value, Opcode opcode) {
|
||||||
const static ExprVt Vt = {.emit_ = RawStringExpr__emit_};
|
const static ExprVt Vt = {.emit_ = RawStringExpr__emit_};
|
||||||
static_assert_expr_size(RawStringExpr);
|
RawStringExpr* self = PK_MALLOC(sizeof(RawStringExpr));
|
||||||
RawStringExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->value = value;
|
self->value = value;
|
||||||
@ -288,8 +281,7 @@ void ImagExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
ImagExpr* ImagExpr__new(int line, double value) {
|
ImagExpr* ImagExpr__new(int line, double value) {
|
||||||
const static ExprVt Vt = {.emit_ = ImagExpr__emit_};
|
const static ExprVt Vt = {.emit_ = ImagExpr__emit_};
|
||||||
static_assert_expr_size(ImagExpr);
|
ImagExpr* self = PK_MALLOC(sizeof(ImagExpr));
|
||||||
ImagExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->value = value;
|
self->value = value;
|
||||||
@ -333,8 +325,7 @@ void LiteralExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
LiteralExpr* LiteralExpr__new(int line, const TokenValue* value) {
|
LiteralExpr* LiteralExpr__new(int line, const TokenValue* value) {
|
||||||
const static ExprVt Vt = {.emit_ = LiteralExpr__emit_, .is_literal = true};
|
const static ExprVt Vt = {.emit_ = LiteralExpr__emit_, .is_literal = true};
|
||||||
static_assert_expr_size(LiteralExpr);
|
LiteralExpr* self = PK_MALLOC(sizeof(LiteralExpr));
|
||||||
LiteralExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->value = value;
|
self->value = value;
|
||||||
@ -362,8 +353,7 @@ void Literal0Expr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
Literal0Expr* Literal0Expr__new(int line, TokenIndex token) {
|
Literal0Expr* Literal0Expr__new(int line, TokenIndex token) {
|
||||||
const static ExprVt Vt = {.emit_ = Literal0Expr__emit_};
|
const static ExprVt Vt = {.emit_ = Literal0Expr__emit_};
|
||||||
static_assert_expr_size(Literal0Expr);
|
Literal0Expr* self = PK_MALLOC(sizeof(Literal0Expr));
|
||||||
Literal0Expr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->token = token;
|
self->token = token;
|
||||||
@ -403,8 +393,7 @@ void SliceExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
SliceExpr* SliceExpr__new(int line) {
|
SliceExpr* SliceExpr__new(int line) {
|
||||||
const static ExprVt Vt = {.dtor = SliceExpr__dtor, .emit_ = SliceExpr__emit_};
|
const static ExprVt Vt = {.dtor = SliceExpr__dtor, .emit_ = SliceExpr__emit_};
|
||||||
static_assert_expr_size(SliceExpr);
|
SliceExpr* self = PK_MALLOC(sizeof(SliceExpr));
|
||||||
SliceExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->start = NULL;
|
self->start = NULL;
|
||||||
@ -433,8 +422,7 @@ static void DictItemExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
static DictItemExpr* DictItemExpr__new(int line) {
|
static DictItemExpr* DictItemExpr__new(int line) {
|
||||||
const static ExprVt Vt = {.dtor = DictItemExpr__dtor, .emit_ = DictItemExpr__emit_};
|
const static ExprVt Vt = {.dtor = DictItemExpr__dtor, .emit_ = DictItemExpr__emit_};
|
||||||
static_assert_expr_size(DictItemExpr);
|
DictItemExpr* self = PK_MALLOC(sizeof(DictItemExpr));
|
||||||
DictItemExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->key = NULL;
|
self->key = NULL;
|
||||||
@ -521,8 +509,7 @@ bool TupleExpr__emit_del(Expr* self_, Ctx* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static SequenceExpr* SequenceExpr__new(int line, const ExprVt* vt, int count, Opcode opcode) {
|
static SequenceExpr* SequenceExpr__new(int line, const ExprVt* vt, int count, Opcode opcode) {
|
||||||
static_assert_expr_size(SequenceExpr);
|
SequenceExpr* self = PK_MALLOC(sizeof(SequenceExpr));
|
||||||
SequenceExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = vt;
|
self->vt = vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->opcode = opcode;
|
self->opcode = opcode;
|
||||||
@ -608,8 +595,7 @@ void CompExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
CompExpr* CompExpr__new(int line, Opcode op0, Opcode op1) {
|
CompExpr* CompExpr__new(int line, Opcode op0, Opcode op1) {
|
||||||
const static ExprVt Vt = {.dtor = CompExpr__dtor, .emit_ = CompExpr__emit_};
|
const static ExprVt Vt = {.dtor = CompExpr__dtor, .emit_ = CompExpr__emit_};
|
||||||
static_assert_expr_size(CompExpr);
|
CompExpr* self = PK_MALLOC(sizeof(CompExpr));
|
||||||
CompExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->op0 = op0;
|
self->op0 = op0;
|
||||||
@ -633,8 +619,7 @@ static void LambdaExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
LambdaExpr* LambdaExpr__new(int line, int index) {
|
LambdaExpr* LambdaExpr__new(int line, int index) {
|
||||||
const static ExprVt Vt = {.emit_ = LambdaExpr__emit_};
|
const static ExprVt Vt = {.emit_ = LambdaExpr__emit_};
|
||||||
static_assert_expr_size(LambdaExpr);
|
LambdaExpr* self = PK_MALLOC(sizeof(LambdaExpr));
|
||||||
LambdaExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->index = index;
|
self->index = index;
|
||||||
@ -665,8 +650,7 @@ void LogicBinaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
LogicBinaryExpr* LogicBinaryExpr__new(int line, Opcode opcode) {
|
LogicBinaryExpr* LogicBinaryExpr__new(int line, Opcode opcode) {
|
||||||
const static ExprVt Vt = {.emit_ = LogicBinaryExpr__emit_, .dtor = LogicBinaryExpr__dtor};
|
const static ExprVt Vt = {.emit_ = LogicBinaryExpr__emit_, .dtor = LogicBinaryExpr__dtor};
|
||||||
static_assert_expr_size(LogicBinaryExpr);
|
LogicBinaryExpr* self = PK_MALLOC(sizeof(LogicBinaryExpr));
|
||||||
LogicBinaryExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->lhs = NULL;
|
self->lhs = NULL;
|
||||||
@ -705,8 +689,7 @@ GroupedExpr* GroupedExpr__new(int line, Expr* child) {
|
|||||||
.emit_ = GroupedExpr__emit_,
|
.emit_ = GroupedExpr__emit_,
|
||||||
.emit_del = GroupedExpr__emit_del,
|
.emit_del = GroupedExpr__emit_del,
|
||||||
.emit_store = GroupedExpr__emit_store};
|
.emit_store = GroupedExpr__emit_store};
|
||||||
static_assert_expr_size(GroupedExpr);
|
GroupedExpr* self = PK_MALLOC(sizeof(GroupedExpr));
|
||||||
GroupedExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->child = child;
|
self->child = child;
|
||||||
@ -833,8 +816,7 @@ BinaryExpr* BinaryExpr__new(int line, TokenIndex op, bool inplace) {
|
|||||||
const static ExprVt Vt = {.emit_ = BinaryExpr__emit_,
|
const static ExprVt Vt = {.emit_ = BinaryExpr__emit_,
|
||||||
.dtor = BinaryExpr__dtor,
|
.dtor = BinaryExpr__dtor,
|
||||||
.is_binary = true};
|
.is_binary = true};
|
||||||
static_assert_expr_size(BinaryExpr);
|
BinaryExpr* self = PK_MALLOC(sizeof(BinaryExpr));
|
||||||
BinaryExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->lhs = NULL;
|
self->lhs = NULL;
|
||||||
@ -871,8 +853,7 @@ void TernaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
TernaryExpr* TernaryExpr__new(int line) {
|
TernaryExpr* TernaryExpr__new(int line) {
|
||||||
const static ExprVt Vt = {.dtor = TernaryExpr__dtor, .emit_ = TernaryExpr__emit_};
|
const static ExprVt Vt = {.dtor = TernaryExpr__dtor, .emit_ = TernaryExpr__emit_};
|
||||||
static_assert_expr_size(TernaryExpr);
|
TernaryExpr* self = PK_MALLOC(sizeof(TernaryExpr));
|
||||||
TernaryExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->cond = NULL;
|
self->cond = NULL;
|
||||||
@ -942,8 +923,7 @@ SubscrExpr* SubscrExpr__new(int line) {
|
|||||||
.emit_del = SubscrExpr__emit_del,
|
.emit_del = SubscrExpr__emit_del,
|
||||||
.is_subscr = true,
|
.is_subscr = true,
|
||||||
};
|
};
|
||||||
static_assert_expr_size(SubscrExpr);
|
SubscrExpr* self = PK_MALLOC(sizeof(SubscrExpr));
|
||||||
SubscrExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->lhs = NULL;
|
self->lhs = NULL;
|
||||||
@ -1005,8 +985,7 @@ AttribExpr* AttribExpr__new(int line, Expr* child, py_Name name) {
|
|||||||
.emit_istore = AttribExpr__emit_istore,
|
.emit_istore = AttribExpr__emit_istore,
|
||||||
.dtor = AttribExpr__dtor,
|
.dtor = AttribExpr__dtor,
|
||||||
.is_attrib = true};
|
.is_attrib = true};
|
||||||
static_assert_expr_size(AttribExpr);
|
AttribExpr* self = PK_MALLOC(sizeof(AttribExpr));
|
||||||
AttribExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->child = child;
|
self->child = child;
|
||||||
@ -1078,8 +1057,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
CallExpr* CallExpr__new(int line, Expr* callable) {
|
CallExpr* CallExpr__new(int line, Expr* callable) {
|
||||||
const static ExprVt Vt = {.dtor = CallExpr__dtor, .emit_ = CallExpr__emit_};
|
const static ExprVt Vt = {.dtor = CallExpr__dtor, .emit_ = CallExpr__emit_};
|
||||||
static_assert_expr_size(CallExpr);
|
CallExpr* self = PK_MALLOC(sizeof(CallExpr));
|
||||||
CallExpr* self = PoolExpr_alloc();
|
|
||||||
self->vt = &Vt;
|
self->vt = &Vt;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
self->callable = callable;
|
self->callable = callable;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "pocketpy/interpreter/frame.h"
|
#include "pocketpy/interpreter/frame.h"
|
||||||
|
#include "pocketpy/common/memorypool.h"
|
||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
#include "pocketpy/objects/base.h"
|
#include "pocketpy/objects/base.h"
|
||||||
#include "pocketpy/objects/codeobject.h"
|
#include "pocketpy/objects/codeobject.h"
|
||||||
@ -42,8 +43,7 @@ Frame* Frame__new(const CodeObject* co,
|
|||||||
py_StackRef p0,
|
py_StackRef p0,
|
||||||
py_StackRef locals,
|
py_StackRef locals,
|
||||||
bool has_function) {
|
bool has_function) {
|
||||||
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
|
Frame* self = FixedMemoryPool__alloc(&pk_current_vm->pool_frame);
|
||||||
Frame* self = PoolFrame_alloc();
|
|
||||||
self->f_back = NULL;
|
self->f_back = NULL;
|
||||||
self->ip = (Bytecode*)co->codes.data - 1;
|
self->ip = (Bytecode*)co->codes.data - 1;
|
||||||
self->co = co;
|
self->co = co;
|
||||||
@ -62,7 +62,7 @@ void Frame__delete(Frame* self) {
|
|||||||
self->uw_list = p->next;
|
self->uw_list = p->next;
|
||||||
UnwindTarget__delete(p);
|
UnwindTarget__delete(p);
|
||||||
}
|
}
|
||||||
PoolFrame_dealloc(self);
|
FixedMemoryPool__dealloc(&pk_current_vm->pool_frame, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
|
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
|
||||||
|
@ -1,39 +1,46 @@
|
|||||||
#include "pocketpy/interpreter/heap.h"
|
#include "pocketpy/interpreter/heap.h"
|
||||||
#include "pocketpy/common/memorypool.h"
|
|
||||||
#include "pocketpy/config.h"
|
#include "pocketpy/config.h"
|
||||||
|
#include "pocketpy/interpreter/objectpool.h"
|
||||||
#include "pocketpy/objects/base.h"
|
#include "pocketpy/objects/base.h"
|
||||||
|
#include "pocketpy/pocketpy.h"
|
||||||
|
|
||||||
void ManagedHeap__ctor(ManagedHeap* self, VM* vm) {
|
void ManagedHeap__ctor(ManagedHeap* self) {
|
||||||
c11_vector__ctor(&self->no_gc, sizeof(PyObject*));
|
MultiPool__ctor(&self->small_objects);
|
||||||
c11_vector__ctor(&self->gen, sizeof(PyObject*));
|
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_threshold = PK_GC_MIN_THRESHOLD;
|
||||||
self->gc_counter = 0;
|
self->gc_counter = 0;
|
||||||
self->gc_enabled = true;
|
self->gc_enabled = true;
|
||||||
|
|
||||||
self->vm = vm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManagedHeap__dtor(ManagedHeap* self) {
|
void ManagedHeap__dtor(ManagedHeap* self) {
|
||||||
for(int i = 0; i < self->gen.length; i++) {
|
// small_objects
|
||||||
PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
|
MultiPool__dtor(&self->small_objects);
|
||||||
PyObject__delete(obj);
|
// 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++) {
|
c11_vector__dtor(&self->large_objects);
|
||||||
PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
|
|
||||||
PyObject__delete(obj);
|
|
||||||
}
|
|
||||||
c11_vector__dtor(&self->no_gc);
|
|
||||||
c11_vector__dtor(&self->gen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManagedHeap__collect_if_needed(ManagedHeap* self) {
|
void ManagedHeap__collect_if_needed(ManagedHeap* self) {
|
||||||
if(!self->gc_enabled) return;
|
if(!self->gc_enabled) return;
|
||||||
if(self->gc_counter < self->gc_threshold) return;
|
if(self->gc_counter < self->gc_threshold) return;
|
||||||
self->gc_counter = 0;
|
self->gc_counter = 0;
|
||||||
ManagedHeap__collect(self);
|
int freed = ManagedHeap__collect(self);
|
||||||
self->gc_threshold = self->gen.length * 2;
|
// adjust `gc_threshold` based on `freed_ma`
|
||||||
if(self->gc_threshold < PK_GC_MIN_THRESHOLD) { self->gc_threshold = PK_GC_MIN_THRESHOLD; }
|
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) {
|
int ManagedHeap__collect(ManagedHeap* self) {
|
||||||
@ -43,71 +50,53 @@ int ManagedHeap__collect(ManagedHeap* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ManagedHeap__sweep(ManagedHeap* self) {
|
int ManagedHeap__sweep(ManagedHeap* self) {
|
||||||
c11_vector alive;
|
// small_objects
|
||||||
c11_vector__ctor(&alive, sizeof(PyObject*));
|
int small_freed = MultiPool__sweep_dealloc(&self->small_objects);
|
||||||
c11_vector__reserve(&alive, self->gen.length / 2);
|
// large_objects
|
||||||
|
int large_living_count = 0;
|
||||||
for(int i = 0; i < self->gen.length; i++) {
|
for(int i = 0; i < self->large_objects.length; i++) {
|
||||||
PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
|
PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
|
||||||
if(obj->gc_marked) {
|
if(obj->gc_marked) {
|
||||||
obj->gc_marked = false;
|
obj->gc_marked = false;
|
||||||
c11_vector__push(PyObject*, &alive, obj);
|
c11__setitem(PyObject*, &self->large_objects, large_living_count, obj);
|
||||||
|
large_living_count++;
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// shrink `self->large_objects`
|
||||||
// clear _no_gc marked flag
|
int large_freed = self->large_objects.length - large_living_count;
|
||||||
for(int i = 0; i < self->no_gc.length; i++) {
|
self->large_objects.length = large_living_count;
|
||||||
PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
|
return small_freed + large_freed;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize) {
|
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);
|
assert(slots >= 0 || slots == -1);
|
||||||
PyObject* self;
|
PyObject* obj;
|
||||||
// header + slots + udsize
|
// header + slots + udsize
|
||||||
size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + size;
|
int size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + udsize;
|
||||||
if(!PK_LOW_MEMORY_MODE && size <= kPoolObjectBlockSize) {
|
if(!PK_LOW_MEMORY_MODE && size <= kPoolMaxBlockSize) {
|
||||||
self = PoolObject_alloc();
|
obj = MultiPool__alloc(&self->small_objects, size);
|
||||||
self->gc_is_large = false;
|
assert(obj != NULL);
|
||||||
} else {
|
} else {
|
||||||
self = PK_MALLOC(size);
|
obj = PK_MALLOC(size);
|
||||||
self->gc_is_large = true;
|
c11_vector__push(PyObject*, &self->large_objects, obj);
|
||||||
}
|
}
|
||||||
self->type = type;
|
obj->type = type;
|
||||||
self->gc_marked = false;
|
obj->gc_marked = false;
|
||||||
self->slots = slots;
|
obj->slots = slots;
|
||||||
|
|
||||||
// initialize slots or dict
|
// initialize slots or dict
|
||||||
if(slots >= 0) {
|
if(slots >= 0) {
|
||||||
memset(self->flex, 0, slots * sizeof(py_TValue));
|
memset(obj->flex, 0, slots * sizeof(py_TValue));
|
||||||
} else {
|
} else {
|
||||||
NameDict__ctor((void*)self->flex);
|
NameDict__ctor((void*)obj->flex);
|
||||||
}
|
}
|
||||||
return self;
|
|
||||||
|
self->gc_counter++;
|
||||||
|
return obj;
|
||||||
}
|
}
|
206
src/interpreter/objectpool.c
Normal file
206
src/interpreter/objectpool.c
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
#include "pocketpy/interpreter/objectpool.h"
|
||||||
|
|
||||||
|
#include "pocketpy/config.h"
|
||||||
|
#include "pocketpy/objects/object.h"
|
||||||
|
#include "pocketpy/common/sstream.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;
|
||||||
|
PoolArena* self = PK_MALLOC(sizeof(PoolArena) + sizeof(int) * block_count);
|
||||||
|
self->block_size = block_size;
|
||||||
|
self->block_count = block_count;
|
||||||
|
self->unused_length = 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_length > 0);
|
||||||
|
int index = self->unused[self->unused_length - 1];
|
||||||
|
self->unused_length--;
|
||||||
|
return self->data + index * self->block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PoolArena__sweep_dealloc(PoolArena* self) {
|
||||||
|
int freed = 0;
|
||||||
|
self->unused_length = 0;
|
||||||
|
for(int i = 0; i < self->block_count; i++) {
|
||||||
|
PyObject* obj = (PyObject*)(self->data + i * self->block_size);
|
||||||
|
if(obj->type == 0) {
|
||||||
|
// free slot
|
||||||
|
self->unused[self->unused_length] = i;
|
||||||
|
self->unused_length++;
|
||||||
|
} else {
|
||||||
|
if(!obj->gc_marked) {
|
||||||
|
// not marked, need to free
|
||||||
|
obj->type = 0;
|
||||||
|
freed++;
|
||||||
|
self->unused[self->unused_length] = i;
|
||||||
|
self->unused_length++;
|
||||||
|
} else {
|
||||||
|
// marked, clear mark
|
||||||
|
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->no_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->no_free_arenas, arena) PoolArena__delete(*arena);
|
||||||
|
c11_vector__dtor(&self->arenas);
|
||||||
|
c11_vector__dtor(&self->no_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_length == 0) {
|
||||||
|
c11_vector__pop(&self->arenas);
|
||||||
|
c11_vector__push(PoolArena*, &self->no_free_arenas, arena);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* no_free_arenas) {
|
||||||
|
c11_vector__clear(arenas);
|
||||||
|
c11_vector__clear(no_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_length > 0);
|
||||||
|
freed += PoolArena__sweep_dealloc(item);
|
||||||
|
if(item->unused_length == item->block_count) {
|
||||||
|
// all free
|
||||||
|
if(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->no_free_arenas.length; i++) {
|
||||||
|
PoolArena* item = c11__getitem(PoolArena*, &self->no_free_arenas, i);
|
||||||
|
freed += PoolArena__sweep_dealloc(item);
|
||||||
|
if(item->unused_length == 0) {
|
||||||
|
// still no free
|
||||||
|
c11_vector__push(PoolArena*, no_free_arenas, item);
|
||||||
|
} else {
|
||||||
|
if(item->unused_length == 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->no_free_arenas, no_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 no_free_arenas;
|
||||||
|
c11_vector__ctor(&arenas, sizeof(PoolArena*));
|
||||||
|
c11_vector__ctor(&no_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, &no_free_arenas);
|
||||||
|
}
|
||||||
|
c11_vector__dtor(&arenas);
|
||||||
|
c11_vector__dtor(&no_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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c11_string* MultiPool__summary(MultiPool* self) {
|
||||||
|
c11_sbuf sbuf;
|
||||||
|
c11_sbuf__ctor(&sbuf);
|
||||||
|
for(int i = 0; i < kMultiPoolCount; i++) {
|
||||||
|
Pool* item = &self->pools[i];
|
||||||
|
int total_bytes = (item->arenas.length + item->no_free_arenas.length) * kPoolArenaSize;
|
||||||
|
int used_bytes = 0;
|
||||||
|
for(int j = 0; j < item->arenas.length; j++) {
|
||||||
|
PoolArena* arena = c11__getitem(PoolArena*, &item->arenas, j);
|
||||||
|
used_bytes += (arena->block_count - arena->unused_length) * arena->block_size;
|
||||||
|
}
|
||||||
|
used_bytes += item->no_free_arenas.length * kPoolArenaSize;
|
||||||
|
float used_pct = (float)used_bytes / total_bytes * 100;
|
||||||
|
char buf[256];
|
||||||
|
snprintf(buf,
|
||||||
|
sizeof(buf),
|
||||||
|
"Pool<%d>: len(arenas)=%d, len(no_free_arenas)=%d, %d/%d (%.1f%% used)",
|
||||||
|
item->block_size,
|
||||||
|
item->arenas.length,
|
||||||
|
item->no_free_arenas.length,
|
||||||
|
used_bytes,
|
||||||
|
total_bytes,
|
||||||
|
used_pct);
|
||||||
|
c11_sbuf__write_cstr(&sbuf, buf);
|
||||||
|
c11_sbuf__write_char(&sbuf, '\n');
|
||||||
|
}
|
||||||
|
return c11_sbuf__submit(&sbuf);
|
||||||
|
}
|
@ -66,6 +66,7 @@ void VM__ctor(VM* self) {
|
|||||||
|
|
||||||
self->callbacks.importfile = pk_default_importfile;
|
self->callbacks.importfile = pk_default_importfile;
|
||||||
self->callbacks.print = pk_default_print;
|
self->callbacks.print = pk_default_print;
|
||||||
|
self->callbacks.getchar = getchar;
|
||||||
|
|
||||||
self->last_retval = *py_NIL();
|
self->last_retval = *py_NIL();
|
||||||
self->curr_exception = *py_NIL();
|
self->curr_exception = *py_NIL();
|
||||||
@ -76,7 +77,9 @@ void VM__ctor(VM* self) {
|
|||||||
self->__curr_class = NULL;
|
self->__curr_class = NULL;
|
||||||
self->__curr_function = NULL;
|
self->__curr_function = NULL;
|
||||||
|
|
||||||
ManagedHeap__ctor(&self->heap, self);
|
FixedMemoryPool__ctor(&self->pool_frame, sizeof(Frame), 32);
|
||||||
|
|
||||||
|
ManagedHeap__ctor(&self->heap);
|
||||||
ValueStack__ctor(&self->stack);
|
ValueStack__ctor(&self->stack);
|
||||||
|
|
||||||
/* Init Builtin Types */
|
/* Init Builtin Types */
|
||||||
@ -247,6 +250,7 @@ void VM__dtor(VM* self) {
|
|||||||
VM__pop_frame(self);
|
VM__pop_frame(self);
|
||||||
ModuleDict__dtor(&self->modules);
|
ModuleDict__dtor(&self->modules);
|
||||||
TypeList__dtor(&self->types);
|
TypeList__dtor(&self->types);
|
||||||
|
FixedMemoryPool__dtor(&self->pool_frame);
|
||||||
ValueStack__clear(&self->stack);
|
ValueStack__clear(&self->stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,15 +573,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);
|
py_TypeInfo* ti = pk__type_info(self->type);
|
||||||
if(ti->dtor) ti->dtor(PyObject__userdata(self));
|
if(ti->dtor) ti->dtor(PyObject__userdata(self));
|
||||||
if(self->slots == -1) NameDict__dtor(PyObject__dict(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);
|
static void mark_object(PyObject* obj);
|
||||||
@ -636,21 +635,25 @@ void CodeObject__gc_mark(const CodeObject* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ManagedHeap__mark(ManagedHeap* self) {
|
void ManagedHeap__mark(ManagedHeap* self) {
|
||||||
VM* vm = self->vm;
|
VM* vm = pk_current_vm;
|
||||||
// mark heap objects
|
// mark large objects
|
||||||
for(int i = 0; i < self->no_gc.length; i++) {
|
for(int i = 0; i < self->large_objects.length; i++) {
|
||||||
PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
|
PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
|
||||||
mark_object(obj);
|
mark_object(obj);
|
||||||
}
|
}
|
||||||
// mark value stack
|
// mark value stack
|
||||||
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) {
|
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) {
|
||||||
pk__mark_value(p);
|
pk__mark_value(p);
|
||||||
}
|
}
|
||||||
|
// mark modules
|
||||||
|
ModuleDict__apply_mark(&vm->modules, mark_object);
|
||||||
// mark types
|
// mark types
|
||||||
int types_length = vm->types.length;
|
int types_length = vm->types.length;
|
||||||
// 0-th type is placeholder
|
// 0-th type is placeholder
|
||||||
for(py_Type i = 1; i < types_length; i++) {
|
for(py_Type i = 1; i < types_length; i++) {
|
||||||
py_TypeInfo* ti = TypeList__get(&vm->types, i);
|
py_TypeInfo* ti = TypeList__get(&vm->types, i);
|
||||||
|
// mark type object
|
||||||
|
pk__mark_value(&ti->self);
|
||||||
// mark common magic slots
|
// mark common magic slots
|
||||||
for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) {
|
for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) {
|
||||||
py_TValue* slot = ti->magic_0 + j;
|
py_TValue* slot = ti->magic_0 + j;
|
||||||
@ -745,8 +748,46 @@ bool pk_wrapper__self(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv) {
|
|
||||||
return py_exception(tp_NotImplementedError, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
py_TypeInfo* pk__type_info(py_Type type) { return TypeList__get(&pk_current_vm->types, type); }
|
py_TypeInfo* pk__type_info(py_Type type) { return TypeList__get(&pk_current_vm->types, type); }
|
||||||
|
|
||||||
|
int py_replinput(char* buf, int max_size) {
|
||||||
|
buf[0] = '\0'; // reset first char because we check '@' at the beginning
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
bool multiline = false;
|
||||||
|
printf(">>> ");
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
int c = pk_current_vm->callbacks.getchar();
|
||||||
|
if(c == EOF) return -1;
|
||||||
|
|
||||||
|
if(c == '\n') {
|
||||||
|
char last = '\0';
|
||||||
|
if(size > 0) last = buf[size - 1];
|
||||||
|
if(multiline) {
|
||||||
|
if(last == '\n') {
|
||||||
|
break; // 2 consecutive newlines to end multiline input
|
||||||
|
} else {
|
||||||
|
printf("... ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') {
|
||||||
|
printf("... ");
|
||||||
|
multiline = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(size == max_size - 1) {
|
||||||
|
buf[size] = '\0';
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[size++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[size] = '\0';
|
||||||
|
return size;
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
#include "pocketpy/interpreter/objectpool.h"
|
||||||
|
#include "pocketpy/objects/base.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
|
|
||||||
#include "pocketpy/common/utils.h"
|
#include "pocketpy/common/utils.h"
|
||||||
@ -33,6 +35,24 @@ DEF_TVALUE_METHODS(float, _f64)
|
|||||||
DEF_TVALUE_METHODS(vec2, _vec2)
|
DEF_TVALUE_METHODS(vec2, _vec2)
|
||||||
DEF_TVALUE_METHODS(vec2i, _vec2i)
|
DEF_TVALUE_METHODS(vec2i, _vec2i)
|
||||||
|
|
||||||
|
static bool pkpy_memory_usage(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(0);
|
||||||
|
ManagedHeap* heap = &pk_current_vm->heap;
|
||||||
|
c11_string* small_objects_usage = MultiPool__summary(&heap->small_objects);
|
||||||
|
int large_object_count = heap->large_objects.length;
|
||||||
|
c11_sbuf buf;
|
||||||
|
c11_sbuf__ctor(&buf);
|
||||||
|
c11_sbuf__write_cstr(&buf, "== heap.small_objects ==\n");
|
||||||
|
c11_sbuf__write_cstr(&buf, small_objects_usage->data);
|
||||||
|
c11_sbuf__write_cstr(&buf, "== heap.large_objects ==\n");
|
||||||
|
c11_sbuf__write_cstr(&buf, "len(large_objects)=");
|
||||||
|
c11_sbuf__write_int(&buf, large_object_count);
|
||||||
|
// c11_sbuf__write_cstr(&buf, "== vm.pool_frame ==\n");
|
||||||
|
c11_sbuf__py_submit(&buf, py_retval());
|
||||||
|
c11_string__delete(small_objects_usage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void pk__add_module_pkpy() {
|
void pk__add_module_pkpy() {
|
||||||
py_Ref mod = py_newmodule("pkpy");
|
py_Ref mod = py_newmodule("pkpy");
|
||||||
|
|
||||||
@ -66,6 +86,8 @@ void pk__add_module_pkpy() {
|
|||||||
|
|
||||||
py_setdict(mod, py_name("TValue"), TValue_dict);
|
py_setdict(mod, py_name("TValue"), TValue_dict);
|
||||||
py_pop();
|
py_pop();
|
||||||
|
|
||||||
|
py_bindfunc(mod, "memory_usage", pkpy_memory_usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef DEF_TVALUE_METHODS
|
#undef DEF_TVALUE_METHODS
|
@ -73,3 +73,9 @@ py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path) {
|
|||||||
bool ModuleDict__contains(ModuleDict* self, const char* path) {
|
bool ModuleDict__contains(ModuleDict* self, const char* path) {
|
||||||
return ModuleDict__try_get(self, path) != NULL;
|
return ModuleDict__try_get(self, path) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModuleDict__apply_mark(ModuleDict *self, void (*marker)(PyObject*)) {
|
||||||
|
if(self->left) ModuleDict__apply_mark(self->left, marker);
|
||||||
|
if(self->right) ModuleDict__apply_mark(self->right, marker);
|
||||||
|
marker(self->module._obj);
|
||||||
|
}
|
||||||
|
@ -27,7 +27,6 @@ void py_initialize() {
|
|||||||
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
|
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
|
||||||
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
||||||
|
|
||||||
MemoryPools__initialize();
|
|
||||||
py_Name__initialize();
|
py_Name__initialize();
|
||||||
|
|
||||||
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
||||||
@ -63,7 +62,6 @@ void py_finalize() {
|
|||||||
VM__dtor(&pk_default_vm);
|
VM__dtor(&pk_default_vm);
|
||||||
pk_current_vm = NULL;
|
pk_current_vm = NULL;
|
||||||
py_Name__finalize();
|
py_Name__finalize();
|
||||||
MemoryPools__finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_switchvm(int index) {
|
void py_switchvm(int index) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "pocketpy/common/str.h"
|
#include "pocketpy/common/str.h"
|
||||||
|
#include "pocketpy/objects/base.h"
|
||||||
#include "pocketpy/objects/codeobject.h"
|
#include "pocketpy/objects/codeobject.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
#include "pocketpy/common/utils.h"
|
#include "pocketpy/common/utils.h"
|
||||||
@ -208,7 +209,7 @@ static bool builtins_input(int argc, py_Ref argv) {
|
|||||||
c11_sbuf buf;
|
c11_sbuf buf;
|
||||||
c11_sbuf__ctor(&buf);
|
c11_sbuf__ctor(&buf);
|
||||||
while(true) {
|
while(true) {
|
||||||
int c = getchar();
|
int c = pk_current_vm->callbacks.getchar();
|
||||||
if(c == '\n') break;
|
if(c == '\n') break;
|
||||||
if(c == EOF) break;
|
if(c == EOF) break;
|
||||||
c11_sbuf__write_char(&buf, c);
|
c11_sbuf__write_char(&buf, c);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user