diff --git a/docs/quick-start/misc.md b/docs/quick-start/misc.md index 7ef512d0..e5925e8a 100644 --- a/docs/quick-start/misc.md +++ b/docs/quick-start/misc.md @@ -9,7 +9,7 @@ order: 0 Sometimes you need to use the following code to prevent the gc from collecting objects. ```cpp -auto _lock = vm->heap.gc_scope_lock(); +auto _lock = vm->gc_scope_lock(); ``` The scope lock is required if you create a PyVar and then try to run python-level bytecodes. @@ -34,7 +34,7 @@ The scope lock prevents this from happening. void some_func(VM* vm){ PyVar obj = VAR(List(5)); // safe - auto _lock = vm->heap.gc_scope_lock(); + auto _lock = vm->gc_scope_lock(); PyVar iter = vm->py_iter(obj); PyVar next = vm->py_next(iter); } diff --git a/include/pocketpy/interpreter/bindings.hpp b/include/pocketpy/interpreter/bindings.hpp index 776d200c..b5bf1ea5 100644 --- a/include/pocketpy/interpreter/bindings.hpp +++ b/include/pocketpy/interpreter/bindings.hpp @@ -111,7 +111,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) { }; _1 = new_object(tp_native_func, fset, 2, field); } - PyObject* prop = heap.gcnew(tp_property, _0, _1); + PyObject* prop = new_object(tp_property, _0, _1).get(); obj->attr().set(StrName(name_sv), prop); return prop; } diff --git a/include/pocketpy/interpreter/gc.h b/include/pocketpy/interpreter/gc.h new file mode 100644 index 00000000..229121de --- /dev/null +++ b/include/pocketpy/interpreter/gc.h @@ -0,0 +1,40 @@ +#include "pocketpy/objects/object.h" +#include "pocketpy/objects/public.h" +#include "pocketpy/common/config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pk_ManagedHeap{ + c11_vector no_gc; + c11_vector gen; + + int gc_threshold; + int gc_counter; + int gc_lock_counter; + pkpy_VM* vm; + + void (*_gc_on_delete)(pkpy_VM*, PyObject*); + void (*_gc_marker_ex)(pkpy_VM*); +} pk_ManagedHeap; + +void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pkpy_VM* vm); +void pk_ManagedHeap__dtor(pk_ManagedHeap* self); + +void pk_ManagedHeap__push_lock(pk_ManagedHeap* self); +void pk_ManagedHeap__pop_lock(pk_ManagedHeap* self); + +void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap* self); +int pk_ManagedHeap__collect(pk_ManagedHeap* self); +int pk_ManagedHeap__sweep(pk_ManagedHeap* self); + +PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, pkpy_Type type, int size, bool gc); + +// external implementation +void pk_ManagedHeap__mark(pk_ManagedHeap* self); +void pk_ManagedHeap__delete_obj(pk_ManagedHeap* self, PyObject* obj); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/pocketpy/interpreter/gc.hpp b/include/pocketpy/interpreter/gc.hpp deleted file mode 100644 index bfe640b4..00000000 --- a/include/pocketpy/interpreter/gc.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include "pocketpy/common/config.h" -#include "pocketpy/common/vector.hpp" -#include "pocketpy/common/utils.h" -#include "pocketpy/objects/object.hpp" -#include "pocketpy/objects/namedict.hpp" - -namespace pkpy { -struct ManagedHeap { - vector _no_gc; - vector gen; - VM* vm; - void (*_gc_on_delete)(VM*, PyObject*) = nullptr; - void (*_gc_marker_ex)(VM*) = nullptr; - - ManagedHeap(VM* vm) : vm(vm) {} - - int gc_threshold = PK_GC_MIN_THRESHOLD; - int gc_counter = 0; - - /********************/ - int _gc_lock_counter = 0; - - struct ScopeLock { - PK_ALWAYS_PASS_BY_POINTER(ScopeLock) - - ManagedHeap* heap; - - ScopeLock(ManagedHeap* heap) : heap(heap) { heap->_gc_lock_counter++; } - - ~ScopeLock() { heap->_gc_lock_counter--; } - }; - - ScopeLock gc_scope_lock() { return ScopeLock(this); } - - /********************/ - template - PyObject* _basic_new(Type type, Args&&... args) { - using __T = std::decay_t; - static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types"); - // https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476 - PyObject* p; - if constexpr(py_sizeof<__T> <= kPoolObjectBlockSize){ - p = new (PoolObject_alloc()) PyObject(type, false); - }else{ - p = new (std::malloc(py_sizeof<__T>)) PyObject(type, true); - } - new (p->_value_ptr()) T(std::forward(args)...); - - // backdoor for important builtin types - if constexpr(std::is_same_v<__T, DummyInstance>) { - p->_attr = new NameDict(); - } else if constexpr(std::is_same_v<__T, Type>) { - p->_attr = new NameDict(); - } else if constexpr(std::is_same_v<__T, DummyModule>) { - p->_attr = new NameDict(); - } - return p; - } - - template - PyObject* gcnew(Type type, Args&&... args) { - PyObject* p = _basic_new(type, std::forward(args)...); - gen.push_back(p); - gc_counter++; - return p; - } - - template - PyObject* _new(Type type, Args&&... args) { - PyObject* p = _basic_new(type, std::forward(args)...); - _no_gc.push_back(p); - return p; - } - - void _delete(PyObject*); - -#if PK_DEBUG_GC_STATS - inline static std::map deleted; -#endif - - int sweep(); - void _auto_collect(); - - bool _should_auto_collect() const { return gc_counter >= gc_threshold; } - - int collect(); - void mark(); -}; - -} // namespace pkpy diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h new file mode 100644 index 00000000..c8928b9e --- /dev/null +++ b/include/pocketpy/interpreter/vm.h @@ -0,0 +1,14 @@ +#include "pocketpy/objects/object.h" + +typedef struct pkpy_VM{ + PyVar True; + PyVar False; + PyVar None; + PyVar NotImplemented; + PyVar Ellipsis; +} pkpy_VM; + +void pkpy_VM__ctor(pkpy_VM* self); +void pkpy_VM__dtor(pkpy_VM* self); + +PyObject* pkpy_VM__gcnew(pkpy_VM* self, pkpy_Type type); diff --git a/include/pocketpy/interpreter/vm.hpp b/include/pocketpy/interpreter/vm.hpp index 5ad9387a..43f7e3bf 100644 --- a/include/pocketpy/interpreter/vm.hpp +++ b/include/pocketpy/interpreter/vm.hpp @@ -4,7 +4,7 @@ #include "pocketpy/objects/dict.hpp" #include "pocketpy/objects/error.hpp" #include "pocketpy/objects/builtins.hpp" -#include "pocketpy/interpreter/gc.hpp" +#include "pocketpy/interpreter/gc.h" #include "pocketpy/interpreter/frame.hpp" #include "pocketpy/interpreter/profiler.hpp" @@ -162,7 +162,7 @@ class VM { VM* vm; // self reference to simplify code public: - ManagedHeap heap; + pk_ManagedHeap heap; ValueStack s_data; CallStack callstack; vector _all_types; @@ -446,7 +446,31 @@ public: template PyVar new_object(Type type, Args&&... args){ static_assert(!is_sso_v); - return heap.gcnew(type, std::forward(args)...); + static_assert(std::is_same_v>); + PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof, true); + new (p->_value_ptr()) T(std::forward(args)...); + // backdoor for important builtin types + if constexpr(std::is_same_v + || std::is_same_v + || std::is_same_v) { + p->_attr = new NameDict(); + } + return p; + } + + template + PyVar new_object_no_gc(Type type, Args&&... args){ + static_assert(!is_sso_v); + static_assert(std::is_same_v>); + PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof, false); + new (p->_value_ptr()) T(std::forward(args)...); + // backdoor for important builtin types + if constexpr(std::is_same_v + || std::is_same_v + || std::is_same_v) { + p->_attr = new NameDict(); + } + return p; } #endif @@ -456,7 +480,14 @@ public: if(it == nullptr) PK_FATAL_ERROR("T not found in cxx_typeid_map\n") return *it; } - + /********** old heap op **********/ + struct HeapScopeLock { + PK_ALWAYS_PASS_BY_POINTER(HeapScopeLock) + pk_ManagedHeap* heap; + HeapScopeLock(pk_ManagedHeap* heap) : heap(heap) { pk_ManagedHeap__push_lock(heap);} + ~HeapScopeLock() { pk_ManagedHeap__pop_lock(heap); } + }; + HeapScopeLock gc_scope_lock(){ return {&heap}; } /********** private **********/ virtual ~VM(); @@ -569,13 +600,13 @@ PyVar py_var(VM* vm, __T&& value) { if constexpr(is_sso_v) return PyVar(const_type, value); else - return vm->heap.gcnew(const_type, std::forward<__T>(value)); + return vm->new_object(const_type, std::forward<__T>(value)); } else { Type type = vm->_find_type_in_cxx_typeid_map(); if constexpr(is_sso_v) return PyVar(type, value); else - return vm->heap.gcnew(type, std::forward<__T>(value)); + return vm->new_object(type, std::forward<__T>(value)); } } } diff --git a/include/pocketpy/objects/public.h b/include/pocketpy/objects/public.h index 97a67410..9aa01488 100644 --- a/include/pocketpy/objects/public.h +++ b/include/pocketpy/objects/public.h @@ -1,6 +1,7 @@ #pragma once #include "stdint.h" +#include "stdbool.h" #ifdef __cplusplus extern "C" { @@ -15,10 +16,24 @@ struct pkpy_G { pkpy_VM* vm; } extern pkpy_g; +void py_initialize(); +void py_switch_vm(const char* name); +void py_finalize(); + bool py_eq(const PyVar*, const PyVar*); bool py_le(const PyVar*, const PyVar*); int64_t py_hash(const PyVar*); + +/* py_var */ +void py_newint(PyVar*, int64_t); +void py_newfloat(PyVar*, double); +void py_newbool(PyVar*, bool); +void py_newstr(PyVar*, const char*); +void py_newstr2(PyVar*, const char*, int); +void py_newbytes(PyVar*, const uint8_t*, int); +void py_newnone(PyVar*); + #ifdef __cplusplus } #endif diff --git a/src/interpreter/ceval.cpp b/src/interpreter/ceval.cpp index 2947278f..918005cb 100644 --- a/src/interpreter/ceval.cpp +++ b/src/interpreter/ceval.cpp @@ -52,7 +52,7 @@ void VM::__op_unpack_sequence(uint16_t arg) { ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size())); } } else { - auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! + auto _lock = gc_scope_lock(); // lock the gc via RAII!! _0 = py_iter(_0); const PyTypeInfo* ti = _tp_info(_0); for(int i = 0; i < arg; i++) { @@ -802,7 +802,7 @@ PyVar VM::__run_top_frame() { DISPATCH() case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH() case OP_CALL: { - if(heap._should_auto_collect()) heap._auto_collect(); + pk_ManagedHeap__collect_if_needed(&heap); PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC (byte.arg >> 8) & 0xFF, // KWARGC true); @@ -814,7 +814,7 @@ PyVar VM::__run_top_frame() { } DISPATCH() case OP_CALL_TP: { - if(heap._should_auto_collect()) heap._auto_collect(); + pk_ManagedHeap__collect_if_needed(&heap); PyVar _0; PyVar _1; PyVar _2; @@ -1000,7 +1000,7 @@ PyVar VM::__run_top_frame() { } DISPATCH() case OP_UNPACK_EX: { - auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! + auto _lock = gc_scope_lock(); // lock the gc via RAII!! PyVar _0 = py_iter(POPX()); const PyTypeInfo* _ti = _tp_info(_0); PyVar _1; diff --git a/src/interpreter/gc.c b/src/interpreter/gc.c new file mode 100644 index 00000000..e373adb1 --- /dev/null +++ b/src/interpreter/gc.c @@ -0,0 +1,109 @@ +#include "pocketpy/interpreter/gc.h" +#include "pocketpy/common/memorypool.h" + +void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pkpy_VM *vm){ + c11_vector__ctor(&self->no_gc, sizeof(PyObject*)); + c11_vector__ctor(&self->gen, sizeof(PyObject*)); + + self->gc_threshold = PK_GC_MIN_THRESHOLD; + self->gc_counter = 0; + self->gc_lock_counter = 0; + self->vm = vm; + + self->_gc_on_delete = NULL; + self->_gc_marker_ex = NULL; +} + +void pk_ManagedHeap__dtor(pk_ManagedHeap *self){ + for(int i = 0; i < self->gen.count; i++){ + PyObject* obj = c11__getitem(PyObject*, &self->gen, i); + pk_ManagedHeap__delete_obj(self, obj); + } + for(int i = 0; i < self->no_gc.count; i++){ + PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i); + pk_ManagedHeap__delete_obj(self, obj); + } + c11_vector__dtor(&self->no_gc); + c11_vector__dtor(&self->gen); +} + +void pk_ManagedHeap__push_lock(pk_ManagedHeap *self){ + self->gc_lock_counter++; +} + +void pk_ManagedHeap__pop_lock(pk_ManagedHeap *self){ + self->gc_lock_counter--; +} + +void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap *self){ + if(self->gc_counter < self->gc_threshold) return; + if(self->gc_lock_counter > 0) return; + self->gc_counter = 0; + pk_ManagedHeap__collect(self); + self->gc_threshold = self->gen.count * 2; + if(self->gc_threshold < PK_GC_MIN_THRESHOLD){ + self->gc_threshold = PK_GC_MIN_THRESHOLD; + } +} + +int pk_ManagedHeap__collect(pk_ManagedHeap *self){ + assert(self->gc_lock_counter == 0); + pk_ManagedHeap__mark(self); + int freed = pk_ManagedHeap__sweep(self); + return freed; +} + +int pk_ManagedHeap__sweep(pk_ManagedHeap *self){ + c11_vector alive; + c11_vector__ctor(&alive, sizeof(PyObject*)); + c11_vector__reserve(&alive, self->gen.count / 2); + + for(int i = 0; i < self->gen.count; i++){ + PyObject* obj = c11__getitem(PyObject*, &self->gen, i); + if(obj->gc_marked) { + obj->gc_marked = false; + c11_vector__push(PyObject*, &alive, obj); + } else { + if(self->_gc_on_delete){ + self->_gc_on_delete(self->vm, obj); + } + pk_ManagedHeap__delete_obj(self, obj); + } + } + + // clear _no_gc marked flag + for(int i=0; ino_gc.count; i++){ + PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i); + obj->gc_marked = false; + } + + int freed = self->gen.count - alive.count; + + // destroy old gen + c11_vector__dtor(&self->gen); + // move alive to gen + self->gen = alive; + + PoolObject_shrink_to_fit(); + return freed; +} + +PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, pkpy_Type type, int size, bool gc){ + PyObject* obj; + // TODO: can we use compile time check? + if(size <= kPoolObjectBlockSize){ + obj = PoolObject_alloc(); + PyObject__ctor(obj, type, false); + }else{ + obj = malloc(size); + PyObject__ctor(obj, type, true); + } + // TODO: can we use compile time check? + if(gc){ + c11_vector__push(PyObject*, &self->gen, obj); + self->gc_counter++; + }else{ + c11_vector__push(PyObject*, &self->no_gc, obj); + } + return obj; +} diff --git a/src/interpreter/gc.cpp b/src/interpreter/gc.cpp deleted file mode 100644 index 8ed0085d..00000000 --- a/src/interpreter/gc.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "pocketpy/interpreter/gc.hpp" - -namespace pkpy { - -int ManagedHeap::sweep() { - vector alive; - alive.reserve(gen.size() / 2); - for(PyObject* obj: gen) { - if(obj->gc_marked) { - obj->gc_marked = false; - alive.push_back(obj); - } else { -#if PK_DEBUG_GC_STATS - deleted[obj->type] += 1; -#endif - if(_gc_on_delete) _gc_on_delete(vm, obj); - _delete(obj); - } - } - - // clear _no_gc marked flag - for(PyObject* obj: _no_gc) - obj->gc_marked = false; - - int freed = gen.size() - alive.size(); - -#if PK_DEBUG_GC_STATS - for(auto& [type, count]: deleted) { - std::cout << "GC: " << _type_name(vm, type).sv() << "=" << count << std::endl; - } - std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl; - deleted.clear(); -#endif - gen.clear(); - gen.swap(alive); - PoolObject_shrink_to_fit(); - return freed; -} - -void ManagedHeap::_auto_collect() { -#if !PK_DEBUG_NO_AUTO_GC - if(_gc_lock_counter > 0) return; - gc_counter = 0; - collect(); - gc_threshold = gen.size() * 2; - if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD; -#endif -} - -int ManagedHeap::collect() { - assert(_gc_lock_counter == 0); - mark(); - int freed = sweep(); - return freed; -} -} // namespace pkpy diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c new file mode 100644 index 00000000..3ac22431 --- /dev/null +++ b/src/interpreter/vm.c @@ -0,0 +1,40 @@ +#include "pocketpy/interpreter/vm.h" +#include "pocketpy/objects/base.h" + +void pkpy_VM__ctor(pkpy_VM* self){ + self->True = (PyVar){ + .type=tp_bool, + .is_ptr=true, + .extra=1, + ._obj=pkpy_VM__gcnew(self, tp_bool) + }; + + self->False = (PyVar){ + .type=tp_bool, + .is_ptr=true, + .extra=0, + ._obj=pkpy_VM__gcnew(self, tp_bool) + }; + + self->None = (PyVar){ + .type=tp_none_type, + .is_ptr=true, + ._obj=pkpy_VM__gcnew(self, tp_none_type) + }; + + self->NotImplemented = (PyVar){ + .type=tp_not_implemented_type, + .is_ptr=true, + ._obj=pkpy_VM__gcnew(self, tp_not_implemented_type) + }; + + self->Ellipsis = (PyVar){ + .type=tp_ellipsis, + .is_ptr=true, + ._obj=pkpy_VM__gcnew(self, tp_ellipsis) + }; +} + +void pkpy_VM__dtor(pkpy_VM* self){ + +} \ No newline at end of file diff --git a/src/interpreter/vm.cpp b/src/interpreter/vm.cpp index 64f32eed..0bc5add3 100644 --- a/src/interpreter/vm.cpp +++ b/src/interpreter/vm.cpp @@ -1,6 +1,7 @@ #include "pocketpy/interpreter/vm.hpp" #include "pocketpy/common/memorypool.h" #include "pocketpy/objects/base.h" +#include "pocketpy/objects/public.h" #include #include @@ -77,16 +78,17 @@ struct JsonSerializer { } Str serialize() { - auto _lock = vm->heap.gc_scope_lock(); + auto _lock = vm->gc_scope_lock(); write_object(root); return ss.str(); } }; -VM::VM(bool enable_os) : heap(this), enable_os(enable_os) { +VM::VM(bool enable_os) : enable_os(enable_os) { + pkpy_g.vm = (pkpy_VM*)this; // setup the current VM Pools_initialize(); pkpy_StrName__initialize(); - pkpy_g.vm = (pkpy_VM*)this; // setup the current VM + pk_ManagedHeap__ctor(&heap, (pkpy_VM*)this); static ::PyObject __true_obj = {tp_bool, false, false, NULL}; static ::PyObject __false_obj = {tp_bool, false, false, NULL}; @@ -226,7 +228,7 @@ PyVar VM::exec(std::string_view source) { return exec(source, "main.py", EXEC_MO PyVar VM::eval(std::string_view source) { return exec(source, "", EVAL_MODE); } PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt) { - PyObject* obj = heap._new(tp_type, Type(_all_types.size())); + PyObject* obj = new_object_no_gc(tp_type, Type(_all_types.size())).get(); const PyTypeInfo& base_info = _all_types[base]; if(!base_info.subclass_enabled) { Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`"); @@ -302,7 +304,7 @@ bool VM::py_callable(PyVar obj) { } PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) { - auto _lock = heap.gc_scope_lock(); + auto _lock = gc_scope_lock(); const Tuple& args_tuple = PK_OBJ_GET(Tuple, args); // from *args, it must be a tuple if(is_none(key) && args_tuple.size() == 2) { // fast path @@ -328,7 +330,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) { if((this->*op)(view[i], res)) res = view[i]; } } else { - auto _lock = heap.gc_scope_lock(); + auto _lock = gc_scope_lock(); for(int i = 1; i < view.size(); i++) { PyVar a = call(key, view[i]); PyVar b = call(key, res); @@ -418,11 +420,8 @@ PyObject* VM::py_import(Str path, bool throw_err) { } VM::~VM() { - // clear managed heap - for(PyObject* obj: heap.gen) - heap._delete(obj); - for(PyObject* obj: heap._no_gc) - heap._delete(obj); + // destroy all objects + pk_ManagedHeap__dtor(&heap); // clear everything callstack.clear(); s_data.clear(); @@ -472,7 +471,7 @@ void VM::__stack_gc_mark(PyVar* begin, PyVar* end) { } List VM::py_list(PyVar it) { - auto _lock = heap.gc_scope_lock(); + auto _lock = gc_scope_lock(); it = py_iter(it); List list; const PyTypeInfo* info = _tp_info(it); @@ -566,7 +565,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals); } - auto _lock = heap.gc_scope_lock(); // for safety + auto _lock = gc_scope_lock(); // for safety PyObject* globals_obj = nullptr; Dict* globals_dict = nullptr; @@ -602,7 +601,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local locals_closure->set(CAST(Str&, k), v); }); PyObject* _callable = - heap.gcnew(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure); + new_object(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get(); retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp); } @@ -722,7 +721,7 @@ PyVar VM::__format_object(PyVar obj, Str spec) { } PyObject* VM::new_module(Str name, Str package) { - PyObject* obj = heap._new(tp_module); + PyObject* obj = new_object_no_gc(tp_module).get(); obj->attr().set(__name__, VAR(name)); obj->attr().set(__package__, VAR(package)); // convert to fullname @@ -872,8 +871,8 @@ void VM::__log_s_data(const char* title) { void VM::__init_builtin_types() { _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); + _all_types.emplace_back(new_object_no_gc(tp_type, tp_object).get(), Type(), nullptr, "object", true); + _all_types.emplace_back(new_object_no_gc(tp_type, tp_type).get(), tp_object, nullptr, "type", false); auto validate = [](Type type, PyObject* ret) { Type ret_t = ret->as(); @@ -945,7 +944,7 @@ void VM::__init_builtin_types() { } void VM::__unpack_as_list(ArgsView args, List& list) { - auto _lock = heap.gc_scope_lock(); + auto _lock = gc_scope_lock(); for(PyVar obj: args) { if(is_type(obj, tp_star_wrapper)) { const StarWrapper& w = _CAST(StarWrapper&, obj); @@ -965,7 +964,7 @@ void VM::__unpack_as_list(ArgsView args, List& list) { } void VM::__unpack_as_dict(ArgsView args, Dict& dict) { - auto _lock = heap.gc_scope_lock(); + auto _lock = gc_scope_lock(); for(PyVar obj: args) { if(is_type(obj, tp_star_wrapper)) { const StarWrapper& w = _CAST(StarWrapper&, obj); @@ -1359,11 +1358,11 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) { } PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) { - PyObject* nf = heap.gcnew(tp_native_func, fn, argc, std::move(userdata)); + PyObject* nf = new_object(tp_native_func, fn, argc, std::move(userdata)).get(); switch(bt) { case BindType::DEFAULT: break; - case BindType::STATICMETHOD: nf = heap.gcnew(tp_staticmethod, nf); break; - case BindType::CLASSMETHOD: nf = heap.gcnew(tp_classmethod, nf); break; + case BindType::STATICMETHOD: nf = new_object(tp_staticmethod, nf).get(); break; + case BindType::CLASSMETHOD: nf = new_object(tp_classmethod, nf).get(); break; } if(obj != nullptr) obj->attr().set(name, nf); return nf; @@ -1383,11 +1382,11 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native FuncDecl_ decl = co->func_decls[0]; decl->docstring = docstring; - PyObject* f_obj = heap.gcnew(tp_native_func, fn, decl, std::move(userdata)); + PyObject* f_obj = new_object(tp_native_func, fn, decl, std::move(userdata)).get(); switch(bt) { - case BindType::STATICMETHOD: f_obj = heap.gcnew(tp_staticmethod, f_obj); break; - case BindType::CLASSMETHOD: f_obj = heap.gcnew(tp_classmethod, f_obj); break; + case BindType::STATICMETHOD: f_obj = new_object(tp_staticmethod, f_obj).get(); break; + case BindType::CLASSMETHOD: f_obj = new_object(tp_classmethod, f_obj).get(); break; case BindType::DEFAULT: break; } if(obj != nullptr) obj->attr().set(decl->code->name, f_obj); @@ -1402,7 +1401,7 @@ PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, N PyVar _0 = new_object(tp_native_func, fget, 1); PyVar _1 = vm->None; if(fset != nullptr) _1 = new_object(tp_native_func, fset, 2); - PyObject* prop = heap.gcnew(tp_property, _0, _1); + PyObject* prop = new_object(tp_property, _0, _1).get(); obj->attr().set(StrName(name_sv), prop); return prop; } @@ -1876,29 +1875,35 @@ void Frame::_gc_mark(VM* vm) const { vm->obj_gc_mark(_callable); } -void ManagedHeap::mark() { - for(PyObject* obj: _no_gc) - vm->__obj_gc_mark(obj); - vm->callstack.apply([this](Frame& frame) { - frame._gc_mark(vm); - }); - vm->obj_gc_mark(vm->__last_exception); - vm->obj_gc_mark(vm->__curr_class); - vm->obj_gc_mark(vm->__c.error); - vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end()); - if(_gc_marker_ex) _gc_marker_ex(vm); -} +extern "C"{ + void pk_ManagedHeap__mark(pk_ManagedHeap* self){ + VM* vm = (VM*)self->vm; + for(int i=0; ino_gc.count; i++){ + PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i); + vm->__obj_gc_mark(obj); + } + vm->callstack.apply([vm](Frame& frame) { + frame._gc_mark(vm); + }); + vm->obj_gc_mark(vm->__last_exception); + vm->obj_gc_mark(vm->__curr_class); + vm->obj_gc_mark(vm->__c.error); + vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end()); + if(self->_gc_marker_ex) self->_gc_marker_ex((pkpy_VM*)vm); + } -void ManagedHeap::_delete(PyObject* obj) { - const PyTypeInfo* ti = vm->_tp_info(obj->type); - if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr()); - if (obj->_attr) - c11_vector__dtor(obj->_attr); - delete obj->_attr; // delete __dict__ if exists - if(obj->gc_is_large){ - std::free(obj); - }else{ - PoolObject_dealloc(obj); + void pk_ManagedHeap__delete_obj(pk_ManagedHeap* self, ::PyObject* __obj){ + PyObject* obj = (PyObject*)__obj; + const PyTypeInfo* ti = ((VM*)(self->vm))->_tp_info(obj->type); + if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr()); + if (obj->_attr) + c11_vector__dtor(obj->_attr); + delete obj->_attr; // delete __dict__ if exists + if(obj->gc_is_large){ + std::free(obj); + }else{ + PoolObject_dealloc(obj); + } } } diff --git a/src/modules/io.cpp b/src/modules/io.cpp index 30847e6b..d047bf4b 100644 --- a/src/modules/io.cpp +++ b/src/modules/io.cpp @@ -151,7 +151,7 @@ void add_module_io(VM* vm) { void add_module_os(VM* vm) { PyObject* mod = vm->new_module("os"); - PyObject* path_obj = vm->heap.gcnew(VM::tp_object); + PyObject* path_obj = vm->new_object(VM::tp_object).get(); mod->attr().set("path", path_obj); // Working directory is shared by all VMs!! diff --git a/src/modules/modules.cpp b/src/modules/modules.cpp index a81634b5..1fc3b04f 100644 --- a/src/modules/modules.cpp +++ b/src/modules/modules.cpp @@ -78,8 +78,8 @@ void add_module_sys(VM* vm) { vm->setattr(mod, "version", VAR(PK_VERSION)); vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM])); - PyObject* stdout_ = vm->heap.gcnew(vm->tp_object); - PyObject* stderr_ = vm->heap.gcnew(vm->tp_object); + PyObject* stdout_ = vm->new_object(vm->tp_object).get(); + PyObject* stderr_ = vm->new_object(vm->tp_object).get(); vm->setattr(mod, "stdout", stdout_); vm->setattr(mod, "stderr", stderr_); @@ -240,7 +240,7 @@ void add_module_dis(VM* vm) { void add_module_gc(VM* vm) { PyObject* mod = vm->new_module("gc"); - vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect()))); + vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(pk_ManagedHeap__collect(&vm->heap)))); } void add_module_enum(VM* vm) { diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 9c8caeab..31dabfac 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -94,7 +94,7 @@ void __init_builtins(VM* _vm) { return vm->None; }); - _vm->bind_func(_vm->builtins, "super", -1, [](VM* vm, ArgsView args) { + _vm->bind_func(_vm->builtins, "super", -1, [](VM* vm, ArgsView args)->PyVar { PyObject* class_arg = nullptr; PyVar self_arg = nullptr; if(args.size() == 2) { @@ -122,13 +122,13 @@ void __init_builtins(VM* _vm) { return vm->new_object(vm->tp_super, self_arg, vm->_all_types[type].base); }); - _vm->bind_func(_vm->builtins, "staticmethod", 1, [](VM* vm, ArgsView args) { + _vm->bind_func(_vm->builtins, "staticmethod", 1, [](VM* vm, ArgsView args)->PyVar { PyVar func = args[0]; vm->check_type(func, vm->tp_function); return vm->new_object(vm->tp_staticmethod, args[0]); }); - _vm->bind_func(_vm->builtins, "classmethod", 1, [](VM* vm, ArgsView args) { + _vm->bind_func(_vm->builtins, "classmethod", 1, [](VM* vm, ArgsView args)->PyVar { PyVar func = args[0]; vm->check_type(func, vm->tp_function); return vm->new_object(vm->tp_classmethod, args[0]); @@ -380,7 +380,7 @@ void __init_builtins(VM* _vm) { return _0._obj == _1._obj ? vm->True : vm->False; }); - _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) { + _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) ->PyVar { vm->check_type(args[0], vm->tp_type); Type t = PK_OBJ_GET(Type, args[0]); return vm->new_object(t); @@ -734,7 +734,7 @@ void __init_builtins(VM* _vm) { }); _vm->bind_func(VM::tp_str, "join", 2, [](VM* vm, ArgsView args) { - auto _lock = vm->heap.gc_scope_lock(); + auto _lock = vm->gc_scope_lock(); const Str& self = _CAST(Str&, args[0]); SStream ss; PyVar it = vm->py_iter(args[1]); // strong ref @@ -964,7 +964,7 @@ void __init_builtins(VM* _vm) { }); _vm->bind_func(VM::tp_list, "extend", 2, [](VM* vm, ArgsView args) { - auto _lock = vm->heap.gc_scope_lock(); + auto _lock = vm->gc_scope_lock(); List& self = _CAST(List&, args[0]); PyVar it = vm->py_iter(args[1]); // strong ref const PyTypeInfo* info = vm->_tp_info(args[1]); @@ -1342,7 +1342,7 @@ void __init_builtins(VM* _vm) { }); // tp_dict - _vm->bind_func(VM::tp_dict, __new__, -1, [](VM* vm, ArgsView args) { + _vm->bind_func(VM::tp_dict, __new__, -1, [](VM* vm, ArgsView args)->PyVar { Type cls_t = PK_OBJ_GET(Type, args[0]); return vm->new_object(cls_t); }); @@ -1350,7 +1350,7 @@ void __init_builtins(VM* _vm) { _vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) { if(args.size() == 1 + 0) return vm->None; if(args.size() == 1 + 1) { - auto _lock = vm->heap.gc_scope_lock(); + auto _lock = vm->gc_scope_lock(); Dict& self = PK_OBJ_GET(Dict, args[0]); if(is_type(args[1], vm->tp_dict)) { Dict& other = CAST(Dict&, args[1]); @@ -1539,7 +1539,7 @@ void __init_builtins(VM* _vm) { _vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args) -> PyVar { Type cls = PK_OBJ_GET(Type, args[0]); StrName cls_name = _type_name(vm, cls); - PyObject* e_obj = vm->heap.gcnew(cls, cls_name.index); + PyObject* e_obj = vm->new_object(cls, cls_name.index).get(); e_obj->_attr = new NameDict(); e_obj->as().self = e_obj; return e_obj; diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index 1807d342..b6be1275 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -428,7 +428,7 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) { VM* vm = (VM*)vm_handle; PK_ASSERT_NO_ERROR() PK_ASSERT_N_EXTRA_ELEMENTS(1) - auto _lock = vm->heap.gc_scope_lock(); + auto _lock = vm->gc_scope_lock(); PK_PROTECTED( PyVar _0 = vm->py_iter(vm->s_data.popx()); for(int i=0; itype = tp_int; + self->is_ptr = false; + self->_i64 = val; +} + +void py_newfloat(PyVar* self, double val){ + self->type = tp_float; + self->is_ptr = false; + self->_f64 = val; +} + +void py_newbool(PyVar* self, bool val){ + // return a global singleton +} + +void py_newnone(PyVar* self){ + // return a heap object +} + +void py_newstr(PyVar* self, const char* val){ + // return a heap object +} + +void py_newstr2(PyVar*, const char*, int); + +void py_newbytes(PyVar*, const uint8_t*, int); +