blueloveTH 1 year ago
parent
commit
a09def4ec3

+ 1 - 2
3rd/lua_bridge/src/lua_bridge.cpp

@@ -82,8 +82,7 @@ struct PyLuaTable: PyLuaObject{
 
         vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
             lua_newtable(_L);    // push an empty table onto the stack
-            PyVar obj = vm->heap.gcnew<PyLuaTable>(PK_OBJ_GET(Type, args[0]));
-            return obj;
+            return vm->new_object<PyLuaTable>(PK_OBJ_GET(Type, args[0]));
         });
 
         vm->bind__len__(t, [](VM* vm, PyVar obj){

+ 0 - 7
docs/modules/linalg.md

@@ -36,10 +36,6 @@ class vec2(_StructLike['vec2']):
     def normalize(self) -> vec2: ...
     def rotate(self, radians: float) -> vec2: ...
 
-    def copy_(self, other: vec2) -> None: ...
-    def normalize_(self) -> None: ...
-    def rotate_(self, radians: float) -> None: ...
-
     @staticmethod
     def angle(__from: vec2, __to: vec2) -> float:
         """Returns the angle in radians between vectors `from` and `to`.
@@ -77,9 +73,6 @@ class vec3(_StructLike['vec3']):
     def length_squared(self) -> float: ...
     def normalize(self) -> vec3: ...
 
-    def copy_(self, other: vec3) -> None: ...
-    def normalize_(self) -> None: ...
-
 class vec4(_StructLike['vec4']):
     x: float
     y: float

+ 2 - 2
include/pocketpy/bindings.h

@@ -97,7 +97,7 @@ PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){
         F T::*field = lambda_get_userdata<F T::*>(args.begin());
         return VAR(self.*field);
     };
-    PyVar _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, field);
+    PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
     PyVar _1 = vm->None;
     if constexpr (!ReadOnly){
         auto fset = [](VM* vm, ArgsView args){
@@ -106,7 +106,7 @@ PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){
             self.*field = py_cast<F>(vm, args[1]);
             return vm->None;
         };
-        _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, field);
+        _1 = new_object<NativeFunc>(tp_native_func, fset, 2, field);
     }
     PyVar prop = VAR(Property(_0, _1));
     obj->attr().set(StrName(name_sv), prop);

+ 2 - 2
include/pocketpy/cffi.h

@@ -38,8 +38,8 @@ struct VoidP{
 #define POINTER_VAR(Tp, NAME)    \
     inline PyVar py_var(VM* vm, Tp val){    \
         const static std::pair<StrName, StrName> P("c", NAME);      \
-        PyVar type = vm->_modules[P.first]->attr(P.second);     \
-        return vm->heap.gcnew<VoidP>(PK_OBJ_GET(Type, type), val);  \
+        PyVar type = vm->_modules[P.first]->attr(P.second);         \
+        return vm->new_object<VoidP>(PK_OBJ_GET(Type, type), val);  \
     }
 
 POINTER_VAR(char*, "char_p")

+ 7 - 0
include/pocketpy/common.h

@@ -185,6 +185,7 @@ struct PyVar final{
     // SSO initialized (is_sso = true)
     template<typename T>
     PyVar(Type type, T value): type(type), is_sso(true), flags(0) {
+        static_assert(sizeof(T) <= sizeof(_bytes), "SSO size exceeded");
         as<T>() = value;
     }
 
@@ -222,6 +223,12 @@ struct PyVar final{
 
 static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
 
+// by default, only `int` and `float` enable SSO
+// users can specialize this template to enable SSO for other types
+// SSO types cannot have instance dict
+template<typename T>
+inline constexpr bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
+
 } // namespace pkpy
 
 

+ 1 - 1
include/pocketpy/config.h

@@ -33,7 +33,7 @@
 /*************** debug settings ***************/
 
 // Enable this may help you find bugs
-#define PK_DEBUG_EXTRA_CHECK        0
+#define PK_DEBUG_EXTRA_CHECK        1
 
 // Do not edit the following settings unless you know what you are doing
 #define PK_DEBUG_CEVAL_STEP         0

+ 2 - 1
include/pocketpy/gc.h

@@ -41,6 +41,7 @@ struct ManagedHeap{
     template<typename T, typename... Args>
     PyVar gcnew(Type type, Args&&... args){
         using __T = Py_<std::decay_t<T>>;
+        static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types");
         // https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
         PyObject* p = new(pool128_alloc<__T>()) Py_<std::decay_t<T>>(std::forward<Args>(args)...);
         PyVar obj(type, p);
@@ -52,7 +53,7 @@ struct ManagedHeap{
     template<typename T, typename... Args>
     PyVar _new(Type type, Args&&... args){
         using __T = Py_<std::decay_t<T>>;
-        // https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
+        static_assert(!is_sso_v<__T>);
         PyObject* p = new(pool128_alloc<__T>()) Py_<std::decay_t<T>>(std::forward<Args>(args)...);
         PyVar obj(type, p);
         obj->gc_enabled = false;

+ 5 - 4
include/pocketpy/linalg.h

@@ -27,8 +27,6 @@ struct Vec2{
     float length_squared() const { return x * x + y * y; }
     Vec2 normalize() const { float l = length(); return Vec2(x / l, y / l); }
     Vec2 rotate(float radian) const { float cr = cosf(radian), sr = sinf(radian); return Vec2(x * cr - y * sr, x * sr + y * cr); }
-    NoReturn normalize_() { float l = length(); x /= l; y /= l; return {}; }
-    NoReturn copy_(const Vec2& v) { x = v.x; y = v.y; return {}; }
 };
 
 struct Vec3{
@@ -51,8 +49,6 @@ struct Vec3{
     float length() const { return sqrtf(x * x + y * y + z * z); }
     float length_squared() const { return x * x + y * y + z * z; }
     Vec3 normalize() const { float l = length(); return Vec3(x / l, y / l, z / l); }
-    NoReturn normalize_() { float l = length(); x /= l; y /= l; z /= l; return {}; }
-    NoReturn copy_(const Vec3& v) { x = v.x; y = v.y; z = v.z; return {}; }
 };
 
 struct Vec4{
@@ -129,4 +125,9 @@ static_assert(is_pod_v<Vec3>);
 static_assert(is_pod_v<Vec4>);
 static_assert(is_pod_v<Mat3x3>);
 
+template<>
+inline constexpr bool is_sso_v<Vec2> = true;
+template<>
+inline constexpr bool is_sso_v<Vec3> = true;
+
 }   // namespace pkpy

+ 11 - 3
include/pocketpy/vm.h

@@ -388,7 +388,13 @@ public:
 
     template<typename T, typename ...Args>
     PyVar new_user_object(Args&&... args){
-        return heap.gcnew<T>(_tp_user<T>(), std::forward<Args>(args)...);
+        return new_object<T>(_tp_user<T>(), std::forward<Args>(args)...);
+    }
+
+    template<typename T, typename ...Args>
+    PyVar new_object(Type type, Args&&... args){
+        if constexpr(is_sso_v<T>) return PyVar(type, T(std::forward<Args>(args)...));
+        else return heap.gcnew<T>(type, std::forward<Args>(args)...);
     }
 #endif
 
@@ -489,11 +495,13 @@ PyVar py_var(VM* vm, __T&& value){
     }else{
         constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
         if constexpr(const_type){
-            return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
+            if constexpr(is_sso_v<T>) return PyVar(const_type, value);
+            else return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
         }
     }
     Type type = vm->_find_type_in_cxx_typeid_map<T>();
-    return vm->heap.gcnew<T>(type, std::forward<__T>(value));
+    if constexpr(is_sso_v<T>) return PyVar(type, value);
+    else return vm->heap.gcnew<T>(type, std::forward<__T>(value));
 }
 
 template<typename __T, bool with_check>

+ 0 - 7
include/typings/linalg.pyi

@@ -27,10 +27,6 @@ class vec2(_StructLike['vec2']):
     def normalize(self) -> vec2: ...
     def rotate(self, radians: float) -> vec2: ...
 
-    def copy_(self, other: vec2) -> None: ...
-    def normalize_(self) -> None: ...
-    def rotate_(self, radians: float) -> None: ...
-
     @staticmethod
     def angle(__from: vec2, __to: vec2) -> float:
         """Returns the angle in radians between vectors `from` and `to`.
@@ -71,9 +67,6 @@ class vec3(_StructLike['vec3']):
     def length_squared(self) -> float: ...
     def normalize(self) -> vec3: ...
 
-    def copy_(self, other: vec3) -> None: ...
-    def normalize_(self) -> None: ...
-
 class vec4(_StructLike['vec4']):
     x: float
     y: float

+ 1 - 1
src/array2d.cpp

@@ -39,7 +39,7 @@ struct Array2d{
     static void _register(VM* vm, PyVar mod, PyVar type){
         vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args){
             Type cls = PK_OBJ_GET(Type, args[0]);
-            return vm->heap.gcnew<Array2d>(cls);
+            return vm->new_object<Array2d>(cls);
         });
 
         vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args){

+ 7 - 7
src/cffi.cpp

@@ -6,7 +6,7 @@ namespace pkpy{
         vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
             Type cls = PK_OBJ_GET(Type, args[0]);
             i64 addr = CAST(i64, args[1]);
-            return vm->heap.gcnew<VoidP>(cls, reinterpret_cast<void*>(addr));
+            return vm->new_object<VoidP>(cls, reinterpret_cast<void*>(addr));
         });
 
         vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj){
@@ -41,7 +41,7 @@ namespace pkpy{
         vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
             Type cls = PK_OBJ_GET(Type, args[0]);
             int size = CAST(int, args[1]);
-            return vm->heap.gcnew<Struct>(cls, size);
+            return vm->new_object<Struct>(cls, size);
         });
 
         vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args){
@@ -91,7 +91,7 @@ namespace pkpy{
 
         vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){
             const Struct& self = _CAST(Struct&, args[0]);
-            return vm->heap.gcnew<Struct>(vm->_tp(args[0]), self);
+            return vm->new_object<Struct>(vm->_tp(args[0]), self);
         });
 
         vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar lhs, PyVar rhs){
@@ -173,7 +173,7 @@ void add_module_c(VM* vm){
         if(!vm->issubclass(cls, vm->_tp_user<VoidP>())){
             vm->ValueError("expected a subclass of void_p");
         }
-        return vm->heap.gcnew<VoidP>(cls, ptr.ptr);
+        return vm->new_object<VoidP>(cls, ptr.ptr);
     });
 
     vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args){
@@ -184,7 +184,7 @@ void add_module_c(VM* vm){
     vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args){
         VoidP& ptr = CAST(VoidP&, args[0]);
         void* value = *reinterpret_cast<void**>(ptr.ptr);
-        return vm->heap.gcnew<VoidP>(args[0].type, value);
+        return vm->new_object<VoidP>(args[0].type, value);
     });
 
     PyVar type;
