This commit is contained in:
blueloveTH 2024-05-19 23:52:08 +08:00
parent 75d6b06509
commit c416faf54d
19 changed files with 256 additions and 283 deletions

View File

@ -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 ```cpp
struct Container{ struct Container{
@ -163,7 +163,7 @@ struct Container{
std::vector<PyVar> b; std::vector<PyVar> b;
// ... // ...
void _gc_mark() const{ void _gc_mark(VM* vm) const{
// mark a // mark a
if(a) PK_OBJ_MARK(a); if(a) PK_OBJ_MARK(a);

View File

@ -81,7 +81,7 @@ struct CodeObject {
} }
CodeObject(std::shared_ptr<SourceData> src, const Str& name); CodeObject(std::shared_ptr<SourceData> src, const Str& name);
void _gc_mark() const; void _gc_mark(VM*) const;
}; };
enum class FuncType{ enum class FuncType{
@ -118,7 +118,7 @@ struct FuncDecl {
kwargs.push_back(KwArg{index, key, value}); kwargs.push_back(KwArg{index, key, value});
} }
void _gc_mark() const; void _gc_mark(VM*) const;
}; };
struct NativeFunc { 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, 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)) {} 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); } 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{ struct Function{
@ -142,33 +143,8 @@ struct Function{
explicit Function(FuncDecl_ decl, PyVar _module, PyVar _class, NameDict_ _closure): explicit Function(FuncDecl_ decl, PyVar _module, PyVar _class, NameDict_ _closure):
decl(decl), _module(_module), _class(_class), _closure(_closure) {} decl(decl), _module(_module), _class(_class), _closure(_closure) {}
};
template<> void _gc_mark(VM*) const;
struct Py_<Function> final: PyObject {
Function _value;
template<typename... Args>
Py_(Args&&... args): PyObject(), _value(std::forward<Args>(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_<NativeFunc> final: PyObject {
NativeFunc _value;
template<typename... Args>
Py_(Args&&... args): PyObject(), _value(std::forward<Args>(args)...) {
// _enable_instance_dict();
}
void _obj_gc_mark() override {
if(_value.decl != nullptr){
_value.decl->_gc_mark();
}
}
}; };
template<typename T> template<typename T>

View File

@ -169,6 +169,8 @@ inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_
inline const char* PK_HEX_TABLE = "0123456789abcdef"; inline const char* PK_HEX_TABLE = "0123456789abcdef";
struct PyObject; struct PyObject;
struct Frame;
class VM;
// by default, only `int` and `float` enable SSO // by default, only `int` and `float` enable SSO
// users can specialize this template to enable SSO for other types // users can specialize this template to enable SSO for other types

View File

@ -66,7 +66,7 @@ struct Dict{
void clear(); void clear();
~Dict(); ~Dict();
void _gc_mark() const; void _gc_mark(VM*) const;
}; };
} // namespace pkpy } // namespace pkpy

View File

@ -117,12 +117,7 @@ struct Frame {
int curr_lineno() const { return co->lines[ip()].lineno; } int curr_lineno() const { return co->lines[ip()].lineno; }
void _gc_mark() const { void _gc_mark(VM* vm) 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);
}
}; };
struct LinkedFrame{ struct LinkedFrame{

View File

@ -61,6 +61,8 @@ struct ManagedHeap{
return obj; return obj;
} }
void _delete(PyVar);
#if PK_DEBUG_GC_STATS #if PK_DEBUG_GC_STATS
inline static std::map<Type, int> deleted; inline static std::map<Type, int> deleted;
#endif #endif
@ -70,7 +72,6 @@ struct ManagedHeap{
bool _should_auto_collect() const { return gc_counter >= gc_threshold; } bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
int collect(); int collect();
void mark(); void mark();
~ManagedHeap();
}; };
} // namespace pkpy } // namespace pkpy

View File

@ -23,7 +23,7 @@ struct ArrayIter{
ArrayIter(PyVar ref, PyVar* begin, PyVar* end) ArrayIter(PyVar ref, PyVar* begin, PyVar* end)
: ref(ref), begin(begin), end(end), current(begin) {} : 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); static void _register(VM* vm, PyVar mod, PyVar type);
}; };
@ -31,7 +31,7 @@ struct StringIter{
PyVar ref; PyVar ref;
int i; // byte index int i; // byte index
StringIter(PyVar ref) : ref(ref), i(0) {} 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); static void _register(VM* vm, PyVar mod, PyVar type);
}; };
@ -44,8 +44,8 @@ struct Generator{
for(PyVar obj: buffer) s_backup.push_back(obj); for(PyVar obj: buffer) s_backup.push_back(obj);
} }
void _gc_mark() const{ void _gc_mark(VM* vm) const{
frame._gc_mark(); frame._gc_mark(vm);
for(PyVar obj: s_backup) PK_OBJ_MARK(obj); for(PyVar obj: s_backup) PK_OBJ_MARK(obj);
} }
@ -59,7 +59,7 @@ struct DictItemsIter{
DictItemsIter(PyVar ref) : ref(ref) { DictItemsIter(PyVar ref) : ref(ref) {
i = PK_OBJ_GET(Dict, ref)._head_idx; 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); static void _register(VM* vm, PyVar mod, PyVar type);
}; };

View File

@ -6,9 +6,6 @@
namespace pkpy { namespace pkpy {
struct Frame;
class VM;
#if PK_ENABLE_STD_FUNCTION #if PK_ENABLE_STD_FUNCTION
using NativeFuncC = std::function<PyVar(VM*, ArgsView)>; using NativeFuncC = std::function<PyVar(VM*, ArgsView)>;
#else #else
@ -25,22 +22,26 @@ struct BoundMethod {
PyVar self; PyVar self;
PyVar func; PyVar func;
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {} BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
void _gc_mark(VM*) const;
}; };
struct StaticMethod{ struct StaticMethod{
PyVar func; PyVar func;
StaticMethod(PyVar func) : func(func) {} StaticMethod(PyVar func) : func(func) {}
void _gc_mark(VM*) const;
}; };
struct ClassMethod{ struct ClassMethod{
PyVar func; PyVar func;
ClassMethod(PyVar func) : func(func) {} ClassMethod(PyVar func) : func(func) {}
void _gc_mark(VM*) const;
}; };
struct Property{ struct Property{
PyVar getter; PyVar getter;
PyVar setter; PyVar setter;
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {} Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
void _gc_mark(VM*) const;
}; };
struct Range { struct Range {
@ -53,6 +54,7 @@ struct StarWrapper{
int level; // either 1 or 2 int level; // either 1 or 2
PyVar obj; PyVar obj;
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {} StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
void _gc_mark(VM*) const;
}; };
struct Bytes{ struct Bytes{
@ -84,13 +86,19 @@ struct Bytes{
~Bytes(){ delete[] _data;} ~Bytes(){ delete[] _data;}
}; };
using Super = std::pair<PyVar, Type>; struct Super{
PyVar first;
Type second;
Super(PyVar first, Type second) : first(first), second(second) {}
void _gc_mark(VM*) const;
};
struct Slice { struct Slice {
PyVar start; PyVar start;
PyVar stop; PyVar stop;
PyVar step; PyVar step;
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {} Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
void _gc_mark(VM*) const;
}; };
struct PyObject{ struct PyObject{
@ -98,6 +106,8 @@ struct PyObject{
bool gc_marked; // whether this object is marked bool gc_marked; // whether this object is marked
NameDict* _attr; NameDict* _attr;
void* _value_ptr() noexcept { return 1 + &_attr; }
bool is_attr_valid() const noexcept { return _attr != nullptr; } bool is_attr_valid() const noexcept { return _attr != nullptr; }
NameDict& attr() { NameDict& attr() {
@ -110,9 +120,6 @@ struct PyObject{
return (*_attr)[name]; return (*_attr)[name];
} }
virtual void _obj_gc_mark() = 0;
virtual ~PyObject();
PyObject() : gc_enabled(true), gc_marked(false), _attr(nullptr) {} PyObject() : gc_enabled(true), gc_marked(false), _attr(nullptr) {}
void _enable_instance_dict() { void _enable_instance_dict() {
@ -124,6 +131,9 @@ struct PyObject{
} }
}; };
template<typename T>
inline constexpr int py_sizeof = sizeof(PyObject) + sizeof(T);
const int kTpIntIndex = 3; const int kTpIntIndex = 3;
const int kTpFloatIndex = 4; const int kTpFloatIndex = 4;
@ -143,14 +153,7 @@ template <typename T>
struct Py_ final: PyObject { struct Py_ final: PyObject {
static_assert(!std::is_reference_v<T>); static_assert(!std::is_reference_v<T>);
static_assert(!is_sso_v<T>); static_assert(!is_sso_v<T>);
T _value; T _value;
void _obj_gc_mark() override {
if constexpr (has_gc_marker<T>::value) {
_value._gc_mark();
}
}
template <typename... Args> template <typename... Args>
Py_(Args&&... args) : PyObject(), _value(std::forward<Args>(args)...) { } Py_(Args&&... args) : PyObject(), _value(std::forward<Args>(args)...) { }
}; };
@ -159,9 +162,9 @@ struct MappingProxy{
PyVar obj; PyVar obj;
MappingProxy(PyVar obj) : obj(obj) {} MappingProxy(PyVar obj) : obj(obj) {}
NameDict& attr() { return obj->attr(); } NameDict& attr() { return obj->attr(); }
void _gc_mark(VM*) const;
}; };
void _gc_mark_namedict(NameDict*);
StrName _type_name(VM* vm, Type type); StrName _type_name(VM* vm, Type type);
template<typename T> T to_void_p(VM*, PyVar); template<typename T> T to_void_p(VM*, PyVar);
PyVar from_void_p(VM*, void*); PyVar from_void_p(VM*, void*);
@ -181,9 +184,7 @@ obj_get_t<T> PyVar::obj_get(){
#define PK_OBJ_MARK(obj) \ #define PK_OBJ_MARK(obj) \
if(!is_tagged(obj) && !(obj)->gc_marked) { \ if(!is_tagged(obj) && !(obj)->gc_marked) { \
(obj)->gc_marked = true; \ vm->__obj_gc_mark(obj); \
(obj)->_obj_gc_mark(); \
if((obj)->is_attr_valid()) _gc_mark_namedict((obj)->_attr); \
} }
#define VAR(x) py_var(vm, x) #define VAR(x) py_var(vm, x)
@ -202,109 +203,12 @@ inline bool try_cast_int(PyVar obj, i64* val) noexcept {
return false; return false;
} }
template<>
struct Py_<List> 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_<Tuple> 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_<MappingProxy> final: PyObject {
MappingProxy _value;
Py_(MappingProxy val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.obj);
}
};
template<>
struct Py_<BoundMethod> 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_<StarWrapper> final: PyObject {
StarWrapper _value;
Py_(StarWrapper val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.obj);
}
};
template<>
struct Py_<StaticMethod> final: PyObject {
StaticMethod _value;
Py_(StaticMethod val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.func);
}
};
template<>
struct Py_<ClassMethod> final: PyObject {
ClassMethod _value;
Py_(ClassMethod val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.func);
}
};
template<>
struct Py_<Property> 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_<Slice> 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_<Super> final: PyObject {
Super _value;
template<typename... Args>
Py_(Args&&... args): PyObject(), _value(std::forward<Args>(args)...) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.first);
}
};
template<> template<>
struct Py_<DummyInstance> final: PyObject { struct Py_<DummyInstance> final: PyObject {
Py_(): PyObject() { _enable_instance_dict(); } Py_(): PyObject() {
void _obj_gc_mark() override {} _enable_instance_dict();
}
}; };
template<> template<>
@ -313,7 +217,6 @@ struct Py_<Type> final: PyObject {
Py_(Type val): PyObject(), _value(val) { Py_(Type val): PyObject(), _value(val) {
_enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR); _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
} }
void _obj_gc_mark() override {}
}; };
template<> template<>
@ -321,7 +224,6 @@ struct Py_<DummyModule> final: PyObject {
Py_(): PyObject() { Py_(): PyObject() {
_enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR); _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
} }
void _obj_gc_mark() override {}
}; };
extern PyVar const PY_NULL; extern PyVar const PY_NULL;

View File

@ -7,7 +7,10 @@
namespace pkpy { namespace pkpy {
using List = pod_vector<PyVar, 4>; struct List: pod_vector<PyVar, 4>{
using pod_vector<PyVar, 4>::pod_vector;
void _gc_mark(VM*) const;
};
struct Tuple { struct Tuple {
static const int INLINED_SIZE = 4; static const int INLINED_SIZE = 4;
@ -35,6 +38,7 @@ struct Tuple {
PyVar* begin() const { return _args; } PyVar* begin() const { return _args; }
PyVar* end() const { return _args + _size; } PyVar* end() const { return _args + _size; }
PyVar* data() const { return _args; } PyVar* data() const { return _args; }
void _gc_mark(VM*) const;
}; };
// a lightweight view for function args, it does not own the memory // a lightweight view for function args, it does not own the memory

View File

@ -42,12 +42,36 @@ struct NextBreakpoint{
#endif #endif
struct PyTypeInfo{ struct PyTypeInfo{
struct Vt{
void (*_dtor)(void*);
void (*_gc_mark)(void*, VM*);
Vt(): _dtor(nullptr), _gc_mark(nullptr) {}
template<typename T>
inline static Vt get(){
static_assert(std::is_same_v<T, std::decay_t<T>>);
Vt vt;
if constexpr(!std::is_trivially_destructible_v<T>){
vt._dtor = [](void* p){ ((T*)p)->~T(); };
}
if constexpr(has_gc_marker<T>::value){
vt._gc_mark = [](void* p, VM* vm){ ((T*)p)->_gc_mark(vm); };
}
return vt;
}
};
PyVar obj; // never be garbage collected PyVar obj; // never be garbage collected
Type base; Type base;
PyVar mod; // never be garbage collected PyVar mod; // never be garbage collected
StrName name; StrName name;
bool subclass_enabled; 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<StrName> annotated_fields = {}; std::vector<StrName> annotated_fields = {};
// unary operators // unary operators
@ -386,7 +410,12 @@ public:
#if PK_REGION("User Type Registration") #if PK_REGION("User Type Registration")
PyVar new_module(Str name, Str package=""); 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<typename T>
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<T>());
}
template<typename T> template<typename T>
Type _tp_user(){ return _find_type_in_cxx_typeid_map<T>(); } Type _tp_user(){ return _find_type_in_cxx_typeid_map<T>(); }
@ -455,6 +484,7 @@ public:
PyVar __pack_next_retval(unsigned); PyVar __pack_next_retval(unsigned);
PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key); PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
bool __py_bool_non_trivial(PyVar); 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<typename T> template<typename T>
PyVar VM::register_user_class(PyVar mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){ 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<T>());
mod->attr().set(name, type); mod->attr().set(name, type);
_cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type); _cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type);
_register(this, mod, type); _register(this, mod, type);

View File

@ -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]); for(int i = 0; i < numel; i++) PK_OBJ_MARK(data[i]);
} }
@ -349,7 +349,7 @@ struct Array2dIter{
int i; int i;
Array2dIter(PyVar ref) : ref(ref), i(0) {} 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){ static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) { return _0; });

View File

@ -924,7 +924,7 @@ __NEXT_STEP:
PyVar _0 = POPX(); // super PyVar _0 = POPX(); // super
if(_0 == None) _0 = _t(tp_object); if(_0 == None) _0 = _t(tp_object);
check_type(_0, tp_type); 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() } DISPATCH()
case OP_END_CLASS: { case OP_END_CLASS: {
PK_ASSERT(__curr_class != nullptr); PK_ASSERT(__curr_class != nullptr);

View File

@ -193,48 +193,48 @@ void add_module_c(VM* vm){
#define BIND_PRIMITIVE(T, CNAME) \ #define BIND_PRIMITIVE(T, CNAME) \
vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args){ \ vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args){ \
T val = CAST(T, args[0]); \ T val = CAST(T, args[0]); \
return vm->new_user_object<Struct>(&val, sizeof(T)); \ return vm->new_user_object<Struct>(&val, sizeof(T)); \
}); \ }); \
type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>()); \ type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \
mod->attr().set(CNAME "_p", type); \ mod->attr().set(CNAME "_p", type); \
type_t = PK_OBJ_GET(Type, type); \ type_t = PK_OBJ_GET(Type, type); \
vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \ vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return VAR(*target); \ return VAR(*target); \
}); \ }); \
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ \ vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
T val = CAST(T, args[1]); \ T val = CAST(T, args[1]); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
*target = val; \ *target = val; \
return vm->None; \ return vm->None; \
}); \ }); \
vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index){ \ vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index){ \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
i64 offset = CAST(i64, index); \ i64 offset = CAST(i64, index); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return VAR(target[offset]); \ return VAR(target[offset]); \
}); \ }); \
vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value){ \ vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value){ \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
i64 offset = CAST(i64, index); \ i64 offset = CAST(i64, index); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
target[offset] = CAST(T, value); \ target[offset] = CAST(T, value); \
}); \ }); \
vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
i64 offset = CAST(i64, rhs); \ i64 offset = CAST(i64, rhs); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return vm->new_object<VoidP>(lhs.type, target + offset); \ return vm->new_object<VoidP>(lhs.type, target + offset); \
}); \ }); \
vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
i64 offset = CAST(i64, rhs); \ i64 offset = CAST(i64, rhs); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return vm->new_object<VoidP>(lhs.type, target - offset); \ return vm->new_object<VoidP>(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); \ VoidP& self = _CAST(VoidP&, obj); \
return _S("<", CNAME, "* at ", self.hex(), ">"); \ return _S("<", CNAME, "* at ", self.hex(), ">"); \
}); \ }); \

View File

@ -7,14 +7,8 @@ namespace pkpy{
blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0, 0)); 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 { struct PySignalObject: PyObject {
PySignalObject() : PyObject() { gc_enabled = false; } PySignalObject() : PyObject() { gc_enabled = false; }
void _obj_gc_mark() override {}
}; };
PyVar const PY_NULL(Type(), new PySignalObject()); PyVar const PY_NULL(Type(), new PySignalObject());

View File

@ -18,7 +18,7 @@ namespace pkpy
{ {
this->is_reversed = true; 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); static void _register(VM *vm, PyVar mod, PyVar type);
}; };
void PyDequeIter::_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 int findIndex(VM *vm, PyVar obj, int start, int stop); // find the index of the given object in the deque
// Special methods // Special methods
static void _register(VM *vm, PyVar mod, PyVar type); // register the type 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) void PyDeque::_register(VM *vm, PyVar mod, PyVar type)
{ {
@ -532,7 +532,7 @@ namespace pkpy
} }
} }
/// @brief marks the deque items for garbage collection /// @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) for (PyVar obj : this->dequeItems)
PK_OBJ_MARK(obj); PK_OBJ_MARK(obj);

View File

@ -169,12 +169,4 @@ namespace pkpy{
pool128_dealloc(_items); pool128_dealloc(_items);
pool64_dealloc(_nodes); pool64_dealloc(_nodes);
} }
void Dict::_gc_mark() const{
apply([](PyVar k, PyVar v){
PK_OBJ_MARK(k);
PK_OBJ_MARK(v);
});
}
} // namespace pkpy } // namespace pkpy

View File

@ -14,8 +14,7 @@ namespace pkpy{
deleted[obj.type] += 1; deleted[obj.type] += 1;
#endif #endif
if(_gc_on_delete) _gc_on_delete(vm, obj); if(_gc_on_delete) _gc_on_delete(vm, obj);
obj->~PyObject(); _delete(obj);
pool128_dealloc(obj.get());
} }
} }
@ -54,16 +53,4 @@ namespace pkpy{
int freed = sweep(); int freed = sweep();
return freed; 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<kwargs.size(); i++) PK_OBJ_MARK(kwargs[i].value);
}
} // namespace pkpy } // namespace pkpy

View File

@ -46,11 +46,4 @@ namespace pkpy{
_size = 0; _size = 0;
return {p, size}; return {p, size};
} }
PyObject::~PyObject(){
if(_attr == nullptr) return;
_attr->~NameDict();
pool128_dealloc(_attr);
}
} // namespace pkpy } // namespace pkpy

View File

@ -205,21 +205,14 @@ namespace pkpy{
return exec(source, "<eval>", EVAL_MODE); return exec(source, "<eval>", 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<Type>(tp_type, Type(_all_types.size())); PyVar obj = heap._new<Type>(tp_type, Type(_all_types.size()));
const PyTypeInfo& base_info = _all_types[base]; const PyTypeInfo& base_info = _all_types[base];
if(!base_info.subclass_enabled){ if(!base_info.subclass_enabled){
Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`"); Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`");
throw std::runtime_error(error.c_str()); throw std::runtime_error(error.c_str());
} }
PyTypeInfo info{ _all_types.emplace_back(obj, base, mod, name, subclass_enabled, vt);
obj,
base,
mod,
name,
subclass_enabled,
};
_all_types.push_back(info);
return obj; return obj;
} }
@ -404,6 +397,10 @@ namespace pkpy{
} }
VM::~VM() { 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(); callstack.clear();
s_data.clear(); s_data.clear();
_all_types.clear(); _all_types.clear();
@ -430,6 +427,17 @@ bool VM::__py_bool_non_trivial(PyVar obj){
return true; 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){ List VM::py_list(PyVar it){
auto _lock = heap.gc_scope_lock(); auto _lock = heap.gc_scope_lock();
it = py_iter(it); it = py_iter(it);
@ -823,49 +831,49 @@ void VM::__log_s_data(const char* title) {
#endif #endif
void VM::__init_builtin_types(){ void VM::__init_builtin_types(){
_all_types.push_back({nullptr, Type(), nullptr, "", false}); // 0 is not used _all_types.emplace_back(nullptr, Type(), nullptr, "", false); // 0 is not used
_all_types.push_back({heap._new<Type>(tp_type, tp_object), Type(), nullptr, "object", true}); _all_types.emplace_back(heap._new<Type>(tp_type, tp_object), Type(), nullptr, "object", true);
_all_types.push_back({heap._new<Type>(tp_type, tp_type), tp_object, nullptr, "type", false}); _all_types.emplace_back(heap._new<Type>(tp_type, tp_type), tp_object, nullptr, "type", false);
auto _new_type = [this](const char* name, Type base=tp_object, bool subclass_enabled=false){ auto validate = [](Type type, PyVar ret){
PyVar obj = new_type_object(nullptr, name, base, subclass_enabled); Type ret_t = PK_OBJ_GET(Type, ret);
return PK_OBJ_GET(Type, obj); if(ret_t != type) exit(-3);
}; };
if(tp_int != _new_type("int")) exit(-3); validate(tp_int, new_type_object(nullptr, "int", tp_object, false));
if((tp_float != _new_type("float"))) exit(-3); 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); validate(tp_str, new_type_object<Str>(nullptr, "str", tp_object, false));
if(tp_str != _new_type("str")) exit(-3); validate(tp_list, new_type_object<List>(nullptr, "list", tp_object, false));
if(tp_list != _new_type("list")) exit(-3); validate(tp_tuple, new_type_object<Tuple>(nullptr, "tuple", tp_object, false));
if(tp_tuple != _new_type("tuple")) exit(-3);
if(tp_slice != _new_type("slice")) exit(-3); validate(tp_slice, new_type_object<Slice>(nullptr, "slice", tp_object, false));
if(tp_range != _new_type("range")) exit(-3); validate(tp_range, new_type_object<Range>(nullptr, "range", tp_object, false));
if(tp_module != _new_type("module")) exit(-3); validate(tp_module, new_type_object<DummyModule>(nullptr, "module", tp_object, false));
if(tp_function != _new_type("function")) exit(-3); validate(tp_function, new_type_object<Function>(nullptr, "function", tp_object, false));
if(tp_native_func != _new_type("native_func")) exit(-3); validate(tp_native_func, new_type_object<NativeFunc>(nullptr, "native_func", tp_object, false));
if(tp_bound_method != _new_type("bound_method")) exit(-3); validate(tp_bound_method, new_type_object<BoundMethod>(nullptr, "bound_method", tp_object, false));
if(tp_super != _new_type("super")) exit(-3); validate(tp_super, new_type_object<Super>(nullptr, "super", tp_object, false));
if(tp_exception != _new_type("Exception", tp_object, true)) exit(-3); validate(tp_exception, new_type_object<Exception>(nullptr, "Exception", tp_object, true));
if(tp_bytes != _new_type("bytes")) exit(-3); validate(tp_bytes, new_type_object<Bytes>(nullptr, "bytes", tp_object, false));
if(tp_mappingproxy != _new_type("mappingproxy")) exit(-3); validate(tp_mappingproxy, new_type_object<MappingProxy>(nullptr, "mappingproxy", tp_object, false));
if(tp_dict != _new_type("dict", tp_object, true)) exit(-3); // dict can be subclassed validate(tp_dict, new_type_object<Dict>(nullptr, "dict", tp_object, true));
if(tp_property != _new_type("property")) exit(-3); validate(tp_property, new_type_object<Property>(nullptr, "property", tp_object, false));
if(tp_star_wrapper != _new_type("_star_wrapper")) exit(-3); validate(tp_star_wrapper, new_type_object<StarWrapper>(nullptr, "_star_wrapper", tp_object, false));
if(tp_staticmethod != _new_type("staticmethod")) exit(-3); validate(tp_staticmethod, new_type_object<StaticMethod>(nullptr, "staticmethod", tp_object, false));
if(tp_classmethod != _new_type("classmethod")) exit(-3); validate(tp_classmethod, new_type_object<ClassMethod>(nullptr, "classmethod", tp_object, false));
if(tp_none != _new_type("NoneType")) exit(-3); validate(tp_none, new_type_object(nullptr, "NoneType", tp_object, false));
if(tp_not_implemented != _new_type("NotImplementedType")) exit(-3); validate(tp_not_implemented, new_type_object(nullptr, "NotImplementedType", tp_object, false));
if(tp_ellipsis != _new_type("ellipsis")) exit(-3); validate(tp_ellipsis, new_type_object(nullptr, "ellipsis", tp_object, false));
// SyntaxError and IndentationError must be created here // SyntaxError and IndentationError must be created here
Type tp_syntax_error = _new_type("SyntaxError", tp_exception, true); PyVar SyntaxError = new_type_object(nullptr, "SyntaxError", tp_exception, true);
Type tp_indentation_error = _new_type("IndentationError", tp_syntax_error, true); PyVar IndentationError = new_type_object(nullptr, "IndentationError", PK_OBJ_GET(Type, SyntaxError), true);
this->StopIteration = _all_types[_new_type("StopIteration", tp_exception)].obj; this->StopIteration = new_type_object(nullptr, "StopIteration", tp_exception, true);
this->builtins = new_module("builtins"); this->builtins = new_module("builtins");
@ -886,8 +894,8 @@ void VM::__init_builtin_types(){
builtins->attr().set("NotImplemented", NotImplemented); builtins->attr().set("NotImplemented", NotImplemented);
builtins->attr().set("slice", _t(tp_slice)); builtins->attr().set("slice", _t(tp_slice));
builtins->attr().set("Exception", _t(tp_exception)); builtins->attr().set("Exception", _t(tp_exception));
builtins->attr().set("SyntaxError", _t(tp_syntax_error)); builtins->attr().set("SyntaxError", SyntaxError);
builtins->attr().set("IndentationError", _t(tp_indentation_error)); builtins->attr().set("IndentationError", IndentationError);
__post_init_builtin_types(); __post_init_builtin_types();
this->_main = new_module("__main__"); 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){ StrName _type_name(VM *vm, Type type){
return vm->_all_types[type].name; 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)){ void VM::bind__getitem__(Type type, PyVar (*f)(VM*, PyVar, PyVar)){
_all_types[type].m__getitem__ = f; _all_types[type].m__getitem__ = f;
@ -1757,4 +1750,108 @@ void VM::__breakpoint(){
#endif #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<kwargs.size(); i++) PK_OBJ_MARK(kwargs[i].value);
}
void List::_gc_mark(VM* vm) const{
for(PyVar obj: *this) PK_OBJ_MARK(obj);
}
void Tuple::_gc_mark(VM* vm) const{
for(PyVar obj: *this) PK_OBJ_MARK(obj);
}
void MappingProxy::_gc_mark(VM* vm) const{
PK_OBJ_MARK(obj);
}
void BoundMethod::_gc_mark(VM* vm) const{
PK_OBJ_MARK(func);
PK_OBJ_MARK(self);
}
void StarWrapper::_gc_mark(VM* vm) const{
PK_OBJ_MARK(obj);
}
void StaticMethod::_gc_mark(VM* vm) const{
PK_OBJ_MARK(func);
}
void ClassMethod::_gc_mark(VM* vm) const{
PK_OBJ_MARK(func);
}
void Property::_gc_mark(VM* vm) const{
PK_OBJ_MARK(getter);
PK_OBJ_MARK(setter);
}
void Slice::_gc_mark(VM* vm) const{
PK_OBJ_MARK(start);
PK_OBJ_MARK(stop);
PK_OBJ_MARK(step);
}
void Super::_gc_mark(VM* vm) const{
PK_OBJ_MARK(first);
}
void Frame::_gc_mark(VM* vm) const {
PK_OBJ_MARK(_module);
co->_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 } // namespace pkpy