blueloveTH пре 1 година
родитељ
комит
175c571fbb

+ 1 - 2
include/pocketpy/common/traits.hpp

@@ -21,9 +21,8 @@ constexpr inline bool is_floating_point_v = std::is_same_v<T, float> || std::is_
 template <typename T>
 constexpr inline bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
 
-// if is_sso_v<T> is true, return T, else return T&
 template <typename T>
-using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
+using obj_get_t = T&;
 
 template <typename T>
 constexpr inline bool is_trivially_relocatable_v =

+ 0 - 1
include/pocketpy/compiler/expr.hpp

@@ -69,7 +69,6 @@ struct CodeEmitContext{
     int curr_iblock = 0;
     bool is_compiling_class = false;
 
-    small_map<PyVar, int> _co_consts_nonstring_dedup_map;
     small_map<std::string_view, int> _co_consts_string_dedup_map;
 
     int get_loop() const noexcept;

+ 20 - 13
include/pocketpy/interpreter/vm.hpp

@@ -175,14 +175,14 @@ public:
         vector<ArgsView> s_view;
     } __c;
 
-    PyVar StopIteration;  // a special Exception class
+    PyObject* StopIteration;  // a special Exception class
     PyObject* builtins;
     PyObject* _main;
 
     // typeid -> Type
     small_map<std::type_index, Type> _cxx_typeid_map;
     // this is for repr() recursion detection (no need to mark)
-    vector<PyVar> _repr_recursion_set;
+    vector<PyObject*> _repr_recursion_set;
 
     ImportContext __import_context;
     PyObject* __last_exception;
@@ -550,10 +550,18 @@ PyVar py_var(VM* vm, __T&& value) {
         return value ? vm->True : vm->False;
     } else if constexpr(is_integral_v<T>) {
         // int
-        return PyVar(VM::tp_int, static_cast<i64>(value));
+        ::PyVar retval;
+        retval.type = tp_int;
+        retval.is_ptr = false;
+        retval._i64 = (i64)value;
+        return retval;
     } else if constexpr(is_floating_point_v<T>) {
         // float
-        return PyVar(VM::tp_float, static_cast<f64>(value));
+        ::PyVar retval;
+        retval.type = tp_float;
+        retval.is_ptr = false;
+        retval._f64 = (f64)value;
+        return retval;
     } else if constexpr(std::is_pointer_v<T>) {
         return from_void_p(vm, (void*)value);
     } else {
@@ -592,23 +600,22 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
         static_assert(!std::is_reference_v<__T>);
         // bool
         if constexpr(with_check) {
-            if(obj == vm->True) return true;
-            if(obj == vm->False) return false;
-            vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
+            if(obj.type != tp_bool){
+                vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
+            }
         }
-        return obj == vm->True;
+        return obj._bool;
     } else if constexpr(is_integral_v<T>) {
         static_assert(!std::is_reference_v<__T>);
         // int
         if constexpr(with_check) {
-            if(is_int(obj)) return (T)obj.as<i64>();
-            vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
+            if(!is_int(obj)) vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
         }
-        return (T)obj.as<i64>();
+        return (T)obj._i64;
     } else if constexpr(is_floating_point_v<T>) {
         static_assert(!std::is_reference_v<__T>);
-        if(is_float(obj)) return (T)obj.as<f64>();
-        if(is_int(obj)) return (T)obj.as<i64>();
+        if(is_float(obj)) return (T)obj._f64;
+        if(is_int(obj)) return (T)obj._i64;
         vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
         return 0.0f;
     } else if constexpr(std::is_enum_v<T>) {

+ 4 - 4
include/pocketpy/modules/linalg.hpp

@@ -207,9 +207,9 @@ static_assert(is_pod_v<Vec3>);
 static_assert(is_pod_v<Vec4>);
 static_assert(is_pod_v<Mat3x3>);
 
-template <>
-constexpr inline bool is_sso_v<Vec2> = true;
-template <>
-constexpr inline bool is_sso_v<Vec3> = true;
+// template <>
+// constexpr inline bool is_sso_v<Vec2> = true;
+// template <>
+// constexpr inline bool is_sso_v<Vec3> = true;
 
 }  // namespace pkpy

