diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ea6255d..c6f18ac4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,6 +46,8 @@ jobs: run: python3 scripts/run_tests.py - name: Benchmark run: python3 scripts/run_tests.py benchmark + - name: GCC Build Test + run: g++ -o pocketpy --std=c++17 src/main.cpp build_macos: runs-on: macos-latest steps: diff --git a/src/cffi.h b/src/cffi.h index 45c1a920..6f97688b 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -5,72 +5,25 @@ namespace pkpy { -// template -// struct NativeProxyFunc { -// static constexpr int N = sizeof...(Params); -// using _Fp = Ret(*)(Params...); -// _Fp func; -// NativeProxyFunc(_Fp func) : func(func) {} +#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 PyObject* register_class(VM* vm, PyObject* mod) { \ + PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \ + if(OBJ_NAME(mod) != #mod) { \ + auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \ + throw std::runtime_error(msg); \ + } \ + T::_register(vm, mod, type); \ + type->attr()._try_perfect_rehash(); \ + return type; \ + } -// PyObject* operator()(VM* vm, ArgsView args) { -// if (args.size() != N) { -// vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size())); -// } -// return call(vm, args, std::make_index_sequence()); -// } +#define VAR_T(T, ...) vm->heap.gcnew(T::_type(vm), T(__VA_ARGS__)) -// template -// std::enable_if_t, PyObject*> call(VM* vm, ArgsView args, std::index_sequence) { -// func(py_cast(vm, args[Is])...); -// return vm->None; -// } - -// template -// std::enable_if_t, PyObject*> call(VM* vm, ArgsView args, std::index_sequence) { -// __Ret ret = func(py_cast(vm, args[Is])...); -// return VAR(std::move(ret)); -// } -// }; - -// template -// struct NativeProxyMethod { -// static constexpr int N = sizeof...(Params); -// using _Fp = Ret(T::*)(Params...); -// _Fp func; -// NativeProxyMethod(_Fp func) : func(func) {} - -// PyObject* operator()(VM* vm, ArgsView 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)); -// } -// return call(vm, args, std::make_index_sequence()); -// } - -// template -// std::enable_if_t, PyObject*> call(VM* vm, ArgsView 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, PyObject*> call(VM* vm, ArgsView 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)); -// } -// }; - -// template -// auto native_proxy_callable(Ret(*func)(Params...)) { -// return NativeProxyFunc(func); -// } - -// template -// auto native_proxy_callable(Ret(T::*func)(Params...)) { -// return NativeProxyMethod(func); -// } struct VoidP{ PY_CLASS(VoidP, c, void_p) diff --git a/src/gc.h b/src/gc.h index f6bb15c8..07567b16 100644 --- a/src/gc.h +++ b/src/gc.h @@ -116,50 +116,4 @@ inline void FuncDecl::_gc_mark() const{ for(int i=0; i inline void gc_mark(List& t){ - for(PyObject* obj: t){ - OBJ_MARK(obj); - } -} - -template<> inline void gc_mark(Tuple& t){ - for(PyObject* obj: t){ - OBJ_MARK(obj); - } -} - -template<> inline void gc_mark(NameDict& t){ - if(t.size() == 0) return; - for(uint16_t i=0; i inline void gc_mark(MappingProxy& t){ - OBJ_MARK(t.obj); -} - -template<> inline void gc_mark(BoundMethod& t){ - OBJ_MARK(t.self); - OBJ_MARK(t.func); -} - -template<> inline void gc_mark(Slice& t){ - OBJ_MARK(t.start); - OBJ_MARK(t.stop); - OBJ_MARK(t.step); -} - -template<> inline void gc_mark(Function& t){ - t.decl->_gc_mark(); - if(t._module != nullptr) OBJ_MARK(t._module); - if(t._closure != nullptr) gc_mark(*t._closure); -} - -template<> inline void gc_mark(Super& t){ - OBJ_MARK(t.first); -} -// NOTE: std::function may capture some PyObject*, they can not be marked - } // namespace pkpy \ No newline at end of file diff --git a/src/io.h b/src/io.h index 2ae87595..b93803eb 100644 --- a/src/io.h +++ b/src/io.h @@ -31,16 +31,16 @@ struct FileIO { bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; } FileIO(VM* vm, Str file, Str mode): file(file), mode(mode) { - std::ios_base::openmode extra = 0; + std::ios_base::openmode extra = static_cast(0); if(mode == "rb" || mode == "wb" || mode == "ab"){ extra |= std::ios::binary; } if(mode == "rt" || mode == "r" || mode == "rb"){ - _fs.open(file.sv(), std::ios::in | extra); + _fs.open(file.str(), std::ios::in | extra); }else if(mode == "wt" || mode == "w" || mode == "wb"){ - _fs.open(file.sv(), std::ios::out | extra); + _fs.open(file.str(), std::ios::out | extra); }else if(mode == "at" || mode == "a" || mode == "ab"){ - _fs.open(file.sv(), std::ios::app | extra); + _fs.open(file.str(), std::ios::app | extra); }else{ vm->ValueError("invalid mode"); } diff --git a/src/iter.h b/src/iter.h index 94c59548..efa642a1 100644 --- a/src/iter.h +++ b/src/iter.h @@ -41,7 +41,7 @@ public: return array->operator[](index++); } - void _gc_mark() const override { + void _gc_mark() const{ OBJ_MARK(ref); } }; @@ -60,7 +60,7 @@ public: return VAR(str->u8_getitem(index++)); } - void _gc_mark() const override { + void _gc_mark() const{ OBJ_MARK(ref); } }; @@ -95,11 +95,4 @@ inline void Generator::_gc_mark() const{ for(PyObject* obj: s_backup) OBJ_MARK(obj); } -template -void gc_mark(T& t) { - if constexpr(std::is_base_of_v){ - t._gc_mark(); - } -} - } // namespace pkpy \ No newline at end of file diff --git a/src/lexer.h b/src/lexer.h index ffe5d5f3..270c7c1d 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -38,7 +38,13 @@ constexpr TokenIndex TK(const char token[]) { while(*i && *j && *i == *j) { i++; j++;} if(*i == *j) return k; } +#ifdef __GNUC__ + // for old version of gcc, it is not smart enough to ignore FATAL_ERROR() + // so we must do a normal return + return 255; +#else FATAL_ERROR(); +#endif } #define TK_STR(t) kTokens[t] @@ -508,4 +514,4 @@ struct Lexer { } }; -} // namespace pkpy \ No newline at end of file +} // namespace pkpy diff --git a/src/obj.h b/src/obj.h index b817c9ee..fc787db5 100644 --- a/src/obj.h +++ b/src/obj.h @@ -103,7 +103,6 @@ protected: VM* vm; public: BaseIter(VM* vm) : vm(vm) {} - virtual void _gc_mark() const {} virtual PyObject* next() = 0; virtual ~BaseIter() = default; }; @@ -125,7 +124,8 @@ struct PyObject{ virtual void* value() = 0; virtual void _obj_gc_mark() = 0; - PyObject(Type type) : type(type) {} + PyObject(Type type) : type(type), _attr(nullptr) {} + virtual ~PyObject() { if(_attr == nullptr) return; _attr->~NameDict(); @@ -137,46 +137,45 @@ struct PyObject{ } }; -template -void gc_mark(T& t); +template struct has_gc_marker : std::false_type {}; +template struct has_gc_marker> : std::true_type {}; template struct Py_ final: PyObject { T _value; - - Py_(Type type, const T& val): PyObject(type), _value(val) { _init(); } - Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); } - - void _init() noexcept { - if constexpr (std::is_same_v || std::is_same_v) { - _attr = new(pool64.alloc()) NameDict(kTypeAttrLoadFactor); - }else if constexpr(std::is_same_v){ - _attr = new(pool64.alloc()) NameDict(kInstAttrLoadFactor); - }else if constexpr(std::is_same_v || std::is_same_v){ - _attr = new(pool64.alloc()) NameDict(kInstAttrLoadFactor); - }else{ - _attr = nullptr; + void* value() override { return &_value; } + void _obj_gc_mark() override { + if constexpr (has_gc_marker::value) { + _value._gc_mark(); } } - void* value() override { return &_value; } - - void _obj_gc_mark() override { - if(gc.marked) return; - gc.marked = true; - if(_attr != nullptr) pkpy::gc_mark(*_attr); - pkpy::gc_mark(_value); // handle PyObject* inside _value `T` - } + Py_(Type type, const T& value) : PyObject(type), _value(value) {} + Py_(Type type, T&& value) : PyObject(type), _value(std::move(value)) {} }; struct MappingProxy{ PyObject* obj; MappingProxy(PyObject* obj) : obj(obj) {} - NameDict& attr() noexcept { return obj->attr(); } }; #define OBJ_GET(T, obj) (((Py_*)(obj))->_value) -#define OBJ_MARK(obj) if(!is_tagged(obj)) (obj)->_obj_gc_mark() +// #define OBJ_GET(T, obj) (*reinterpret_cast((obj)->value())) + +#define OBJ_MARK(obj) \ + if(!is_tagged(obj) && !(obj)->gc.marked) { \ + (obj)->gc.marked = true; \ + (obj)->_obj_gc_mark(); \ + if((obj)->is_attr_valid()) gc_mark_namedict((obj)->attr()); \ + } + +inline void gc_mark_namedict(NameDict& t){ + if(t.size() == 0) return; + for(uint16_t i=0; itype == type; } -#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 PyObject* register_class(VM* vm, PyObject* mod) { \ - PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \ - if(OBJ_NAME(mod) != #mod) { \ - auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \ - throw std::runtime_error(msg); \ - } \ - T::_register(vm, mod, type); \ - type->attr()._try_perfect_rehash(); \ - return type; \ - } - union BitsCvt { i64 _int; f64 _float; @@ -265,8 +247,130 @@ __T _py_cast(VM* vm, PyObject* obj) { } #define VAR(x) py_var(vm, x) -#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) +/*****************************************************************/ +template<> +struct Py_ final: PyObject { + List _value; + void* value() override { return &_value; } + + Py_(Type type, List&& val): PyObject(type), _value(std::move(val)) {} + Py_(Type type, const List& val): PyObject(type), _value(val) {} + + void _obj_gc_mark() override { + for(PyObject* obj: _value) OBJ_MARK(obj); + } +}; + +template<> +struct Py_ final: PyObject { + Tuple _value; + void* value() override { return &_value; } + + Py_(Type type, Tuple&& val): PyObject(type), _value(std::move(val)) {} + Py_(Type type, const Tuple& val): PyObject(type), _value(val) {} + + void _obj_gc_mark() override { + for(PyObject* obj: _value) OBJ_MARK(obj); + } +}; + +template<> +struct Py_ final: PyObject { + MappingProxy _value; + void* value() override { return &_value; } + Py_(Type type, MappingProxy val): PyObject(type), _value(val) {} + void _obj_gc_mark() override { + OBJ_MARK(_value.obj); + } +}; + +template<> +struct Py_ final: PyObject { + BoundMethod _value; + void* value() override { return &_value; } + Py_(Type type, BoundMethod val): PyObject(type), _value(val) {} + void _obj_gc_mark() override { + OBJ_MARK(_value.self); + OBJ_MARK(_value.func); + } +}; + +template<> +struct Py_ final: PyObject { + Slice _value; + void* value() override { return &_value; } + Py_(Type type, Slice val): PyObject(type), _value(val) {} + void _obj_gc_mark() override { + OBJ_MARK(_value.start); + OBJ_MARK(_value.stop); + OBJ_MARK(_value.step); + } +}; + +template<> +struct Py_ final: PyObject { + Function _value; + void* value() override { return &_value; } + Py_(Type type, Function val): PyObject(type), _value(val) { + enable_instance_dict(); + } + void _obj_gc_mark() override { + _value.decl->_gc_mark(); + if(_value._module != nullptr) OBJ_MARK(_value._module); + if(_value._closure != nullptr) gc_mark_namedict(*_value._closure); + } +}; + +template<> +struct Py_ final: PyObject { + NativeFunc _value; + void* value() override { return &_value; } + Py_(Type type, NativeFunc val): PyObject(type), _value(val) { + enable_instance_dict(); + } + void _obj_gc_mark() override {} +}; + +template<> +struct Py_ final: PyObject { + Super _value; + void* value() override { return &_value; } + Py_(Type type, Super val): PyObject(type), _value(val) {} + void _obj_gc_mark() override { + OBJ_MARK(_value.first); + } +}; + +template<> +struct Py_ final: PyObject { + void* value() override { return nullptr; } + Py_(Type type, DummyInstance val): PyObject(type) { + enable_instance_dict(); + } + void _obj_gc_mark() override {} +}; + +template<> +struct Py_ final: PyObject { + Type _value; + void* value() override { return &_value; } + Py_(Type type, Type val): PyObject(type), _value(val) { + enable_instance_dict(kTypeAttrLoadFactor); + } + void _obj_gc_mark() override {} +}; + +template<> +struct Py_ final: PyObject { + void* value() override { return nullptr; } + Py_(Type type, DummyModule val): PyObject(type) { + enable_instance_dict(kTypeAttrLoadFactor); + } + void _obj_gc_mark() override {} +}; + + } // namespace pkpy diff --git a/src/vm.h b/src/vm.h index 9ca31153..a6612a47 100644 --- a/src/vm.h +++ b/src/vm.h @@ -55,7 +55,7 @@ public: } PyObject* next() override; - void _gc_mark() const override; + void _gc_mark() const; }; struct PyTypeInfo{