diff --git a/src/gc.h b/src/gc.h new file mode 100644 index 00000000..3081b259 --- /dev/null +++ b/src/gc.h @@ -0,0 +1,51 @@ +#pragma once + +#include "obj.h" + +namespace pkpy { + using PyVar0 = PyObject*; + + // a generational mark and sweep garbage collector + struct GC{ + using Generation = std::vector; + static const int kTotalGen = 3; + Generation gen[kTotalGen]; + + void add(PyVar0 obj){ + if(!obj->need_gc) return; + gen[0].push_back(obj); + } + + void sweep(int index){ + Generation& g = gen[index]; + if(index < kTotalGen-1){ + for(int i=0; imarked){ + g[i]->marked = false; + gen[index+1].push_back(g[i]); + }else{ + delete g[i]; + } + } + g.clear(); + }else{ + Generation alive; + // the oldest generation + for(int i=0; imarked){ + g[i]->marked = false; + alive.push_back(g[i]); + }else{ + delete g[i]; + } + } + g = std::move(alive); + } + } + + void collect(int index){ + sweep(index); + } + }; + +} // namespace pkpy \ No newline at end of file diff --git a/src/namedict.h b/src/namedict.h index 8b8a3516..90f8d34a 100644 --- a/src/namedict.h +++ b/src/namedict.h @@ -230,6 +230,13 @@ while(!_keys[i].empty()) { \ } return v; } + + void apply_v(void(*f)(PyVar)) { + for(uint16_t i=0; i<_capacity; i++){ + if(_keys[i].empty()) continue; + f(value(i)); + } + } #undef HASH_PROBE #undef _hash }; diff --git a/src/obj.h b/src/obj.h index fb2a0e12..46acb280 100644 --- a/src/obj.h +++ b/src/obj.h @@ -88,6 +88,9 @@ public: }; struct PyObject { + bool need_gc; + bool marked; + /**********/ Type type; NameDict* _attr; @@ -96,6 +99,12 @@ struct PyObject { inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); } virtual void* value() = 0; + virtual void mark() { + if(!need_gc || marked) return; + marked = true; + if(is_attr_valid()) attr().apply_v([](PyVar v){ v->mark(); }); + } + PyObject(Type type) : type(type) {} virtual ~PyObject() { delete _attr; } }; @@ -119,9 +128,14 @@ struct Py_ : PyObject { } } void* value() override { return &_value; } + + void mark() override { + PyObject::mark(); + // extra mark for `T` + } }; -#define OBJ_GET(T, obj) (((Py_*)((obj).get()))->_value) +#define OBJ_GET(T, obj) (((Py_*)(obj))->_value) #define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) const int kTpIntIndex = 2; diff --git a/src/tuplelist.h b/src/tuplelist.h index 5594a563..a07459e8 100644 --- a/src/tuplelist.h +++ b/src/tuplelist.h @@ -5,12 +5,12 @@ #include "str.h" namespace pkpy { - using List = std::vector; + using List = std::vector; class Args { - static THREAD_LOCAL SmallArrayPool _pool; + static THREAD_LOCAL SmallArrayPool _pool; - PyVar* _args; + PyObject** _args; int _size; inline void _alloc(int n){ @@ -35,14 +35,14 @@ namespace pkpy { static pkpy::Args from_list(List&& other) noexcept { Args ret(other.size()); - memcpy((void*)ret._args, (void*)other.data(), sizeof(PyVar)*ret.size()); - memset((void*)other.data(), 0, sizeof(PyVar)*ret.size()); + memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size()); + memset((void*)other.data(), 0, sizeof(PyObject*)*ret.size()); other.clear(); return ret; } - PyVar& operator[](int i){ return _args[i]; } - const PyVar& operator[](int i) const { return _args[i]; } + PyObject*& operator[](int i){ return _args[i]; } + PyObject* operator[](int i) const { return _args[i]; } Args& operator=(Args&& other) noexcept { _pool.dealloc(_args, _size); @@ -57,29 +57,30 @@ namespace pkpy { List move_to_list() noexcept { List ret(_size); - memcpy((void*)ret.data(), (void*)_args, sizeof(PyVar)*_size); - memset((void*)_args, 0, sizeof(PyVar)*_size); + memcpy((void*)ret.data(), (void*)_args, sizeof(PyObject*)*_size); + memset((void*)_args, 0, sizeof(PyObject*)*_size); return ret; } - void extend_self(const PyVar& self){ - static_assert(std::is_standard_layout_v); - PyVar* old_args = _args; + void extend_self(PyObject* self){ + PyObject** old_args = _args; int old_size = _size; _alloc(old_size+1); _args[0] = self; if(old_size == 0) return; - memcpy((void*)(_args+1), (void*)old_args, sizeof(PyVar)*old_size); - memset((void*)old_args, 0, sizeof(PyVar)*old_size); + memcpy((void*)(_args+1), (void*)old_args, sizeof(PyObject*)*old_size); + memset((void*)old_args, 0, sizeof(PyObject*)*old_size); _pool.dealloc(old_args, old_size); } ~Args(){ _pool.dealloc(_args, _size); } }; - static const Args _zero(0); - inline const Args& no_arg() { return _zero; } + inline const Args& no_arg() { + static const Args _zero(0); + return _zero; + } template Args one_arg(T&& a) { @@ -106,5 +107,5 @@ namespace pkpy { } typedef Args Tuple; - THREAD_LOCAL SmallArrayPool Args::_pool; + THREAD_LOCAL SmallArrayPool Args::_pool; } // namespace pkpy \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index 22523e45..e90b1544 100644 --- a/src/vm.h +++ b/src/vm.h @@ -6,22 +6,22 @@ namespace pkpy{ #define DEF_NATIVE_2(ctype, ptype) \ - template<> ctype py_cast(VM* vm, const PyVar& obj) { \ + template<> ctype py_cast(VM* vm, PyObject* obj) { \ vm->check_type(obj, vm->ptype); \ return OBJ_GET(ctype, obj); \ } \ - template<> ctype _py_cast(VM* vm, const PyVar& obj) { \ + template<> ctype _py_cast(VM* vm, PyObject* obj) { \ return OBJ_GET(ctype, obj); \ } \ - template<> ctype& py_cast(VM* vm, const PyVar& obj) { \ + template<> ctype& py_cast(VM* vm, PyObject* obj) { \ vm->check_type(obj, vm->ptype); \ return OBJ_GET(ctype, obj); \ } \ - template<> ctype& _py_cast(VM* vm, const PyVar& obj) { \ + template<> ctype& _py_cast(VM* vm, PyObject* obj) { \ return OBJ_GET(ctype, obj); \ } \ - PyVar py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \ - PyVar py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));} + PyObject* py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \ + PyObject* py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));} class Generator: public BaseIter { std::unique_ptr frame; @@ -30,11 +30,11 @@ public: Generator(VM* vm, std::unique_ptr&& frame) : BaseIter(vm, nullptr), frame(std::move(frame)), state(0) {} - PyVar next(); + PyObject* next(); }; struct PyTypeInfo{ - PyVar obj; + PyObject* obj; Type base; Str name; }; @@ -43,23 +43,27 @@ class VM { VM* vm; // self reference for simplify code public: std::stack< std::unique_ptr > callstack; - PyVar _py_op_call; - PyVar _py_op_yield; std::vector _all_types; - PyVar run_frame(Frame* frame); + PyObject* run_frame(Frame* frame); NameDict _modules; // loaded modules std::map _lazy_modules; // lazy loaded modules - PyVar None, True, False, Ellipsis; + + // singleton objects, need_gc=false + PyObject* _py_op_call; + PyObject* _py_op_yield; + PyObject* None; + PyObject* True; + PyObject* False; + PyObject* Ellipsis; + + PyObject* builtins; // builtins module + PyObject* _main; // __main__ module bool use_stdio; std::ostream* _stdout; std::ostream* _stderr; - - PyVar builtins; // builtins module - PyVar _main; // __main__ module - int recursionlimit = 1000; VM(bool use_stdio){ @@ -77,7 +81,7 @@ public: // for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i)); } - PyVar asStr(const PyVar& obj){ + PyObject* asStr(PyObject* obj){ PyVarOrNull f = getattr(obj, __str__, false, true); if(f != nullptr) return call(f); return asRepr(obj); @@ -90,7 +94,7 @@ public: return callstack.top().get(); } - PyVar asIter(const PyVar& obj){ + PyObject* asIter(PyObject* obj){ if(is_type(obj, tp_native_iterator)) return obj; PyVarOrNull iter_f = getattr(obj, __iter__, false, true); if(iter_f != nullptr) return call(iter_f); @@ -98,25 +102,25 @@ public: return nullptr; } - PyVar asList(const PyVar& iterable){ + PyObject* asList(PyObject* iterable){ if(is_type(iterable, tp_list)) return iterable; return call(_t(tp_list), one_arg(iterable)); } - PyVar* find_name_in_mro(PyObject* cls, StrName name){ - PyVar* val; + PyObject** find_name_in_mro(PyObject* cls, StrName name){ + PyObject** val; do{ val = cls->attr().try_get(name); if(val != nullptr) return val; Type cls_t = static_cast*>(cls)->_value; Type base = _all_types[cls_t.index].base; if(base.index == -1) break; - cls = _all_types[base.index].obj.get(); + cls = _all_types[base.index].obj; }while(true); return nullptr; } - bool isinstance(const PyVar& obj, Type cls_t){ + bool isinstance(PyObject* obj, Type cls_t){ Type obj_t = OBJ_GET(Type, _t(obj)); do{ if(obj_t == cls_t) return true; @@ -127,36 +131,36 @@ public: return false; } - PyVar fast_call(StrName name, Args&& args){ - PyVar* val = find_name_in_mro(_t(args[0]).get(), name); + PyObject* fast_call(StrName name, Args&& args){ + PyObject** val = find_name_in_mro(_t(args[0]).get(), name); if(val != nullptr) return call(*val, std::move(args)); AttributeError(args[0], name); return nullptr; } - inline PyVar call(const PyVar& _callable){ + inline PyObject* call(PyObject* _callable){ return call(_callable, no_arg(), no_arg(), false); } template - inline std::enable_if_t, Args>, PyVar> - call(const PyVar& _callable, ArgT&& args){ + inline std::enable_if_t, Args>, PyObject*> + call(PyObject* _callable, ArgT&& args){ return call(_callable, std::forward(args), no_arg(), false); } template - inline std::enable_if_t, Args>, PyVar> - call(const PyVar& obj, const StrName name, ArgT&& args){ + inline std::enable_if_t, Args>, PyObject*> + call(PyObject* obj, const StrName name, ArgT&& args){ return call(getattr(obj, name, true, true), std::forward(args), no_arg(), false); } - inline PyVar call(const PyVar& obj, StrName name){ + inline PyObject* call(PyObject* obj, StrName name){ return call(getattr(obj, name, true, true), no_arg(), no_arg(), false); } // repl mode is only for setting `frame->id` to 0 - PyVarOrNull exec(Str source, Str filename, CompileMode mode, PyVar _module=nullptr){ + PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){ if(_module == nullptr) _module = _main; try { CodeObject_ code = compile(source, filename, mode); @@ -180,19 +184,20 @@ public: } template - inline PyVar _exec(Args&&... args){ + inline PyObject* _exec(Args&&... args){ callstack.push(_new_frame(std::forward(args)...)); return _exec(); } - PyVar property(NativeFuncRaw fget){ - PyVar p = builtins->attr("property"); - PyVar method = new_object(tp_native_function, NativeFunc(fget, 1, false)); + PyObject* property(NativeFuncRaw fget){ + PyObject* p = builtins->attr("property"); + PyObject* method = new_object(tp_native_function, NativeFunc(fget, 1, false)); return call(p, one_arg(method)); } - PyVar new_type_object(PyVar mod, StrName name, Type base){ - PyVar obj = make_sp>(tp_type, _all_types.size()); + PyObject* new_type_object(PyObject* mod, StrName name, Type base){ + // use gcnew + PyObject* obj = make_sp>(tp_type, _all_types.size()); PyTypeInfo info{ .obj = obj, .base = base, @@ -204,19 +209,19 @@ public: } Type _new_type_object(StrName name, Type base=0) { - PyVar obj = new_type_object(nullptr, name, base); + PyObject* obj = new_type_object(nullptr, name, base); return OBJ_GET(Type, obj); } template - inline PyVar new_object(const PyVar& type, const T& _value) { + inline PyObject* new_object(PyObject* type, const T& _value) { #if PK_EXTRA_CHECK if(!is_type(type, tp_type)) UNREACHABLE(); #endif return make_sp>>(OBJ_GET(Type, type), _value); } template - inline PyVar new_object(const PyVar& type, T&& _value) { + inline PyObject* new_object(PyObject* type, T&& _value) { #if PK_EXTRA_CHECK if(!is_type(type, tp_type)) UNREACHABLE(); #endif @@ -224,16 +229,16 @@ public: } template - inline PyVar new_object(Type type, const T& _value) { + inline PyObject* new_object(Type type, const T& _value) { return make_sp>>(type, _value); } template - inline PyVar new_object(Type type, T&& _value) { + inline PyObject* new_object(Type type, T&& _value) { return make_sp>>(type, std::move(_value)); } - PyVar _find_type(const Str& type){ - PyVar* obj = builtins->attr().try_get(type); + PyObject* _find_type(const Str& type){ + PyObject** obj = builtins->attr().try_get(type); if(!obj){ for(auto& t: _all_types) if(t.name == type) return t.obj; throw std::runtime_error("type not found: " + type); @@ -282,12 +287,12 @@ public: Type tp_super, tp_exception, tp_star_wrapper; template - inline PyVar PyIter(P&& value) { + inline PyObject* PyIter(P&& value) { static_assert(std::is_base_of_v>); return new_object(tp_native_iterator, std::forward