+ 41 - 28
include/pocketpy/objects/base.h

@@ -19,8 +19,7 @@ typedef struct PyObject PyObject;
 typedef struct PyVar{
     pkpy_Type type;
     bool is_ptr;
-    uint8_t flags;
-    int flags_ex;
+    int extra;
     union {
         int64_t _i64;
         double _f64;
@@ -31,48 +30,62 @@ typedef struct PyVar{
     };
 } PyVar;
 
+
+#define PyVar__as(T, self)  _Generic((T), \
+    int64_t: self->_i64, \
+    double: self->_f64, \
+    bool: self->_bool, \
+    PyObject*: self->_obj, \
+    void*: self->_ptr, \
+)
+
 static_assert(sizeof(PyVar) == 16, "sizeof(PyVar) != 16");
 
-PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
-PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->flags_ex + self->_i64; }
+extern const pkpy_Type tp_object, tp_type;
+extern const pkpy_Type tp_int, tp_float, tp_bool, tp_str;
+extern const pkpy_Type tp_list, tp_tuple;
+extern const pkpy_Type tp_slice, tp_range, tp_module;
+extern const pkpy_Type tp_function, tp_native_func, tp_bound_method;
+extern const pkpy_Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
+extern const pkpy_Type tp_dict, tp_property, tp_star_wrapper;
+extern const pkpy_Type tp_staticmethod, tp_classmethod;
+extern const pkpy_Type tp_none_type, tp_not_implemented_type;
+extern const pkpy_Type tp_ellipsis;
+extern const pkpy_Type tp_op_call, tp_op_yield;
 
-PK_INLINE bool PyVar__less(const PyVar* self, const PyVar* other){
-    return memcmp(self, other, sizeof(PyVar)) < 0;
-}
-PK_INLINE bool PyVar__equal(const PyVar* self, const PyVar* other){
-    return memcmp(self, other, sizeof(PyVar)) == 0;
-}
+PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
+PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->extra + self->_i64; }
 
 PK_INLINE void PyVar__ctor(PyVar* self, pkpy_Type type, PyObject* obj){
     self->type = type;
     self->is_ptr = true;
-    self->flags = 0;
-    self->flags_ex = 0;
     self->_obj = obj;
 }
 
-void PyVar__ctor2(PyVar* self, PyObject* existing);
+void PyVar__ctor3(PyVar* self, PyObject* existing);
+
+PK_INLINE bool PyVar__IS_OP(const PyVar* a, const PyVar* b){
+    return a->is_ptr && b->is_ptr && a->_obj == b->_obj;
+}
 
 #define pkpy_Var__is_null(self) ((self)->type == 0)
 #define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0)
 bool pkpy_Var__eq__(void *vm, PyVar a, PyVar b);
 int64_t pkpy_Var__hash__(void *vm, PyVar a);
 
-extern const pkpy_Type tp_object, tp_type;
-extern const pkpy_Type tp_int, tp_float, tp_bool, tp_str;
-extern const pkpy_Type tp_list, tp_tuple;
-extern const pkpy_Type tp_slice, tp_range, tp_module;
-extern const pkpy_Type tp_function, tp_native_func, tp_bound_method;
-extern const pkpy_Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
-extern const pkpy_Type tp_dict, tp_property, tp_star_wrapper;
-extern const pkpy_Type tp_staticmethod, tp_classmethod;
-extern const pkpy_Type tp_none_type, tp_not_implemented_type;
-extern const pkpy_Type tp_ellipsis;
-
-extern const PyVar pkpy_True, pkpy_False, pkpy_None;
-extern const PyVar pkpy_NotImplemented, pkpy_Ellipsis;
-extern const PyVar pkpy_NULL;
+extern PyVar pkpy_True, pkpy_False, pkpy_None;
+extern PyVar pkpy_NotImplemented, pkpy_Ellipsis;
+extern PyVar pkpy_NULL, pkpy_OP_CALL, pkpy_OP_YIELD;
 
 #ifdef __cplusplus
 }