@@ -226,13 +226,13 @@ void add_module_c(VM* vm){
         VoidP& voidp = PK_OBJ_GET(VoidP, lhs);                          \
         i64 offset = CAST(i64, rhs);                                    \
         T* target = (T*)voidp.ptr;                                      \
-        return vm->heap.gcnew<VoidP>(lhs.type, target + offset);        \
+        return vm->new_object<VoidP>(lhs.type, target + offset);        \
     });                                                                 \
     vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){   \
         VoidP& voidp = PK_OBJ_GET(VoidP, lhs);                          \
         i64 offset = CAST(i64, rhs);                                    \
         T* target = (T*)voidp.ptr;                                      \
-        return vm->heap.gcnew<VoidP>(lhs.type, target - offset);        \
+        return vm->new_object<VoidP>(lhs.type, target - offset);        \
     });                                                                 \
     vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str{          \
         VoidP& self = _CAST(VoidP&, obj);                               \

+ 1 - 1
src/collections.cpp

@@ -63,7 +63,7 @@ namespace pkpy
                      Type cls_t = PK_OBJ_GET(Type, args[0]);
                      PyVar iterable = args[1];
                      PyVar maxlen = args[2];
-                     return vm->heap.gcnew<PyDeque>(cls_t, vm, iterable, maxlen);
+                     return vm->new_object<PyDeque>(cls_t, vm, iterable, maxlen);
                  });
         // gets the item at the given index, if index is negative, it will be treated as index + len(deque)
         // if the index is out of range, IndexError will be thrown --> required for [] operator

