From bfe471dc121c34438e1cf322615cfb610e7e2da3 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 24 Nov 2025 11:41:37 +0800 Subject: [PATCH] small refactor --- docs/modules/gc.md | 16 ++-------- docs/modules/json.md | 8 ++--- docs/retype.yml | 2 +- include/pocketpy/config.h | 4 +-- include/pocketpy/interpreter/heap.h | 2 +- include/pocketpy/interpreter/objectpool.h | 2 +- include/typings/gc.pyi | 27 +++++++++++++++++ include/typings/inspect.pyi | 7 ++++- include/typings/json.pyi | 2 ++ include/typings/pkpy.pyi | 6 +--- src/interpreter/ceval.c | 2 +- src/interpreter/heap.c | 10 ++---- src/interpreter/objectpool.c | 2 +- src/modules/gc.c | 37 +++++++++++++++++------ src/modules/inspect.c | 14 ++++++--- src/modules/pkpy.c | 18 ----------- tests/71_gc.py | 3 +- tests/92_pkpy.py | 2 +- 18 files changed, 92 insertions(+), 72 deletions(-) create mode 100644 include/typings/gc.pyi create mode 100644 include/typings/json.pyi diff --git a/docs/modules/gc.md b/docs/modules/gc.md index 6f70c10b..d40d805d 100644 --- a/docs/modules/gc.md +++ b/docs/modules/gc.md @@ -3,18 +3,8 @@ icon: package label: gc --- -### `gc.collect()` +Garbage collection interface module. -Invoke the garbage collector. +#### Source code -### `gc.enable()` - -Enable automatic garbage collection. - -### `gc.disable()` - -Disable automatic garbage collection. - -### `gc.isenabled()` - -Return `True` if automatic garbage collection is enabled, `False` otherwise. \ No newline at end of file +:::code source="../../include/typings/gc.pyi" ::: diff --git a/docs/modules/json.md b/docs/modules/json.md index 56a69519..18157b6c 100644 --- a/docs/modules/json.md +++ b/docs/modules/json.md @@ -3,11 +3,9 @@ icon: package label: json --- -### `json.loads(data: str)` +JSON serialization and deserialization module. -Decode a JSON string into a python object. +#### Source code -### `json.dumps(obj, indent=0) -> str` - -Encode a python object into a JSON string. +:::code source="../../include/typings/json.pyi" ::: diff --git a/docs/retype.yml b/docs/retype.yml index 3df985fc..dffb6bc1 100644 --- a/docs/retype.yml +++ b/docs/retype.yml @@ -3,7 +3,7 @@ output: .retype url: https://pocketpy.dev branding: title: pocketpy - label: v2.1.4 + label: v2.1.5 logo: "./static/logo.png" favicon: "./static/logo.png" meta: diff --git a/include/pocketpy/config.h b/include/pocketpy/config.h index a5fd1528..17400e25 100644 --- a/include/pocketpy/config.h +++ b/include/pocketpy/config.h @@ -1,10 +1,10 @@ #pragma once // clang-format off -#define PK_VERSION "2.1.4" +#define PK_VERSION "2.1.5" #define PK_VERSION_MAJOR 2 #define PK_VERSION_MINOR 1 -#define PK_VERSION_PATCH 4 +#define PK_VERSION_PATCH 5 /*************** feature settings ***************/ #ifndef PK_ENABLE_OS // can be overridden by cmake diff --git a/include/pocketpy/interpreter/heap.h b/include/pocketpy/interpreter/heap.h index 9b79824c..f09d882a 100644 --- a/include/pocketpy/interpreter/heap.h +++ b/include/pocketpy/interpreter/heap.h @@ -44,7 +44,7 @@ void ManagedHeap__dtor(ManagedHeap* self); ManagedHeapSwpetInfo* ManagedHeapSwpetInfo__new(); void ManagedHeapSwpetInfo__delete(ManagedHeapSwpetInfo* self); -void ManagedHeap__collect_if_needed(ManagedHeap* self); +void ManagedHeap__collect_hint(ManagedHeap* self); int ManagedHeap__collect(ManagedHeap* self); int ManagedHeap__sweep(ManagedHeap* self, ManagedHeapSwpetInfo* out_info); diff --git a/include/pocketpy/interpreter/objectpool.h b/include/pocketpy/interpreter/objectpool.h index 91271601..67145e3e 100644 --- a/include/pocketpy/interpreter/objectpool.h +++ b/include/pocketpy/interpreter/objectpool.h @@ -5,7 +5,7 @@ #define kPoolArenaSize (120 * 1024) #define kMultiPoolCount 5 -#define kPoolMaxBlockSize (32 * kMultiPoolCount) +// #define kPoolMaxBlockSize (32 * kMultiPoolCount) typedef struct PoolArena { int block_size; diff --git a/include/typings/gc.pyi b/include/typings/gc.pyi new file mode 100644 index 00000000..449a48e6 --- /dev/null +++ b/include/typings/gc.pyi @@ -0,0 +1,27 @@ +from typing import Callable + +def isenabled() -> bool: + """Check if automatic garbage collection is enabled.""" + +def enable() -> None: + """Enable automatic garbage collection.""" + +def disable() -> None: + """Disable automatic garbage collection.""" + +def collect() -> int: + """Run a full collection immediately. + + Returns an integer indicating the number of unreachable objects found. + """ + +def collect_hint() -> None: + """Hint the garbage collector to run a collection. + + The typical usage scenario for this function is in frame-driven games, + where `gc.disable()` is called at the start of the game, + and `gc.collect_hint()` is called at the end of each frame. + """ + +def setup_debug_callback(cb: Callable[[str], None] | None) -> None: + """Setup a callback that will be triggered at the end of each collection.""" diff --git a/include/typings/inspect.pyi b/include/typings/inspect.pyi index 93c18d98..513e2493 100644 --- a/include/typings/inspect.pyi +++ b/include/typings/inspect.pyi @@ -1 +1,6 @@ -def isgeneratorfunction(obj) -> bool: ... \ No newline at end of file +def isgeneratorfunction(obj) -> bool: ... + +def is_user_defined_type(t: type) -> bool: + """Check if a type is user-defined. + + This means the type was created by executing python `class` statement.""" \ No newline at end of file diff --git a/include/typings/json.pyi b/include/typings/json.pyi new file mode 100644 index 00000000..805d3ce1 --- /dev/null +++ b/include/typings/json.pyi @@ -0,0 +1,2 @@ +def loads(s: str): ... +def dumps(obj, indent=0): ... diff --git a/include/typings/pkpy.pyi b/include/typings/pkpy.pyi index 7648542b..23291faf 100644 --- a/include/typings/pkpy.pyi +++ b/include/typings/pkpy.pyi @@ -1,4 +1,4 @@ -from typing import Self, Literal, Callable +from typing import Self, Literal from vmath import vec2, vec2i class TValue[T]: @@ -16,11 +16,7 @@ configmacros: dict[str, int] def memory_usage() -> str: """Return a summary of the memory usage.""" -def setup_gc_debug_callback(cb: Callable[[str], None]) -> None: - """Setup a callback that will be triggered at the end of GC.""" -def is_user_defined_type(t: type) -> bool: - """Check if a type is user-defined. This means the type was created by executing python `class` statement.""" def currentvm() -> int: """Return the current VM index.""" diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 0133ff0f..5bddb613 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -729,7 +729,7 @@ __NEXT_STEP: } /*****************************************/ case OP_CALL: { - ManagedHeap__collect_if_needed(&self->heap); + if(self->heap.gc_enabled) ManagedHeap__collect_hint(&self->heap); vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8); DISPATCH(); } diff --git a/src/interpreter/heap.c b/src/interpreter/heap.c index 3ad5e941..f4298001 100644 --- a/src/interpreter/heap.c +++ b/src/interpreter/heap.c @@ -94,8 +94,7 @@ static void ManagedHeap__fire_debug_callback(ManagedHeap* self, ManagedHeapSwpet } } -void ManagedHeap__collect_if_needed(ManagedHeap* self) { - if(!self->gc_enabled) return; +void ManagedHeap__collect_hint(ManagedHeap* self) { if(self->gc_counter < self->gc_threshold) return; self->gc_counter = 0; @@ -185,13 +184,10 @@ int ManagedHeap__sweep(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) { PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize) { assert(slots >= 0 || slots == -1); - PyObject* obj; // header + slots + udsize int size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + udsize; - if(size <= kPoolMaxBlockSize) { - obj = MultiPool__alloc(&self->small_objects, size); - assert(obj != NULL); - } else { + PyObject* obj = MultiPool__alloc(&self->small_objects, size); + if(obj == NULL) { obj = PK_MALLOC(size); c11_vector__push(PyObject*, &self->large_objects, obj); } diff --git a/src/interpreter/objectpool.c b/src/interpreter/objectpool.c index 436d3bfb..ad4fe725 100644 --- a/src/interpreter/objectpool.c +++ b/src/interpreter/objectpool.c @@ -141,7 +141,7 @@ static int Pool__sweep_dealloc(Pool* self, } void* MultiPool__alloc(MultiPool* self, int size) { - if(size == 0) return NULL; + assert(size > 0); int index = (size - 1) >> 5; if(index < kMultiPoolCount) { Pool* pool = &self->pools[index]; diff --git a/src/modules/gc.c b/src/modules/gc.c index 6bb7fcb9..caa5530f 100644 --- a/src/modules/gc.c +++ b/src/modules/gc.c @@ -1,14 +1,6 @@ #include "pocketpy/pocketpy.h" #include "pocketpy/interpreter/vm.h" -static bool gc_collect(int argc, py_Ref argv) { - PY_CHECK_ARGC(0); - ManagedHeap* heap = &pk_current_vm->heap; - int res = ManagedHeap__collect(heap); - py_newint(py_retval(), res); - return true; -} - static bool gc_enable(int argc, py_Ref argv) { PY_CHECK_ARGC(0); ManagedHeap* heap = &pk_current_vm->heap; @@ -32,11 +24,38 @@ static bool gc_isenabled(int argc, py_Ref argv) { return true; } +static bool gc_collect(int argc, py_Ref argv) { + PY_CHECK_ARGC(0); + ManagedHeap* heap = &pk_current_vm->heap; + int res = ManagedHeap__collect(heap); + py_newint(py_retval(), res); + return true; +} + +static bool gc_collect_hint(int argc, py_Ref argv) { + PY_CHECK_ARGC(0); + ManagedHeap* heap = &pk_current_vm->heap; + ManagedHeap__collect_hint(heap); + py_newnone(py_retval()); + return true; +} + +static bool gc_setup_debug_callback(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + ManagedHeap* heap = &pk_current_vm->heap; + heap->debug_callback = *argv; + py_newnone(py_retval()); + return true; +} + void pk__add_module_gc() { py_Ref mod = py_newmodule("gc"); - py_bindfunc(mod, "collect", gc_collect); py_bindfunc(mod, "enable", gc_enable); py_bindfunc(mod, "disable", gc_disable); py_bindfunc(mod, "isenabled", gc_isenabled); + + py_bindfunc(mod, "collect", gc_collect); + py_bindfunc(mod, "collect_hint", gc_collect_hint); + py_bindfunc(mod, "setup_debug_callback", gc_setup_debug_callback); } diff --git a/src/modules/inspect.c b/src/modules/inspect.c index d32a4740..0898a7b1 100644 --- a/src/modules/inspect.c +++ b/src/modules/inspect.c @@ -1,8 +1,5 @@ #include "pocketpy/pocketpy.h" - -#include "pocketpy/common/utils.h" #include "pocketpy/objects/object.h" -#include "pocketpy/common/sstream.h" #include "pocketpy/interpreter/vm.h" static bool inspect_isgeneratorfunction(int argc, py_Ref argv) { @@ -21,8 +18,17 @@ static bool inspect_isgeneratorfunction(int argc, py_Ref argv) { return true; } +static bool inspect_is_user_defined_type(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + PY_CHECK_ARG_TYPE(0, tp_type); + py_TypeInfo* ti = py_touserdata(argv); + py_newbool(py_retval(), ti->is_python); + return true; +} + void pk__add_module_inspect() { py_Ref mod = py_newmodule("inspect"); py_bindfunc(mod, "isgeneratorfunction", inspect_isgeneratorfunction); -} \ No newline at end of file + py_bindfunc(mod, "is_user_defined_type", inspect_is_user_defined_type); +} diff --git a/src/modules/pkpy.c b/src/modules/pkpy.c index a8ad1909..0e8116fb 100644 --- a/src/modules/pkpy.c +++ b/src/modules/pkpy.c @@ -57,22 +57,6 @@ static bool pkpy_memory_usage(int argc, py_Ref argv) { return true; } -static bool pkpy_setup_gc_debug_callback(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - ManagedHeap* heap = &pk_current_vm->heap; - heap->debug_callback = *argv; - py_newnone(py_retval()); - return true; -} - -static bool pkpy_is_user_defined_type(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - PY_CHECK_ARG_TYPE(0, tp_type); - py_TypeInfo* ti = py_touserdata(argv); - py_newbool(py_retval(), ti->is_python); - return true; -} - static bool pkpy_currentvm(int argc, py_Ref argv) { PY_CHECK_ARGC(0); py_newint(py_retval(), py_currentvm()); @@ -538,8 +522,6 @@ void pk__add_module_pkpy() { py_pop(); py_bindfunc(mod, "memory_usage", pkpy_memory_usage); - py_bindfunc(mod, "setup_gc_debug_callback", pkpy_setup_gc_debug_callback); - py_bindfunc(mod, "is_user_defined_type", pkpy_is_user_defined_type); py_bindfunc(mod, "currentvm", pkpy_currentvm); diff --git a/tests/71_gc.py b/tests/71_gc.py index ee18b6eb..b763b583 100644 --- a/tests/71_gc.py +++ b/tests/71_gc.py @@ -1,7 +1,6 @@ import gc -from pkpy import setup_gc_debug_callback -setup_gc_debug_callback(print) +gc.setup_debug_callback(print) gc.collect() def create_garbage(): diff --git a/tests/92_pkpy.py b/tests/92_pkpy.py index 8c0b164d..b053317a 100644 --- a/tests/92_pkpy.py +++ b/tests/92_pkpy.py @@ -1,4 +1,4 @@ -from pkpy import is_user_defined_type +from inspect import is_user_defined_type class A: pass