diff --git a/docs/quick-start/example.md b/docs/quick-start/example.md index 3e117c7f..078db4f4 100644 --- a/docs/quick-start/example.md +++ b/docs/quick-start/example.md @@ -56,14 +56,14 @@ struct PyVec2: Vec2 { return VAR(Vec2(x, y)); }); - vm->bind__repr__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ PyVec2& self = _CAST(PyVec2&, obj); std::stringstream ss; ss << "vec2(" << self.x << ", " << self.y << ")"; return VAR(ss.str()); }); - vm->bind__add__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* other){ + vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* other){ PyVec2& self = _CAST(PyVec2&, obj); PyVec2& other_ = CAST(PyVec2&, other); return VAR_T(PyVec2, self + other_); diff --git a/src/ceval.h b/src/ceval.h index bcc5b3b4..521e3079 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -23,7 +23,7 @@ inline PyObject* VM::_run_top_frame(){ StrName _name; while(true){ -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK if(frame.index < base_id) FATAL_ERROR(); #endif try{ @@ -34,9 +34,16 @@ inline PyObject* VM::_run_top_frame(){ * DO NOT leave any strong reference of PyObject* in the C stack */ { + +#if PK_ENABLE_CEVAL_CALLBACK +#define CEVAL_STEP() byte = frame->next_bytecode(); if(_ceval_on_step) _ceval_on_step(this, frame, byte) +#else +#define CEVAL_STEP() byte = frame->next_bytecode() +#endif + #define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; } __NEXT_FRAME: - Bytecode byte = frame->next_bytecode(); + Bytecode CEVAL_STEP(); // cache const CodeObject* co = frame->co; const auto& co_consts = co->consts; @@ -49,16 +56,16 @@ static void* OP_LABELS[] = { #undef OPCODE }; -#define DISPATCH() { byte = frame->next_bytecode(); goto *OP_LABELS[byte.op];} +#define DISPATCH() { CEVAL_STEP(); goto *OP_LABELS[byte.op];} #define TARGET(op) CASE_OP_##op: goto *OP_LABELS[byte.op]; #else #define TARGET(op) case OP_##op: -#define DISPATCH() { byte = frame->next_bytecode(); goto __NEXT_STEP;} +#define DISPATCH() { CEVAL_STEP(); goto __NEXT_STEP;} __NEXT_STEP:; -#if DEBUG_CEVAL_STEP +#if PK_DEBUG_CEVAL_STEP _log_s_data(); #endif switch (byte.op) @@ -624,7 +631,7 @@ __NEXT_STEP:; _0 = POPX(); // super if(_0 == None) _0 = _t(tp_object); check_non_tagged_type(_0, tp_type); - _1 = new_type_object(frame->_module, _name, OBJ_GET(Type, _0)); + _1 = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0)); PUSH(_1); DISPATCH(); TARGET(END_CLASS) @@ -703,7 +710,7 @@ __NEXT_STEP:; } DISPATCH(); #if !PK_ENABLE_COMPUTED_GOTO -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK default: throw std::runtime_error(fmt(OP_NAMES[byte.op], " is not implemented")); #else default: UNREACHABLE(); @@ -715,6 +722,7 @@ __NEXT_STEP:; #undef DISPATCH #undef TARGET #undef DISPATCH_OP_CALL +#undef CEVAL_STEP /**********************************************************************/ UNREACHABLE(); }catch(HandledException& e){ @@ -725,7 +733,7 @@ __NEXT_STEP:; _e.st_push(frame->snapshot()); _pop_frame(); if(callstack.empty()){ -#if DEBUG_FULL_EXCEPTION +#if PK_DEBUG_FULL_EXCEPTION std::cerr << _e.summary() << std::endl; #endif throw _e; diff --git a/src/cffi.h b/src/cffi.h index 87c3f362..fee224a3 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -9,7 +9,7 @@ namespace pkpy { static Type _type(VM* vm) { \ static const StrName __x0(#mod); \ static const StrName __x1(#name); \ - return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ + return PK_OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ } \ static void _check_type(VM* vm, PyObject* val){ \ if(!vm->isinstance(val, T::_type(vm))){ \ @@ -72,7 +72,7 @@ struct VoidP{ return VAR(self.hex()); }); - vm->bind__repr__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ VoidP& self = _CAST(VoidP&, obj); std::stringstream ss; ss << "bind##name(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ \ + vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ \ if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return vm->NotImplemented; \ return VAR(_CAST(VoidP&, lhs) op _CAST(VoidP&, rhs)); \ }); @@ -95,7 +95,7 @@ struct VoidP{ #undef BIND_CMP - vm->bind__hash__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ VoidP& self = _CAST(VoidP&, obj); return reinterpret_cast(self.ptr); }); @@ -122,13 +122,13 @@ struct VoidP{ return VAR_T(VoidP, (char*)self.ptr + offset * self.base_offset); }); - vm->bind__add__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ VoidP& self = _CAST(VoidP&, lhs); i64 offset = CAST(i64, rhs); return VAR_T(VoidP, (char*)self.ptr + offset); }); - vm->bind__sub__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ VoidP& self = _CAST(VoidP&, lhs); i64 offset = CAST(i64, rhs); return VAR_T(VoidP, (char*)self.ptr - offset); @@ -243,7 +243,7 @@ struct C99Struct{ return VAR_T(C99Struct, self); }); - vm->bind__eq__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ C99Struct& self = _CAST(C99Struct&, lhs); if(!is_non_tagged_type(rhs, C99Struct::_type(vm))) return vm->NotImplemented; C99Struct& other = _CAST(C99Struct&, rhs); @@ -328,7 +328,7 @@ struct C99ReflType final: ReflType{ return VAR(self.size); }); - vm->bind__getitem__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* key){ + vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* key){ C99ReflType& self = _CAST(C99ReflType&, obj); const Str& name = CAST(Str&, key); auto it = std::lower_bound(self.fields.begin(), self.fields.end(), name.sv()); diff --git a/src/common.h b/src/common.h index 781c8938..4cffbbb2 100644 --- a/src/common.h +++ b/src/common.h @@ -39,11 +39,11 @@ struct GIL { explicit GIL() { _mutex.lock(); } ~GIL() { _mutex.unlock(); } }; -#define GLOBAL_SCOPE_LOCK() auto _lock = GIL(); +#define PK_GLOBAL_SCOPE_LOCK() auto _lock = GIL(); #else #define THREAD_LOCAL -#define GLOBAL_SCOPE_LOCK() +#define PK_GLOBAL_SCOPE_LOCK() #endif /*******************************************************************************/ @@ -119,11 +119,11 @@ struct Type { #define PK_ASSERT(x) if(!(x)) FATAL_ERROR(); 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_special(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b11; } +#define PK_BITS(p) (reinterpret_cast(p)) +inline bool is_tagged(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; } +inline bool is_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b01; } +inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; } +inline bool is_special(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b11; } inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept { return is_tagged(a) && is_tagged(b); diff --git a/src/compiler.h b/src/compiler.h index b78bf1c4..5a7b24e5 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1101,4 +1101,7 @@ public: } }; +#undef BC_NOARG +#undef BC_KEEPLINE + } // namespace pkpy \ No newline at end of file diff --git a/src/config.h b/src/config.h index 0546dfbc..cd8b6d96 100644 --- a/src/config.h +++ b/src/config.h @@ -14,6 +14,9 @@ // This triggers necessary locks to make the VM thread-safe #define PK_ENABLE_THREAD 0 +// Enable this for `vm->_ceval_on_step` +#define PK_ENABLE_CEVAL_CALLBACK 0 + // Whether to use `std::function` to do bindings or not // By default, functions to be binded must be a C function pointer without capture // However, someone thinks it's not convenient. @@ -24,17 +27,17 @@ /*************** debug settings ***************/ // Enable this may help you find bugs -#define DEBUG_EXTRA_CHECK 0 +#define PK_DEBUG_EXTRA_CHECK 0 // Do not edit the following settings unless you know what you are doing -#define DEBUG_NO_BUILTIN_MODULES 0 -#define DEBUG_DIS_EXEC 0 -#define DEBUG_CEVAL_STEP 0 -#define DEBUG_FULL_EXCEPTION 0 -#define DEBUG_MEMORY_POOL 0 -#define DEBUG_NO_MEMORY_POOL 0 -#define DEBUG_NO_AUTO_GC 0 -#define DEBUG_GC_STATS 0 +#define PK_DEBUG_NO_BUILTINS 0 +#define PK_DEBUG_DIS_EXEC 0 +#define PK_DEBUG_CEVAL_STEP 0 +#define PK_DEBUG_FULL_EXCEPTION 0 +#define PK_DEBUG_MEMORY_POOL 0 +#define PK_DEBUG_NO_MEMORY_POOL 0 +#define PK_DEBUG_NO_AUTO_GC 0 +#define PK_DEBUG_GC_STATS 0 /*************** internal settings ***************/ @@ -75,7 +78,7 @@ inline const float kTypeAttrLoadFactor = 0.5f; #endif -#if DEBUG_CEVAL_STEP && defined(PK_ENABLE_COMPUTED_GOTO) +#if PK_DEBUG_CEVAL_STEP && defined(PK_ENABLE_COMPUTED_GOTO) #undef PK_ENABLE_COMPUTED_GOTO #endif diff --git a/src/frame.h b/src/frame.h index 3960dfc2..8afd6cdf 100644 --- a/src/frame.h +++ b/src/frame.h @@ -86,7 +86,7 @@ struct ValueStackImpl { PyObject** begin() { return _begin; } PyObject** end() { return _sp; } void reset(PyObject** sp) { -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK if(sp < _begin || sp > _begin + MAX_SIZE) FATAL_ERROR(); #endif _sp = sp; @@ -118,7 +118,7 @@ struct Frame { PyObject* f_closure_try_get(StrName name){ if(_callable == nullptr) return nullptr; - Function& fn = OBJ_GET(Function, _callable); + Function& fn = PK_OBJ_GET(Function, _callable); if(fn._closure == nullptr) return nullptr; return fn._closure->try_get(name); } @@ -134,7 +134,7 @@ struct Frame { Bytecode next_bytecode() { _ip = _next_ip++; -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK if(_ip >= co->codes.size()) FATAL_ERROR(); #endif return co->codes[_ip]; diff --git a/src/gc.h b/src/gc.h index d7db4d74..b247b295 100644 --- a/src/gc.h +++ b/src/gc.h @@ -65,7 +65,7 @@ struct ManagedHeap{ return obj; } -#if DEBUG_GC_STATS +#if PK_DEBUG_GC_STATS inline static std::map deleted; #endif @@ -76,7 +76,7 @@ struct ManagedHeap{ obj->gc.marked = false; alive.push_back(obj); }else{ -#if DEBUG_GC_STATS +#if PK_DEBUG_GC_STATS deleted[obj->type] += 1; #endif if(_gc_on_delete) _gc_on_delete(vm, obj); @@ -96,7 +96,7 @@ struct ManagedHeap{ } void _auto_collect(){ -#if !DEBUG_NO_AUTO_GC +#if !PK_DEBUG_NO_AUTO_GC if(_gc_lock_counter > 0) return; if(gc_counter < gc_threshold) return; gc_counter = 0; @@ -118,7 +118,7 @@ struct ManagedHeap{ ~ManagedHeap(){ for(PyObject* obj: _no_gc) { obj->~PyObject(); pool64.dealloc(obj); } for(PyObject* obj: gen) { obj->~PyObject(); pool64.dealloc(obj); } -#if DEBUG_GC_STATS +#if PK_DEBUG_GC_STATS for(auto& [type, count]: deleted){ std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl; } diff --git a/src/iter.h b/src/iter.h index 42ed993d..469e4316 100644 --- a/src/iter.h +++ b/src/iter.h @@ -13,10 +13,10 @@ struct RangeIter{ RangeIter(Range r) : r(r), current(r.start) {} static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->_all_types[OBJ_GET(Type, type)].subclass_enabled = false; + vm->_all_types[PK_OBJ_GET(Type, type)].subclass_enabled = false; vm->bind_notimplemented_constructor(type); - vm->bind__iter__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); - vm->bind__next__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); + vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ RangeIter& self = _CAST(RangeIter&, obj); bool has_next = self.r.step > 0 ? self.current < self.r.stop : self.current > self.r.stop; if(!has_next) return vm->StopIteration; @@ -39,10 +39,10 @@ struct ArrayIter{ void _gc_mark() const{ OBJ_MARK(ref); } static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->_all_types[OBJ_GET(Type, type)].subclass_enabled = false; + vm->_all_types[PK_OBJ_GET(Type, type)].subclass_enabled = false; vm->bind_notimplemented_constructor(type); - vm->bind__iter__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); - vm->bind__next__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); + vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ ArrayIter& self = _CAST(ArrayIter&, obj); if(self.current == self.end) return vm->StopIteration; return *self.current++; @@ -56,15 +56,15 @@ struct StringIter{ Str* str; int index; - StringIter(PyObject* ref) : ref(ref), str(&OBJ_GET(Str, ref)), index(0) {} + StringIter(PyObject* ref) : ref(ref), str(&PK_OBJ_GET(Str, ref)), index(0) {} void _gc_mark() const{ OBJ_MARK(ref); } static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->_all_types[OBJ_GET(Type, type)].subclass_enabled = false; + vm->_all_types[PK_OBJ_GET(Type, type)].subclass_enabled = false; vm->bind_notimplemented_constructor(type); - vm->bind__iter__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); - vm->bind__next__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); + vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ StringIter& self = _CAST(StringIter&, obj); // TODO: optimize this... operator[] is of O(n) complexity if(self.index == self.str->u8_length()) return vm->StopIteration; @@ -114,10 +114,10 @@ struct Generator{ } static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->_all_types[OBJ_GET(Type, type)].subclass_enabled = false; + vm->_all_types[PK_OBJ_GET(Type, type)].subclass_enabled = false; vm->bind_notimplemented_constructor(type); - vm->bind__iter__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); - vm->bind__next__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ return obj; }); + vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ Generator& self = _CAST(Generator&, obj); return self.next(vm); }); diff --git a/src/linalg.h b/src/linalg.h index 92b9a08f..31a22fb1 100644 --- a/src/linalg.h +++ b/src/linalg.h @@ -335,7 +335,7 @@ struct PyVec2: Vec2 { return VAR(Tuple({ VAR(self.x), VAR(self.y) })); }); - vm->bind__repr__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ PyVec2& self = _CAST(PyVec2&, obj); std::stringstream ss; ss << "vec2(" << self.x << ", " << self.y << ")"; @@ -395,7 +395,7 @@ struct PyVec3: Vec3 { return VAR(Tuple({ VAR(self.x), VAR(self.y), VAR(self.z) })); }); - vm->bind__repr__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ PyVec3& self = _CAST(PyVec3&, obj); std::stringstream ss; ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")"; @@ -476,7 +476,7 @@ struct PyMat3x3: Mat3x3{ #undef METHOD_PROXY_NONE - vm->bind__repr__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ PyMat3x3& self = _CAST(PyMat3x3&, obj); std::stringstream ss; ss << std::fixed << std::setprecision(4); @@ -491,7 +491,7 @@ struct PyMat3x3: Mat3x3{ return VAR_T(PyMat3x3, self); }); - vm->bind__getitem__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* index){ + vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* index){ PyMat3x3& self = _CAST(PyMat3x3&, obj); Tuple& t = CAST(Tuple&, index); if(t.size() != 2){ diff --git a/src/memory.h b/src/memory.h index 996952ae..ec2d2893 100644 --- a/src/memory.h +++ b/src/memory.h @@ -40,7 +40,7 @@ struct DoubleLinkedList{ } void pop_back(){ -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); #endif tail.prev->prev->next = &tail; @@ -49,7 +49,7 @@ struct DoubleLinkedList{ } void pop_front(){ -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list"); #endif head.next->next->prev = &head; @@ -58,21 +58,21 @@ struct DoubleLinkedList{ } T* back() const { -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list"); #endif return static_cast(tail.prev); } T* front() const { -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list"); #endif return static_cast(head.next); } void erase(T* node){ -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list"); LinkedListNode* n = head.next; while(n != &tail){ @@ -99,7 +99,7 @@ struct DoubleLinkedList{ } bool empty() const { -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(size() == 0){ if(head.next != &tail || tail.prev != &head){ throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty"); @@ -152,7 +152,7 @@ struct MemoryPool{ } Block* alloc(){ -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena"); #endif _free_list_size--; @@ -160,7 +160,7 @@ struct MemoryPool{ } void dealloc(Block* block){ -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(full()) throw std::runtime_error("Arena::dealloc() called on full arena"); #endif _free_list[_free_list_size] = block; @@ -175,8 +175,8 @@ struct MemoryPool{ void* alloc() { return alloc(sizeof(__T)); } void* alloc(size_t size){ - GLOBAL_SCOPE_LOCK(); -#if DEBUG_NO_MEMORY_POOL + PK_GLOBAL_SCOPE_LOCK(); +#if PK_DEBUG_NO_MEMORY_POOL return malloc(size); #endif if(size > __BlockSize){ @@ -200,12 +200,12 @@ struct MemoryPool{ } void dealloc(void* p){ - GLOBAL_SCOPE_LOCK(); -#if DEBUG_NO_MEMORY_POOL + PK_GLOBAL_SCOPE_LOCK(); +#if PK_DEBUG_NO_MEMORY_POOL free(p); return; #endif -#if DEBUG_MEMORY_POOL +#if PK_DEBUG_MEMORY_POOL if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr"); #endif Block* block = (Block*)((char*)p - sizeof(void*)); diff --git a/src/obj.h b/src/obj.h index c089c4db..471dd71f 100644 --- a/src/obj.h +++ b/src/obj.h @@ -43,7 +43,7 @@ struct NativeFunc { T get_userdata() const { static_assert(std::is_trivially_copyable_v); static_assert(sizeof(T) <= sizeof(UserData)); -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK if(!_has_userdata) throw std::runtime_error("userdata not set"); #endif return reinterpret_cast(_userdata); @@ -199,7 +199,7 @@ struct MappingProxy{ NameDict& attr() noexcept { return obj->attr(); } }; -#define OBJ_GET(T, obj) (((Py_*)(obj))->_value) +#define PK_OBJ_GET(T, obj) (((Py_*)(obj))->_value) #define OBJ_MARK(obj) \ if(!is_tagged(obj) && !(obj)->gc.marked) { \ @@ -218,18 +218,18 @@ inline void gc_mark_namedict(NameDict& t){ Str obj_type_name(VM* vm, Type type); -#if DEBUG_NO_BUILTIN_MODULES +#if PK_DEBUG_NO_BUILTINS #define OBJ_NAME(obj) Str("") #else DEF_SNAME(__name__); -#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) +#define OBJ_NAME(obj) PK_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 PK_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 @@ -241,7 +241,7 @@ inline bool is_type(PyObject* obj, Type type) { } inline bool is_non_tagged_type(PyObject* obj, Type type) { -#if DEBUG_EXTRA_CHECK +#if PK_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 @@ -270,7 +270,7 @@ __T py_cast(VM* vm, PyObject* obj) { return to_void_p(vm, obj); }else if constexpr(is_py_class::value){ T::_check_type(vm, obj); - return OBJ_GET(T, obj); + return PK_OBJ_GET(T, obj); }else if constexpr(std::is_pod_v){ return to_c99_struct(vm, obj); }else { @@ -286,7 +286,7 @@ __T _py_cast(VM* vm, PyObject* obj) { }else if constexpr(std::is_pointer_v<__T>){ return to_void_p<__T>(vm, obj); }else if constexpr(is_py_class::value){ - return OBJ_GET(T, obj); + return PK_OBJ_GET(T, obj); }else if constexpr(std::is_pod_v){ return to_c99_struct(vm, obj); }else { @@ -430,8 +430,8 @@ struct Py_ final: PyObject { template inline T lambda_get_userdata(PyObject** p){ - if(p[-1] != PY_NULL) return OBJ_GET(NativeFunc, p[-1]).get_userdata(); - else return OBJ_GET(NativeFunc, p[-2]).get_userdata(); + if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1]).get_userdata(); + else return PK_OBJ_GET(NativeFunc, p[-2]).get_userdata(); } diff --git a/src/pocketpy.h b/src/pocketpy.h index 6b60a2e9..6783ebd7 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -24,7 +24,7 @@ inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool try{ return compiler.compile(); }catch(Exception& e){ -#if DEBUG_FULL_EXCEPTION +#if PK_DEBUG_FULL_EXCEPTION std::cerr << e.summary() << std::endl; #endif _error(e); @@ -75,9 +75,9 @@ inline void init_builtins(VM* _vm) { _vm->bind_builtin_func<2>("super", [](VM* vm, ArgsView args) { vm->check_non_tagged_type(args[0], vm->tp_type); - Type type = OBJ_GET(Type, args[0]); + Type type = PK_OBJ_GET(Type, args[0]); if(!vm->isinstance(args[1], type)){ - Str _0 = obj_type_name(vm, OBJ_GET(Type, vm->_t(args[1]))); + Str _0 = obj_type_name(vm, PK_OBJ_GET(Type, vm->_t(args[1]))); Str _1 = obj_type_name(vm, type); vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape()); } @@ -87,7 +87,7 @@ inline void init_builtins(VM* _vm) { _vm->bind_builtin_func<2>("isinstance", [](VM* vm, ArgsView args) { vm->check_non_tagged_type(args[1], vm->tp_type); - Type type = OBJ_GET(Type, args[1]); + Type type = PK_OBJ_GET(Type, args[1]); return VAR(vm->isinstance(args[0], type)); }); @@ -260,11 +260,11 @@ inline void init_builtins(VM* _vm) { }); _vm->bind__eq__(_vm->tp_object, [](VM* vm, PyObject* lhs, PyObject* rhs) { return VAR(lhs == rhs); }); - _vm->bind__hash__(_vm->tp_object, [](VM* vm, PyObject* obj) { return BITS(obj); }); + _vm->bind__hash__(_vm->tp_object, [](VM* vm, PyObject* obj) { return PK_BITS(obj); }); _vm->cached_object__new__ = _vm->bind_constructor<1>("object", [](VM* vm, ArgsView args) { vm->check_non_tagged_type(args[0], vm->tp_type); - Type t = OBJ_GET(Type, args[0]); + Type t = PK_OBJ_GET(Type, args[0]); return vm->heap.gcnew(t, {}); }); @@ -282,7 +282,7 @@ inline void init_builtins(VM* _vm) { return VAR(r); }); - _vm->bind__iter__(_vm->tp_range, [](VM* vm, PyObject* obj) { return VAR_T(RangeIter, OBJ_GET(Range, obj)); }); + _vm->bind__iter__(_vm->tp_range, [](VM* vm, PyObject* obj) { return VAR_T(RangeIter, PK_OBJ_GET(Range, obj)); }); _vm->bind__repr__(_vm->_type("NoneType"), [](VM* vm, PyObject* obj) { return VAR("None"); }); _vm->bind__json__(_vm->_type("NoneType"), [](VM* vm, PyObject* obj) { return VAR("null"); }); @@ -1362,11 +1362,11 @@ inline void VM::post_init(){ _t(tp_object)->attr().set("__class__", property(CPP_LAMBDA(vm->_t(args[0])))); _t(tp_type)->attr().set("__base__", property([](VM* vm, ArgsView args){ - const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])]; + const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj; })); _t(tp_type)->attr().set("__name__", property([](VM* vm, ArgsView args){ - const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])]; + const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; return VAR(info.name); })); @@ -1396,7 +1396,7 @@ inline void VM::post_init(){ return VAR(MappingProxy(args[0])); })); -#if !DEBUG_NO_BUILTIN_MODULES +#if !PK_DEBUG_NO_BUILTINS add_module_sys(this); add_module_traceback(this); add_module_time(this); diff --git a/src/vm.h b/src/vm.h index 38496941..70b5246f 100644 --- a/src/vm.h +++ b/src/vm.h @@ -28,17 +28,17 @@ namespace pkpy{ #define DEF_NATIVE_2(ctype, ptype) \ template<> inline ctype py_cast(VM* vm, PyObject* obj) { \ vm->check_non_tagged_type(obj, vm->ptype); \ - return OBJ_GET(ctype, obj); \ + return PK_OBJ_GET(ctype, obj); \ } \ template<> inline ctype _py_cast(VM* vm, PyObject* obj) { \ - return OBJ_GET(ctype, obj); \ + return PK_OBJ_GET(ctype, obj); \ } \ template<> inline ctype& py_cast(VM* vm, PyObject* obj) { \ vm->check_non_tagged_type(obj, vm->ptype); \ - return OBJ_GET(ctype, obj); \ + return PK_OBJ_GET(ctype, obj); \ } \ template<> inline ctype& _py_cast(VM* vm, PyObject* obj) { \ - return OBJ_GET(ctype, obj); \ + return PK_OBJ_GET(ctype, obj); \ } \ inline PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);} \ inline PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));} @@ -124,6 +124,10 @@ public: PyObject* _last_exception; +#if PK_ENABLE_CEVAL_CALLBACK + void (*_ceval_on_step)(VM*, Frame*, Bytecode bc) = nullptr; +#endif + PrintFunc _stdout; PrintFunc _stderr; Bytes (*_import_handler)(const Str& name); @@ -152,7 +156,7 @@ public: } FrameId top_frame() { -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK if(callstack.empty()) FATAL_ERROR(); #endif return FrameId(&callstack.data(), callstack.size()-1); @@ -194,7 +198,7 @@ public: do{ val = cls->attr().try_get(name); if(val != nullptr) return val; - Type base = _all_types[OBJ_GET(Type, cls)].base; + Type base = _all_types[PK_OBJ_GET(Type, cls)].base; if(base.index == -1) break; cls = _all_types[base].obj; }while(true); @@ -202,7 +206,7 @@ public: } bool isinstance(PyObject* obj, Type cls_t){ - Type obj_t = OBJ_GET(Type, _t(obj)); + Type obj_t = PK_OBJ_GET(Type, _t(obj)); do{ if(obj_t == cls_t) return true; Type base = _all_types[obj_t].base; @@ -216,14 +220,14 @@ public: if(_module == nullptr) _module = _main; try { CodeObject_ code = compile(source, filename, mode); -#if DEBUG_DIS_EXEC +#if PK_DEBUG_DIS_EXEC if(_module == _main) std::cout << disassemble(code) << '\n'; #endif return _exec(code, _module); }catch (const Exception& e){ _stderr(this, e.summary() + "\n"); } -#if !DEBUG_FULL_EXCEPTION +#if !PK_DEBUG_FULL_EXCEPTION catch (const std::exception& e) { Str msg = "An std::exception occurred! It could be a bug.\n"; msg = msg + e.what(); @@ -301,7 +305,7 @@ public: Type _new_type_object(StrName name, Type base=0) { PyObject* obj = new_type_object(nullptr, name, base, false); - return OBJ_GET(Type, obj); + return PK_OBJ_GET(Type, obj); } PyObject* _find_type_object(const Str& type){ @@ -316,7 +320,7 @@ public: Type _type(const Str& type){ PyObject* obj = _find_type_object(type); - return OBJ_GET(Type, obj); + return PK_OBJ_GET(Type, obj); } PyTypeInfo* _type_info(const Str& type){ @@ -325,7 +329,7 @@ public: for(auto& t: _all_types) if(t.name == type) return &t; FATAL_ERROR(); } - return &_all_types[OBJ_GET(Type, obj)]; + return &_all_types[PK_OBJ_GET(Type, obj)]; } PyTypeInfo* _type_info(Type type){ @@ -344,7 +348,7 @@ public: PyObject* nf = bind_method<0>(_t(type), #name, [](VM* vm, ArgsView args){ \ return lambda_get_userdata(args.begin())(vm, args[0]);\ }); \ - OBJ_GET(NativeFunc, nf).set_userdata(f); \ + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); \ } BIND_UNARY_SPECIAL(__repr__) @@ -367,7 +371,7 @@ public: PyObject* nf = bind_method<1>(obj, #name, [](VM* vm, ArgsView args){ \ return lambda_get_userdata(args.begin())(vm, args[0], args[1]); \ }); \ - OBJ_GET(NativeFunc, nf).set_userdata(f); \ + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); \ } BIND_BINARY_SPECIAL(__eq__) @@ -400,7 +404,7 @@ public: PyObject* nf = bind_method<1>(obj, "__getitem__", [](VM* vm, ArgsView args){ return lambda_get_userdata(args.begin())(vm, args[0], args[1]); }); - OBJ_GET(NativeFunc, nf).set_userdata(f); + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); } void bind__setitem__(Type type, void (*f)(VM*, PyObject*, PyObject*, PyObject*)){ @@ -410,7 +414,7 @@ public: lambda_get_userdata(args.begin())(vm, args[0], args[1], args[2]); return vm->None; }); - OBJ_GET(NativeFunc, nf).set_userdata(f); + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); } void bind__delitem__(Type type, void (*f)(VM*, PyObject*, PyObject*)){ @@ -420,7 +424,7 @@ public: lambda_get_userdata(args.begin())(vm, args[0], args[1]); return vm->None; }); - OBJ_GET(NativeFunc, nf).set_userdata(f); + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); } bool py_equals(PyObject* lhs, PyObject* rhs){ @@ -463,7 +467,7 @@ public: template PyObject* bind_default_constructor(__T&& type) { return bind_constructor<1>(std::forward<__T>(type), [](VM* vm, ArgsView args){ - Type t = OBJ_GET(Type, args[0]); + Type t = PK_OBJ_GET(Type, args[0]); return vm->heap.gcnew(t, T()); }); } @@ -513,7 +517,7 @@ public: void IndexError(const Str& msg){ _error("IndexError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); } void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } - void KeyError(PyObject* obj){ _error("KeyError", OBJ_GET(Str, py_repr(obj))); } + void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); } void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); } void AttributeError(PyObject* obj, StrName name){ @@ -638,7 +642,7 @@ public: _modules.clear(); _lazy_modules.clear(); } -#if DEBUG_CEVAL_STEP +#if PK_DEBUG_CEVAL_STEP void _log_s_data(const char* title = nullptr); #endif void _unpack_as_list(ArgsView args, List& list); @@ -672,7 +676,7 @@ inline PyObject* NativeFunc::operator()(VM* vm, ArgsView args) const{ if(args.size() != argc && argc != -1) { vm->TypeError(fmt("expected ", argc, " arguments, got ", args.size())); } -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK if(f == nullptr) FATAL_ERROR(); #endif return f(vm, args); @@ -698,10 +702,10 @@ DEF_NATIVE_2(StarWrapper, tp_star_wrapper) #define PY_CAST_INT(T) \ template<> inline T py_cast(VM* vm, PyObject* obj){ \ vm->check_int(obj); \ - return (T)(BITS(obj) >> 2); \ + return (T)(PK_BITS(obj) >> 2); \ } \ template<> inline T _py_cast(VM* vm, PyObject* obj){ \ - return (T)(BITS(obj) >> 2); \ + return (T)(PK_BITS(obj) >> 2); \ } PY_CAST_INT(char) @@ -718,20 +722,20 @@ PY_CAST_INT(unsigned long long) template<> inline float py_cast(VM* vm, PyObject* obj){ vm->check_float(obj); - i64 bits = BITS(obj) & Number::c1; + i64 bits = PK_BITS(obj) & Number::c1; return BitsCvt(bits)._float; } template<> inline float _py_cast(VM* vm, PyObject* obj){ - i64 bits = BITS(obj) & Number::c1; + i64 bits = PK_BITS(obj) & Number::c1; return BitsCvt(bits)._float; } template<> inline double py_cast(VM* vm, PyObject* obj){ vm->check_float(obj); - i64 bits = BITS(obj) & Number::c1; + i64 bits = PK_BITS(obj) & Number::c1; return BitsCvt(bits)._float; } template<> inline double _py_cast(VM* vm, PyObject* obj){ - i64 bits = BITS(obj) & Number::c1; + i64 bits = PK_BITS(obj) & Number::c1; return BitsCvt(bits)._float; } @@ -1050,7 +1054,7 @@ inline Str VM::disassemble(CodeObject_ co){ return Str(ss.str()); } -#if DEBUG_CEVAL_STEP +#if PK_DEBUG_CEVAL_STEP inline void VM::_log_s_data(const char* title) { if(_main == nullptr) return; if(callstack.empty()) return; @@ -1080,7 +1084,7 @@ inline void VM::_log_s_data(const char* title) { auto& f = CAST(Function&, obj); ss << f.decl->code->name << "(...)"; } else if(is_type(obj, tp_type)){ - Type t = OBJ_GET(Type, obj); + Type t = PK_OBJ_GET(Type, obj); ss << ""; } else if(is_type(obj, tp_list)){ auto& t = CAST(List&, obj); @@ -1220,7 +1224,7 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ ArgsView args(p1 - ARGC - int(method_call), p1); if(is_non_tagged_type(callable, tp_native_func)){ - const auto& f = OBJ_GET(NativeFunc, callable); + const auto& f = PK_OBJ_GET(NativeFunc, callable); if(KWARGC != 0) TypeError("native_func does not accept keyword arguments"); PyObject* ret = f(this, args); s_data.reset(p0); @@ -1327,12 +1331,12 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ DEF_SNAME(__new__); PyObject* new_f = find_name_in_mro(callable, __new__); PyObject* obj; -#if DEBUG_EXTRA_CHECK +#if PK_DEBUG_EXTRA_CHECK PK_ASSERT(new_f != nullptr); #endif if(new_f == cached_object__new__) { // fast path for object.__new__ - Type t = OBJ_GET(Type, callable); + Type t = PK_OBJ_GET(Type, callable); obj= vm->heap.gcnew(t, {}); }else{ PUSH(new_f); @@ -1382,7 +1386,7 @@ inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){ PyObject* objtype; // handle super() proxy if(is_non_tagged_type(obj, tp_super)){ - const Super& super = OBJ_GET(Super, obj); + const Super& super = PK_OBJ_GET(Super, obj); obj = super.first; objtype = _t(super.second); }else{ @@ -1419,7 +1423,7 @@ inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** PyObject* objtype; // handle super() proxy if(is_non_tagged_type(obj, tp_super)){ - const Super& super = OBJ_GET(Super, obj); + const Super& super = PK_OBJ_GET(Super, obj); obj = super.first; objtype = _t(super.second); }else{ @@ -1456,7 +1460,7 @@ inline void VM::setattr(PyObject* obj, StrName name, PyObject* value){ PyObject* objtype; // handle super() proxy if(is_non_tagged_type(obj, tp_super)){ - Super& super = OBJ_GET(Super, obj); + Super& super = PK_OBJ_GET(Super, obj); obj = super.first; objtype = _t(super.second); }else{ @@ -1547,7 +1551,7 @@ inline void VM::bind__hash__(Type type, i64 (*f)(VM*, PyObject*)){ i64 ret = lambda_get_userdata(args.begin())(vm, args[0]); return VAR(ret); }); - OBJ_GET(NativeFunc, nf).set_userdata(f); + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); } inline void VM::bind__len__(Type type, i64 (*f)(VM*, PyObject*)){ @@ -1557,7 +1561,7 @@ inline void VM::bind__len__(Type type, i64 (*f)(VM*, PyObject*)){ i64 ret = lambda_get_userdata(args.begin())(vm, args[0]); return VAR(ret); }); - OBJ_GET(NativeFunc, nf).set_userdata(f); + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); }