From c416faf54d4d66a8d6314aa9a2b16c7a337ee187 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 19 May 2024 23:52:08 +0800 Subject: [PATCH] backup --- docs/bindings.md | 4 +- include/pocketpy/codeobject.h | 34 +----- include/pocketpy/common.h | 2 + include/pocketpy/dict.h | 2 +- include/pocketpy/frame.h | 7 +- include/pocketpy/gc.h | 3 +- include/pocketpy/iter.h | 10 +- include/pocketpy/obj.h | 142 ++++------------------ include/pocketpy/tuplelist.h | 6 +- include/pocketpy/vm.h | 34 +++++- src/array2d.cpp | 4 +- src/ceval.cpp | 2 +- src/cffi.cpp | 32 ++--- src/codeobject.cpp | 6 - src/collections.cpp | 6 +- src/dict.cpp | 8 -- src/gc.cpp | 15 +-- src/obj.cpp | 7 -- src/vm.cpp | 215 ++++++++++++++++++++++++---------- 19 files changed, 256 insertions(+), 283 deletions(-) diff --git a/docs/bindings.md b/docs/bindings.md index e0fff7c5..68edbff7 100644 --- a/docs/bindings.md +++ b/docs/bindings.md @@ -155,7 +155,7 @@ struct Container{ } ``` -Add a magic method `_gc_mark() const` to your custom type. +Add a magic method `_gc_mark(VM*) const` to your custom type. ```cpp struct Container{ @@ -163,7 +163,7 @@ struct Container{ std::vector b; // ... - void _gc_mark() const{ + void _gc_mark(VM* vm) const{ // mark a if(a) PK_OBJ_MARK(a); diff --git a/include/pocketpy/codeobject.h b/include/pocketpy/codeobject.h index 07c22c98..fd3b6638 100644 --- a/include/pocketpy/codeobject.h +++ b/include/pocketpy/codeobject.h @@ -81,7 +81,7 @@ struct CodeObject { } CodeObject(std::shared_ptr src, const Str& name); - void _gc_mark() const; + void _gc_mark(VM*) const; }; enum class FuncType{ @@ -118,7 +118,7 @@ struct FuncDecl { kwargs.push_back(KwArg{index, key, value}); } - void _gc_mark() const; + void _gc_mark(VM*) const; }; struct NativeFunc { @@ -130,8 +130,9 @@ struct NativeFunc { NativeFunc(NativeFuncC f, int argc, any userdata={}): f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {} NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata={}): f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {} - void check_size(VM* vm, ArgsView args) const; PyVar call(VM* vm, ArgsView args) const { return f(vm, args); } + void check_size(VM* vm, ArgsView args) const; + void _gc_mark(VM*) const; }; struct Function{ @@ -142,33 +143,8 @@ struct Function{ explicit Function(FuncDecl_ decl, PyVar _module, PyVar _class, NameDict_ _closure): decl(decl), _module(_module), _class(_class), _closure(_closure) {} -}; -template<> -struct Py_ final: PyObject { - Function _value; - template - Py_(Args&&... args): PyObject(), _value(std::forward(args)...) { - // _enable_instance_dict(); - } - void _obj_gc_mark() override { - _value.decl->_gc_mark(); - if(_value._closure != nullptr) _gc_mark_namedict(_value._closure.get()); - } -}; - -template<> -struct Py_ final: PyObject { - NativeFunc _value; - template - Py_(Args&&... args): PyObject(), _value(std::forward(args)...) { - // _enable_instance_dict(); - } - void _obj_gc_mark() override { - if(_value.decl != nullptr){ - _value.decl->_gc_mark(); - } - } + void _gc_mark(VM*) const; }; template diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index c425b4f8..0405a8b4 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -169,6 +169,8 @@ inline constexpr bool is_floating_point_v = std::is_same_v || std::is_ inline const char* PK_HEX_TABLE = "0123456789abcdef"; struct PyObject; +struct Frame; +class VM; // by default, only `int` and `float` enable SSO // users can specialize this template to enable SSO for other types diff --git a/include/pocketpy/dict.h b/include/pocketpy/dict.h index 46647722..b2f98371 100644 --- a/include/pocketpy/dict.h +++ b/include/pocketpy/dict.h @@ -66,7 +66,7 @@ struct Dict{ void clear(); ~Dict(); - void _gc_mark() const; + void _gc_mark(VM*) const; }; } // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/frame.h b/include/pocketpy/frame.h index fafafb83..2b08904e 100644 --- a/include/pocketpy/frame.h +++ b/include/pocketpy/frame.h @@ -117,12 +117,7 @@ struct Frame { int curr_lineno() const { return co->lines[ip()].lineno; } - void _gc_mark() const { - PK_OBJ_MARK(_module); - co->_gc_mark(); - // Frame could be stored in a generator, so mark _callable for safety - if(_callable != nullptr) PK_OBJ_MARK(_callable); - } + void _gc_mark(VM* vm) const; }; struct LinkedFrame{ diff --git a/include/pocketpy/gc.h b/include/pocketpy/gc.h index 2f5d4eee..5f3dd6a7 100644 --- a/include/pocketpy/gc.h +++ b/include/pocketpy/gc.h @@ -61,6 +61,8 @@ struct ManagedHeap{ return obj; } + void _delete(PyVar); + #if PK_DEBUG_GC_STATS inline static std::map deleted; #endif @@ -70,7 +72,6 @@ struct ManagedHeap{ bool _should_auto_collect() const { return gc_counter >= gc_threshold; } int collect(); void mark(); - ~ManagedHeap(); }; } // namespace pkpy diff --git a/include/pocketpy/iter.h b/include/pocketpy/iter.h index 7f02ee01..e3c8d6e5 100644 --- a/include/pocketpy/iter.h +++ b/include/pocketpy/iter.h @@ -23,7 +23,7 @@ struct ArrayIter{ ArrayIter(PyVar ref, PyVar* begin, PyVar* end) : ref(ref), begin(begin), end(end), current(begin) {} - void _gc_mark() const{ PK_OBJ_MARK(ref); } + void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } static void _register(VM* vm, PyVar mod, PyVar type); }; @@ -31,7 +31,7 @@ struct StringIter{ PyVar ref; int i; // byte index StringIter(PyVar ref) : ref(ref), i(0) {} - void _gc_mark() const{ PK_OBJ_MARK(ref); } + void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } static void _register(VM* vm, PyVar mod, PyVar type); }; @@ -44,8 +44,8 @@ struct Generator{ for(PyVar obj: buffer) s_backup.push_back(obj); } - void _gc_mark() const{ - frame._gc_mark(); + void _gc_mark(VM* vm) const{ + frame._gc_mark(vm); for(PyVar obj: s_backup) PK_OBJ_MARK(obj); } @@ -59,7 +59,7 @@ struct DictItemsIter{ DictItemsIter(PyVar ref) : ref(ref) { i = PK_OBJ_GET(Dict, ref)._head_idx; } - void _gc_mark() const{ PK_OBJ_MARK(ref); } + void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } static void _register(VM* vm, PyVar mod, PyVar type); }; diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index 6b4765ea..75287bc6 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -6,9 +6,6 @@ namespace pkpy { -struct Frame; -class VM; - #if PK_ENABLE_STD_FUNCTION using NativeFuncC = std::function; #else @@ -25,22 +22,26 @@ struct BoundMethod { PyVar self; PyVar func; BoundMethod(PyVar self, PyVar func) : self(self), func(func) {} + void _gc_mark(VM*) const; }; struct StaticMethod{ PyVar func; StaticMethod(PyVar func) : func(func) {} + void _gc_mark(VM*) const; }; struct ClassMethod{ PyVar func; ClassMethod(PyVar func) : func(func) {} + void _gc_mark(VM*) const; }; struct Property{ PyVar getter; PyVar setter; Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {} + void _gc_mark(VM*) const; }; struct Range { @@ -53,6 +54,7 @@ struct StarWrapper{ int level; // either 1 or 2 PyVar obj; StarWrapper(int level, PyVar obj) : level(level), obj(obj) {} + void _gc_mark(VM*) const; }; struct Bytes{ @@ -84,13 +86,19 @@ struct Bytes{ ~Bytes(){ delete[] _data;} }; -using Super = std::pair; +struct Super{ + PyVar first; + Type second; + Super(PyVar first, Type second) : first(first), second(second) {} + void _gc_mark(VM*) const; +}; struct Slice { PyVar start; PyVar stop; PyVar step; Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {} + void _gc_mark(VM*) const; }; struct PyObject{ @@ -98,6 +106,8 @@ struct PyObject{ bool gc_marked; // whether this object is marked NameDict* _attr; + void* _value_ptr() noexcept { return 1 + &_attr; } + bool is_attr_valid() const noexcept { return _attr != nullptr; } NameDict& attr() { @@ -110,9 +120,6 @@ struct PyObject{ return (*_attr)[name]; } - virtual void _obj_gc_mark() = 0; - virtual ~PyObject(); - PyObject() : gc_enabled(true), gc_marked(false), _attr(nullptr) {} void _enable_instance_dict() { @@ -124,6 +131,9 @@ struct PyObject{ } }; +template +inline constexpr int py_sizeof = sizeof(PyObject) + sizeof(T); + const int kTpIntIndex = 3; const int kTpFloatIndex = 4; @@ -143,14 +153,7 @@ template struct Py_ final: PyObject { static_assert(!std::is_reference_v); static_assert(!is_sso_v); - T _value; - void _obj_gc_mark() override { - if constexpr (has_gc_marker::value) { - _value._gc_mark(); - } - } - template Py_(Args&&... args) : PyObject(), _value(std::forward(args)...) { } }; @@ -159,9 +162,9 @@ struct MappingProxy{ PyVar obj; MappingProxy(PyVar obj) : obj(obj) {} NameDict& attr() { return obj->attr(); } + void _gc_mark(VM*) const; }; -void _gc_mark_namedict(NameDict*); StrName _type_name(VM* vm, Type type); template T to_void_p(VM*, PyVar); PyVar from_void_p(VM*, void*); @@ -181,9 +184,7 @@ obj_get_t PyVar::obj_get(){ #define PK_OBJ_MARK(obj) \ if(!is_tagged(obj) && !(obj)->gc_marked) { \ - (obj)->gc_marked = true; \ - (obj)->_obj_gc_mark(); \ - if((obj)->is_attr_valid()) _gc_mark_namedict((obj)->_attr); \ + vm->__obj_gc_mark(obj); \ } #define VAR(x) py_var(vm, x) @@ -202,109 +203,12 @@ inline bool try_cast_int(PyVar obj, i64* val) noexcept { return false; } -template<> -struct Py_ final: PyObject { - List _value; - Py_(List&& val): PyObject(), _value(std::move(val)) {} - Py_(const List& val): PyObject(), _value(val) {} - - void _obj_gc_mark() override { - for(PyVar obj: _value) PK_OBJ_MARK(obj); - } -}; - -template<> -struct Py_ final: PyObject { - Tuple _value; - Py_(Tuple&& val): PyObject(), _value(std::move(val)) {} - Py_(const Tuple& val): PyObject(), _value(val) {} - - void _obj_gc_mark() override { - for(PyVar obj: _value) PK_OBJ_MARK(obj); - } -}; - -template<> -struct Py_ final: PyObject { - MappingProxy _value; - Py_(MappingProxy val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.obj); - } -}; - -template<> -struct Py_ final: PyObject { - BoundMethod _value; - Py_(BoundMethod val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.self); - PK_OBJ_MARK(_value.func); - } -}; - -template<> -struct Py_ final: PyObject { - StarWrapper _value; - Py_(StarWrapper val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.obj); - } -}; - -template<> -struct Py_ final: PyObject { - StaticMethod _value; - Py_(StaticMethod val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.func); - } -}; - -template<> -struct Py_ final: PyObject { - ClassMethod _value; - Py_(ClassMethod val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.func); - } -}; - -template<> -struct Py_ final: PyObject { - Property _value; - Py_(Property val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.getter); - PK_OBJ_MARK(_value.setter); - } -}; - -template<> -struct Py_ final: PyObject { - Slice _value; - Py_(Slice val): PyObject(), _value(val) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.start); - PK_OBJ_MARK(_value.stop); - PK_OBJ_MARK(_value.step); - } -}; - -template<> -struct Py_ final: PyObject { - Super _value; - template - Py_(Args&&... args): PyObject(), _value(std::forward(args)...) {} - void _obj_gc_mark() override { - PK_OBJ_MARK(_value.first); - } -}; template<> struct Py_ final: PyObject { - Py_(): PyObject() { _enable_instance_dict(); } - void _obj_gc_mark() override {} + Py_(): PyObject() { + _enable_instance_dict(); + } }; template<> @@ -313,7 +217,6 @@ struct Py_ final: PyObject { Py_(Type val): PyObject(), _value(val) { _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR); } - void _obj_gc_mark() override {} }; template<> @@ -321,7 +224,6 @@ struct Py_ final: PyObject { Py_(): PyObject() { _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR); } - void _obj_gc_mark() override {} }; extern PyVar const PY_NULL; diff --git a/include/pocketpy/tuplelist.h b/include/pocketpy/tuplelist.h index e8fd5779..6df7f9b7 100644 --- a/include/pocketpy/tuplelist.h +++ b/include/pocketpy/tuplelist.h @@ -7,7 +7,10 @@ namespace pkpy { -using List = pod_vector; +struct List: pod_vector{ + using pod_vector::pod_vector; + void _gc_mark(VM*) const; +}; struct Tuple { static const int INLINED_SIZE = 4; @@ -35,6 +38,7 @@ struct Tuple { PyVar* begin() const { return _args; } PyVar* end() const { return _args + _size; } PyVar* data() const { return _args; } + void _gc_mark(VM*) const; }; // a lightweight view for function args, it does not own the memory diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index fbc33a0c..f788ef8f 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -42,12 +42,36 @@ struct NextBreakpoint{ #endif struct PyTypeInfo{ + struct Vt{ + void (*_dtor)(void*); + void (*_gc_mark)(void*, VM*); + + Vt(): _dtor(nullptr), _gc_mark(nullptr) {} + + template + inline static Vt get(){ + static_assert(std::is_same_v>); + Vt vt; + if constexpr(!std::is_trivially_destructible_v){ + vt._dtor = [](void* p){ ((T*)p)->~T(); }; + } + if constexpr(has_gc_marker::value){ + vt._gc_mark = [](void* p, VM* vm){ ((T*)p)->_gc_mark(vm); }; + } + return vt; + } + }; + PyVar obj; // never be garbage collected Type base; PyVar mod; // never be garbage collected StrName name; bool subclass_enabled; + Vt vt; + PyTypeInfo(PyVar obj, Type base, PyVar mod, StrName name, bool subclass_enabled, Vt vt={}): + obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {} + std::vector annotated_fields = {}; // unary operators @@ -386,7 +410,12 @@ public: #if PK_REGION("User Type Registration") PyVar new_module(Str name, Str package=""); - PyVar new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled=true); + PyVar new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt={}); + + template + PyVar new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled){ + return new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get()); + } template Type _tp_user(){ return _find_type_in_cxx_typeid_map(); } @@ -455,6 +484,7 @@ public: PyVar __pack_next_retval(unsigned); PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key); bool __py_bool_non_trivial(PyVar); + void __obj_gc_mark(PyVar); }; @@ -595,7 +625,7 @@ __T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj) template PyVar VM::register_user_class(PyVar mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){ - PyVar type = new_type_object(mod, name, base, subclass_enabled); + PyVar type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get()); mod->attr().set(name, type); _cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type); _register(this, mod, type); diff --git a/src/array2d.cpp b/src/array2d.cpp index 2334b6dd..cf8a4f18 100644 --- a/src/array2d.cpp +++ b/src/array2d.cpp @@ -332,7 +332,7 @@ struct Array2d{ }); } - void _gc_mark() const{ + void _gc_mark(VM* vm) const{ for(int i = 0; i < numel; i++) PK_OBJ_MARK(data[i]); } @@ -349,7 +349,7 @@ struct Array2dIter{ int i; Array2dIter(PyVar ref) : ref(ref), i(0) {} - void _gc_mark() const{ PK_OBJ_MARK(ref); } + void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } static void _register(VM* vm, PyVar mod, PyVar type){ vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) { return _0; }); diff --git a/src/ceval.cpp b/src/ceval.cpp index fb711af9..b5fa3e2c 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -924,7 +924,7 @@ __NEXT_STEP: PyVar _0 = POPX(); // super if(_0 == None) _0 = _t(tp_object); check_type(_0, tp_type); - __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0)); + __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true); } DISPATCH() case OP_END_CLASS: { PK_ASSERT(__curr_class != nullptr); diff --git a/src/cffi.cpp b/src/cffi.cpp index e9218fbf..cf6ac12b 100644 --- a/src/cffi.cpp +++ b/src/cffi.cpp @@ -193,48 +193,48 @@ void add_module_c(VM* vm){ #define BIND_PRIMITIVE(T, CNAME) \ vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args){ \ T val = CAST(T, args[0]); \ - return vm->new_user_object(&val, sizeof(T)); \ - }); \ - type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user()); \ + return vm->new_user_object(&val, sizeof(T)); \ + }); \ + type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user(), true); \ mod->attr().set(CNAME "_p", type); \ type_t = PK_OBJ_GET(Type, type); \ - vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \ - obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); \ + vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \ + obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); \ T* target = (T*)voidp.ptr; \ return VAR(*target); \ }); \ - vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ \ - obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); \ + vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ \ + obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); \ T val = CAST(T, args[1]); \ T* target = (T*)voidp.ptr; \ *target = val; \ return vm->None; \ }); \ - vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index){ \ - obj_get_t voidp = PK_OBJ_GET(VoidP, obj); \ + vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index){ \ + obj_get_t voidp = PK_OBJ_GET(VoidP, obj); \ i64 offset = CAST(i64, index); \ T* target = (T*)voidp.ptr; \ return VAR(target[offset]); \ }); \ - vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value){ \ - obj_get_t voidp = PK_OBJ_GET(VoidP, obj); \ + vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value){ \ + obj_get_t voidp = PK_OBJ_GET(VoidP, obj); \ i64 offset = CAST(i64, index); \ T* target = (T*)voidp.ptr; \ target[offset] = CAST(T, value); \ }); \ - vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ - obj_get_t voidp = PK_OBJ_GET(VoidP, lhs); \ + vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ + obj_get_t voidp = PK_OBJ_GET(VoidP, lhs); \ i64 offset = CAST(i64, rhs); \ T* target = (T*)voidp.ptr; \ return vm->new_object(lhs.type, target + offset); \ }); \ - vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ - obj_get_t voidp = PK_OBJ_GET(VoidP, lhs); \ + vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ + obj_get_t voidp = PK_OBJ_GET(VoidP, lhs); \ i64 offset = CAST(i64, rhs); \ T* target = (T*)voidp.ptr; \ return vm->new_object(lhs.type, target - offset); \ }); \ - vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str{ \ + vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str{ \ VoidP& self = _CAST(VoidP&, obj); \ return _S("<", CNAME, "* at ", self.hex(), ">"); \ }); \ diff --git a/src/codeobject.cpp b/src/codeobject.cpp index a807ff7f..8b2f277d 100644 --- a/src/codeobject.cpp +++ b/src/codeobject.cpp @@ -7,14 +7,8 @@ namespace pkpy{ blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0, 0)); } - void CodeObject::_gc_mark() const { - for(PyVar v : consts) PK_OBJ_MARK(v); - for(auto& decl: func_decls) decl->_gc_mark(); - } - struct PySignalObject: PyObject { PySignalObject() : PyObject() { gc_enabled = false; } - void _obj_gc_mark() override {} }; PyVar const PY_NULL(Type(), new PySignalObject()); diff --git a/src/collections.cpp b/src/collections.cpp index d861b434..aa93b4f5 100644 --- a/src/collections.cpp +++ b/src/collections.cpp @@ -18,7 +18,7 @@ namespace pkpy { this->is_reversed = true; } - void _gc_mark() const { PK_OBJ_MARK(ref); } + void _gc_mark(VM* vm) const { PK_OBJ_MARK(ref); } static void _register(VM *vm, PyVar mod, PyVar type); }; void PyDequeIter::_register(VM *vm, PyVar mod, PyVar type) @@ -53,7 +53,7 @@ namespace pkpy int findIndex(VM *vm, PyVar obj, int start, int stop); // find the index of the given object in the deque // Special methods static void _register(VM *vm, PyVar mod, PyVar type); // register the type - void _gc_mark() const; // needed for container types, mark all objects in the deque for gc + void _gc_mark(VM*) const; // needed for container types, mark all objects in the deque for gc }; void PyDeque::_register(VM *vm, PyVar mod, PyVar type) { @@ -532,7 +532,7 @@ namespace pkpy } } /// @brief marks the deque items for garbage collection - void PyDeque::_gc_mark() const + void PyDeque::_gc_mark(VM* vm) const { for (PyVar obj : this->dequeItems) PK_OBJ_MARK(obj); diff --git a/src/dict.cpp b/src/dict.cpp index 1e37632e..f83d6bc9 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -169,12 +169,4 @@ namespace pkpy{ pool128_dealloc(_items); pool64_dealloc(_nodes); } - - void Dict::_gc_mark() const{ - apply([](PyVar k, PyVar v){ - PK_OBJ_MARK(k); - PK_OBJ_MARK(v); - }); - } - } // namespace pkpy \ No newline at end of file diff --git a/src/gc.cpp b/src/gc.cpp index f2cb4466..f58d7a0d 100644 --- a/src/gc.cpp +++ b/src/gc.cpp @@ -14,8 +14,7 @@ namespace pkpy{ deleted[obj.type] += 1; #endif if(_gc_on_delete) _gc_on_delete(vm, obj); - obj->~PyObject(); - pool128_dealloc(obj.get()); + _delete(obj); } } @@ -54,16 +53,4 @@ namespace pkpy{ int freed = sweep(); return freed; } - - ManagedHeap::~ManagedHeap(){ - for(PyVar obj: _no_gc) { obj->~PyObject(); pool128_dealloc(obj.get()); } - for(PyVar obj: gen) { obj->~PyObject(); pool128_dealloc(obj.get()); } - } - - -void FuncDecl::_gc_mark() const{ - code->_gc_mark(); - for(int i=0; i~NameDict(); - pool128_dealloc(_attr); - } - } // namespace pkpy \ No newline at end of file diff --git a/src/vm.cpp b/src/vm.cpp index 2ad6034d..68568049 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -205,21 +205,14 @@ namespace pkpy{ return exec(source, "", EVAL_MODE); } - PyVar VM::new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled){ + PyVar VM::new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt){ PyVar obj = heap._new(tp_type, Type(_all_types.size())); const PyTypeInfo& base_info = _all_types[base]; if(!base_info.subclass_enabled){ Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`"); throw std::runtime_error(error.c_str()); } - PyTypeInfo info{ - obj, - base, - mod, - name, - subclass_enabled, - }; - _all_types.push_back(info); + _all_types.emplace_back(obj, base, mod, name, subclass_enabled, vt); return obj; } @@ -404,6 +397,10 @@ namespace pkpy{ } VM::~VM() { + // clear managed heap + for(PyVar obj: heap.gen) heap._delete(obj); + for(PyVar obj: heap._no_gc) heap._delete(obj); + // clear everything callstack.clear(); s_data.clear(); _all_types.clear(); @@ -430,6 +427,17 @@ bool VM::__py_bool_non_trivial(PyVar obj){ return true; } +void VM::__obj_gc_mark(PyVar obj){ + obj->gc_marked = true; + const PyTypeInfo* ti = _tp_info(obj); + if(ti->vt._gc_mark) ti->vt._gc_mark(obj->_value_ptr(), this); + if(obj->is_attr_valid()){ + obj->attr().apply([this](StrName _, PyVar obj){ + PK_OBJ_MARK(obj); + }); + } +} + List VM::py_list(PyVar it){ auto _lock = heap.gc_scope_lock(); it = py_iter(it); @@ -823,49 +831,49 @@ void VM::__log_s_data(const char* title) { #endif void VM::__init_builtin_types(){ - _all_types.push_back({nullptr, Type(), nullptr, "", false}); // 0 is not used - _all_types.push_back({heap._new(tp_type, tp_object), Type(), nullptr, "object", true}); - _all_types.push_back({heap._new(tp_type, tp_type), tp_object, nullptr, "type", false}); + _all_types.emplace_back(nullptr, Type(), nullptr, "", false); // 0 is not used + _all_types.emplace_back(heap._new(tp_type, tp_object), Type(), nullptr, "object", true); + _all_types.emplace_back(heap._new(tp_type, tp_type), tp_object, nullptr, "type", false); - auto _new_type = [this](const char* name, Type base=tp_object, bool subclass_enabled=false){ - PyVar obj = new_type_object(nullptr, name, base, subclass_enabled); - return PK_OBJ_GET(Type, obj); + auto validate = [](Type type, PyVar ret){ + Type ret_t = PK_OBJ_GET(Type, ret); + if(ret_t != type) exit(-3); }; - if(tp_int != _new_type("int")) exit(-3); - if((tp_float != _new_type("float"))) exit(-3); + validate(tp_int, new_type_object(nullptr, "int", tp_object, false)); + validate(tp_float, new_type_object(nullptr, "float", tp_object, false)); + validate(tp_bool, new_type_object(nullptr, "bool", tp_object, false)); - if(tp_bool != _new_type("bool")) exit(-3); - if(tp_str != _new_type("str")) exit(-3); - if(tp_list != _new_type("list")) exit(-3); - if(tp_tuple != _new_type("tuple")) exit(-3); + validate(tp_str, new_type_object(nullptr, "str", tp_object, false)); + validate(tp_list, new_type_object(nullptr, "list", tp_object, false)); + validate(tp_tuple, new_type_object(nullptr, "tuple", tp_object, false)); - if(tp_slice != _new_type("slice")) exit(-3); - if(tp_range != _new_type("range")) exit(-3); - if(tp_module != _new_type("module")) exit(-3); - if(tp_function != _new_type("function")) exit(-3); - if(tp_native_func != _new_type("native_func")) exit(-3); - if(tp_bound_method != _new_type("bound_method")) exit(-3); + validate(tp_slice, new_type_object(nullptr, "slice", tp_object, false)); + validate(tp_range, new_type_object(nullptr, "range", tp_object, false)); + validate(tp_module, new_type_object(nullptr, "module", tp_object, false)); + validate(tp_function, new_type_object(nullptr, "function", tp_object, false)); + validate(tp_native_func, new_type_object(nullptr, "native_func", tp_object, false)); + validate(tp_bound_method, new_type_object(nullptr, "bound_method", tp_object, false)); - if(tp_super != _new_type("super")) exit(-3); - if(tp_exception != _new_type("Exception", tp_object, true)) exit(-3); - if(tp_bytes != _new_type("bytes")) exit(-3); - if(tp_mappingproxy != _new_type("mappingproxy")) exit(-3); - if(tp_dict != _new_type("dict", tp_object, true)) exit(-3); // dict can be subclassed - if(tp_property != _new_type("property")) exit(-3); - if(tp_star_wrapper != _new_type("_star_wrapper")) exit(-3); + validate(tp_super, new_type_object(nullptr, "super", tp_object, false)); + validate(tp_exception, new_type_object(nullptr, "Exception", tp_object, true)); + validate(tp_bytes, new_type_object(nullptr, "bytes", tp_object, false)); + validate(tp_mappingproxy, new_type_object(nullptr, "mappingproxy", tp_object, false)); + validate(tp_dict, new_type_object(nullptr, "dict", tp_object, true)); + validate(tp_property, new_type_object(nullptr, "property", tp_object, false)); + validate(tp_star_wrapper, new_type_object(nullptr, "_star_wrapper", tp_object, false)); - if(tp_staticmethod != _new_type("staticmethod")) exit(-3); - if(tp_classmethod != _new_type("classmethod")) exit(-3); + validate(tp_staticmethod, new_type_object(nullptr, "staticmethod", tp_object, false)); + validate(tp_classmethod, new_type_object(nullptr, "classmethod", tp_object, false)); - if(tp_none != _new_type("NoneType")) exit(-3); - if(tp_not_implemented != _new_type("NotImplementedType")) exit(-3); - if(tp_ellipsis != _new_type("ellipsis")) exit(-3); + validate(tp_none, new_type_object(nullptr, "NoneType", tp_object, false)); + validate(tp_not_implemented, new_type_object(nullptr, "NotImplementedType", tp_object, false)); + validate(tp_ellipsis, new_type_object(nullptr, "ellipsis", tp_object, false)); // SyntaxError and IndentationError must be created here - Type tp_syntax_error = _new_type("SyntaxError", tp_exception, true); - Type tp_indentation_error = _new_type("IndentationError", tp_syntax_error, true); - this->StopIteration = _all_types[_new_type("StopIteration", tp_exception)].obj; + PyVar SyntaxError = new_type_object(nullptr, "SyntaxError", tp_exception, true); + PyVar IndentationError = new_type_object(nullptr, "IndentationError", PK_OBJ_GET(Type, SyntaxError), true); + this->StopIteration = new_type_object(nullptr, "StopIteration", tp_exception, true); this->builtins = new_module("builtins"); @@ -886,8 +894,8 @@ void VM::__init_builtin_types(){ builtins->attr().set("NotImplemented", NotImplemented); builtins->attr().set("slice", _t(tp_slice)); builtins->attr().set("Exception", _t(tp_exception)); - builtins->attr().set("SyntaxError", _t(tp_syntax_error)); - builtins->attr().set("IndentationError", _t(tp_indentation_error)); + builtins->attr().set("SyntaxError", SyntaxError); + builtins->attr().set("IndentationError", IndentationError); __post_init_builtin_types(); this->_main = new_module("__main__"); @@ -1414,26 +1422,11 @@ void VM::__raise_exc(bool re_raise){ } } -void ManagedHeap::mark() { - for(PyVar obj: _no_gc) PK_OBJ_MARK(obj); - vm->callstack.apply([](Frame& frame){ frame._gc_mark(); }); - for(PyVar obj: vm->s_data) PK_OBJ_MARK(obj); - for(auto [_, co]: vm->__cached_codes) co->_gc_mark(); - if(vm->__last_exception) PK_OBJ_MARK(vm->__last_exception); - if(vm->__curr_class) PK_OBJ_MARK(vm->__curr_class); - if(vm->__c.error != nullptr) PK_OBJ_MARK(vm->__c.error); - if(_gc_marker_ex) _gc_marker_ex(vm); -} StrName _type_name(VM *vm, Type type){ return vm->_all_types[type].name; } -void _gc_mark_namedict(NameDict* t){ - t->apply([](StrName name, PyVar obj){ - PK_OBJ_MARK(obj); - }); -} void VM::bind__getitem__(Type type, PyVar (*f)(VM*, PyVar, PyVar)){ _all_types[type].m__getitem__ = f; @@ -1757,4 +1750,108 @@ void VM::__breakpoint(){ #endif } +/**************************************************************************/ +void Function::_gc_mark(VM* vm) const{ + decl->_gc_mark(vm); + if(_closure){ + _closure->apply([=](StrName _, PyVar obj){ + PK_OBJ_MARK(obj); + }); + } +} + +void NativeFunc::_gc_mark(VM* vm) const{ + if(decl) decl->_gc_mark(vm); +} + +void FuncDecl::_gc_mark(VM* vm) const{ + code->_gc_mark(vm); + for(int i=0; i_gc_mark(vm); + // Frame could be stored in a generator, so mark _callable for safety + if(_callable != nullptr) PK_OBJ_MARK(_callable); +} + +void ManagedHeap::mark() { + for(PyVar obj: _no_gc) PK_OBJ_MARK(obj); + vm->callstack.apply([this](Frame& frame){ frame._gc_mark(vm); }); + for(PyVar obj: vm->s_data) PK_OBJ_MARK(obj); + for(auto [_, co]: vm->__cached_codes) co->_gc_mark(vm); + if(vm->__last_exception) PK_OBJ_MARK(vm->__last_exception); + if(vm->__curr_class) PK_OBJ_MARK(vm->__curr_class); + if(vm->__c.error != nullptr) PK_OBJ_MARK(vm->__c.error); + if(_gc_marker_ex) _gc_marker_ex(vm); +} + +void ManagedHeap::_delete(PyVar obj){ + PK_DEBUG_ASSERT(!obj.is_sso) + const PyTypeInfo* ti = vm->_tp_info(obj); + if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr()); + if(obj->_attr){ + obj->_attr->~NameDict(); + pool128_dealloc(obj->_attr); + } + pool128_dealloc(obj.get()); +} + +void Dict::_gc_mark(VM* vm) const{ + apply([vm](PyVar k, PyVar v){ + PK_OBJ_MARK(k); + PK_OBJ_MARK(v); + }); +} + +void CodeObject::_gc_mark(VM* vm) const { + for(PyVar v : consts) PK_OBJ_MARK(v); + for(auto& decl: func_decls) decl->_gc_mark(vm); +} + } // namespace pkpy \ No newline at end of file