(value)); } - inline BaseIter* PyIter_AS_C(const PyVar& obj) + inline BaseIter* PyIter_AS_C(PyObject* obj) { check_type(obj, tp_native_iterator); return static_cast(obj->value()); @@ -313,22 +318,22 @@ public: void ValueError(const Str& msg){ _error("ValueError", msg); } void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); } - void AttributeError(PyVar obj, StrName name){ + void AttributeError(PyObject* obj, StrName name){ _error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true)); } void AttributeError(Str msg){ _error("AttributeError", msg); } - inline void check_type(const PyVar& obj, Type type){ + inline void check_type(PyObject* obj, Type type){ if(is_type(obj, type)) return; TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true)); } - inline PyVar& _t(Type t){ + inline PyObject* _t(Type t){ return _all_types[t.index].obj; } - inline PyVar& _t(const PyVar& obj){ + inline PyObject* _t(PyObject* obj){ if(is_int(obj)) return _t(tp_int); if(is_float(obj)) return _t(tp_float); return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj; @@ -341,42 +346,34 @@ public: } } - inline PyVarOrNull getattr(const PyVar& obj, StrName name, bool throw_err=true, bool class_only=false){ - return getattr(&obj, name, throw_err, class_only); - } - template - inline void setattr(PyVar& obj, StrName name, T&& value){ - setattr(&obj, name, std::forward(value)); - } - CodeObject_ compile(Str source, Str filename, CompileMode mode); void post_init(); - PyVar num_negated(const PyVar& obj); - f64 num_to_float(const PyVar& obj); - const PyVar& asBool(const PyVar& obj); - i64 hash(const PyVar& obj); - PyVar asRepr(const PyVar& obj); - PyVar new_module(StrName name); + PyObject* num_negated(PyObject* obj); + f64 num_to_float(PyObject* obj); + PyObject* asBool(PyObject* obj); + i64 hash(PyObject* obj); + PyObject* asRepr(PyObject* obj); + PyObject* new_module(StrName name); Str disassemble(CodeObject_ co); void init_builtin_types(); - PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall); + PyObject* call(PyObject* _callable, Args args, const Args& kwargs, bool opCall); void unpack_args(Args& args); - PyVarOrNull getattr(const PyVar* obj, StrName name, bool throw_err=true, bool class_only=false); + PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true, bool class_only=false); template - void setattr(PyVar* obj, StrName name, T&& value); + void setattr(PyObject* obj, StrName name, T&& value); template - void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn); + void bind_method(PyObject* obj, Str funcName, NativeFuncRaw fn); template - void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn); + void bind_func(PyObject* obj, Str funcName, NativeFuncRaw fn); void _error(Exception e); - PyVar _exec(); + PyObject* _exec(); template PyVarRef PyRef(P&& value); - const BaseRef* PyRef_AS_C(const PyVar& obj); + const BaseRef* PyRef_AS_C(PyObject* obj); }; -PyVar NativeFunc::operator()(VM* vm, Args& args) const{ +PyObject* NativeFunc::operator()(VM* vm, Args& args) const{ int args_size = args.size() - (int)method; // remove self if(argc != -1 && args_size != argc) { vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size)); @@ -437,11 +434,11 @@ DEF_NATIVE_2(Exception, tp_exception) DEF_NATIVE_2(StarWrapper, tp_star_wrapper) #define PY_CAST_INT(T) \ -template<> T py_cast(VM* vm, const PyVar& obj){ \ +template<> T py_cast(VM* vm, PyObject* obj){ \ vm->check_type(obj, vm->tp_int); \ return (T)(obj.bits >> 2); \ } \ -template<> T _py_cast(VM* vm, const PyVar& obj){ \ +template<> T _py_cast(VM* vm, PyObject* obj){ \ return (T)(obj.bits >> 2); \ } @@ -457,38 +454,38 @@ PY_CAST_INT(unsigned long) PY_CAST_INT(unsigned long long) -template<> float py_cast(VM* vm, const PyVar& obj){ +template<> float py_cast(VM* vm, PyObject* obj){ vm->check_type(obj, vm->tp_float); i64 bits = obj.bits; bits = (bits >> 2) << 2; return __8B(bits)._float; } -template<> float _py_cast(VM* vm, const PyVar& obj){ +template<> float _py_cast(VM* vm, PyObject* obj){ i64 bits = obj.bits; bits = (bits >> 2) << 2; return __8B(bits)._float; } -template<> double py_cast(VM* vm, const PyVar& obj){ +template<> double py_cast(VM* vm, PyObject* obj){ vm->check_type(obj, vm->tp_float); i64 bits = obj.bits; bits = (bits >> 2) << 2; return __8B(bits)._float; } -template<> double _py_cast(VM* vm, const PyVar& obj){ +template<> double _py_cast(VM* vm, PyObject* obj){ i64 bits = obj.bits; bits = (bits >> 2) << 2; return __8B(bits)._float; } -#define PY_VAR_INT(T) \ - PyVar py_var(VM* vm, T _val){ \ - i64 val = static_cast(_val); \ - if(((val << 2) >> 2) != val){ \ +#define PY_VAR_INT(T) \ + PyObject* py_var(VM* vm, T _val){ \ + i64 val = static_cast(_val); \ + if(((val << 2) >> 2) != val){ \ vm->_error("OverflowError", std::to_string(val) + " is out of range"); \ } \ val = (val << 2) | 0b01; \ - return PyVar(reinterpret_cast(val)); \ + return reinterpret_cast(val); \ } PY_VAR_INT(char) @@ -502,44 +499,44 @@ PY_VAR_INT(unsigned int) PY_VAR_INT(unsigned long) PY_VAR_INT(unsigned long long) -#define PY_VAR_FLOAT(T) \ - PyVar py_var(VM* vm, T _val){ \ - f64 val = static_cast(_val); \ - i64 bits = __8B(val)._int; \ - bits = (bits >> 2) << 2; \ - bits |= 0b10; \ - return PyVar(reinterpret_cast(bits)); \ +#define PY_VAR_FLOAT(T) \ + PyObject* py_var(VM* vm, T _val){ \ + f64 val = static_cast(_val); \ + i64 bits = __8B(val)._int; \ + bits = (bits >> 2) << 2; \ + bits |= 0b10; \ + return reinterpret_cast(bits); \ } PY_VAR_FLOAT(float) PY_VAR_FLOAT(double) -const PyVar& py_var(VM* vm, bool val){ +PyObject* py_var(VM* vm, bool val){ return val ? vm->True : vm->False; } -template<> bool py_cast(VM* vm, const PyVar& obj){ +template<> bool py_cast(VM* vm, PyObject* obj){ vm->check_type(obj, vm->tp_bool); return obj == vm->True; } -template<> bool _py_cast(VM* vm, const PyVar& obj){ +template<> bool _py_cast(VM* vm, PyObject* obj){ return obj == vm->True; } -PyVar py_var(VM* vm, const char val[]){ +PyObject* py_var(VM* vm, const char val[]){ return VAR(Str(val)); } -PyVar py_var(VM* vm, std::string val){ +PyObject* py_var(VM* vm, std::string val){ return VAR(Str(std::move(val))); } template -void _check_py_class(VM* vm, const PyVar& obj){ +void _check_py_class(VM* vm, PyObject* obj){ vm->check_type(obj, T::_type(vm)); } -PyVar VM::num_negated(const PyVar& obj){ +PyObject* VM::num_negated(PyObject* obj){ if (is_int(obj)){ return VAR(-CAST(i64, obj)); }else if(is_float(obj)){ @@ -549,7 +546,7 @@ PyVar VM::num_negated(const PyVar& obj){ return nullptr; } -f64 VM::num_to_float(const PyVar& obj){ +f64 VM::num_to_float(PyObject* obj){ if(is_float(obj)){ return CAST(f64, obj); } else if (is_int(obj)){ @@ -559,20 +556,20 @@ f64 VM::num_to_float(const PyVar& obj){ return 0; } -const PyVar& VM::asBool(const PyVar& obj){ +PyObject* VM::asBool(PyObject* obj){ if(is_type(obj, tp_bool)) return obj; if(obj == None) return False; if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0); if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0); PyVarOrNull len_fn = getattr(obj, __len__, false, true); if(len_fn != nullptr){ - PyVar ret = call(len_fn); + PyObject* ret = call(len_fn); return VAR(CAST(i64, ret) > 0); } return True; } -i64 VM::hash(const PyVar& obj){ +i64 VM::hash(PyObject* obj){ if (is_type(obj, tp_str)) return CAST(Str&, obj).hash(); if (is_int(obj)) return CAST(i64, obj); if (is_type(obj, tp_tuple)) { @@ -594,12 +591,12 @@ i64 VM::hash(const PyVar& obj){ return 0; } -PyVar VM::asRepr(const PyVar& obj){ +PyObject* VM::asRepr(PyObject* obj){ return call(obj, __repr__); } -PyVar VM::new_module(StrName name) { - PyVar obj = new_object(tp_module, DummyModule()); +PyObject* VM::new_module(StrName name) { + PyObject* obj = new_object(tp_module, DummyModule()); obj->attr().set(__name__, VAR(name.str())); _modules.set(name, obj); return obj; @@ -665,7 +662,7 @@ Str VM::disassemble(CodeObject_ co){ ss << '\n' << consts.str() << '\n' << names.str() << '\n'; for(int i=0; iconsts.size(); i++){ - PyVar obj = co->consts[i]; + PyObject* obj = co->consts[i]; if(is_type(obj, tp_function)){ const auto& f = CAST(Function&, obj); ss << disassemble(f.code); @@ -731,10 +728,10 @@ void VM::init_builtin_types(){ for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash(); } -PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){ - if(is_type(_callable, tp_type)){ - PyVar* new_f = _callable->attr().try_get(__new__); - PyVar obj; +PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCall){ + if(is_type(callable, tp_type)){ + PyObject** new_f = callable->attr().try_get(__new__); + PyObject* obj; if(new_f != nullptr){ obj = call(*new_f, std::move(args), kwargs, false); }else{ @@ -745,19 +742,18 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal return obj; } - const PyVar* callable = &_callable; - if(is_type(*callable, tp_bound_method)){ - auto& bm = CAST(BoundMethod&, *callable); - callable = &bm.method; // get unbound method + if(is_type(callable, tp_bound_method)){ + auto& bm = CAST(BoundMethod&, callable); + callable = bm.method; // get unbound method args.extend_self(bm.obj); } - if(is_type(*callable, tp_native_function)){ - const auto& f = OBJ_GET(NativeFunc, *callable); + if(is_type(callable, tp_native_function)){ + const auto& f = OBJ_GET(NativeFunc, callable); if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments"); return f(this, args); - } else if(is_type(*callable, tp_function)){ - const Function& fn = CAST(Function&, *callable); + } else if(is_type(callable, tp_function)){ + const Function& fn = CAST(Function&, callable); NameDict_ locals = make_sp( fn.code->perfect_locals_capacity, kLocalsLoadFactor, @@ -797,7 +793,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal } locals->set(key, kwargs[i+1]); } - const PyVar& _module = fn._module != nullptr ? fn._module : top_frame()->_module; + PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module; auto _frame = _new_frame(fn.code, _module, locals, fn._closure); if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame))); callstack.push(std::move(_frame)); @@ -819,7 +815,7 @@ void VM::unpack_args(Args& args){ if(is_type(args[i], tp_star_wrapper)){ auto& star = _CAST(StarWrapper&, args[i]); if(!star.rvalue) UNREACHABLE(); - PyVar list = asList(star.obj); + PyObject* list = asList(star.obj); List& list_c = CAST(List&, list); unpacked.insert(unpacked.end(), list_c.begin(), list_c.end()); }else{ @@ -829,25 +825,25 @@ void VM::unpack_args(Args& args){ args = Args::from_list(std::move(unpacked)); } -using Super = std::pair; +using Super = std::pair; // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance -PyVarOrNull VM::getattr(const PyVar* obj, StrName name, bool throw_err, bool class_only){ +PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){ PyObject* objtype = _t(*obj).get(); if(is_type(*obj, tp_super)){ const Super& super = OBJ_GET(Super, *obj); obj = &super.first; objtype = _t(super.second).get(); } - PyVar* cls_var = find_name_in_mro(objtype, name); + PyObject** cls_var = find_name_in_mro(objtype, name); if(cls_var != nullptr){ // handle descriptor - PyVar* descr_get = _t(*cls_var)->attr().try_get(__get__); + PyObject** descr_get = _t(*cls_var)->attr().try_get(__get__); if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj)); } // handle instance __dict__ if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){ - PyVar* val = (*obj)->attr().try_get(name); + PyObject** val = (*obj)->attr().try_get(name); if(val != nullptr) return *val; } if(cls_var != nullptr){ @@ -862,22 +858,22 @@ PyVarOrNull VM::getattr(const PyVar* obj, StrName name, bool throw_err, bool cla } template -void VM::setattr(PyVar* obj, StrName name, T&& value){ +void VM::setattr(PyObject* obj, StrName name, T&& value){ static_assert(std::is_same_v, PyVar>); - PyObject* objtype = _t(*obj).get(); - if(is_type(*obj, tp_super)){ + PyObject* objtype = _t(obj).get(); + if(is_type(obj, tp_super)){ Super& super = OBJ_GET(Super, *obj); - obj = &super.first; + obj = super.first; objtype = _t(super.second).get(); } - PyVar* cls_var = find_name_in_mro(objtype, name); + PyObject** cls_var = find_name_in_mro(objtype, name); if(cls_var != nullptr){ // handle descriptor - const PyVar& cls_var_t = _t(*cls_var); + PyObject* cls_var_t = _t(*cls_var); if(cls_var_t->attr().contains(__get__)){ - PyVar* descr_set = cls_var_t->attr().try_get(__set__); + PyObject** descr_set = cls_var_t->attr().try_get(__set__); if(descr_set != nullptr){ - call(*descr_set, three_args(*cls_var, *obj, std::forward(value))); + call(*descr_set, three_args(*cls_var, obj, std::forward(value))); }else{ TypeError("readonly attribute: " + name.str().escape(true)); } @@ -885,18 +881,18 @@ void VM::setattr(PyVar* obj, StrName name, T&& value){ } } // handle instance __dict__ - if((*obj).is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute"); - (*obj)->attr().set(name, std::forward(value)); + if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute"); + obj->attr().set(name, std::forward(value)); } template -void VM::bind_method(PyVar obj, Str name, NativeFuncRaw fn) { +void VM::bind_method(PyObject* obj, Str name, NativeFuncRaw fn) { check_type(obj, tp_type); obj->attr().set(name, VAR(NativeFunc(fn, ARGC, true))); } template -void VM::bind_func(PyVar obj, Str name, NativeFuncRaw fn) { +void VM::bind_func(PyObject* obj, Str name, NativeFuncRaw fn) { obj->attr().set(name, VAR(NativeFunc(fn, ARGC, false))); } @@ -909,10 +905,10 @@ void VM::_error(Exception e){ _raise(); } -PyVar VM::_exec(){ +PyObject* VM::_exec(){ Frame* frame = top_frame(); i64 base_id = frame->id; - PyVar ret = nullptr; + PyObject* ret = nullptr; bool need_raise = false; while(true){ @@ -936,7 +932,7 @@ PyVar VM::_exec(){ }catch(HandledException& e){ continue; }catch(UnhandledException& e){ - PyVar obj = frame->pop(); + PyObject* obj = frame->pop(); Exception& _e = CAST(Exception&, obj); _e.st_push(frame->snapshot()); callstack.pop();