#pragma once #include "common.h" #include "namedict.h" #include "tuplelist.h" namespace pkpy { struct CodeObject; struct Frame; struct Function; class VM; typedef PyObject* (*NativeFuncC)(VM*, ArgsView); typedef int (*LuaStyleFuncC)(VM*); struct NativeFunc { NativeFuncC f; int argc; // DONOT include self bool method; // this is designed for lua style C bindings // access it via `CAST(NativeFunc&, args[-2])._lua_f` LuaStyleFuncC _lua_f; NativeFunc(NativeFuncC f, int argc, bool method) : f(f), argc(argc), method(method), _lua_f(nullptr) {} PyObject* operator()(VM* vm, ArgsView args) const; }; typedef shared_ptr CodeObject_; struct FuncDecl { struct KwArg { int key; // index in co->varnames PyObject* value; // default value }; CodeObject_ code; // code object of this function pod_vector args; // indices in co->varnames int starred_arg = -1; // index in co->varnames, -1 if no *arg pod_vector kwargs; // indices in co->varnames bool nested = false; // whether this function is nested void _gc_mark() const; }; using FuncDecl_ = shared_ptr; struct Function{ FuncDecl_ decl; bool is_simple; int argc; // cached argc PyObject* _module; NameDict_ _closure; }; struct BoundMethod { PyObject* self; PyObject* func; BoundMethod(PyObject* self, PyObject* func) : self(self), func(func) {} bool operator==(const BoundMethod& rhs) const noexcept { return self == rhs.self && func == rhs.func; } bool operator!=(const BoundMethod& rhs) const noexcept { return self != rhs.self || func != rhs.func; } }; struct Range { i64 start = 0; i64 stop = -1; i64 step = 1; }; struct Bytes{ std::vector _data; bool _ok; int size() const noexcept { return _data.size(); } int operator[](int i) const noexcept { return (int)(uint8_t)_data[i]; } const char* data() const noexcept { return _data.data(); } bool operator==(const Bytes& rhs) const noexcept { return _data == rhs._data; } bool operator!=(const Bytes& rhs) const noexcept { return _data != rhs._data; } std::string str() const noexcept { return std::string(_data.begin(), _data.end()); } Bytes() : _data(), _ok(false) {} Bytes(std::vector&& data) : _data(std::move(data)), _ok(true) {} Bytes(const std::string& data) : _data(data.begin(), data.end()), _ok(true) {} operator bool() const noexcept { return _ok; } }; using Super = std::pair; struct Slice { PyObject* start; PyObject* stop; PyObject* step; Slice(PyObject* start, PyObject* stop, PyObject* step) : start(start), stop(stop), step(step) {} }; class BaseIter { protected: VM* vm; public: BaseIter(VM* vm) : vm(vm) {} virtual PyObject* next() = 0; virtual ~BaseIter() = default; }; struct GCHeader { bool enabled; // whether this object is managed by GC bool marked; // whether this object is marked GCHeader() : enabled(true), marked(false) {} }; struct PyObject{ GCHeader gc; Type type; NameDict* _attr; bool is_attr_valid() const noexcept { return _attr != nullptr; } NameDict& attr() noexcept { return *_attr; } PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; } virtual void* value() = 0; virtual void _obj_gc_mark() = 0; PyObject(Type type) : type(type), _attr(nullptr) {} virtual ~PyObject() { if(_attr == nullptr) return; _attr->~NameDict(); pool64.dealloc(_attr); } void enable_instance_dict(float lf=kInstAttrLoadFactor) noexcept { _attr = new(pool64.alloc()) NameDict(lf); } }; template struct has_gc_marker : std::false_type {}; template struct has_gc_marker> : std::true_type {}; template struct Py_ final: PyObject { T _value; void* value() override { return &_value; } void _obj_gc_mark() override { if constexpr (has_gc_marker::value) { _value._gc_mark(); } } 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_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; i") #else #define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) #endif const int kTpIntIndex = 2; const int kTpFloatIndex = 3; inline bool is_type(PyObject* obj, Type type) { #if DEBUG_EXTRA_CHECK if(obj == nullptr) throw std::runtime_error("is_type() called with nullptr"); if(is_special(obj)) throw std::runtime_error("is_type() called with special object"); #endif switch(type.index){ case kTpIntIndex: return is_int(obj); case kTpFloatIndex: return is_float(obj); default: return !is_tagged(obj) && obj->type == type; } } inline bool is_non_tagged_type(PyObject* obj, Type type) { #if DEBUG_EXTRA_CHECK if(obj == nullptr) throw std::runtime_error("is_non_tagged_type() called with nullptr"); if(is_special(obj)) throw std::runtime_error("is_non_tagged_type() called with special object"); #endif return !is_tagged(obj) && obj->type == type; } union BitsCvt { i64 _int; f64 _float; 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*, PyObject*); template T py_pointer_cast(VM*, PyObject*); template __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); }else if constexpr(is_py_class::value){ _check_py_class(vm, obj); return OBJ_GET(T, obj); }else { return Discarded(); } } template __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); }else if constexpr(is_py_class::value){ return OBJ_GET(T, obj); }else{ return Discarded(); } } #define VAR(x) py_var(vm, x) #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