From 44be9e8bde02408ad22d37051bea8dffd1756896 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 20 Feb 2023 02:56:52 +0800 Subject: [PATCH] tag pointers --- src/ceval.h | 2 +- src/memory.h | 66 +++++++++++++++----------- src/obj.h | 97 +++++++++++++------------------------- src/pocketpy.h | 48 +++++++++---------- src/vm.h | 123 +++++++++++++++++++++++++++++++------------------ 5 files changed, 173 insertions(+), 163 deletions(-) diff --git a/src/ceval.h b/src/ceval.h index 76fcb5ec..22f55e5e 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -69,7 +69,7 @@ PyVar VM::run_frame(Frame* frame){ pkpy::Args items = frame->pop_n_reversed(byte.arg); bool done = false; for(int i=0; iis_type(tp_ref)) { + if(!is_type(items[i], tp_ref)) { done = true; for(int j=i; jtry_deref(this, items[j]); frame->push(PyTuple(std::move(items))); diff --git a/src/memory.h b/src/memory.h index eeb3db16..ed295d6b 100644 --- a/src/memory.h +++ b/src/memory.h @@ -20,38 +20,38 @@ namespace pkpy{ class shared_ptr { int* counter; -#define _t() ((T*)(counter + 1)) -#define _inc_counter() if(counter) ++(*counter) -#define _dec_counter() if(counter && --(*counter) == 0){ SpAllocator::dealloc(counter); } + inline T* _t() const { + if(is_tagged()) UNREACHABLE(); + return (T*)(counter + 1); + } + inline void _inc_counter() const { if(counter) ++(*counter); } + inline void _dec_counter() const { if(counter && --(*counter) == 0){ SpAllocator::dealloc(counter); } } public: shared_ptr() : counter(nullptr) {} shared_ptr(int* counter) : counter(counter) {} shared_ptr(const shared_ptr& other) : counter(other.counter) { - _inc_counter(); + if(!is_tagged()) _inc_counter(); } shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) { other.counter = nullptr; } - ~shared_ptr() { _dec_counter(); } + ~shared_ptr() { if(!is_tagged()) _dec_counter(); } - bool operator==(const shared_ptr& other) const { - return counter == other.counter; - } - - bool operator!=(const shared_ptr& other) const { - return counter != other.counter; - } - - bool operator==(std::nullptr_t) const { - return counter == nullptr; - } - - bool operator!=(std::nullptr_t) const { - return counter != nullptr; - } + bool operator==(const shared_ptr& other) const { return counter == other.counter; } + bool operator!=(const shared_ptr& other) const { return counter != other.counter; } + bool operator<(const shared_ptr& other) const { return counter < other.counter; } + bool operator>(const shared_ptr& other) const { return counter > other.counter; } + bool operator<=(const shared_ptr& other) const { return counter <= other.counter; } + bool operator>=(const shared_ptr& other) const { return counter >= other.counter; } + bool operator==(std::nullptr_t) const { return counter == nullptr; } + bool operator!=(std::nullptr_t) const { return counter != nullptr; } shared_ptr& operator=(const shared_ptr& other) { + if(is_tagged()) { + counter = other.counter; + return *this; + } _dec_counter(); counter = other.counter; _inc_counter(); @@ -59,6 +59,11 @@ namespace pkpy{ } shared_ptr& operator=(shared_ptr&& other) noexcept { + if(is_tagged()) { + counter = other.counter; + other.counter = nullptr; + return *this; + } _dec_counter(); counter = other.counter; other.counter = nullptr; @@ -68,17 +73,26 @@ namespace pkpy{ T& operator*() const { return *_t(); } T* operator->() const { return _t(); } T* get() const { return _t(); } - int use_count() const { return counter ? *counter : 0; } + + int use_count() const { + if(is_tagged()) return 1; + return counter ? *counter : 0; + } void reset(){ - _dec_counter(); + if(!is_tagged()) _dec_counter(); counter = nullptr; } - }; -#undef _t -#undef _inc_counter -#undef _dec_counter + template + inline __VAL cast() const { return reinterpret_cast<__VAL>(counter); } + + inline bool is_tagged() const { return (cast() & 0b11) != 0b00; } + inline bool is_tag_00() const { return (cast() & 0b11) == 0b00; } + inline bool is_tag_01() const { return (cast() & 0b11) == 0b01; } + inline bool is_tag_10() const { return (cast() & 0b11) == 0b10; } + inline bool is_tag_11() const { return (cast() & 0b11) == 0b11; } + }; template shared_ptr make_shared(Args&&... args) { diff --git a/src/obj.h b/src/obj.h index 596c8d41..b8b8c8bd 100644 --- a/src/obj.h +++ b/src/obj.h @@ -79,17 +79,13 @@ public: struct PyObject { Type type; pkpy::NameDict* _attr; - // void* _tid; - const int _size; inline bool is_attr_valid() const noexcept { return _attr != nullptr; } inline pkpy::NameDict& attr() noexcept { return *_attr; } inline PyVar& attr(const Str& name) noexcept { return (*_attr)[name]; } - - inline bool is_type(Type type) const noexcept{ return this->type == type; } virtual void* value() = 0; - PyObject(Type type, const int size) : type(type), _size(size) {} + PyObject(Type type) : type(type) {} virtual ~PyObject() { delete _attr; } }; @@ -97,8 +93,8 @@ template struct Py_ : PyObject { T _value; - Py_(Type type, const T& val): PyObject(type, sizeof(Py_)), _value(val) { _init(); } - Py_(Type type, T&& val): PyObject(type, sizeof(Py_)), _value(std::move(val)) { _init(); } + Py_(Type type, const T& val): PyObject(type), _value(val) { _init(); } + Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); } inline void _init() noexcept { if constexpr (std::is_same_v || std::is_same_v) { @@ -113,66 +109,37 @@ struct Py_ : PyObject { #define OBJ_GET(T, obj) (((Py_*)((obj).get()))->_value) #define OBJ_NAME(obj) OBJ_GET(Str, (obj)->attr(__name__)) +const int kTpIntIndex = 2; +const int kTpFloatIndex = 3; + +inline bool is_type(const PyVar& obj, Type type) noexcept { + switch(type.index){ + case kTpIntIndex: return obj.is_tag_01(); + case kTpFloatIndex: return obj.is_tag_10(); + default: return obj->type == type; + } +} + +inline bool is_int_or_float(const PyVar& obj) noexcept { + return obj.is_tag_01() || obj.is_tag_10(); +} + +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(mod, name) \ inline static Type _type(VM* vm) { return OBJ_GET(Type, vm->_modules[#mod]->attr(#name)); } \ inline static const char* _mod() { return #mod; } \ inline static const char* _name() { return #name; } - -namespace pkpy { - template - struct MemBlock { - std::vector a; - int block_size; - - MemBlock(int block_size) : block_size(block_size) { - new_block(); - } - - void new_block(){ - int8_t* total = (int8_t*)malloc(N * block_size); - for(int i = 0; i < block_size; ++i){ - a.push_back((void*)(total + i * N)); - } - } - - inline void* alloc(){ - if(a.empty()) new_block(); - void* p = a.back(); - a.pop_back(); - return p; - } - - inline void dealloc(void* p) noexcept{ - a.push_back(p); - } - - ~MemBlock(){ - free(a[0]); - } - }; - - constexpr int kMemObjSize = sizeof(int) + sizeof(Py_); - static THREAD_LOCAL MemBlock _mem_pool(512); - - template<> - struct SpAllocator { - template - inline static int* alloc(){ - if constexpr (sizeof(int) + sizeof(U) == kMemObjSize) { - return (int*)_mem_pool.alloc(); - } - return (int*)malloc(sizeof(int) + sizeof(U)); - } - - inline static void dealloc(int* counter){ - PyObject* obj = (PyObject*)(counter + 1); - obj->~PyObject(); - if(obj->_size == kMemObjSize - sizeof(int)){ - _mem_pool.dealloc(counter); - }else{ - free(counter); - } - } - }; -} \ No newline at end of file +union __8B { + i64 _int; + f64 _float; + __8B(i64 val) : _int(val) {} + __8B(f64 val) : _float(val) {} +}; \ No newline at end of file diff --git a/src/pocketpy.h b/src/pocketpy.h index 72918acb..eb5b74ea 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -19,8 +19,8 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) { } #define BIND_NUM_ARITH_OPT(name, op) \ - _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \ - if(args[0]->is_type(vm->tp_int) && args[1]->is_type(vm->tp_int)){ \ + _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \ + if(is_type(args[0], vm->tp_int) && is_type(args[1], vm->tp_int)){ \ return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \ }else{ \ return vm->PyFloat(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ @@ -28,11 +28,9 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) { }); #define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \ - _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \ - bool _0 = args[0]->is_type(vm->tp_int) || args[0]->is_type(vm->tp_float); \ - bool _1 = args[1]->is_type(vm->tp_int) || args[1]->is_type(vm->tp_float); \ - if(!_0 || !_1){ \ - if constexpr(is_eq) return vm->PyBool(args[0].get() op args[1].get()); \ + _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \ + if(!is_int_or_float(args[0]) || !is_int_or_float(args[1])){ \ + if constexpr(is_eq) return vm->PyBool(args[0] op args[1]); \ vm->TypeError("unsupported operand type(s) for " #op ); \ } \ return vm->PyBool(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ @@ -170,7 +168,7 @@ void init_builtins(VM* _vm) { }); _vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, pkpy::Args& args) { - if(args[0]->is_type(vm->tp_int) && args[1]->is_type(vm->tp_int)){ + if(is_int(args[0]) && is_int(args[1])){ i64 lhs = vm->PyInt_AS_C(args[0]); i64 rhs = vm->PyInt_AS_C(args[1]); bool flag = false; @@ -190,18 +188,18 @@ void init_builtins(VM* _vm) { /************ PyInt ************/ _vm->bind_static_method<1>("int", "__new__", [](VM* vm, pkpy::Args& args) { - if (args[0]->is_type(vm->tp_int)) return args[0]; - if (args[0]->is_type(vm->tp_float)) return vm->PyInt((i64)vm->PyFloat_AS_C(args[0])); - if (args[0]->is_type(vm->tp_bool)) return vm->PyInt(vm->PyBool_AS_C(args[0]) ? 1 : 0); - if (args[0]->is_type(vm->tp_str)) { + if (is_type(args[0], vm->tp_int)) return args[0]; + if (is_type(args[0], vm->tp_float)) return vm->PyInt((i64)vm->PyFloat_AS_C(args[0])); + if (is_type(args[0], vm->tp_bool)) return vm->PyInt(vm->PyBool_AS_C(args[0]) ? 1 : 0); + if (is_type(args[0], vm->tp_str)) { const Str& s = vm->PyStr_AS_C(args[0]); try{ size_t parsed = 0; i64 val = std::stoll(s, &parsed, 10); - if(parsed != s.size()) throw std::invalid_argument(""); + if(parsed != s.size()) throw std::invalid_argument(""); return vm->PyInt(val); }catch(std::invalid_argument&){ - vm->ValueError("invalid literal for int(): '" + s + "'"); + vm->ValueError("invalid literal for int(): " + s.escape(true)); } } vm->TypeError("int() argument must be a int, float, bool or str"); @@ -236,10 +234,10 @@ void init_builtins(VM* _vm) { /************ PyFloat ************/ _vm->bind_static_method<1>("float", "__new__", [](VM* vm, pkpy::Args& args) { - if (args[0]->is_type(vm->tp_int)) return vm->PyFloat((f64)vm->PyInt_AS_C(args[0])); - if (args[0]->is_type(vm->tp_float)) return args[0]; - if (args[0]->is_type(vm->tp_bool)) return vm->PyFloat(vm->PyBool_AS_C(args[0]) ? 1.0 : 0.0); - if (args[0]->is_type(vm->tp_str)) { + if (is_type(args[0], vm->tp_int)) return vm->PyFloat((f64)vm->PyInt_AS_C(args[0])); + if (is_type(args[0], vm->tp_float)) return args[0]; + if (is_type(args[0], vm->tp_bool)) return vm->PyFloat(vm->PyBool_AS_C(args[0]) ? 1.0 : 0.0); + if (is_type(args[0], vm->tp_str)) { const Str& s = vm->PyStr_AS_C(args[0]); if(s == "inf") return vm->PyFloat(INFINITY); if(s == "-inf") return vm->PyFloat(-INFINITY); @@ -258,7 +256,7 @@ void init_builtins(VM* _vm) { f64 val = vm->PyFloat_AS_C(args[0]); if(std::isinf(val) || std::isnan(val)) return vm->PyStr(std::to_string(val)); StrStream ss; - ss << std::setprecision(std::numeric_limits::max_digits10-1) << val; + ss << std::setprecision(std::numeric_limits::max_digits10-1-2) << val; std::string s = ss.str(); if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0"; return vm->PyStr(s); @@ -307,13 +305,13 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("str", "__eq__", [](VM* vm, pkpy::Args& args) { - if(args[0]->is_type(vm->tp_str) && args[1]->is_type(vm->tp_str)) + if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str)) return vm->PyBool(vm->PyStr_AS_C(args[0]) == vm->PyStr_AS_C(args[1])); return vm->PyBool(args[0] == args[1]); }); _vm->bind_method<1>("str", "__ne__", [](VM* vm, pkpy::Args& args) { - if(args[0]->is_type(vm->tp_str) && args[1]->is_type(vm->tp_str)) + if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str)) return vm->PyBool(vm->PyStr_AS_C(args[0]) != vm->PyStr_AS_C(args[1])); return vm->PyBool(args[0] != args[1]); }); @@ -321,7 +319,7 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("str", "__getitem__", [](VM* vm, pkpy::Args& args) { const Str& _self (vm->PyStr_AS_C(args[0])); - if(args[1]->is_type(vm->tp_slice)){ + if(is_type(args[1], vm->tp_slice)){ pkpy::Slice s = vm->PySlice_AS_C(args[1]); s.normalize(_self.u8_length()); return vm->PyStr(_self.u8_substr(s.start, s.stop)); @@ -441,7 +439,7 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("list", "__getitem__", [](VM* vm, pkpy::Args& args) { const pkpy::List& self = vm->PyList_AS_C(args[0]); - if(args[1]->is_type(vm->tp_slice)){ + if(is_type(args[1], vm->tp_slice)){ pkpy::Slice s = vm->PySlice_AS_C(args[1]); s.normalize(self.size()); pkpy::List new_list; @@ -483,7 +481,7 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, pkpy::Args& args) { const pkpy::Tuple& self = vm->PyTuple_AS_C(args[0]); - if(args[1]->is_type(vm->tp_slice)){ + if(is_type(args[1], vm->tp_slice)){ pkpy::Slice s = vm->PySlice_AS_C(args[1]); s.normalize(self.size()); pkpy::List new_list; @@ -592,7 +590,7 @@ void add_module_dis(VM* vm){ PyVar mod = vm->new_module("dis"); vm->bind_func<1>(mod, "dis", [](VM* vm, pkpy::Args& args) { PyVar f = args[0]; - if(f->is_type(vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method; + if(is_type(f, vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method; CodeObject_ code = vm->PyFunction_AS_C(f).code; (*vm->_stdout) << vm->disassemble(code); return vm->None; diff --git a/src/vm.h b/src/vm.h index d13e46a1..363a7fa5 100644 --- a/src/vm.h +++ b/src/vm.h @@ -63,15 +63,15 @@ public: } PyVar asRepr(const PyVar& obj){ - if(obj->is_type(tp_type)) return PyStr("attr(__name__)) + "'>"); + if(is_type(obj, tp_type)) return PyStr("attr(__name__)) + "'>"); return call(obj, __repr__); } const PyVar& asBool(const PyVar& obj){ - if(obj->is_type(tp_bool)) return obj; + if(is_type(obj, tp_bool)) return obj; if(obj == None) return False; - if(obj->is_type(tp_int)) return PyBool(PyInt_AS_C(obj) != 0); - if(obj->is_type(tp_float)) return PyBool(PyFloat_AS_C(obj) != 0.0); + if(is_type(obj, tp_int)) return PyBool(PyInt_AS_C(obj) != 0); + if(is_type(obj, tp_float)) return PyBool(PyFloat_AS_C(obj) != 0.0); PyVarOrNull len_fn = getattr(obj, __len__, false); if(len_fn != nullptr){ PyVar ret = call(len_fn); @@ -81,7 +81,7 @@ public: } PyVar asIter(const PyVar& obj){ - if(obj->is_type(tp_native_iterator)) return obj; + if(is_type(obj, tp_native_iterator)) return obj; PyVarOrNull iter_f = getattr(obj, __iter__, false); if(iter_f != nullptr) return call(iter_f); TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable"); @@ -89,7 +89,7 @@ public: } PyVar asList(const PyVar& iterable){ - if(iterable->is_type(tp_list)) return iterable; + if(is_type(iterable, tp_list)) return iterable; return call(_t(tp_list), pkpy::one_arg(iterable)); } @@ -125,7 +125,7 @@ public: } PyVar call(const PyVar& _callable, pkpy::Args args, const pkpy::Args& kwargs, bool opCall){ - if(_callable->is_type(tp_type)){ + if(is_type(_callable, tp_type)){ PyVar* new_f = _callable->attr().try_get(__new__); PyVar obj; if(new_f != nullptr){ @@ -139,17 +139,17 @@ public: } const PyVar* callable = &_callable; - if((*callable)->is_type(tp_bound_method)){ + if(is_type(*callable, tp_bound_method)){ auto& bm = PyBoundMethod_AS_C((*callable)); callable = &bm.method; // get unbound method args.extend_self(bm.obj); } - if((*callable)->is_type(tp_native_function)){ + if(is_type(*callable, tp_native_function)){ const auto& f = OBJ_GET(pkpy::NativeFunc, *callable); if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments"); return f(this, args); - } else if((*callable)->is_type(tp_function)){ + } else if(is_type(*callable, tp_function)){ const pkpy::Function& fn = PyFunction_AS_C(*callable); pkpy::shared_ptr _locals = pkpy::make_shared(); pkpy::NameDict& locals = *_locals; @@ -285,7 +285,7 @@ public: } PyVar new_type_object(PyVar mod, Str name, PyVar base){ - if(!base->is_type(tp_type)) UNREACHABLE(); + if(!is_type(base, tp_type)) UNREACHABLE(); PyVar obj = pkpy::make_shared>(tp_type, _all_types.size()); setattr(obj, __base__, base); Str fullName = name; @@ -306,12 +306,12 @@ public: template inline PyVar new_object(const PyVar& type, const T& _value) { - if(!type->is_type(tp_type)) UNREACHABLE(); + if(!is_type(type, tp_type)) UNREACHABLE(); return pkpy::make_shared>(OBJ_GET(Type, type), _value); } template inline PyVar new_object(const PyVar& type, T&& _value) { - if(!type->is_type(tp_type)) UNREACHABLE(); + if(!is_type(type, tp_type)) UNREACHABLE(); return pkpy::make_shared>(OBJ_GET(Type, type), std::move(_value)); } @@ -340,12 +340,12 @@ public: pkpy::NameDict::iterator it; PyObject* cls; - if(obj->is_type(tp_super)){ + if(is_type(obj, tp_super)){ const PyVar* root = &obj; int depth = 1; while(true){ root = &OBJ_GET(PyVar, *root); - if(!(*root)->is_type(tp_super)) break; + if(!is_type(*root, tp_super)) break; depth++; } cls = _t(*root).get(); @@ -364,14 +364,13 @@ public: while(cls != None.get()) { it = cls->attr().find(name); if(it != cls->attr().end()){ - PyVar valueFromCls = it->second; - if(valueFromCls->is_type(tp_function) || valueFromCls->is_type(tp_native_function)){ - return PyBoundMethod({obj, std::move(valueFromCls)}); + if(is_type(it->second, tp_function) || is_type(it->second, tp_native_function)){ + return PyBoundMethod({obj, it->second}); }else{ - return valueFromCls; + return it->second; } } - cls = cls->attr()[__base__].get(); + cls = cls->attr(__base__).get(); } if(throw_err) AttributeError(obj, name); return nullptr; @@ -379,10 +378,11 @@ public: template inline void setattr(PyVar& obj, const Str& name, T&& value) { + if(obj.is_tagged()) TypeError("cannot set attribute"); PyObject* p = obj.get(); - while(p->is_type(tp_super)) p = static_cast(p->value())->get(); + while(p->type == tp_super) p = static_cast(p->value())->get(); if(!p->is_attr_valid()) TypeError("cannot set attribute"); - p->attr()[name] = std::forward(value); + p->attr(name) = std::forward(value); } template @@ -422,9 +422,9 @@ public: } inline f64 num_to_float(const PyVar& obj){ - if (obj->is_type(tp_int)){ + if (is_int(obj)){ return (f64)PyInt_AS_C(obj); - }else if(obj->is_type(tp_float)){ + }else if(is_float(obj)){ return PyFloat_AS_C(obj); } TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true)); @@ -432,12 +432,12 @@ public: } PyVar num_negated(const PyVar& obj){ - if (obj->is_type(tp_int)){ + if (is_int(obj)){ return PyInt(-PyInt_AS_C(obj)); - }else if(obj->is_type(tp_float)){ + }else if(is_float(obj)){ return PyFloat(-PyFloat_AS_C(obj)); } - TypeError("unsupported operand type(s) for -"); + TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true)); return nullptr; } @@ -510,7 +510,7 @@ public: for(int i=0; iconsts.size(); i++){ PyVar obj = co->consts[i]; - if(obj->is_type(tp_function)){ + if(is_type(obj, tp_function)){ const auto& f = PyFunction_AS_C(obj); ss << disassemble(f.code); } @@ -533,8 +533,8 @@ public: inline const BaseRef* PyRef_AS_C(const PyVar& obj) { - if(!obj->is_type(tp_ref)) TypeError("expected an l-value"); - return (const BaseRef*)(obj->value()); + if(!is_type(obj, tp_ref)) TypeError("expected an l-value"); + return static_cast(obj->value()); } inline const Str& PyStr_AS_C(const PyVar& obj) { @@ -550,8 +550,35 @@ public: return new_object(tp_str, value); } - DEF_NATIVE(Int, i64, tp_int) - DEF_NATIVE(Float, f64, tp_float) + inline PyVar PyInt(i64 value) { + const i64 MIN_SAFE_INT = -((i64)1 << 62); + const i64 MAX_SAFE_INT = ((i64)1 << 62) - 1; + if(value < MIN_SAFE_INT || value > MAX_SAFE_INT){ + _error("OverflowError", std::to_string(value) + " is out of range"); + } + value = (value << 2) | 0b01; + return PyVar(reinterpret_cast(value)); + } + + inline i64 PyInt_AS_C(const PyVar& obj){ + check_type(obj, tp_int); + i64 value = obj.cast(); + return value >> 2; + } + + inline PyVar PyFloat(f64 value) { + auto bits = __8B(value); + i64 _int = bits._int; + bits._int = (_int & 0b00) | 0b10; + return PyVar(reinterpret_cast(bits._int)); + } + + inline f64 PyFloat_AS_C(const PyVar& obj){ + check_type(obj, tp_float); + i64 _int = obj.cast(); + return __8B(_int)._float; + } + DEF_NATIVE(List, pkpy::List, tp_list) DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple) DEF_NATIVE(Function, pkpy::Function, tp_function) @@ -576,9 +603,11 @@ public: _types["object"] = _tp_object; _types["type"] = _tp_type; - tp_bool = _new_type_object("bool"); tp_int = _new_type_object("int"); tp_float = _new_type_object("float"); + if(tp_int.index != kTpIntIndex || tp_float.index != kTpFloatIndex) UNREACHABLE(); + + tp_bool = _new_type_object("bool"); tp_str = _new_type_object("str"); tp_list = _new_type_object("list"); tp_tuple = _new_type_object("tuple"); @@ -617,15 +646,9 @@ public: } i64 hash(const PyVar& obj){ - if (obj->is_type(tp_int)) return PyInt_AS_C(obj); - if (obj->is_type(tp_bool)) return PyBool_AS_C(obj) ? 1 : 0; - if (obj->is_type(tp_float)){ - f64 val = PyFloat_AS_C(obj); - return (i64)std::hash()(val); - } - if (obj->is_type(tp_str)) return PyStr_AS_C(obj).hash(); - if (obj->is_type(tp_type)) return (i64)obj.get(); - if (obj->is_type(tp_tuple)) { + if (is_type(obj, tp_str)) return PyStr_AS_C(obj).hash(); + if (is_int(obj)) return PyInt_AS_C(obj); + if (is_type(obj, tp_tuple)) { i64 x = 1000003; const pkpy::Tuple& items = PyTuple_AS_C(obj); for (int i=0; i(); + if (is_type(obj, tp_bool)) return PyBool_AS_C(obj) ? 1 : 0; + if (is_float(obj)){ + f64 val = PyFloat_AS_C(obj); + return (i64)std::hash()(val); + } TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape(true)); return 0; } @@ -673,7 +702,7 @@ public: } inline void check_type(const PyVar& obj, Type type){ - if(obj->is_type(type)) return; + if(is_type(obj, type)) return; TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true)); } @@ -682,6 +711,8 @@ public: } inline PyVar& _t(const PyVar& obj){ + if(is_int(obj)) return _t(tp_int); + if(is_float(obj)) return _t(tp_float); return _all_types[OBJ_GET(Type, _t(obj->type)).index]; } @@ -805,10 +836,10 @@ void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{ if(args.size() < objs.size()) vm->ValueError("not enough values to unpack"); \ for (int i = 0; i < objs.size(); i++) vm->PyRef_AS_C(objs[i])->set(vm, frame, args[i]); - if(val->is_type(vm->tp_tuple)){ + if(is_type(val, vm->tp_tuple)){ const pkpy::Tuple& args = OBJ_GET(pkpy::Tuple, val); TUPLE_REF_SET() - }else if(val->is_type(vm->tp_list)){ + }else if(is_type(val, vm->tp_list)){ const pkpy::List& args = OBJ_GET(pkpy::List, val); TUPLE_REF_SET() }else{ @@ -823,7 +854,7 @@ void TupleRef::del(VM* vm, Frame* frame) const{ /***** Frame's Impl *****/ inline void Frame::try_deref(VM* vm, PyVar& v){ - if(v->is_type(vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this); + if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this); } PyVar pkpy::NativeFunc::operator()(VM* vm, pkpy::Args& args) const{