diff --git a/src/ceval.h b/src/ceval.h index 2eaed684..643d5042 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -7,7 +7,7 @@ namespace pkpy{ Str _read_file_cwd(const Str& name, bool* ok); -PyVar VM::run_frame(Frame* frame){ +PyObject* VM::run_frame(Frame* frame){ while(frame->has_next_bytecode()){ const Bytecode& byte = frame->next_bytecode(); switch (byte.op) @@ -16,7 +16,7 @@ PyVar VM::run_frame(Frame* frame){ case OP_SETUP_DECORATOR: continue; case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue; case OP_LOAD_FUNCTION: { - const PyVar obj = frame->co->consts[byte.arg]; + PyObject* obj = frame->co->consts[byte.arg]; Function f = CAST(Function, obj); // copy f._module = frame->_module; frame->push(VAR(f)); @@ -37,13 +37,13 @@ PyVar VM::run_frame(Frame* frame){ } continue; case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: { auto& attr = frame->co->names[byte.arg]; - PyVar obj = frame->pop_value(this); + PyObject* obj = frame->pop_value(this); AttrRef ref = AttrRef(obj, NameRef(attr)); if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame)); else frame->push(PyRef(ref)); } continue; case OP_BUILD_INDEX: { - PyVar index = frame->pop_value(this); + PyObject* index = frame->pop_value(this); auto ref = IndexRef(frame->pop_value(this), index); if(byte.arg > 0) frame->push(ref.get(this, frame)); else frame->push(PyRef(ref)); @@ -57,9 +57,6 @@ PyVar VM::run_frame(Frame* frame){ } continue; case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue; case OP_STORE_REF: { - // PyVar obj = frame->pop_value(this); - // PyVarRef r = frame->pop(); - // PyRef_AS_C(r)->set(this, frame, std::move(obj)); PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this)); frame->_pop(); frame->_pop(); } continue; @@ -84,25 +81,25 @@ PyVar VM::run_frame(Frame* frame){ case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue; case OP_BEGIN_CLASS: { auto& name = frame->co->names[byte.arg]; - PyVar clsBase = frame->pop_value(this); + PyObject* clsBase = frame->pop_value(this); if(clsBase == None) clsBase = _t(tp_object); check_type(clsBase, tp_type); - PyVar cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase)); + PyObject* cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase)); frame->push(cls); } continue; case OP_END_CLASS: { - PyVar cls = frame->pop(); + PyObject* cls = frame->pop(); cls->attr()._try_perfect_rehash(); }; continue; case OP_STORE_CLASS_ATTR: { auto& name = frame->co->names[byte.arg]; - PyVar obj = frame->pop_value(this); - PyVar& cls = frame->top(); + PyObject* obj = frame->pop_value(this); + PyObject* cls = frame->top(); cls->attr().set(name.first, std::move(obj)); } continue; case OP_RETURN_VALUE: return frame->pop_value(this); case OP_PRINT_EXPR: { - const PyVar expr = frame->top_value(this); + PyObject* expr = frame->top_value(this); if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n'; } continue; case OP_POP_TOP: frame->_pop(); continue; @@ -122,7 +119,7 @@ PyVar VM::run_frame(Frame* frame){ Args args(2); args[1] = frame->pop(); args[0] = frame->top_value(this); - PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); + PyObject* ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); PyRef_AS_C(frame->top())->set(this, frame, std::move(ret)); frame->_pop(); } continue; @@ -130,7 +127,7 @@ PyVar VM::run_frame(Frame* frame){ Args args(2); args[1] = frame->pop_value(this); args[0] = frame->top_value(this); - PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args)); + PyObject* ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args)); PyRef_AS_C(frame->top())->set(this, frame, std::move(ret)); frame->_pop(); } continue; @@ -141,14 +138,14 @@ PyVar VM::run_frame(Frame* frame){ frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args)); } continue; case OP_IS_OP: { - PyVar rhs = frame->pop_value(this); + PyObject* rhs = frame->pop_value(this); bool ret_c = rhs == frame->top_value(this); if(byte.arg == 1) ret_c = !ret_c; frame->top() = VAR(ret_c); } continue; case OP_CONTAINS_OP: { - PyVar rhs = frame->pop_value(this); - bool ret_c = CAST(bool, call(rhs, __contains__, one_arg(frame->pop_value(this)))); + PyObject* rhs = frame->pop_value(this); + bool ret_c = CAST(bool, call(rhs, __contains__, Args{frame->pop_value(this)})); if(byte.arg == 1) ret_c = !ret_c; frame->push(VAR(ret_c)); } continue; @@ -156,8 +153,8 @@ PyVar VM::run_frame(Frame* frame){ frame->top() = num_negated(frame->top_value(this)); continue; case OP_UNARY_NOT: { - PyVar obj = frame->pop_value(this); - const PyVar& obj_bool = asBool(obj); + PyObject* obj = frame->pop_value(this); + PyObject* obj_bool = asBool(obj); frame->push(VAR(!_CAST(bool, obj_bool))); } continue; case OP_POP_JUMP_IF_FALSE: @@ -168,9 +165,9 @@ PyVar VM::run_frame(Frame* frame){ case OP_LOAD_FALSE: frame->push(False); continue; case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue; case OP_ASSERT: { - PyVar _msg = frame->pop_value(this); + PyObject* _msg = frame->pop_value(this); Str msg = CAST(Str, asStr(_msg)); - PyVar expr = frame->pop_value(this); + PyObject* expr = frame->pop_value(this); if(asBool(expr) != True) _error("AssertionError", msg); } continue; case OP_EXCEPTION_MATCH: { @@ -179,7 +176,7 @@ PyVar VM::run_frame(Frame* frame){ frame->push(VAR(e.match_type(name))); } continue; case OP_RAISE: { - PyVar obj = frame->pop_value(this); + PyObject* obj = frame->pop_value(this); Str msg = obj == None ? "" : CAST(Str, asStr(obj)); StrName type = frame->co->names[byte.arg].first; _error(type, msg); @@ -190,32 +187,32 @@ PyVar VM::run_frame(Frame* frame){ continue; case OP_BUILD_MAP: { Args items = frame->pop_n_values_reversed(this, byte.arg*2); - PyVar obj = call(builtins->attr("dict")); + PyObject* obj = call(builtins->attr("dict")); for(int i=0; ipush(obj); } continue; case OP_BUILD_SET: { - PyVar list = VAR( + PyObject* list = VAR( frame->pop_n_values_reversed(this, byte.arg).move_to_list() ); - PyVar obj = call(builtins->attr("set"), one_arg(list)); + PyObject* obj = call(builtins->attr("set"), Args{list}); frame->push(obj); } continue; case OP_LIST_APPEND: { - PyVar obj = frame->pop_value(this); + PyObject* obj = frame->pop_value(this); List& list = CAST(List&, frame->top_1()); list.push_back(std::move(obj)); } continue; case OP_MAP_ADD: { - PyVar value = frame->pop_value(this); - PyVar key = frame->pop_value(this); - call(frame->top_1(), __setitem__, two_args(key, value)); + PyObject* value = frame->pop_value(this); + PyObject* key = frame->pop_value(this); + call(frame->top_1(), __setitem__, Args{key, value}); } continue; case OP_SET_ADD: { - PyVar obj = frame->pop_value(this); - call(frame->top_1(), "add", one_arg(obj)); + PyObject* obj = frame->pop_value(this); + call(frame->top_1(), "add", Args{obj}); } continue; case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue; case OP_UNARY_STAR: { @@ -232,16 +229,16 @@ PyVar VM::run_frame(Frame* frame){ Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2); Args args = frame->pop_n_values_reversed(this, ARGC); if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args); - PyVar callable = frame->pop_value(this); - PyVar ret = call(callable, std::move(args), kwargs, true); + PyObject* callable = frame->pop_value(this); + PyObject* ret = call(callable, std::move(args), kwargs, true); if(ret == _py_op_call) return ret; frame->push(std::move(ret)); } continue; case OP_CALL_UNPACK: case OP_CALL: { Args args = frame->pop_n_values_reversed(this, byte.arg); if(byte.op == OP_CALL_UNPACK) unpack_args(args); - PyVar callable = frame->pop_value(this); - PyVar ret = call(callable, std::move(args), no_arg(), true); + PyObject* callable = frame->pop_value(this); + PyObject* ret = call(callable, std::move(args), no_arg(), true); if(ret == _py_op_call) return ret; frame->push(std::move(ret)); } continue; @@ -254,15 +251,15 @@ PyVar VM::run_frame(Frame* frame){ frame->jump_abs_safe(it->second); } continue; case OP_GET_ITER: { - PyVar obj = frame->pop_value(this); - PyVar iter = asIter(obj); + PyObject* obj = frame->pop_value(this); + PyObject* iter = asIter(obj); check_type(frame->top(), tp_ref); PyIter_AS_C(iter)->loop_var = frame->pop(); frame->push(std::move(iter)); } continue; case OP_FOR_ITER: { BaseIter* it = PyIter_AS_C(frame->top()); - PyVar obj = it->next(); + PyObject* obj = it->next(); if(obj != nullptr){ PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj)); }else{ @@ -279,18 +276,18 @@ PyVar VM::run_frame(Frame* frame){ frame->jump_abs_safe(blockEnd); } continue; case OP_JUMP_IF_FALSE_OR_POP: { - const PyVar expr = frame->top_value(this); + PyObject* expr = frame->top_value(this); if(asBool(expr)==False) frame->jump_abs(byte.arg); else frame->pop_value(this); } continue; case OP_JUMP_IF_TRUE_OR_POP: { - const PyVar expr = frame->top_value(this); + PyObject* expr = frame->top_value(this); if(asBool(expr)==True) frame->jump_abs(byte.arg); else frame->pop_value(this); } continue; case OP_BUILD_SLICE: { - PyVar stop = frame->pop_value(this); - PyVar start = frame->pop_value(this); + PyObject* stop = frame->pop_value(this); + PyObject* start = frame->pop_value(this); Slice s; if(start != None) { s.start = CAST(int, start);} if(stop != None) { s.stop = CAST(int, stop);} @@ -298,7 +295,7 @@ PyVar VM::run_frame(Frame* frame){ } continue; case OP_IMPORT_NAME: { StrName name = frame->co->names[byte.arg].first; - PyVar* ext_mod = _modules.try_get(name); + PyObject** ext_mod = _modules.try_get(name); if(ext_mod == nullptr){ Str source; auto it2 = _lazy_modules.find(name); @@ -311,7 +308,7 @@ PyVar VM::run_frame(Frame* frame){ _lazy_modules.erase(it2); } CodeObject_ code = compile(source, name.str(), EXEC_MODE); - PyVar new_mod = new_module(name); + PyObject* new_mod = new_module(name); _exec(code, new_mod); frame->push(new_mod); new_mod->attr()._try_perfect_rehash(); @@ -320,7 +317,7 @@ PyVar VM::run_frame(Frame* frame){ } } continue; case OP_STORE_ALL_NAMES: { - PyVar obj = frame->pop_value(this); + PyObject* obj = frame->pop_value(this); for(auto& [name, value]: obj->attr().items()){ Str s = name.str(); if(s.empty() || s[0] == '_') continue; diff --git a/src/cffi.h b/src/cffi.h index de589893..3039ce9a 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -14,7 +14,7 @@ struct NativeProxyFunc { _Fp func; NativeProxyFunc(_Fp func) : func(func) {} - PyVar operator()(VM* vm, Args& args) { + PyObject* operator()(VM* vm, Args& args) { if (args.size() != N) { vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size())); } @@ -22,13 +22,13 @@ struct NativeProxyFunc { } template - std::enable_if_t, PyVar> call(VM* vm, Args& args, std::index_sequence) { + std::enable_if_t, PyObject*> call(VM* vm, Args& args, std::index_sequence) { func(py_cast(vm, args[Is])...); return vm->None; } template - std::enable_if_t, PyVar> call(VM* vm, Args& args, std::index_sequence) { + std::enable_if_t, PyObject*> call(VM* vm, Args& args, std::index_sequence) { __Ret ret = func(py_cast(vm, args[Is])...); return VAR(std::move(ret)); } @@ -41,7 +41,7 @@ struct NativeProxyMethod { _Fp func; NativeProxyMethod(_Fp func) : func(func) {} - PyVar operator()(VM* vm, Args& args) { + PyObject* operator()(VM* vm, Args& args) { int actual_size = args.size() - 1; if (actual_size != N) { vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size)); @@ -50,14 +50,14 @@ struct NativeProxyMethod { } template - std::enable_if_t, PyVar> call(VM* vm, Args& args, std::index_sequence) { + std::enable_if_t, PyObject*> call(VM* vm, Args& args, std::index_sequence) { T& self = py_cast(vm, args[0]); (self.*func)(py_cast(vm, args[Is+1])...); return vm->None; } template - std::enable_if_t, PyVar> call(VM* vm, Args& args, std::index_sequence) { + std::enable_if_t, PyObject*> call(VM* vm, Args& args, std::index_sequence) { T& self = py_cast(vm, args[0]); __Ret ret = (self.*func)(py_cast(vm, args[Is+1])...); return VAR(std::move(ret)); @@ -200,7 +200,7 @@ struct Pointer{ return Pointer(ctype, level, ptr-offset*unit_size()); } - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { @@ -268,7 +268,7 @@ struct Pointer{ template inline T& ref() noexcept { return *reinterpret_cast(ptr); } - PyVar get(VM* vm){ + PyObject* get(VM* vm){ if(level > 1) return VAR_T(Pointer, ctype, level-1, ref()); switch(ctype->index){ #define CASE(T) case type_index(): return VAR(ref()) @@ -291,7 +291,7 @@ struct Pointer{ return VAR_T(Pointer, *this); } - void set(VM* vm, const PyVar& val){ + void set(VM* vm, PyObject* val){ if(level > 1) { Pointer& p = CAST(Pointer&, val); ref() = p.ptr; // We don't check the type, just copy the underlying address @@ -359,7 +359,7 @@ struct Value { Value& operator=(const Value& other) = delete; Value(const Value& other) = delete; - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "ptr", [](VM* vm, Args& args) { @@ -388,7 +388,7 @@ struct CType{ CType() : type(_type_db.get()) {} CType(const TypeInfo* type) : type(type) {} - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) { const Str& name = CAST(Str&, args[0]); const TypeInfo* type = _type_db.get(name); @@ -404,8 +404,8 @@ struct CType{ }; void add_module_c(VM* vm){ - PyVar mod = vm->new_module("c"); - PyVar ptr_t = Pointer::register_class(vm, mod); + PyObject* mod = vm->new_module("c"); + PyObject* ptr_t = Pointer::register_class(vm, mod); Value::register_class(vm, mod); CType::register_class(vm, mod); @@ -462,11 +462,11 @@ void add_module_c(VM* vm){ }); } -PyVar py_var(VM* vm, void* p){ +PyObject* py_var(VM* vm, void* p){ return VAR_T(Pointer, _type_db.get(), (char*)p); } -PyVar py_var(VM* vm, char* p){ +PyObject* py_var(VM* vm, char* p){ return VAR_T(Pointer, _type_db.get(), (char*)p); } @@ -491,7 +491,7 @@ struct pointer { }; template -T py_pointer_cast(VM* vm, const PyVar& var){ +T py_pointer_cast(VM* vm, PyObject* var){ static_assert(std::is_pointer_v); Pointer& p = CAST(Pointer&, var); const TypeInfo* type = _type_db.get::baseT>(); @@ -503,14 +503,14 @@ T py_pointer_cast(VM* vm, const PyVar& var){ } template -T py_value_cast(VM* vm, const PyVar& var){ +T py_value_cast(VM* vm, PyObject* var){ static_assert(std::is_pod_v); Value& v = CAST(Value&, var); return *reinterpret_cast(v.data); } template -std::enable_if_t>, PyVar> +std::enable_if_t>, PyObject*> py_var(VM* vm, T p){ const TypeInfo* type = _type_db.get::baseT>(); if(type == nullptr) type = _type_db.get(); @@ -518,9 +518,9 @@ py_var(VM* vm, T p){ } template -std::enable_if_t>, PyVar> +std::enable_if_t>, PyObject*> py_var(VM* vm, T p){ - if constexpr(std::is_same_v) return p; + if constexpr(std::is_same_v) return p; const TypeInfo* type = _type_db.get(); return VAR_T(Value, type, &p); } diff --git a/src/codeobject.h b/src/codeobject.h index 97ad83b7..27981b72 100644 --- a/src/codeobject.h +++ b/src/codeobject.h @@ -94,7 +94,7 @@ struct CodeObject { return names.size() - 1; } - int add_const(PyVar v){ + int add_const(PyObject* v){ consts.push_back(v); return consts.size() - 1; } diff --git a/src/common.h b/src/common.h index 01a3609e..1cce45e6 100644 --- a/src/common.h +++ b/src/common.h @@ -57,7 +57,6 @@ namespace std = ::std; struct Dummy { }; struct DummyInstance { }; struct DummyModule { }; -#define DUMMY_VAL Dummy() struct Type { int index; @@ -85,4 +84,24 @@ struct Type { const float kLocalsLoadFactor = 0.67f; const float kInstAttrLoadFactor = 0.67f; const float kTypeAttrLoadFactor = 0.5f; + +static_assert(sizeof(i64) == sizeof(int*)); +static_assert(sizeof(f64) == sizeof(int*)); +static_assert(std::numeric_limits::is_iec559); +static_assert(std::numeric_limits::is_iec559); + +struct PyObject; +#define BITS(p) (reinterpret_cast(p)) +inline bool is_tagged(PyObject* p) noexcept { return (BITS(p) & 0b11) != 0b00; } +inline bool is_int(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b01; } +inline bool is_float(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b10; } + +inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept { + return is_tagged(a) && is_tagged(b); +} + +inline bool is_both_int(PyObject* a, PyObject* b) noexcept { + return is_int(a) && is_int(b); +} + } // namespace pkpy \ No newline at end of file diff --git a/src/compiler.h b/src/compiler.h index 3312d5be..0e6a5bb8 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -353,14 +353,14 @@ private: } void exprLiteral() { - PyVar value = parser->prev.value; + PyObject* value = parser->prev.value; int index = co()->add_const(value); emit(OP_LOAD_CONST, index); } void exprFString() { static const std::regex pattern(R"(\{(.*?)\})"); - PyVar value = parser->prev.value; + PyObject* value = parser->prev.value; Str s = CAST(Str, value); std::sregex_iterator begin(s.begin(), s.end(), pattern); std::sregex_iterator end; @@ -1059,7 +1059,7 @@ private: case 1: func.starred_arg = name; state+=1; break; case 2: { consume(TK("=")); - PyVarOrNull value = read_literal(); + PyObject* value = read_literal(); if(value == nullptr){ SyntaxError(Str("expect a literal, not ") + TK_STR(parser->curr.type)); } @@ -1115,10 +1115,10 @@ private: } } - PyVarOrNull read_literal(){ + PyObject* read_literal(){ if(match(TK("-"))){ consume(TK("@num")); - PyVar val = parser->prev.value; + PyObject* val = parser->prev.value; return vm->num_negated(val); } if(match(TK("@num"))) return parser->prev.value; @@ -1166,7 +1166,7 @@ public: code->optimize(vm); return code; }else if(mode()==JSON_MODE){ - PyVarOrNull value = read_literal(); + PyObject* value = read_literal(); if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value)); else if(match(TK("{"))) exprMap(); else if(match(TK("["))) exprList(); diff --git a/src/frame.h b/src/frame.h index 4b456d33..850cc6f8 100644 --- a/src/frame.h +++ b/src/frame.h @@ -7,27 +7,27 @@ namespace pkpy{ static THREAD_LOCAL uint64_t kFrameGlobalId = 0; struct Frame { - std::vector _data; + std::vector _data; int _ip = -1; int _next_ip = 0; const CodeObject* co; - PyVar _module; + PyObject* _module; NameDict_ _locals; NameDict_ _closure; const uint64_t id; - std::vector>> s_try_block; + std::vector>> s_try_block; inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); } inline NameDict& f_globals() noexcept { return _module->attr(); } - inline PyVar* f_closure_try_get(StrName name) noexcept { + inline PyObject** f_closure_try_get(StrName name) noexcept { if(_closure == nullptr) return nullptr; return _closure->try_get(name); } Frame(const CodeObject_& co, - const PyVar& _module, + PyObject* _module, const NameDict_& _locals=nullptr, const NameDict_& _closure=nullptr) : co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { } @@ -57,11 +57,11 @@ struct Frame { return _next_ip < co->codes.size(); } - inline PyVar pop(){ + inline PyObject* pop(){ #if PK_EXTRA_CHECK if(_data.empty()) throw std::runtime_error("_data.empty() is true"); #endif - PyVar v = std::move(_data.back()); + PyObject* v = _data.back(); _data.pop_back(); return v; } @@ -73,28 +73,28 @@ struct Frame { _data.pop_back(); } - inline void try_deref(VM*, PyVar&); + inline void try_deref(VM*, PyObject*&); - inline PyVar pop_value(VM* vm){ - PyVar value = pop(); + inline PyObject* pop_value(VM* vm){ + PyObject* value = pop(); try_deref(vm, value); return value; } - inline PyVar top_value(VM* vm){ - PyVar value = top(); + inline PyObject* top_value(VM* vm){ + PyObject* value = top(); try_deref(vm, value); return value; } - inline PyVar& top(){ + inline PyObject*& top(){ #if PK_EXTRA_CHECK if(_data.empty()) throw std::runtime_error("_data.empty() is true"); #endif return _data.back(); } - inline PyVar& top_1(){ + inline PyObject*& top_1(){ #if PK_EXTRA_CHECK if(_data.size() < 2) throw std::runtime_error("_data.size() < 2"); #endif @@ -117,7 +117,7 @@ struct Frame { bool jump_to_exception_handler(){ if(s_try_block.empty()) return false; - PyVar obj = pop(); + PyObject* obj = pop(); auto& p = s_try_block.back(); _data = std::move(p.second); _data.push_back(obj); diff --git a/src/gc.h b/src/gc.h index 3081b259..ce85395e 100644 --- a/src/gc.h +++ b/src/gc.h @@ -3,49 +3,38 @@ #include "obj.h" namespace pkpy { - using PyVar0 = PyObject*; + struct ManagedHeap{ + std::vector heap; - // 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); + template + PyObject* gcnew(Type type, T&& val){ + PyObject* obj = new Py_>(type, std::forward(val)); + obj->gc.enabled = true; + heap.push_back(obj); + return 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]; - } + void sweep(){ + std::vector alive; + for(PyObject* obj: heap){ + if(obj->gc.marked){ + obj->gc.marked = false; + alive.push_back(obj); + }else{ + delete obj; } - 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); } + heap.clear(); + heap.swap(alive); } - void collect(int index){ - sweep(index); + void collect(VM* vm){ + std::vector roots = get_roots(vm); + for(PyObject* obj: roots) obj->mark(); + sweep(); } + + std::vector get_roots(VM* vm); }; } // namespace pkpy \ No newline at end of file diff --git a/src/io.h b/src/io.h index 549a9c6c..6ee42756 100644 --- a/src/io.h +++ b/src/io.h @@ -42,7 +42,7 @@ struct FileIO { if(!_fs.is_open()) vm->IOError(strerror(errno)); } - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){ return VAR_T(FileIO, vm, CAST(Str, args[0]), CAST(Str, args[1]) @@ -79,15 +79,15 @@ struct FileIO { }; void add_module_io(VM* vm){ - PyVar mod = vm->new_module("io"); - PyVar type = FileIO::register_class(vm, mod); + PyObject* mod = vm->new_module("io"); + PyObject* type = FileIO::register_class(vm, mod); vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){ return vm->call(type, args); }); } void add_module_os(VM* vm){ - PyVar mod = vm->new_module("os"); + PyObject* mod = vm->new_module("os"); // Working directory is shared by all VMs!! vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){ return VAR(std::filesystem::current_path().string()); diff --git a/src/iter.h b/src/iter.h index 293602b4..1ebdbdb6 100644 --- a/src/iter.h +++ b/src/iter.h @@ -8,7 +8,7 @@ class RangeIter : public BaseIter { i64 current; Range r; public: - RangeIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { + RangeIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) { this->r = OBJ_GET(Range, _ref); this->current = r.start; } @@ -17,7 +17,7 @@ public: return r.step > 0 ? current < r.stop : current > r.stop; } - PyVar next(){ + PyObject* next(){ if(!_has_next()) return nullptr; current += r.step; return VAR(current-r.step); @@ -29,8 +29,8 @@ class ArrayIter : public BaseIter { size_t index = 0; const T* p; public: - ArrayIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);} - PyVar next(){ + ArrayIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);} + PyObject* next(){ if(index == p->size()) return nullptr; return p->operator[](index++); } @@ -40,20 +40,20 @@ class StringIter : public BaseIter { int index = 0; Str* str; public: - StringIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { + StringIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) { str = &OBJ_GET(Str, _ref); } - PyVar next() { + PyObject* next() { if(index == str->u8_length()) return nullptr; return VAR(str->u8_getitem(index++)); } }; -PyVar Generator::next(){ +PyObject* Generator::next(){ if(state == 2) return nullptr; vm->callstack.push(std::move(frame)); - PyVar ret = vm->_exec(); + PyObject* ret = vm->_exec(); if(ret == vm->_py_op_yield){ frame = std::move(vm->callstack.top()); vm->callstack.pop(); diff --git a/src/main.cpp b/src/main.cpp index 432cef8a..7ac4146f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,7 +75,7 @@ int main(int argc, char** argv){ // set parent path as cwd std::filesystem::current_path(filepath.parent_path()); - pkpy::PyVarOrNull ret = nullptr; + pkpy::PyObject* ret = nullptr; ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE); pkpy_delete(vm); return ret != nullptr ? 0 : 1; diff --git a/src/memory.h b/src/memory.h index 2e446528..404a423b 100644 --- a/src/memory.h +++ b/src/memory.h @@ -4,31 +4,12 @@ namespace pkpy{ -struct PyObject; - -template -struct SpAllocator { - template - inline static int* alloc(){ - return (int*)malloc(sizeof(int) + sizeof(U)); - } - - inline static void dealloc(int* counter){ - ((T*)(counter + 1))->~T(); - free(counter); - } -}; - template struct shared_ptr { - union { - int* counter; - i64 bits; - }; - + int* counter; #define _t() (T*)(counter + 1) -#define _inc_counter() if(!is_tagged() && counter) ++(*counter) -#define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator::dealloc(counter) +#define _inc_counter() if(counter) ++(*counter) +#define _dec_counter() if(counter && --(*counter) == 0) {((T*)(counter + 1))->~T(); free(counter);} public: shared_ptr() : counter(nullptr) {} @@ -69,7 +50,6 @@ public: T* get() const { return _t(); } int use_count() const { - if(is_tagged()) return 0; return counter ? *counter : 0; } @@ -77,44 +57,20 @@ public: _dec_counter(); counter = nullptr; } - - inline constexpr bool is_tagged() const { - if constexpr(!std::is_same_v) return false; - return (bits & 0b11) != 0b00; - } - inline bool is_tag_00() const { return (bits & 0b11) == 0b00; } - inline bool is_tag_01() const { return (bits & 0b11) == 0b01; } - inline bool is_tag_10() const { return (bits & 0b11) == 0b10; } - inline bool is_tag_11() const { return (bits & 0b11) == 0b11; } }; #undef _t #undef _inc_counter #undef _dec_counter - template - shared_ptr make_sp(Args&&... args) { - static_assert(std::is_base_of_v, "U must be derived from T"); - static_assert(std::has_virtual_destructor_v, "T must have virtual destructor"); - static_assert(!std::is_same_v || (!std::is_same_v && !std::is_same_v)); - int* p = SpAllocator::template alloc(); *p = 1; - new(p+1) U(std::forward(args)...); - return shared_ptr(p); - } - template shared_ptr make_sp(Args&&... args) { - int* p = SpAllocator::template alloc(); *p = 1; + int* p = (int*)malloc(sizeof(int) + sizeof(T)); + *p = 1; new(p+1) T(std::forward(args)...); return shared_ptr(p); } -static_assert(sizeof(i64) == sizeof(int*)); -static_assert(sizeof(f64) == sizeof(int*)); -static_assert(sizeof(shared_ptr) == sizeof(int*)); -static_assert(std::numeric_limits::is_iec559); -static_assert(std::numeric_limits::is_iec559); - template struct SmallArrayPool { std::vector buckets[__Bucket+1]; @@ -145,10 +101,4 @@ struct SmallArrayPool { } } }; - - -typedef shared_ptr PyVar; -typedef PyVar PyVarOrNull; -typedef PyVar PyVarRef; - }; // namespace pkpy diff --git a/src/namedict.h b/src/namedict.h index 90f8d34a..22d6b783 100644 --- a/src/namedict.h +++ b/src/namedict.h @@ -6,7 +6,7 @@ namespace pkpy{ -const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyVar); +const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyObject*); template struct DictArrayPool { @@ -26,9 +26,7 @@ struct DictArrayPool { } void dealloc(StrName* head, uint16_t n){ - PyVar* _values = (PyVar*)(head + n); if(n > __Bucket || buckets[n].size() >= __BucketSize){ - for(int i=0; i(_keys + _capacity)[i]; + inline PyObject*& value(uint16_t i){ + return reinterpret_cast(_keys + _capacity)[i]; } - inline const PyVar& value(uint16_t i) const { - return reinterpret_cast(_keys + _capacity)[i]; + inline PyObject* value(uint16_t i) const { + return reinterpret_cast(_keys + _capacity)[i]; } NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]): @@ -123,19 +121,19 @@ while(!_keys[i].empty()) { \ i = (i + 1) & _mask; \ } - const PyVar& operator[](StrName key) const { + PyObject* operator[](StrName key) const { bool ok; uint16_t i; HASH_PROBE(key, ok, i); if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); return value(i); } - PyVar& get(StrName key){ - bool ok; uint16_t i; - HASH_PROBE(key, ok, i); - if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); - return value(i); - } + // PyObject*& get(StrName key){ + // bool ok; uint16_t i; + // HASH_PROBE(key, ok, i); + // if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); + // return value(i); + // } template void set(StrName key, T&& val){ @@ -154,7 +152,7 @@ while(!_keys[i].empty()) { \ void _rehash(bool resize){ StrName* old_keys = _keys; - PyVar* old_values = &value(0); + PyObject** old_values = &value(0); uint16_t old_capacity = _capacity; if(resize){ _capacity = find_next_capacity(_capacity * 2); @@ -177,18 +175,18 @@ while(!_keys[i].empty()) { \ _rehash(false); // do not resize } - inline PyVar* try_get(StrName key){ + inline PyObject** try_get(StrName key){ bool ok; uint16_t i; HASH_PROBE(key, ok, i); if(!ok) return nullptr; return &value(i); } - inline bool try_set(StrName key, PyVar&& val){ + inline bool try_set(StrName key, PyObject* val){ bool ok; uint16_t i; HASH_PROBE(key, ok, i); if(!ok) return false; - value(i) = std::move(val); + value(i) = val; return true; } @@ -213,8 +211,8 @@ while(!_keys[i].empty()) { \ _size--; } - std::vector> items() const { - std::vector> v; + std::vector> items() const { + std::vector> v; for(uint16_t i=0; i<_capacity; i++){ if(_keys[i].empty()) continue; v.push_back(std::make_pair(_keys[i], value(i))); @@ -231,7 +229,7 @@ while(!_keys[i].empty()) { \ return v; } - void apply_v(void(*f)(PyVar)) { + void apply_v(void(*f)(PyObject*)) { for(uint16_t i=0; i<_capacity; i++){ if(_keys[i].empty()) continue; f(value(i)); diff --git a/src/obj.h b/src/obj.h index 46acb280..80bfa100 100644 --- a/src/obj.h +++ b/src/obj.h @@ -12,7 +12,7 @@ struct Frame; struct BaseRef; class VM; -typedef std::function NativeFuncRaw; +typedef std::function NativeFuncRaw; typedef shared_ptr CodeObject_; typedef shared_ptr NameDict_; @@ -22,7 +22,7 @@ struct NativeFunc { bool method; NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {} - inline PyVar operator()(VM* vm, Args& args) const; + inline PyObject* operator()(VM* vm, Args& args) const; }; struct Function { @@ -34,7 +34,7 @@ struct Function { std::vector kwargs_order; // runtime settings - PyVar _module = nullptr; + PyObject* _module = nullptr; NameDict_ _closure = nullptr; bool has_name(StrName val) const { @@ -46,9 +46,9 @@ struct Function { }; struct BoundMethod { - PyVar obj; - PyVar method; - BoundMethod(const PyVar& obj, const PyVar& method) : obj(obj), method(method) {} + PyObject* obj; + PyObject* method; + BoundMethod(PyObject* obj, PyObject* method) : obj(obj), method(method) {} }; struct Range { @@ -58,9 +58,9 @@ struct Range { }; struct StarWrapper { - PyVar obj; + PyObject* obj; bool rvalue; - StarWrapper(const PyVar& obj, bool rvalue): obj(obj), rvalue(rvalue) {} + StarWrapper(PyObject* obj, bool rvalue): obj(obj), rvalue(rvalue) {} }; struct Slice { @@ -79,30 +79,34 @@ struct Slice { class BaseIter { protected: VM* vm; - PyVar _ref; // keep a reference to the object so it will not be deleted while iterating + PyObject* _ref; // keep a reference to the object so it will not be deleted while iterating public: - virtual PyVar next() = 0; - PyVarRef loop_var; - BaseIter(VM* vm, PyVar _ref) : vm(vm), _ref(_ref) {} + virtual PyObject* next() = 0; + PyObject* loop_var; + BaseIter(VM* vm, PyObject* _ref) : vm(vm), _ref(_ref) {} virtual ~BaseIter() = default; }; +struct GCHeader { + bool enabled; // whether this object is managed by GC + bool marked; // whether this object is marked + GCHeader() : enabled(false), marked(false) {} +}; + struct PyObject { - bool need_gc; - bool marked; - /**********/ + GCHeader gc; Type type; NameDict* _attr; inline bool is_attr_valid() const noexcept { return _attr != nullptr; } inline NameDict& attr() noexcept { return *_attr; } - inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); } + inline PyObject* attr(StrName name) const noexcept { return (*_attr)[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(); }); + if(!gc.enabled || gc.marked) return; + gc.marked = true; + if(is_attr_valid()) attr().apply_v([](PyObject* v){ v->mark(); }); } PyObject(Type type) : type(type) {} @@ -141,67 +145,51 @@ struct Py_ : PyObject { const int kTpIntIndex = 2; const int kTpFloatIndex = 3; -inline bool is_type(const PyVar& obj, Type type) noexcept { +inline bool is_type(PyObject* obj, Type type) noexcept { switch(type.index){ - case kTpIntIndex: return obj.is_tag_01(); - case kTpFloatIndex: return obj.is_tag_10(); - default: return !obj.is_tagged() && obj->type == type; + case kTpIntIndex: return is_tag_01(obj); + case kTpFloatIndex: return is_tag_10(obj); + default: return !is_tagged(obj) && obj->type == type; } } -inline bool is_both_int_or_float(const PyVar& a, const PyVar& b) noexcept { - return a.is_tagged() && b.is_tagged(); -} - -inline bool is_both_int(const PyVar& a, const PyVar& b) noexcept { - return (a.bits & b.bits & 0b11) == 0b01; -} - -inline bool is_int(const PyVar& obj) noexcept { - return obj.is_tag_01(); -} - -inline bool is_float(const PyVar& obj) noexcept { - return obj.is_tag_10(); -} - #define PY_CLASS(T, mod, name) \ static Type _type(VM* vm) { \ static const StrName __x0(#mod); \ static const StrName __x1(#name); \ return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ } \ - static PyVar register_class(VM* vm, PyVar mod) { \ - PyVar type = vm->new_type_object(mod, #name, vm->tp_object); \ + static PyObject* register_class(VM* vm, PyObject* mod) { \ + PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \ if(OBJ_NAME(mod) != #mod) UNREACHABLE(); \ T::_register(vm, mod, type); \ type->attr()._try_perfect_rehash(); \ return type; \ } -union __8B { +union BitsCvt { i64 _int; f64 _float; - __8B(i64 val) : _int(val) {} - __8B(f64 val) : _float(val) {} + BitsCvt(i64 val) : _int(val) {} + BitsCvt(f64 val) : _float(val) {} }; template struct is_py_class : std::false_type {}; template struct is_py_class> : std::true_type {}; template -void _check_py_class(VM* vm, const PyVar& var); +void _check_py_class(VM* vm, PyObject* var); template -T py_pointer_cast(VM* vm, const PyVar& var); +T py_pointer_cast(VM* vm, PyObject* var); template -T py_value_cast(VM* vm, const PyVar& var); +T py_value_cast(VM* vm, PyObject* var); struct Discarded {}; template -__T py_cast(VM* vm, const PyVar& obj) { +__T py_cast(VM* vm, PyObject* obj) { using T = std::decay_t<__T>; if constexpr(std::is_pointer_v){ return py_pointer_cast(vm, obj); @@ -216,7 +204,7 @@ __T py_cast(VM* vm, const PyVar& obj) { } template -__T _py_cast(VM* vm, const PyVar& obj) { +__T _py_cast(VM* vm, PyObject* obj) { using T = std::decay_t<__T>; if constexpr(std::is_pointer_v<__T>){ return py_pointer_cast<__T>(vm, obj); @@ -228,7 +216,7 @@ __T _py_cast(VM* vm, const PyVar& obj) { } #define VAR(x) py_var(vm, x) -#define VAR_T(T, ...) vm->new_object(T::_type(vm), T(__VA_ARGS__)) +#define VAR_T(T, ...) vm->heap.gcnew(T::_type(vm), T(__VA_ARGS__)) #define CAST(T, x) py_cast(vm, x) #define _CAST(T, x) _py_cast(vm, x) diff --git a/src/parser.h b/src/parser.h index c867ea4a..63b450ff 100644 --- a/src/parser.h +++ b/src/parser.h @@ -54,7 +54,7 @@ struct Token{ const char* start; int length; int line; - PyVar value; + PyObject* value; Str str() const { return Str(start, length);} @@ -271,7 +271,7 @@ struct Parser { return true; } - void set_next_token(TokenIndex type, PyVar value=nullptr) { + void set_next_token(TokenIndex type, PyObject* value=nullptr) { switch(type){ case TK("{"): case TK("["): case TK("("): brackets_level++; break; case TK(")"): case TK("]"): case TK("}"): brackets_level--; break; diff --git a/src/pocketpy.h b/src/pocketpy.h index 0b105367..6bf8bb66 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -69,7 +69,7 @@ void init_builtins(VM* _vm) { vm->TypeError("super(type, obj): obj must be an instance or subtype of type"); } Type base = vm->_all_types[type.index].base; - return vm->new_object(vm->tp_super, Super(args[1], base)); + return vm->heap.gcnew(vm->tp_super, Super(args[1], base)); }); _vm->bind_builtin_func<2>("isinstance", [](VM* vm, Args& args) { @@ -79,16 +79,16 @@ void init_builtins(VM* _vm) { }); _vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) { - const PyVar& obj = args[0]; - if(obj.is_tagged()) return VAR((i64)0); - return VAR(obj.bits); + PyObject* obj = args[0]; + if(is_tagged(obj)) return VAR((i64)0); + return VAR(BITS(obj)); }); _vm->bind_builtin_func<2>("divmod", [](VM* vm, Args& args) { i64 lhs = CAST(i64, args[0]); i64 rhs = CAST(i64, args[1]); if(rhs == 0) vm->ZeroDivisionError(); - return VAR(two_args(VAR(lhs/rhs), VAR(lhs%rhs))); + return VAR(Tuple{VAR(lhs/rhs), VAR(lhs%rhs)}); }); _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) { @@ -169,8 +169,8 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) { - PyVar self = args[0]; - std::uintptr_t addr = self.is_tagged() ? 0 : (uintptr_t)self.get(); + PyObject* self = args[0]; + std::uintptr_t addr = is_tagged(self) ? 0 : (uintptr_t)self; StrStream ss; ss << std::hex << addr; Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">"; @@ -405,7 +405,7 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) { const Str& self = CAST(Str&, args[0]); StrStream ss; - PyVar obj = vm->asList(args[1]); + PyObject* obj = vm->asList(args[1]); const List& list = CAST(List&, obj); for (int i = 0; i < list.size(); ++i) { if (i > 0) ss << self; @@ -423,7 +423,7 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("list", "extend", [](VM* vm, Args& args) { List& self = CAST(List&, args[0]); - PyVar obj = vm->asList(args[1]); + PyObject* obj = vm->asList(args[1]); const List& list = CAST(List&, obj); self.insert(self.end(), list.begin(), list.end()); return vm->None; @@ -575,7 +575,7 @@ void init_builtins(VM* _vm) { #endif void add_module_time(VM* vm){ - PyVar mod = vm->new_module("time"); + PyObject* mod = vm->new_module("time"); vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) { auto now = std::chrono::high_resolution_clock::now(); return VAR(std::chrono::duration_cast(now.time_since_epoch()).count() / 1000000.0); @@ -583,7 +583,7 @@ void add_module_time(VM* vm){ } void add_module_sys(VM* vm){ - PyVar mod = vm->new_module("sys"); + PyObject* mod = vm->new_module("sys"); vm->setattr(mod, "version", VAR(PK_VERSION)); vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(VAR(args[0].use_count()))); @@ -596,7 +596,7 @@ void add_module_sys(VM* vm){ } void add_module_json(VM* vm){ - PyVar mod = vm->new_module("json"); + PyObject* mod = vm->new_module("json"); vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) { const Str& expr = CAST(Str&, args[0]); CodeObject_ code = vm->compile(expr, "", JSON_MODE); @@ -607,7 +607,7 @@ void add_module_json(VM* vm){ } void add_module_math(VM* vm){ - PyVar mod = vm->new_module("math"); + PyObject* mod = vm->new_module("math"); vm->setattr(mod, "pi", VAR(3.1415926535897932384)); vm->setattr(mod, "e" , VAR(2.7182818284590452354)); @@ -626,9 +626,9 @@ void add_module_math(VM* vm){ } void add_module_dis(VM* vm){ - PyVar mod = vm->new_module("dis"); + PyObject* mod = vm->new_module("dis"); vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) { - PyVar f = args[0]; + PyObject* f = args[0]; if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).method; CodeObject_ code = CAST(Function, f).code; (*vm->_stdout) << vm->disassemble(code); @@ -644,14 +644,14 @@ struct ReMatch { std::smatch m; ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {} - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).start))); vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).end))); vm->bind_method<0>(type, "span", [](VM* vm, Args& args) { auto& self = CAST(ReMatch&, args[0]); - return VAR(two_args(VAR(self.start), VAR(self.end))); + return VAR(Tuple{VAR(self.start), VAR(self.end)}); }); vm->bind_method<1>(type, "group", [](VM* vm, Args& args) { @@ -663,7 +663,7 @@ struct ReMatch { } }; -PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){ +PyObject* _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){ std::regex re(pattern); std::smatch m; if(std::regex_search(string, m, re)){ @@ -676,7 +676,7 @@ PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* v }; void add_module_re(VM* vm){ - PyVar mod = vm->new_module("re"); + PyObject* mod = vm->new_module("re"); ReMatch::register_class(vm, mod); vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) { @@ -740,7 +740,7 @@ struct Random{ gen.seed(seed); } - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random))); vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed)); vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint)); @@ -750,7 +750,7 @@ struct Random{ }; void add_module_random(VM* vm){ - PyVar mod = vm->new_module("random"); + PyObject* mod = vm->new_module("random"); Random::register_class(vm, mod); CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE); vm->_exec(code, mod); @@ -851,7 +851,7 @@ extern "C" { /// Return `__repr__` of the result. /// If the variable is not found, return `nullptr`. char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){ - pkpy::PyVar* val = vm->_main->attr().try_get(name); + pkpy::PyObject** val = vm->_main->attr().try_get(name); if(val == nullptr) return nullptr; try{ pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val)); @@ -867,7 +867,7 @@ extern "C" { /// Return `__repr__` of the result. /// If there is any error, return `nullptr`. char* pkpy_vm_eval(pkpy::VM* vm, const char* source){ - pkpy::PyVarOrNull ret = vm->exec(source, "", pkpy::EVAL_MODE); + pkpy::PyObject* ret = vm->exec(source, "", pkpy::EVAL_MODE); if(ret == nullptr) return nullptr; try{ pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret)); @@ -950,13 +950,13 @@ extern "C" { for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr; for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr; std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++); - pkpy::PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod); + pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod); vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){ pkpy::StrStream ss; ss << f_header; for(int i=0; icall(args[i], pkpy::__json__); + pkpy::PyObject* x = vm->call(args[i], pkpy::__json__); ss << pkpy::CAST(pkpy::Str&, x); } char* packet = strdup(ss.str().c_str()); diff --git a/src/ref.h b/src/ref.h index 9719d218..88d3e58a 100644 --- a/src/ref.h +++ b/src/ref.h @@ -6,8 +6,8 @@ namespace pkpy { struct BaseRef { - virtual PyVar get(VM*, Frame*) const = 0; - virtual void set(VM*, Frame*, PyVar) const = 0; + virtual PyObject* get(VM*, Frame*) const = 0; + virtual void set(VM*, Frame*, PyObject*) const = 0; virtual void del(VM*, Frame*) const = 0; virtual ~BaseRef() = default; }; @@ -18,8 +18,8 @@ struct NameRef : BaseRef { inline NameScope scope() const { return pair.second; } NameRef(const std::pair& pair) : pair(pair) {} - PyVar get(VM* vm, Frame* frame) const{ - PyVar* val; + PyObject* get(VM* vm, Frame* frame) const{ + PyObject** val; val = frame->f_locals().try_get(name()); if(val != nullptr) return *val; val = frame->f_closure_try_get(name()); @@ -32,12 +32,12 @@ struct NameRef : BaseRef { return nullptr; } - void set(VM* vm, Frame* frame, PyVar val) const{ + void set(VM* vm, Frame* frame, PyObject* val) const{ switch(scope()) { - case NAME_LOCAL: frame->f_locals().set(name(), std::move(val)); break; + case NAME_LOCAL: frame->f_locals().set(name(), val); break; case NAME_GLOBAL: - if(frame->f_locals().try_set(name(), std::move(val))) return; - frame->f_globals().set(name(), std::move(val)); + if(frame->f_locals().try_set(name(), val)) return; + frame->f_globals().set(name(), val); break; default: UNREACHABLE(); } @@ -70,15 +70,15 @@ struct NameRef : BaseRef { }; struct AttrRef : BaseRef { - mutable PyVar obj; + mutable PyObject* obj; NameRef attr; - AttrRef(PyVar obj, NameRef attr) : obj(obj), attr(attr) {} + AttrRef(PyObject* obj, NameRef attr) : obj(obj), attr(attr) {} - PyVar get(VM* vm, Frame* frame) const{ + PyObject* get(VM* vm, Frame* frame) const{ return vm->getattr(obj, attr.name()); } - void set(VM* vm, Frame* frame, PyVar val) const{ + void set(VM* vm, Frame* frame, PyObject* val) const{ vm->setattr(obj, attr.name(), std::move(val)); } @@ -90,22 +90,22 @@ struct AttrRef : BaseRef { }; struct IndexRef : BaseRef { - mutable PyVar obj; - PyVar index; - IndexRef(PyVar obj, PyVar index) : obj(obj), index(index) {} + mutable PyObject* obj; + PyObject* index; + IndexRef(PyObject* obj, PyObject* index) : obj(obj), index(index) {} - PyVar get(VM* vm, Frame* frame) const{ - return vm->fast_call(__getitem__, two_args(obj, index)); + PyObject* get(VM* vm, Frame* frame) const{ + return vm->fast_call(__getitem__, Args{obj, index}); } - void set(VM* vm, Frame* frame, PyVar val) const{ + void set(VM* vm, Frame* frame, PyObject* val) const{ Args args(3); args[0] = obj; args[1] = index; args[2] = std::move(val); vm->fast_call(__setitem__, std::move(args)); } void del(VM* vm, Frame* frame) const{ - vm->fast_call(__delitem__, two_args(obj, index)); + vm->fast_call(__delitem__, Args{obj, index}); } }; @@ -113,7 +113,7 @@ struct TupleRef : BaseRef { Tuple objs; TupleRef(Tuple&& objs) : objs(std::move(objs)) {} - PyVar get(VM* vm, Frame* frame) const{ + PyObject* get(VM* vm, Frame* frame) const{ Tuple args(objs.size()); for (int i = 0; i < objs.size(); i++) { args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame); @@ -121,11 +121,11 @@ struct TupleRef : BaseRef { return VAR(std::move(args)); } - void set(VM* vm, Frame* frame, PyVar val) const{ + void set(VM* vm, Frame* frame, PyObject* val) const{ val = vm->asIter(val); BaseIter* iter = vm->PyIter_AS_C(val); for(int i=0; itp_star_wrapper)){ auto& star = _CAST(StarWrapper&, objs[i]); if(star.rvalue) vm->ValueError("can't use starred expression here"); @@ -141,7 +141,7 @@ struct TupleRef : BaseRef { vm->PyRef_AS_C(objs[i])->set(vm, frame, x); } } - PyVarOrNull x = iter->next(); + PyObject* x = iter->next(); if(x != nullptr) vm->ValueError("too many values to unpack"); } @@ -152,19 +152,19 @@ struct TupleRef : BaseRef { template -PyVarRef VM::PyRef(P&& value) { +PyObject* VM::PyRef(P&& value) { static_assert(std::is_base_of_v>); - return new_object(tp_ref, std::forward

(value)); + return heap.gcnew

(tp_ref, std::forward

(value)); } -const BaseRef* VM::PyRef_AS_C(const PyVar& obj) +const BaseRef* VM::PyRef_AS_C(PyObject* obj) { if(!is_type(obj, tp_ref)) TypeError("expected an l-value"); return static_cast(obj->value()); } /***** Frame's Impl *****/ -inline void Frame::try_deref(VM* vm, PyVar& v){ +inline void Frame::try_deref(VM* vm, PyObject*& v){ if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this); } diff --git a/src/tuplelist.h b/src/tuplelist.h index a07459e8..97710de4 100644 --- a/src/tuplelist.h +++ b/src/tuplelist.h @@ -3,6 +3,7 @@ #include "common.h" #include "memory.h" #include "str.h" +#include namespace pkpy { using List = std::vector; @@ -33,6 +34,11 @@ namespace pkpy { other._size = 0; } + Args(std::initializer_list list) : Args(list.size()){ + int i=0; + for(auto& p : list) _args[i++] = p; + } + static pkpy::Args from_list(List&& other) noexcept { Args ret(other.size()); memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size()); @@ -82,30 +88,6 @@ namespace pkpy { return _zero; } - template - Args one_arg(T&& a) { - Args ret(1); - ret[0] = std::forward(a); - return ret; - } - - template - Args two_args(T1&& a, T2&& b) { - Args ret(2); - ret[0] = std::forward(a); - ret[1] = std::forward(b); - return ret; - } - - template - Args three_args(T1&& a, T2&& b, T3&& c) { - Args ret(3); - ret[0] = std::forward(a); - ret[1] = std::forward(b); - ret[2] = std::forward(c); - return ret; - } - typedef Args Tuple; THREAD_LOCAL SmallArrayPool Args::_pool; } // namespace pkpy \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index e90b1544..bde67257 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1,7 +1,9 @@ #pragma once +#include "common.h" #include "frame.h" #include "error.h" +#include "gc.h" namespace pkpy{ @@ -20,8 +22,8 @@ namespace pkpy{ template<> ctype& _py_cast(VM* vm, PyObject* obj) { \ return OBJ_GET(ctype, obj); \ } \ - 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));} + PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);} \ + PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));} class Generator: public BaseIter { std::unique_ptr frame; @@ -41,6 +43,7 @@ struct PyTypeInfo{ class VM { VM* vm; // self reference for simplify code + ManagedHeap heap; public: std::stack< std::unique_ptr > callstack; std::vector _all_types; @@ -78,11 +81,10 @@ public: } init_builtin_types(); - // for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i)); } PyObject* asStr(PyObject* obj){ - PyVarOrNull f = getattr(obj, __str__, false, true); + PyObject* f = getattr(obj, __str__, false, true); if(f != nullptr) return call(f); return asRepr(obj); } @@ -95,8 +97,8 @@ public: } PyObject* asIter(PyObject* obj){ - if(is_type(obj, tp_native_iterator)) return obj; - PyVarOrNull iter_f = getattr(obj, __iter__, false, true); + if(is_type(obj, tp_iterator)) return obj; + PyObject* iter_f = getattr(obj, __iter__, false, true); if(iter_f != nullptr) return call(iter_f); TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable"); return nullptr; @@ -104,7 +106,7 @@ public: PyObject* asList(PyObject* iterable){ if(is_type(iterable, tp_list)) return iterable; - return call(_t(tp_list), one_arg(iterable)); + return call(_t(tp_list), Args{iterable}); } PyObject** find_name_in_mro(PyObject* cls, StrName name){ @@ -191,13 +193,13 @@ public: 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)); + PyObject* method = heap.gcnew(tp_native_function, NativeFunc(fget, 1, false)); + return call(p, Args{method}); } PyObject* new_type_object(PyObject* mod, StrName name, Type base){ // use gcnew - PyObject* obj = make_sp>(tp_type, _all_types.size()); + PyObject* obj = new Py_(tp_type, _all_types.size()); PyTypeInfo info{ .obj = obj, .base = base, @@ -213,30 +215,6 @@ public: return OBJ_GET(Type, obj); } - template - 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 PyObject* new_object(PyObject* type, T&& _value) { -#if PK_EXTRA_CHECK - if(!is_type(type, tp_type)) UNREACHABLE(); -#endif - return make_sp>>(OBJ_GET(Type, type), std::move(_value)); - } - - template - inline PyObject* new_object(Type type, const T& _value) { - return make_sp>>(type, _value); - } - template - inline PyObject* new_object(Type type, T&& _value) { - return make_sp>>(type, std::move(_value)); - } - PyObject* _find_type(const Str& type){ PyObject** obj = builtins->attr().try_get(type); if(!obj){ @@ -282,19 +260,19 @@ public: // for quick access Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str; Type tp_list, tp_tuple; - Type tp_function, tp_native_function, tp_native_iterator, tp_bound_method; + Type tp_function, tp_native_function, tp_iterator, tp_bound_method; Type tp_slice, tp_range, tp_module, tp_ref; Type tp_super, tp_exception, tp_star_wrapper; template inline PyObject* PyIter(P&& value) { static_assert(std::is_base_of_v>); - return new_object(tp_native_iterator, std::forward

(value)); + return heap.gcnew

(tp_iterator, std::forward

(value)); } inline BaseIter* PyIter_AS_C(PyObject* obj) { - check_type(obj, tp_native_iterator); + check_type(obj, tp_iterator); return static_cast(obj->value()); } @@ -369,7 +347,7 @@ public: PyObject* _exec(); template - PyVarRef PyRef(P&& value); + PyObject* PyRef(P&& value); const BaseRef* PyRef_AS_C(PyObject* obj); }; @@ -458,23 +436,23 @@ 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; + return BitsCvt(bits)._float; } template<> float _py_cast(VM* vm, PyObject* obj){ i64 bits = obj.bits; bits = (bits >> 2) << 2; - return __8B(bits)._float; + return BitsCvt(bits)._float; } 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; + return BitsCvt(bits)._float; } template<> double _py_cast(VM* vm, PyObject* obj){ i64 bits = obj.bits; bits = (bits >> 2) << 2; - return __8B(bits)._float; + return BitsCvt(bits)._float; } @@ -502,7 +480,7 @@ PY_VAR_INT(unsigned long long) #define PY_VAR_FLOAT(T) \ PyObject* py_var(VM* vm, T _val){ \ f64 val = static_cast(_val); \ - i64 bits = __8B(val)._int; \ + i64 bits = BitsCvt(val)._int; \ bits = (bits >> 2) << 2; \ bits |= 0b10; \ return reinterpret_cast(bits); \ @@ -561,7 +539,7 @@ PyObject* VM::asBool(PyObject* 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); + PyObject* len_fn = getattr(obj, __len__, false, true); if(len_fn != nullptr){ PyObject* ret = call(len_fn); return VAR(CAST(i64, ret) > 0); @@ -596,8 +574,11 @@ PyObject* VM::asRepr(PyObject* obj){ } PyObject* VM::new_module(StrName name) { - PyObject* obj = new_object(tp_module, DummyModule()); + PyObject* obj = new Py_(tp_module, DummyModule()); obj->attr().set(__name__, VAR(name.str())); + // we do not allow override in order to avoid memory leak + // it is because Module objects are not garbage collected + if(_modules.contains(name)) UNREACHABLE(); _modules.set(name, obj); return obj; } @@ -672,9 +653,11 @@ Str VM::disassemble(CodeObject_ co){ } void VM::init_builtin_types(){ - // Py_(Type type, T&& val) - PyVar _tp_object = make_sp>(Type(1), Type(0)); - PyVar _tp_type = make_sp>(Type(1), Type(1)); + PyObject* _tp_object = new Py_(Type(1), Type(0)); + PyObject* _tp_type = new Py_(Type(1), Type(1)); + // PyTypeObject is managed by _all_types + // PyModuleObject is managed by _modules + // They are not managed by GC, so we use a simple "new" _all_types.push_back({.obj = _tp_object, .base = -1, .name = "object"}); _all_types.push_back({.obj = _tp_type, .base = 0, .name = "type"}); tp_object = 0; tp_type = 1; @@ -695,17 +678,17 @@ void VM::init_builtin_types(){ tp_function = _new_type_object("function"); tp_native_function = _new_type_object("native_function"); - tp_native_iterator = _new_type_object("native_iterator"); + tp_iterator = _new_type_object("iterator"); tp_bound_method = _new_type_object("bound_method"); tp_super = _new_type_object("super"); tp_exception = _new_type_object("Exception"); - this->None = new_object(_new_type_object("NoneType"), DUMMY_VAL); - this->Ellipsis = new_object(_new_type_object("ellipsis"), DUMMY_VAL); - this->True = new_object(tp_bool, true); - this->False = new_object(tp_bool, false); - this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL); - this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL); + this->None = new Py_(_new_type_object("NoneType"), {}); + this->Ellipsis = new Py_(_new_type_object("ellipsis"), {}); + this->True = new Py_(tp_bool, {}); + this->False = new Py_(tp_bool, {}); + this->_py_op_call = new Py_(_new_type_object("_py_op_call"), {}); + this->_py_op_yield = new Py_(_new_type_object("_py_op_yield"), {}); this->builtins = new_module("builtins"); this->_main = new_module("__main__"); @@ -735,8 +718,8 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal if(new_f != nullptr){ obj = call(*new_f, std::move(args), kwargs, false); }else{ - obj = new_object(_callable, DummyInstance()); - PyVarOrNull init_f = getattr(obj, __init__, false, true); + obj = heap.gcnew(_callable, {}); + PyObject* init_f = getattr(obj, __init__, false, true); if (init_f != nullptr) call(init_f, std::move(args), kwargs, false); } return obj; @@ -801,7 +784,7 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal return _exec(); } - PyVarOrNull call_f = getattr(_callable, __call__, false, true); + PyObject* call_f = getattr(_callable, __call__, false, true); if(call_f != nullptr){ return call(call_f, std::move(args), kwargs, false); } @@ -829,42 +812,44 @@ using Super = std::pair; // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance 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(); + PyObject* objtype = _t(obj); + // handle super() proxy + if(is_type(obj, tp_super)){ + const Super& super = OBJ_GET(Super, obj); + obj = super.first; + objtype = _t(super.second); } PyObject** cls_var = find_name_in_mro(objtype, name); if(cls_var != nullptr){ // handle descriptor PyObject** descr_get = _t(*cls_var)->attr().try_get(__get__); - if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj)); + if(descr_get != nullptr) return call(*descr_get, Args{*cls_var, obj}); } // handle instance __dict__ - if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){ - PyObject** val = (*obj)->attr().try_get(name); + if(!class_only && !is_tagged(obj) && obj->is_attr_valid()){ + PyObject** val = obj->attr().try_get(name); if(val != nullptr) return *val; } if(cls_var != nullptr){ // bound method is non-data descriptor if(is_type(*cls_var, tp_function) || is_type(*cls_var, tp_native_function)){ - return VAR(BoundMethod(*obj, *cls_var)); + return VAR(BoundMethod(obj, *cls_var)); } return *cls_var; } - if(throw_err) AttributeError(*obj, name); + if(throw_err) AttributeError(obj, name); return nullptr; } template void VM::setattr(PyObject* obj, StrName name, T&& value){ - static_assert(std::is_same_v, PyVar>); - PyObject* objtype = _t(obj).get(); + static_assert(std::is_same_v, PyObject*>); + PyObject* objtype = _t(obj); + // handle super() proxy if(is_type(obj, tp_super)){ Super& super = OBJ_GET(Super, *obj); obj = super.first; - objtype = _t(super.second).get(); + objtype = _t(super.second); } PyObject** cls_var = find_name_in_mro(objtype, name); if(cls_var != nullptr){ @@ -873,7 +858,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){ if(cls_var_t->attr().contains(__get__)){ 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, Args{*cls_var, obj, std::forward(value)}); }else{ TypeError("readonly attribute: " + name.str().escape(true)); } @@ -881,7 +866,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){ } } // handle instance __dict__ - if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute"); + if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute"); obj->attr().set(name, std::forward(value)); }