-#endif
+#endif
+
+/*
+SSO types:
+1. int64_t
+2. double
+3. bool (dummy)
+4. tuple (extra + void*)
+5. string (extra + void* or buf)
+*/

+ 9 - 28
include/pocketpy/objects/base.hpp

@@ -26,7 +26,7 @@ struct PyVar final: ::PyVar {
 
     // implict conversion
     PyVar(PyObject* existing){
-        PyVar__ctor2(this, (::PyObject*)existing);
+        PyVar__ctor3(this, (::PyObject*)existing);
     }
 
     /* We must initialize all members to allow == operator to work correctly */
@@ -40,26 +40,10 @@ struct PyVar final: ::PyVar {
         PyVar__ctor(this, type, (::PyObject*)p);
     }
 
-    // SSO initialized (is_sso = true)
-    template <typename T>
-    PyVar(Type type, T value){
-        static_assert(sizeof(T) <= 12, "SSO size exceeded");
+    PyVar(Type type, i64 value){
         this->type = type;
         this->is_ptr = false;
-        this->flags = 0;
-        this->flags_ex = 0;
-        this->_i64 = 0;
-        as<T>() = value;
-    }
-
-    template <typename T>
-    T& as() {
-        static_assert(!std::is_reference_v<T>);
-        if constexpr(sizeof(T) <= 8) {
-            return reinterpret_cast<T&>(_i64);
-        } else {
-            return reinterpret_cast<T&>(flags_ex);
-        }
+        this->_i64 = value;
     }
 
     explicit operator bool () const { return (bool)type; }
@@ -68,10 +52,12 @@ struct PyVar final: ::PyVar {
         memset(this, 0, sizeof(PyVar));
     }
 
-    bool operator== (const PyVar& other) const { return PyVar__equal(this, &other); }
-    bool operator!= (const PyVar& other) const { return !PyVar__equal(this, &other); }
-    bool operator== (std::nullptr_t) const { return !(bool)type; }
-    bool operator!= (std::nullptr_t) const { return (bool)type; }
+    bool operator==(PyObject* other){
+        return is_ptr && (PyObject*)_obj == other;
+    }
+    bool operator!=(PyObject* other){
+        return !is_ptr || (PyObject*)_obj != other;
+    }
 
     PyObject* get() const {
         assert(is_ptr);
@@ -88,11 +74,6 @@ struct PyVar final: ::PyVar {
     template <typename T>
     obj_get_t<T> obj_get();
 
-    // std::less<> for map-like containers
-    bool operator< (const PyVar& other) const {
-        return PyVar__less(this, &other);
-    }
-
     // implicit convert from ::PyVar
     PyVar(const ::PyVar& var) {
         memcpy(this, &var, sizeof(var));

+ 5 - 10
include/pocketpy/objects/builtins.hpp

@@ -116,14 +116,11 @@ T to_void_p(VM*, PyVar);
 PyVar from_void_p(VM*, void*);
 
 template <typename T>
-obj_get_t<T> PyVar::obj_get() {
-    if constexpr(is_sso_v<T>) {
-        return as<T>();
-    } else {
-        assert(is_ptr);
-        void* v = PyObject__value_ptr(_obj);
-        return *reinterpret_cast<T*>(v);
-    }
+T& PyVar::obj_get() {
+    static_assert(!is_sso_v<T>, "unsupported");
+    assert(is_ptr);
+    void* v = PyObject__value_ptr(_obj);
+    return *reinterpret_cast<T*>(v);
 }
 
 #define PK_OBJ_GET(T, obj) ((obj).obj_get<T>())
@@ -140,7 +137,5 @@ obj_get_t<T> PyVar::obj_get() {
 
 /*****************************************************************/
 #define PY_NULL nullptr
-extern PyVar PY_OP_CALL;
-extern PyVar PY_OP_YIELD;
 
 }  // namespace pkpy

+ 2 - 1
include/pocketpy/objects/object.hpp

@@ -12,9 +12,10 @@ struct NameDict;
 struct PyObject final: ::PyObject {
     bool is_attr_valid() const noexcept { return _attr != nullptr; }
 
-    void* _value_ptr() noexcept { return (char*)this + 16; }
+    void* _value_ptr() noexcept { return PyObject__value_ptr(this); }
 
     NameDict& attr() const{
+        assert(is_attr_valid());
         return *(NameDict*)_attr;
     }
 

+ 1 - 1
src/common/sstream.c

@@ -51,7 +51,7 @@ void pkpy_SStream__write_i64(pkpy_SStream* self, int64_t val) {
 }
 
 void pkpy_SStream__write_float(pkpy_SStream* self, float val, int precision){
-    return pkpy_SStream__write_double(self, val, precision);
+    pkpy_SStream__write_double(self, val, precision);
 }
 
 void pkpy_SStream__write_double(pkpy_SStream* self, double val, int precision){

+ 3 - 10
src/compiler/expr.cpp

@@ -137,16 +137,9 @@ int CodeEmitContext::add_const_string(std::string_view key) noexcept{
 
 int CodeEmitContext::add_const(PyVar v) noexcept{
     assert(!is_type(v, VM::tp_str));
-    // non-string deduplication
-    int* val = _co_consts_nonstring_dedup_map.try_get(v);
-    if(val) {
-        return *val;
-    } else {
-        co->consts.push_back(v);
-        int index = co->consts.size() - 1;
-        _co_consts_nonstring_dedup_map.insert(v, index);
-        return index;
-    }
+    co->consts.push_back(v);
+    int index = co->consts.size() - 1;
+    return index;
 }
 
 int CodeEmitContext::add_func_decl(FuncDecl_ decl) noexcept{

+ 21 - 16
src/interpreter/ceval.cpp

@@ -1,18 +1,19 @@
 #include "pocketpy/interpreter/ceval.hpp"
+#include "pocketpy/objects/base.h"
 
 namespace pkpy {
 
 #define PREDICT_INT_OP(op)                                                                                             \
     if(is_int(_0) && is_int(_1)) {                                                                                     \
-        TOP() = VAR(_0.as<i64>() op _1.as<i64>());                                                                     \
+        TOP() = VAR(_0._i64 op _1._i64);                                                                     \
         DISPATCH()                                                                                                     \
     }
 
 #define PREDICT_INT_DIV_OP(op)                                                                                         \
     if(is_int(_0) && is_int(_1)) {                                                                                     \
-        i64 divisor = _1.as<i64>();                                                                                    \
+        i64 divisor = _1._i64;                                                                                    \
         if(divisor == 0) ZeroDivisionError();                                                                          \
-        TOP() = VAR(_0.as<i64>() op divisor);                                                                          \
+        TOP() = VAR(_0._i64 op divisor);                                                                          \
         DISPATCH()                                                                                                     \
     }
 
@@ -24,7 +25,7 @@ namespace pkpy {
     } else {                                                                                                           \
         PyVar self;                                                                                                    \
         PyVar _2 = get_unbound_method(_0, func, &self, false);                                                         \
-        if(_2 != nullptr)                                                                                              \
+        if(_2)                                                                                              \
             ret = call_method(self, _2, _1);                                                                           \
         else                                                                                                           \
             ret = NotImplemented;                                                                                      \
@@ -32,7 +33,7 @@ namespace pkpy {
     if(is_not_implemented(ret)) {                                                                                      \
         PyVar self;                                                                                                    \
         PyVar _2 = get_unbound_method(_1, rfunc, &self, false);                                                        \
-        if(_2 != nullptr)                                                                                              \
+        if(_2)                                                                                              \
             ret = call_method(self, _2, _0);                                                                           \
         else                                                                                                           \
             BinaryOptError(op, _0, _1);                                                                                \
@@ -65,22 +66,26 @@ void VM::__op_unpack_sequence(uint16_t arg) {
 
 bool VM::py_lt(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__lt__, "<", __gt__);
-    return ret == True;
+    assert(ret.type == tp_bool);
+    return ret._bool;
 }
 
 bool VM::py_le(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__le__, "<=", __ge__);
-    return ret == True;
+    assert(ret.type == tp_bool);
+    return ret._bool;
 }
 
 bool VM::py_gt(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__gt__, ">", __lt__);
-    return ret == True;
+    assert(ret.type == tp_bool);
+    return ret._bool;
 }
 
 bool VM::py_ge(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__ge__, ">=", __le__);
-    return ret == True;
+    assert(ret.type == tp_bool);
+    return ret._bool;
 }
 
 #undef BINARY_F_COMPARE
@@ -167,7 +172,7 @@ PyVar VM::__run_top_frame() {
                     }
                         DISPATCH()
                     case OP_PRINT_EXPR:
-                        if(TOP() != None) stdout_write(py_repr(TOP()) + "\n");
+                        if(!is_none(TOP())) stdout_write(py_repr(TOP()) + "\n");
                         POP();
                         DISPATCH()
                     /*****************************************/
@@ -717,13 +722,13 @@ PyVar VM::__run_top_frame() {
                     case OP_IS_OP: {
                         PyVar _1 = POPX();  // rhs
                         PyVar _0 = TOP();   // lhs
-                        TOP() = _0 == _1 ? True : False;
+                        TOP() = PyVar__IS_OP(&_0, &_1) ? True : False;
                     }
                         DISPATCH()
                     case OP_IS_NOT_OP: {
                         PyVar _1 = POPX();  // rhs
                         PyVar _0 = TOP();   // lhs
-                        TOP() = _0 != _1 ? True : False;
+                        TOP() = PyVar__IS_OP(&_0, &_1) ? False : True;
                     }
                         DISPATCH()
                     case OP_CONTAINS_OP: {
@@ -801,7 +806,7 @@ PyVar VM::__run_top_frame() {
                         PyVar _0 = vectorcall(byte.arg & 0xFF,         // ARGC
                                               (byte.arg >> 8) & 0xFF,  // KWARGC
                                               true);
-                        if(_0 == PY_OP_CALL) {
+                        if(_0.type == tp_op_call) {
                             frame = &callstack.top();
                             goto __NEXT_FRAME;
                         }
@@ -835,7 +840,7 @@ PyVar VM::__run_top_frame() {
                                             0,                         // KWARGC
                                             true);
                         }
-                        if(_0 == PY_OP_CALL) {
+                        if(_0.type == tp_op_call) {
                             frame = &callstack.top();
                             goto __NEXT_FRAME;
                         }
@@ -854,7 +859,7 @@ PyVar VM::__run_top_frame() {
                         }
                     }
                         DISPATCH()
-                    case OP_YIELD_VALUE: return PY_OP_YIELD;
+                    case OP_YIELD_VALUE: return pkpy_OP_YIELD;
                     /*****************************************/
                     case OP_LIST_APPEND: {
                         PyVar _0 = POPX();
@@ -926,7 +931,7 @@ PyVar VM::__run_top_frame() {
                             DISPATCH_JUMP_ABSOLUTE(target)
                         } else {
                             PUSH(_0);
-                            return PY_OP_YIELD;
+                            return pkpy_OP_YIELD;
                         }
                     }
                     case OP_FOR_ITER_UNPACK: {

+ 2 - 1
src/interpreter/iter.cpp

@@ -1,4 +1,5 @@
 #include "pocketpy/interpreter/iter.hpp"
+#include "pocketpy/objects/base.h"
 
 namespace pkpy {
 
@@ -76,7 +77,7 @@ PyVar Generator::next(VM* vm) {
         throw;
     }
 
-    if(ret == PY_OP_YIELD) {
+    if(ret->type == tp_op_yield) {
         // backup the context
         lf = vm->callstack.popx();
         ret = vm->s_data.popx();

+ 14 - 10
src/interpreter/vm.cpp

@@ -60,7 +60,7 @@ struct JsonSerializer {
             if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
             ss << val;
         } else if(obj_t == vm->tp_bool) {
-            ss << (obj == vm->True ? "true" : "false");
+            ss << (obj._bool ? "true" : "false");
         } else if(obj_t == vm->tp_str) {
             ss << _CAST(Str&, obj).escape('"');
         } else if(obj_t == vm->tp_list) {
@@ -230,23 +230,23 @@ PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subcl
 }
 
 bool VM::py_eq(PyVar lhs, PyVar rhs) {
-    if(is_int(lhs) && is_int(rhs)) return lhs.as<i64>() == rhs.as<i64>();
+    if(is_int(lhs) && is_int(rhs)) return lhs._i64 == rhs._i64;
     const PyTypeInfo* ti = _tp_info(lhs);
     PyVar res;
     if(ti->m__eq__) {
         res = ti->m__eq__(this, lhs, rhs);
-        if(!is_not_implemented(res)) return res == vm->True;
+        if(!is_not_implemented(res)) return res._bool;
     }
     res = call_method(lhs, __eq__, rhs);
-    if(!is_not_implemented(res)) return res == vm->True;
+    if(!is_not_implemented(res)) return res._bool;
 
     ti = _tp_info(rhs);
     if(ti->m__eq__) {
         res = ti->m__eq__(this, rhs, lhs);
-        if(!is_not_implemented(res)) return res == vm->True;
+        if(!is_not_implemented(res)) return res._bool;
     }
     res = call_method(rhs, __eq__, lhs);
-    if(!is_not_implemented(res)) return res == vm->True;
+    if(!is_not_implemented(res)) return res._bool;
     return false;
 }
 
@@ -538,7 +538,8 @@ i64 VM::py_hash(PyVar obj) {
         has_custom_eq = true;
     else {
         f = get_unbound_method(obj, __eq__, &self, false);
-        has_custom_eq = f != _t(tp_object)->attr()[__eq__];
+        PyVar base_eq = _t(tp_object)->attr()[__eq__];
+        has_custom_eq = !PyVar__IS_OP(&f, &base_eq);
     }
     if(has_custom_eq) {
         TypeError(_S("unhashable type: ", ti->name.escape()));
@@ -901,6 +902,9 @@ void VM::__init_builtin_types() {
     validate(tp_not_implemented_type, new_type_object(nullptr, "NotImplementedType", tp_object, false));
     validate(tp_ellipsis, new_type_object(nullptr, "ellipsis", tp_object, false));
 
+    validate(::tp_op_call, new_type_object(nullptr, "__op_call", tp_object, false));
+    validate(::tp_op_yield, new_type_object(nullptr, "__op_yield", tp_object, false));
+
     // SyntaxError and IndentationError must be created here
     PyObject* SyntaxError = new_type_object(nullptr, "SyntaxError", tp_exception, true);
     PyObject* IndentationError = new_type_object(nullptr, "IndentationError", SyntaxError->as<Type>(), true);
@@ -1103,7 +1107,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
 
         // simple or normal
         callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
-        if(op_call) return PY_OP_CALL;
+        if(op_call) return pkpy_OP_CALL;
         return __run_top_frame();
         /*****************_py_call*****************/
     }
@@ -1137,7 +1141,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
         PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
         PyVar obj;
         assert(new_f != nullptr && p0[1] == PY_NULL);
-        if(new_f == __cached_object_new) {
+        if(PyVar__IS_OP(&new_f, &__cached_object_new)) {
             // fast path for object.__new__
             obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
         } else {
@@ -1326,7 +1330,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
         // handle descriptor
         if(is_type(*cls_var, tp_property)) {
             const Property& prop = _CAST(Property&, *cls_var);
-            if(prop.setter != vm->None) {
+            if(!is_none(prop.setter)) {
                 call(prop.setter, obj, value);
             } else {
                 TypeError(_S("readonly attribute: ", name.escape()));

+ 4 - 4
src/modules/array2d.cpp

@@ -113,8 +113,8 @@ struct Array2d {
             const Tuple& xy = CAST(Tuple&, _1);
 
             if(is_int(xy[0]) && is_int(xy[1])) {
-                i64 col = xy[0].as<i64>();
-                i64 row = xy[1].as<i64>();
+                i64 col = xy[0]._i64;
+                i64 row = xy[1]._i64;
                 self.check_valid(vm, col, row);
                 return self._get(col, row);
             }
@@ -138,8 +138,8 @@ struct Array2d {
             Array2d& self = PK_OBJ_GET(Array2d, _0);
             const Tuple& xy = CAST(Tuple&, _1);
             if(is_int(xy[0]) && is_int(xy[1])) {
-                i64 col = xy[0].as<i64>();
-                i64 row = xy[1].as<i64>();
+                i64 col = xy[0]._i64;
+                i64 row = xy[1]._i64;
                 self.check_valid(vm, col, row);
                 self._set(col, row, _2);
                 return;

+ 9 - 6
src/objects/base.c

@@ -11,10 +11,13 @@ const pkpy_Type tp_dict = 19, tp_property = 20, tp_star_wrapper = 21;
 const pkpy_Type tp_staticmethod = 22, tp_classmethod = 23;
 const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25;
 const pkpy_Type tp_ellipsis = 26;
+const pkpy_Type tp_op_call = 27, tp_op_yield = 28;
 
-const PyVar pkpy_True = {.type=tp_bool, .is_ptr=false, .flags=0, .flags_ex=0, ._bool=true};
-const PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, .flags=0, .flags_ex=0, ._bool=false};
-const PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
-const PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
-const PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
-const PyVar pkpy_NULL = {.type=0, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
+PyVar pkpy_True = {.type=tp_bool, .is_ptr=false, ._bool=true};
+PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, ._bool=false};
+PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false};
+PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false};
+PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false};
+PyVar pkpy_NULL = {.type=0, .is_ptr=false};
+PyVar pkpy_OP_CALL = {.type=tp_op_call, .is_ptr=false};
+PyVar pkpy_OP_YIELD = {.type=tp_op_yield, .is_ptr=false};

+ 0 - 6
src/objects/builtins.cpp

@@ -1,6 +0,0 @@
-#include "pocketpy/objects/builtins.hpp"
-
-namespace pkpy {
-PyVar PY_OP_CALL(Type(), new PyObject(Type(), true));
-PyVar PY_OP_YIELD(Type(), new PyObject(Type(), true));
-}  // namespace pkpy

+ 1 - 3
src/objects/object.c

@@ -1,10 +1,8 @@
 #include "pocketpy/objects/object.h"
 
-void PyVar__ctor2(PyVar* self, PyObject* existing){
+void PyVar__ctor3(PyVar* self, PyObject* existing){
     assert(existing);
     self->type = existing->type;
     self->is_ptr = true;
-    self->flags = 0;
-    self->flags_ex = 0;
     self->_obj = existing;
 }

+ 14 - 13
src/pocketpy.cpp

@@ -11,6 +11,7 @@
 #include "pocketpy/modules/linalg.hpp"
 #include "pocketpy/modules/random.hpp"
 #include "pocketpy/modules/modules.hpp"
+#include "pocketpy/objects/base.h"
 
 #include <iostream>
 #include <algorithm>
@@ -26,7 +27,7 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1) {
     static_assert(std::is_same_v<T, List> || std::is_same_v<T, Tuple>);
     const T& self = _CAST(T&, _0);
     if(is_int(_1)) {
-        i64 index = _1.as<i64>();
+        i64 index = _1._i64;
         index = vm->normalized_index(index, self.size());
         return self[index];
     }
@@ -374,7 +375,7 @@ void __init_builtins(VM* _vm) {
     });
 
     _vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) {
-        return VAR(_0 == _1);
+        return PyVar__IS_OP(&_0, &_1) ? vm->True : vm->False;
     });
 
     _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
@@ -461,7 +462,7 @@ void __init_builtins(VM* _vm) {
             switch(vm->_tp(args[1])) {
                 case VM::tp_float: return VAR((i64)_CAST(f64, args[1]));
                 case VM::tp_int: return args[1];
-                case VM::tp_bool: return VAR(args[1] == vm->True ? 1 : 0);
+                case VM::tp_bool: return VAR(args[1]._bool ? 1 : 0);
                 case VM::tp_str: break;
                 default: vm->TypeError("invalid arguments for int()");
             }
@@ -542,7 +543,7 @@ void __init_builtins(VM* _vm) {
         switch(vm->_tp(args[1])) {
             case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
             case VM::tp_float: return args[1];
-            case VM::tp_bool: return VAR(args[1] == vm->True ? 1.0 : 0.0);
+            case VM::tp_bool: return VAR(args[1]._bool ? 1.0 : 0.0);
             case VM::tp_str: break;
             default: vm->TypeError("invalid arguments for float()");
         }
@@ -847,11 +848,11 @@ void __init_builtins(VM* _vm) {
     });
 
     _vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str {
-        if(vm->_repr_recursion_set.contains(_0)) return "[...]";
+        if(vm->_repr_recursion_set.contains(_0.get())) return "[...]";
         List& iterable = _CAST(List&, _0);
         SStream ss;
         ss << '[';
-        vm->_repr_recursion_set.push_back(_0);
+        vm->_repr_recursion_set.push_back(_0.get());
         for(int i = 0; i < iterable.size(); i++) {
             ss << vm->py_repr(iterable[i]);
             if(i != iterable.size() - 1) ss << ", ";
@@ -1150,7 +1151,7 @@ void __init_builtins(VM* _vm) {
         return VAR(_CAST(bool, _0) != CAST(bool, _1));
     });
     _vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
-        if(is_type(_1, vm->tp_bool)) return VAR(_0 == _1);
+        if(is_type(_1, vm->tp_bool)) return VAR(_0._bool == _1._bool);
         if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
         return vm->NotImplemented;
     });
@@ -1316,12 +1317,12 @@ void __init_builtins(VM* _vm) {
     });
 
     _vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str {
-        if(vm->_repr_recursion_set.contains(_0)) return "{...}";
+        if(vm->_repr_recursion_set.contains(_0.get())) return "{...}";
         MappingProxy& self = _CAST(MappingProxy&, _0);
         SStream ss;
         ss << "mappingproxy({";
         bool first = true;
-        vm->_repr_recursion_set.push_back(_0);
+        vm->_repr_recursion_set.push_back(_0.get());
         for(auto [k, v]: self.attr().items()) {
             if(!first) ss << ", ";
             first = false;
@@ -1472,12 +1473,12 @@ void __init_builtins(VM* _vm) {
     });
 
     _vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str {
-        if(vm->_repr_recursion_set.contains(_0)) return "{...}";
+        if(vm->_repr_recursion_set.contains(_0.get())) return "{...}";
         Dict& self = _CAST(Dict&, _0);
         SStream ss;
         ss << "{";
         bool first = true;
-        vm->_repr_recursion_set.push_back(_0);
+        vm->_repr_recursion_set.push_back(_0.get());
         self.apply([&](PyVar k, PyVar v) {
             if(!first) ss << ", ";
             first = false;
@@ -1544,7 +1545,7 @@ void __init_builtins(VM* _vm) {
 
     _vm->bind(_vm->_t(VM::tp_exception), "__init__(self, msg=...)", [](VM* vm, ArgsView args) {
         Exception& self = _CAST(Exception&, args[0]);
-        if(args[1] == vm->Ellipsis) {
+        if(args[1].type == tp_ellipsis) {
             self.msg = "";
         } else {
             self.msg = CAST(Str, args[1]);
@@ -1627,7 +1628,7 @@ void VM::__post_init_builtin_types() {
         if(!is_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
         const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
         const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
-        return VAR(_0.self == _1.self && _0.func == _1.func);
+        return VAR(PyVar__IS_OP(&_0.self, &_1.self) && PyVar__IS_OP(&_0.func, &_1.func));
     });
 
     bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) {