+ 1 - 0
src/gc.cpp

@@ -5,6 +5,7 @@ namespace pkpy{
     int ManagedHeap::sweep(){
         std::vector<PyVar> alive;
         for(PyVar obj: gen){
+            PK_DEBUG_ASSERT(!obj.is_sso)
             if(obj->gc_marked){
                 obj->gc_marked = false;
                 alive.push_back(obj);

+ 2 - 2
src/io.cpp

@@ -56,7 +56,7 @@ unsigned char* _default_import_handler(const char* name, int* out_size){
 void FileIO::_register(VM* vm, PyVar mod, PyVar type){
     vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){
         Type cls = PK_OBJ_GET(Type, args[0]);
-        return vm->heap.gcnew<FileIO>(cls, vm,
+        return vm->new_object<FileIO>(cls, vm,
                     py_cast<Str&>(vm, args[1]),
                     py_cast<Str&>(vm, args[2]));
     });
@@ -154,7 +154,7 @@ void add_module_io(VM* vm){
 
 void add_module_os(VM* vm){
     PyVar mod = vm->new_module("os");
-    PyVar path_obj = vm->heap.gcnew<DummyInstance>(vm->tp_object);
+    PyVar path_obj = vm->new_object<DummyInstance>(vm->tp_object);
     mod->attr().set("path", path_obj);
     
     // Working directory is shared by all VMs!!

+ 6 - 17
src/linalg.cpp

@@ -123,7 +123,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
         vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){
             float x = CAST_F(args[1]);
             float y = CAST_F(args[2]);
-            return vm->heap.gcnew<Vec2>(PK_OBJ_GET(Type, args[0]), x, y);
+            return vm->new_object<Vec2>(PK_OBJ_GET(Type, args[0]), x, y);
         });
 
         // @staticmethod
@@ -163,13 +163,6 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
             return vm->new_user_object<Vec2>(self.rotate(radian));
         });
 
-        vm->bind_func(type, "rotate_", 2, [](VM* vm, ArgsView args){
-            Vec2& self = _CAST(Vec2&, args[0]);
-            float radian = CAST(f64, args[1]);
-            self = self.rotate(radian);
-            return vm->None;
-        });
-
         PY_FIELD(Vec2, "x", x)
         PY_FIELD(Vec2, "y", y)
 
@@ -179,11 +172,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
         BIND_VEC_FLOAT_OP(2, __truediv__, /)
         BIND_VEC_FUNCTION_1(2, dot)
         BIND_VEC_FUNCTION_1(2, cross)
-        BIND_VEC_FUNCTION_1(2, copy_)
         BIND_VEC_FUNCTION_0(2, length)
         BIND_VEC_FUNCTION_0(2, length_squared)
         BIND_VEC_FUNCTION_0(2, normalize)
-        BIND_VEC_FUNCTION_0(2, normalize_)
         BIND_VEC_GETITEM(2)
     }
 
@@ -197,7 +188,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
             float x = CAST_F(args[1]);
             float y = CAST_F(args[2]);
             float z = CAST_F(args[3]);
-            return vm->heap.gcnew<Vec3>(PK_OBJ_GET(Type, args[0]), x, y, z);
+            return vm->new_object<Vec3>(PK_OBJ_GET(Type, args[0]), x, y, z);
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{
@@ -217,11 +208,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
         BIND_VEC_MUL_OP(3)
         BIND_VEC_FUNCTION_1(3, dot)
         BIND_VEC_FUNCTION_1(3, cross)
-        BIND_VEC_FUNCTION_1(3, copy_)
         BIND_VEC_FUNCTION_0(3, length)
         BIND_VEC_FUNCTION_0(3, length_squared)
         BIND_VEC_FUNCTION_0(3, normalize)
-        BIND_VEC_FUNCTION_0(3, normalize_)
         BIND_VEC_GETITEM(3)
     }
 
@@ -236,7 +225,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
             float y = CAST_F(args[2]);
             float z = CAST_F(args[3]);
             float w = CAST_F(args[4]);
-            return vm->heap.gcnew<Vec4>(PK_OBJ_GET(Type, args[0]), x, y, z, w);
+            return vm->new_object<Vec4>(PK_OBJ_GET(Type, args[0]), x, y, z, w);
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{
@@ -274,18 +263,18 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
         PY_STRUCT_LIKE(Mat3x3)
 
         vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
-            if(args.size() == 1+0) return vm->heap.gcnew<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
+            if(args.size() == 1+0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
             if(args.size() == 1+1){
                 const List& list = CAST(List&, args[1]);
                 if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
                 Mat3x3 mat;
                 for(int i=0; i<9; i++) mat.v[i] = CAST_F(list[i]);
-                return vm->heap.gcnew<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
+                return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
             }
             if(args.size() == 1+9){
                 Mat3x3 mat;
                 for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
-                return vm->heap.gcnew<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
+                return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
             }
             vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size()-1));
             return vm->None;

+ 3 - 3
src/modules.cpp

@@ -71,8 +71,8 @@ void add_module_sys(VM* vm){
     vm->setattr(mod, "version", VAR(PK_VERSION));
     vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM]));
 
-    PyVar stdout_ = vm->heap.gcnew<DummyInstance>(vm->tp_object);
-    PyVar stderr_ = vm->heap.gcnew<DummyInstance>(vm->tp_object);
+    PyVar stdout_ = vm->new_object<DummyInstance>(vm->tp_object);
+    PyVar stderr_ = vm->new_object<DummyInstance>(vm->tp_object);
     vm->setattr(mod, "stdout", stdout_);
     vm->setattr(mod, "stderr", stderr_);
 
@@ -287,7 +287,7 @@ struct LineProfilerW{
     static void _register(VM* vm, PyVar mod, PyVar type){
         vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
             Type cls = PK_OBJ_GET(Type, args[0]);
-            return vm->heap.gcnew<LineProfilerW>(cls);
+            return vm->new_object<LineProfilerW>(cls);
         });
 
         vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args){

+ 6 - 6
src/pocketpy.cpp

@@ -104,19 +104,19 @@ void __init_builtins(VM* _vm) {
             StrName _1 = _type_name(vm, type);
             vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape());
         }
-        return vm->heap.gcnew<Super>(vm->tp_super, self_arg, vm->_all_types[type].base);
+        return vm->new_object<Super>(vm->tp_super, self_arg, vm->_all_types[type].base);
     });
 
     _vm->bind_func(_vm->builtins, "staticmethod", 1, [](VM* vm, ArgsView args) {
         PyVar func = args[0];
         vm->check_type(func, vm->tp_function);
-        return vm->heap.gcnew<StaticMethod>(vm->tp_staticmethod, args[0]);
+        return vm->new_object<StaticMethod>(vm->tp_staticmethod, args[0]);
     });
 
     _vm->bind_func(_vm->builtins, "classmethod", 1, [](VM* vm, ArgsView args) {
         PyVar func = args[0];
         vm->check_type(func, vm->tp_function);
-        return vm->heap.gcnew<ClassMethod>(vm->tp_classmethod, args[0]);
+        return vm->new_object<ClassMethod>(vm->tp_classmethod, args[0]);
     });
 
     _vm->bind_func(_vm->builtins, "isinstance", 2, [](VM* vm, ArgsView args) {
@@ -343,7 +343,7 @@ void __init_builtins(VM* _vm) {
     _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
         vm->check_type(args[0], vm->tp_type);
         Type t = PK_OBJ_GET(Type, args[0]);
-        return vm->heap.gcnew<DummyInstance>(t);
+        return vm->new_object<DummyInstance>(t);
     });
 
     // tp_type
@@ -1264,7 +1264,7 @@ void __init_builtins(VM* _vm) {
     // tp_dict
     _vm->bind_func(VM::tp_dict, __new__, -1, [](VM* vm, ArgsView args){
         Type cls_t = PK_OBJ_GET(Type, args[0]);
-        return vm->heap.gcnew<Dict>(cls_t, vm);
+        return vm->new_object<Dict>(cls_t, vm);
     });
 
     _vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args){
@@ -1464,7 +1464,7 @@ void __init_builtins(VM* _vm) {
     _vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args){
         Type cls = PK_OBJ_GET(Type, args[0]);
         StrName cls_name = _type_name(vm, cls);
-        PyVar e_obj = vm->heap.gcnew<Exception>(cls, cls_name);
+        PyVar e_obj = vm->new_object<Exception>(cls, cls_name);
         e_obj->_enable_instance_dict();
         PK_OBJ_GET(Exception, e_obj)._self = e_obj;
         return e_obj;

+ 1 - 1
src/random.cpp

@@ -136,7 +136,7 @@ struct Random{
     static void _register(VM* vm, PyVar mod, PyVar type){
         vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
             Type cls = PK_OBJ_GET(Type, args[0]);
-            return vm->heap.gcnew<Random>(cls);
+            return vm->new_object<Random>(cls);
         });
 
         vm->bind_func(type, "seed", 2, [](VM* vm, ArgsView args) {

+ 4 - 4
src/vm.cpp

@@ -541,7 +541,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
         }else{
             check_compatible_type(globals, VM::tp_dict);
             // make a temporary object and copy globals into it
-            globals_obj = heap.gcnew<DummyInstance>(VM::tp_object);
+            globals_obj = new_object<DummyInstance>(VM::tp_object);
             globals_obj->_enable_instance_dict();
             globals_dict = &PK_OBJ_GET(Dict, globals);
             globals_dict->apply([&](PyVar k, PyVar v){
@@ -1095,7 +1095,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
         PK_DEBUG_ASSERT(new_f != nullptr && !method_call);
         if(new_f == __cached_object_new) {
             // fast path for object.__new__
-            obj = vm->heap.gcnew<DummyInstance>(PK_OBJ_GET(Type, callable));
+            obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
         }else{
             PUSH(new_f);
             PUSH(PY_NULL);
@@ -1361,9 +1361,9 @@ PyVar VM::bind_property(PyVar obj, const char* name, NativeFuncC fget, NativeFun
     PK_ASSERT(is_type(obj, tp_type));
     std::string_view name_sv(name); int pos = name_sv.find(':');
     if(pos > 0) name_sv = name_sv.substr(0, pos);
-    PyVar _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1);
+    PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
     PyVar _1 = vm->None;
-    if(fset != nullptr) _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2);
+    if(fset != nullptr) _1 = new_object<NativeFunc>(tp_native_func, fset, 2);
     PyVar prop = VAR(Property(_0, _1));
     obj->attr().set(StrName(name_sv), prop);
     return prop;

+ 0 - 2
tests/80_linalg.py

@@ -39,8 +39,6 @@ test_vec2_copy = test_vec2.copy()
 radians = random.uniform(-10*math.pi, 10*math.pi)
 test_vec2_copy = rotated_vec2(test_vec2_copy, radians)
 assert test_vec2.rotate(radians) == test_vec2_copy
-test_vec2.rotate_(radians)
-assert test_vec2 == test_vec2_copy
 
 # test smooth_damp
 vel = vec2(0, 0)