Bladeren bron

update gc

blueloveTH 2 jaren geleden
bovenliggende
commit
f57fa16ee2
18 gewijzigde bestanden met toevoegingen van 323 en 415 verwijderingen
  1. 44 47
      src/ceval.h
  2. 20 20
      src/cffi.h
  3. 1 1
      src/codeobject.h
  4. 20 1
      src/common.h
  5. 6 6
      src/compiler.h
  6. 15 15
      src/frame.h
  7. 24 35
      src/gc.h
  8. 4 4
      src/io.h
  9. 8 8
      src/iter.h
  10. 1 1
      src/main.cpp
  11. 5 55
      src/memory.h
  12. 19 21
      src/namedict.h
  13. 38 50
      src/obj.h
  14. 2 2
      src/parser.h
  15. 25 25
      src/pocketpy.h
  16. 27 27
      src/ref.h
  17. 6 24
      src/tuplelist.h
  18. 58 73
      src/vm.h

+ 44 - 47
src/ceval.h

@@ -7,7 +7,7 @@ namespace pkpy{
 
 Str _read_file_cwd(const Str& name, bool* ok);
 
-PyVar VM::run_frame(Frame* frame){
+PyObject* VM::run_frame(Frame* frame){
     while(frame->has_next_bytecode()){
         const Bytecode& byte = frame->next_bytecode();
         switch (byte.op)
@@ -16,7 +16,7 @@ PyVar VM::run_frame(Frame* frame){
         case OP_SETUP_DECORATOR: continue;
         case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
         case OP_LOAD_FUNCTION: {
-            const PyVar obj = frame->co->consts[byte.arg];
+            PyObject* obj = frame->co->consts[byte.arg];
             Function f = CAST(Function, obj);  // copy
             f._module = frame->_module;
             frame->push(VAR(f));
@@ -37,13 +37,13 @@ PyVar VM::run_frame(Frame* frame){
         } continue;
         case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: {
             auto& attr = frame->co->names[byte.arg];
-            PyVar obj = frame->pop_value(this);
+            PyObject* obj = frame->pop_value(this);
             AttrRef ref = AttrRef(obj, NameRef(attr));
             if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame));
             else frame->push(PyRef(ref));
         } continue;
         case OP_BUILD_INDEX: {
-            PyVar index = frame->pop_value(this);
+            PyObject* index = frame->pop_value(this);
             auto ref = IndexRef(frame->pop_value(this), index);
             if(byte.arg > 0) frame->push(ref.get(this, frame));
             else frame->push(PyRef(ref));
@@ -57,9 +57,6 @@ PyVar VM::run_frame(Frame* frame){
         } continue;
         case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue;
         case OP_STORE_REF: {
-            // PyVar obj = frame->pop_value(this);
-            // PyVarRef r = frame->pop();
-            // PyRef_AS_C(r)->set(this, frame, std::move(obj));
             PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this));
             frame->_pop(); frame->_pop();
         } continue;
@@ -84,25 +81,25 @@ PyVar VM::run_frame(Frame* frame){
         case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
         case OP_BEGIN_CLASS: {
             auto& name = frame->co->names[byte.arg];
-            PyVar clsBase = frame->pop_value(this);
+            PyObject* clsBase = frame->pop_value(this);
             if(clsBase == None) clsBase = _t(tp_object);
             check_type(clsBase, tp_type);
-            PyVar cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase));
+            PyObject* cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase));
             frame->push(cls);
         } continue;
         case OP_END_CLASS: {
-            PyVar cls = frame->pop();
+            PyObject* cls = frame->pop();
             cls->attr()._try_perfect_rehash();
         }; continue;
         case OP_STORE_CLASS_ATTR: {
             auto& name = frame->co->names[byte.arg];
-            PyVar obj = frame->pop_value(this);
-            PyVar& cls = frame->top();
+            PyObject* obj = frame->pop_value(this);
+            PyObject* cls = frame->top();
             cls->attr().set(name.first, std::move(obj));
         } continue;
         case OP_RETURN_VALUE: return frame->pop_value(this);
         case OP_PRINT_EXPR: {
-            const PyVar expr = frame->top_value(this);
+            PyObject* expr = frame->top_value(this);
             if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
         } continue;
         case OP_POP_TOP: frame->_pop(); continue;
@@ -122,7 +119,7 @@ PyVar VM::run_frame(Frame* frame){
             Args args(2);
             args[1] = frame->pop();
             args[0] = frame->top_value(this);
-            PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
+            PyObject* ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
             PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
             frame->_pop();
         } continue;
@@ -130,7 +127,7 @@ PyVar VM::run_frame(Frame* frame){
             Args args(2);
             args[1] = frame->pop_value(this);
             args[0] = frame->top_value(this);
-            PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
+            PyObject* ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
             PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
             frame->_pop();
         } continue;
@@ -141,14 +138,14 @@ PyVar VM::run_frame(Frame* frame){
             frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
         } continue;
         case OP_IS_OP: {
-            PyVar rhs = frame->pop_value(this);
+            PyObject* rhs = frame->pop_value(this);
             bool ret_c = rhs == frame->top_value(this);
             if(byte.arg == 1) ret_c = !ret_c;
             frame->top() = VAR(ret_c);
         } continue;
         case OP_CONTAINS_OP: {
-            PyVar rhs = frame->pop_value(this);
-            bool ret_c = CAST(bool, call(rhs, __contains__, one_arg(frame->pop_value(this))));
+            PyObject* rhs = frame->pop_value(this);
+            bool ret_c = CAST(bool, call(rhs, __contains__, Args{frame->pop_value(this)}));
             if(byte.arg == 1) ret_c = !ret_c;
             frame->push(VAR(ret_c));
         } continue;
@@ -156,8 +153,8 @@ PyVar VM::run_frame(Frame* frame){
             frame->top() = num_negated(frame->top_value(this));
             continue;
         case OP_UNARY_NOT: {
-            PyVar obj = frame->pop_value(this);
-            const PyVar& obj_bool = asBool(obj);
+            PyObject* obj = frame->pop_value(this);
+            PyObject* obj_bool = asBool(obj);
             frame->push(VAR(!_CAST(bool, obj_bool)));
         } continue;
         case OP_POP_JUMP_IF_FALSE:
@@ -168,9 +165,9 @@ PyVar VM::run_frame(Frame* frame){
         case OP_LOAD_FALSE: frame->push(False); continue;
         case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue;
         case OP_ASSERT: {
-            PyVar _msg = frame->pop_value(this);
+            PyObject* _msg = frame->pop_value(this);
             Str msg = CAST(Str, asStr(_msg));
-            PyVar expr = frame->pop_value(this);
+            PyObject* expr = frame->pop_value(this);
             if(asBool(expr) != True) _error("AssertionError", msg);
         } continue;
         case OP_EXCEPTION_MATCH: {
@@ -179,7 +176,7 @@ PyVar VM::run_frame(Frame* frame){
             frame->push(VAR(e.match_type(name)));
         } continue;
         case OP_RAISE: {
-            PyVar obj = frame->pop_value(this);
+            PyObject* obj = frame->pop_value(this);
             Str msg = obj == None ? "" : CAST(Str, asStr(obj));
             StrName type = frame->co->names[byte.arg].first;
             _error(type, msg);
@@ -190,32 +187,32 @@ PyVar VM::run_frame(Frame* frame){
             continue;
         case OP_BUILD_MAP: {
             Args items = frame->pop_n_values_reversed(this, byte.arg*2);
-            PyVar obj = call(builtins->attr("dict"));
+            PyObject* obj = call(builtins->attr("dict"));
             for(int i=0; i<items.size(); i+=2){
-                call(obj, __setitem__, two_args(items[i], items[i+1]));
+                call(obj, __setitem__, Args{items[i], items[i+1]});
             }
             frame->push(obj);
         } continue;
         case OP_BUILD_SET: {
-            PyVar list = VAR(
+            PyObject* list = VAR(
                 frame->pop_n_values_reversed(this, byte.arg).move_to_list()
             );
-            PyVar obj = call(builtins->attr("set"), one_arg(list));
+            PyObject* obj = call(builtins->attr("set"), Args{list});
             frame->push(obj);
         } continue;
         case OP_LIST_APPEND: {
-            PyVar obj = frame->pop_value(this);
+            PyObject* obj = frame->pop_value(this);
             List& list = CAST(List&, frame->top_1());
             list.push_back(std::move(obj));
         } continue;
         case OP_MAP_ADD: {
-            PyVar value = frame->pop_value(this);
-            PyVar key = frame->pop_value(this);
-            call(frame->top_1(), __setitem__, two_args(key, value));
+            PyObject* value = frame->pop_value(this);
+            PyObject* key = frame->pop_value(this);
+            call(frame->top_1(), __setitem__, Args{key, value});
         } continue;
         case OP_SET_ADD: {
-            PyVar obj = frame->pop_value(this);
-            call(frame->top_1(), "add", one_arg(obj));
+            PyObject* obj = frame->pop_value(this);
+            call(frame->top_1(), "add", Args{obj});
         } continue;
         case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
         case OP_UNARY_STAR: {
@@ -232,16 +229,16 @@ PyVar VM::run_frame(Frame* frame){
             Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
             Args args = frame->pop_n_values_reversed(this, ARGC);
             if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
-            PyVar callable = frame->pop_value(this);
-            PyVar ret = call(callable, std::move(args), kwargs, true);
+            PyObject* callable = frame->pop_value(this);
+            PyObject* ret = call(callable, std::move(args), kwargs, true);
             if(ret == _py_op_call) return ret;
             frame->push(std::move(ret));
         } continue;
         case OP_CALL_UNPACK: case OP_CALL: {
             Args args = frame->pop_n_values_reversed(this, byte.arg);
             if(byte.op == OP_CALL_UNPACK) unpack_args(args);
-            PyVar callable = frame->pop_value(this);
-            PyVar ret = call(callable, std::move(args), no_arg(), true);
+            PyObject* callable = frame->pop_value(this);
+            PyObject* ret = call(callable, std::move(args), no_arg(), true);
             if(ret == _py_op_call) return ret;
             frame->push(std::move(ret));
         } continue;
@@ -254,15 +251,15 @@ PyVar VM::run_frame(Frame* frame){
             frame->jump_abs_safe(it->second);
         } continue;
         case OP_GET_ITER: {
-            PyVar obj = frame->pop_value(this);
-            PyVar iter = asIter(obj);
+            PyObject* obj = frame->pop_value(this);
+            PyObject* iter = asIter(obj);
             check_type(frame->top(), tp_ref);
             PyIter_AS_C(iter)->loop_var = frame->pop();
             frame->push(std::move(iter));
         } continue;
         case OP_FOR_ITER: {
             BaseIter* it = PyIter_AS_C(frame->top());
-            PyVar obj = it->next();
+            PyObject* obj = it->next();
             if(obj != nullptr){
                 PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj));
             }else{
@@ -279,18 +276,18 @@ PyVar VM::run_frame(Frame* frame){
             frame->jump_abs_safe(blockEnd);
         } continue;
         case OP_JUMP_IF_FALSE_OR_POP: {
-            const PyVar expr = frame->top_value(this);
+            PyObject* expr = frame->top_value(this);
             if(asBool(expr)==False) frame->jump_abs(byte.arg);
             else frame->pop_value(this);
         } continue;
         case OP_JUMP_IF_TRUE_OR_POP: {
-            const PyVar expr = frame->top_value(this);
+            PyObject* expr = frame->top_value(this);
             if(asBool(expr)==True) frame->jump_abs(byte.arg);
             else frame->pop_value(this);
         } continue;
         case OP_BUILD_SLICE: {
-            PyVar stop = frame->pop_value(this);
-            PyVar start = frame->pop_value(this);
+            PyObject* stop = frame->pop_value(this);
+            PyObject* start = frame->pop_value(this);
             Slice s;
             if(start != None) { s.start = CAST(int, start);}
             if(stop != None) { s.stop = CAST(int, stop);}
@@ -298,7 +295,7 @@ PyVar VM::run_frame(Frame* frame){
         } continue;
         case OP_IMPORT_NAME: {
             StrName name = frame->co->names[byte.arg].first;
-            PyVar* ext_mod = _modules.try_get(name);
+            PyObject** ext_mod = _modules.try_get(name);
             if(ext_mod == nullptr){
                 Str source;
                 auto it2 = _lazy_modules.find(name);
@@ -311,7 +308,7 @@ PyVar VM::run_frame(Frame* frame){
                     _lazy_modules.erase(it2);
                 }
                 CodeObject_ code = compile(source, name.str(), EXEC_MODE);
-                PyVar new_mod = new_module(name);
+                PyObject* new_mod = new_module(name);
                 _exec(code, new_mod);
                 frame->push(new_mod);
                 new_mod->attr()._try_perfect_rehash();
@@ -320,7 +317,7 @@ PyVar VM::run_frame(Frame* frame){
             }
         } continue;
         case OP_STORE_ALL_NAMES: {
-            PyVar obj = frame->pop_value(this);
+            PyObject* obj = frame->pop_value(this);
             for(auto& [name, value]: obj->attr().items()){
                 Str s = name.str();
                 if(s.empty() || s[0] == '_') continue;

+ 20 - 20
src/cffi.h

@@ -14,7 +14,7 @@ struct NativeProxyFunc {
     _Fp func;
     NativeProxyFunc(_Fp func) : func(func) {}
 
-    PyVar operator()(VM* vm, Args& args) {
+    PyObject* operator()(VM* vm, Args& args) {
         if (args.size() != N) {
             vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size()));
         }
@@ -22,13 +22,13 @@ struct NativeProxyFunc {
     }
 
     template<typename __Ret, size_t... Is>
-    std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
+    std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
         func(py_cast<Params>(vm, args[Is])...);
         return vm->None;
     }
 
     template<typename __Ret, size_t... Is>
-    std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
+    std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
         __Ret ret = func(py_cast<Params>(vm, args[Is])...);
         return VAR(std::move(ret));
     }
@@ -41,7 +41,7 @@ struct NativeProxyMethod {
     _Fp func;
     NativeProxyMethod(_Fp func) : func(func) {}
 
-    PyVar operator()(VM* vm, Args& args) {
+    PyObject* operator()(VM* vm, Args& args) {
         int actual_size = args.size() - 1;
         if (actual_size != N) {
             vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size));
@@ -50,14 +50,14 @@ struct NativeProxyMethod {
     }
 
     template<typename __Ret, size_t... Is>
-    std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
+    std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
         T& self = py_cast<T&>(vm, args[0]);
         (self.*func)(py_cast<Params>(vm, args[Is+1])...);
         return vm->None;
     }
 
     template<typename __Ret, size_t... Is>
-    std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
+    std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
         T& self = py_cast<T&>(vm, args[0]);
         __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
         return VAR(std::move(ret));
@@ -200,7 +200,7 @@ struct Pointer{
         return Pointer(ctype, level, ptr-offset*unit_size());
     }
 
-    static void _register(VM* vm, PyVar mod, PyVar type){
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
 
         vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
@@ -268,7 +268,7 @@ struct Pointer{
     template<typename T>
     inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
 
-    PyVar get(VM* vm){
+    PyObject* get(VM* vm){
         if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>());
         switch(ctype->index){
 #define CASE(T) case type_index<T>(): return VAR(ref<T>())
@@ -291,7 +291,7 @@ struct Pointer{
         return VAR_T(Pointer, *this);
     }
 
-    void set(VM* vm, const PyVar& val){
+    void set(VM* vm, PyObject* val){
         if(level > 1) {
             Pointer& p = CAST(Pointer&, val);
             ref<char*>() = p.ptr;   // We don't check the type, just copy the underlying address
@@ -359,7 +359,7 @@ struct Value {
     Value& operator=(const Value& other) = delete;
     Value(const Value& other) = delete;
     
-    static void _register(VM* vm, PyVar mod, PyVar type){
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
 
         vm->bind_method<0>(type, "ptr", [](VM* vm, Args& args) {
@@ -388,7 +388,7 @@ struct CType{
     CType() : type(_type_db.get<void>()) {}
     CType(const TypeInfo* type) : type(type) {}
 
-    static void _register(VM* vm, PyVar mod, PyVar type){
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) {
             const Str& name = CAST(Str&, args[0]);
             const TypeInfo* type = _type_db.get(name);
@@ -404,8 +404,8 @@ struct CType{
 };
 
 void add_module_c(VM* vm){
-    PyVar mod = vm->new_module("c");
-    PyVar ptr_t = Pointer::register_class(vm, mod);
+    PyObject* mod = vm->new_module("c");
+    PyObject* ptr_t = Pointer::register_class(vm, mod);
     Value::register_class(vm, mod);
     CType::register_class(vm, mod);
 
@@ -462,11 +462,11 @@ void add_module_c(VM* vm){
     });
 }
 
-PyVar py_var(VM* vm, void* p){
+PyObject* py_var(VM* vm, void* p){
     return VAR_T(Pointer, _type_db.get<void>(), (char*)p);
 }
 
-PyVar py_var(VM* vm, char* p){
+PyObject* py_var(VM* vm, char* p){
     return VAR_T(Pointer, _type_db.get<char>(), (char*)p);
 }
 
@@ -491,7 +491,7 @@ struct pointer {
 };
 
 template<typename T>
-T py_pointer_cast(VM* vm, const PyVar& var){
+T py_pointer_cast(VM* vm, PyObject* var){
     static_assert(std::is_pointer_v<T>);
     Pointer& p = CAST(Pointer&, var);
     const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
@@ -503,14 +503,14 @@ T py_pointer_cast(VM* vm, const PyVar& var){
 }
 
 template<typename T>
-T py_value_cast(VM* vm, const PyVar& var){
+T py_value_cast(VM* vm, PyObject* var){
     static_assert(std::is_pod_v<T>);
     Value& v = CAST(Value&, var);
     return *reinterpret_cast<T*>(v.data);
 }
 
 template<typename T>
-std::enable_if_t<std::is_pointer_v<std::decay_t<T>>, PyVar>
+std::enable_if_t<std::is_pointer_v<std::decay_t<T>>, PyObject*>
 py_var(VM* vm, T p){
     const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
     if(type == nullptr) type = _type_db.get<void>();
@@ -518,9 +518,9 @@ py_var(VM* vm, T p){
 }
 
 template<typename T>
-std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyVar>
+std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyObject*>
 py_var(VM* vm, T p){
-    if constexpr(std::is_same_v<T, PyVar>) return p;
+    if constexpr(std::is_same_v<T, PyObject*>) return p;
     const TypeInfo* type = _type_db.get<T>();
     return VAR_T(Value, type, &p);
 }

+ 1 - 1
src/codeobject.h

@@ -94,7 +94,7 @@ struct CodeObject {
         return names.size() - 1;
     }
 
-    int add_const(PyVar v){
+    int add_const(PyObject* v){
         consts.push_back(v);
         return consts.size() - 1;
     }

+ 20 - 1
src/common.h

@@ -57,7 +57,6 @@ namespace std = ::std;
 struct Dummy {  };
 struct DummyInstance {  };
 struct DummyModule { };
-#define DUMMY_VAL Dummy()
 
 struct Type {
 	int index;
@@ -85,4 +84,24 @@ struct Type {
 const float kLocalsLoadFactor = 0.67f;
 const float kInstAttrLoadFactor = 0.67f;
 const float kTypeAttrLoadFactor = 0.5f;
+
+static_assert(sizeof(i64) == sizeof(int*));
+static_assert(sizeof(f64) == sizeof(int*));
+static_assert(std::numeric_limits<float>::is_iec559);
+static_assert(std::numeric_limits<double>::is_iec559);
+
+struct PyObject;
+#define BITS(p) (reinterpret_cast<i64>(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_both_int_or_float(PyObject* a, PyObject* b) noexcept {
+    return is_tagged(a) && is_tagged(b);
+}
+
+inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
+    return is_int(a) && is_int(b);
+}
+
 } // namespace pkpy

+ 6 - 6
src/compiler.h

@@ -353,14 +353,14 @@ private:
     }
 
     void exprLiteral() {
-        PyVar value = parser->prev.value;
+        PyObject* value = parser->prev.value;
         int index = co()->add_const(value);
         emit(OP_LOAD_CONST, index);
     }
 
     void exprFString() {
         static const std::regex pattern(R"(\{(.*?)\})");
-        PyVar value = parser->prev.value;
+        PyObject* value = parser->prev.value;
         Str s = CAST(Str, value);
         std::sregex_iterator begin(s.begin(), s.end(), pattern);
         std::sregex_iterator end;
@@ -1059,7 +1059,7 @@ private:
                 case 1: func.starred_arg = name; state+=1; break;
                 case 2: {
                     consume(TK("="));
-                    PyVarOrNull value = read_literal();
+                    PyObject* value = read_literal();
                     if(value == nullptr){
                         SyntaxError(Str("expect a literal, not ") + TK_STR(parser->curr.type));
                     }
@@ -1115,10 +1115,10 @@ private:
         }
     }
 
-    PyVarOrNull read_literal(){
+    PyObject* read_literal(){
         if(match(TK("-"))){
             consume(TK("@num"));
-            PyVar val = parser->prev.value;
+            PyObject* val = parser->prev.value;
             return vm->num_negated(val);
         }
         if(match(TK("@num"))) return parser->prev.value;
@@ -1166,7 +1166,7 @@ public:
             code->optimize(vm);
             return code;
         }else if(mode()==JSON_MODE){
-            PyVarOrNull value = read_literal();
+            PyObject* value = read_literal();
             if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
             else if(match(TK("{"))) exprMap();
             else if(match(TK("["))) exprList();

+ 15 - 15
src/frame.h

@@ -7,27 +7,27 @@ namespace pkpy{
 static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
 
 struct Frame {
-    std::vector<PyVar> _data;
+    std::vector<PyObject*> _data;
     int _ip = -1;
     int _next_ip = 0;
 
     const CodeObject* co;
-    PyVar _module;
+    PyObject* _module;
     NameDict_ _locals;
     NameDict_ _closure;
     const uint64_t id;
-    std::vector<std::pair<int, std::vector<PyVar>>> s_try_block;
+    std::vector<std::pair<int, std::vector<PyObject*>>> s_try_block;
 
     inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
     inline NameDict& f_globals() noexcept { return _module->attr(); }
 
-    inline PyVar* f_closure_try_get(StrName name) noexcept {
+    inline PyObject** f_closure_try_get(StrName name) noexcept {
         if(_closure == nullptr) return nullptr;
         return _closure->try_get(name);
     }
 
     Frame(const CodeObject_& co,
-        const PyVar& _module,
+        PyObject* _module,
         const NameDict_& _locals=nullptr,
         const NameDict_& _closure=nullptr)
             : co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { }
@@ -57,11 +57,11 @@ struct Frame {
         return _next_ip < co->codes.size();
     }
 
-    inline PyVar pop(){
+    inline PyObject* pop(){
 #if PK_EXTRA_CHECK
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
 #endif
-        PyVar v = std::move(_data.back());
+        PyObject* v = _data.back();
         _data.pop_back();
         return v;
     }
@@ -73,28 +73,28 @@ struct Frame {
         _data.pop_back();
     }
 
-    inline void try_deref(VM*, PyVar&);
+    inline void try_deref(VM*, PyObject*&);
 
-    inline PyVar pop_value(VM* vm){
-        PyVar value = pop();
+    inline PyObject* pop_value(VM* vm){
+        PyObject* value = pop();
         try_deref(vm, value);
         return value;
     }
 
-    inline PyVar top_value(VM* vm){
-        PyVar value = top();
+    inline PyObject* top_value(VM* vm){
+        PyObject* value = top();
         try_deref(vm, value);
         return value;
     }
 
-    inline PyVar& top(){
+    inline PyObject*& top(){
 #if PK_EXTRA_CHECK
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
 #endif
         return _data.back();
     }
 
-    inline PyVar& top_1(){
+    inline PyObject*& top_1(){
 #if PK_EXTRA_CHECK
         if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
 #endif
@@ -117,7 +117,7 @@ struct Frame {
 
     bool jump_to_exception_handler(){
         if(s_try_block.empty()) return false;
-        PyVar obj = pop();
+        PyObject* obj = pop();
         auto& p = s_try_block.back();
         _data = std::move(p.second);
         _data.push_back(obj);

+ 24 - 35
src/gc.h

@@ -3,49 +3,38 @@
 #include "obj.h"
 
 namespace pkpy {
-    using PyVar0 = PyObject*;
+    struct ManagedHeap{
+        std::vector<PyObject*> heap;
 
-    // a generational mark and sweep garbage collector
-    struct GC{
-        using Generation = std::vector<PyVar0>;
-        static const int kTotalGen = 3;
-        Generation gen[kTotalGen];
-
-        void add(PyVar0 obj){
-            if(!obj->need_gc) return;
-            gen[0].push_back(obj);
+        template<typename T>
+        PyObject* gcnew(Type type, T&& val){
+            PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
+            obj->gc.enabled = true;
+            heap.push_back(obj);
+            return obj;
         }
 
-        void sweep(int index){
-            Generation& g = gen[index];
-            if(index < kTotalGen-1){
-                for(int i=0; i<g.size(); i++){
-                    if(g[i]->marked){
-                        g[i]->marked = false;
-                        gen[index+1].push_back(g[i]);
-                    }else{
-                        delete g[i];
-                    }
-                }
-                g.clear();
-            }else{
-                Generation alive;
-                // the oldest generation
-                for(int i=0; i<g.size(); i++){
-                    if(g[i]->marked){
-                        g[i]->marked = false;
-                        alive.push_back(g[i]);
-                    }else{
-                        delete g[i];
-                    }
+        void sweep(){
+            std::vector<PyObject*> alive;
+            for(PyObject* obj: heap){
+                if(obj->gc.marked){
+                    obj->gc.marked = false;
+                    alive.push_back(obj);
+                }else{
+                    delete obj;
                 }
-                g = std::move(alive);
             }
+            heap.clear();
+            heap.swap(alive);
         }
 
-        void collect(int index){
-            sweep(index);
+        void collect(VM* vm){
+            std::vector<PyObject*> roots = get_roots(vm);
+            for(PyObject* obj: roots) obj->mark();
+            sweep();
         }
+
+        std::vector<PyObject*> get_roots(VM* vm);
     };
 
 }   // namespace pkpy

+ 4 - 4
src/io.h

@@ -42,7 +42,7 @@ struct FileIO {
         if(!_fs.is_open()) vm->IOError(strerror(errno));
     }
 
-    static void _register(VM* vm, PyVar mod, PyVar type){
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
             return VAR_T(FileIO, 
                 vm, CAST(Str, args[0]), CAST(Str, args[1])
@@ -79,15 +79,15 @@ struct FileIO {
 };
 
 void add_module_io(VM* vm){
-    PyVar mod = vm->new_module("io");
-    PyVar type = FileIO::register_class(vm, mod);
+    PyObject* mod = vm->new_module("io");
+    PyObject* type = FileIO::register_class(vm, mod);
     vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
         return vm->call(type, args);
     });
 }
 
 void add_module_os(VM* vm){
-    PyVar mod = vm->new_module("os");
+    PyObject* mod = vm->new_module("os");
     // Working directory is shared by all VMs!!
     vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){
         return VAR(std::filesystem::current_path().string());

+ 8 - 8
src/iter.h

@@ -8,7 +8,7 @@ class RangeIter : public BaseIter {
     i64 current;
     Range r;
 public:
-    RangeIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
+    RangeIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) {
         this->r = OBJ_GET(Range, _ref);
         this->current = r.start;
     }
@@ -17,7 +17,7 @@ public:
         return r.step > 0 ? current < r.stop : current > r.stop;
     }
 
-    PyVar next(){
+    PyObject* next(){
         if(!_has_next()) return nullptr;
         current += r.step;
         return VAR(current-r.step);
@@ -29,8 +29,8 @@ class ArrayIter : public BaseIter {
     size_t index = 0;
     const T* p;
 public:
-    ArrayIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);}
-    PyVar next(){
+    ArrayIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);}
+    PyObject* next(){
         if(index == p->size()) return nullptr;
         return p->operator[](index++); 
     }
@@ -40,20 +40,20 @@ class StringIter : public BaseIter {
     int index = 0;
     Str* str;
 public:
-    StringIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
+    StringIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) {
         str = &OBJ_GET(Str, _ref);
     }
 
-    PyVar next() {
+    PyObject* next() {
         if(index == str->u8_length()) return nullptr;
         return VAR(str->u8_getitem(index++));
     }
 };
 
-PyVar Generator::next(){
+PyObject* Generator::next(){
     if(state == 2) return nullptr;
     vm->callstack.push(std::move(frame));
-    PyVar ret = vm->_exec();
+    PyObject* ret = vm->_exec();
     if(ret == vm->_py_op_yield){
         frame = std::move(vm->callstack.top());
         vm->callstack.pop();

+ 1 - 1
src/main.cpp

@@ -75,7 +75,7 @@ int main(int argc, char** argv){
         // set parent path as cwd
         std::filesystem::current_path(filepath.parent_path());
 
-        pkpy::PyVarOrNull ret = nullptr;
+        pkpy::PyObject* ret = nullptr;
         ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
         pkpy_delete(vm);
         return ret != nullptr ? 0 : 1;

+ 5 - 55
src/memory.h

@@ -4,31 +4,12 @@
 
 namespace pkpy{
 
-struct PyObject;
-
-template<typename T>
-struct SpAllocator {
-    template<typename U>
-    inline static int* alloc(){
-        return (int*)malloc(sizeof(int) + sizeof(U));
-    }
-
-    inline static void dealloc(int* counter){
-        ((T*)(counter + 1))->~T();
-        free(counter);
-    }
-};
-
 template <typename T>
 struct shared_ptr {
-    union {
-        int* counter;
-        i64 bits;
-    };
-
+    int* counter;
 #define _t() (T*)(counter + 1)
-#define _inc_counter() if(!is_tagged() && counter) ++(*counter)
-#define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator<T>::dealloc(counter)
+#define _inc_counter() if(counter) ++(*counter)
+#define _dec_counter() if(counter && --(*counter) == 0) {((T*)(counter + 1))->~T(); free(counter);}
 
 public:
     shared_ptr() : counter(nullptr) {}
@@ -69,7 +50,6 @@ public:
     T* get() const { return _t(); }
 
     int use_count() const { 
-        if(is_tagged()) return 0;
         return counter ? *counter : 0;
     }
 
@@ -77,44 +57,20 @@ public:
         _dec_counter();
         counter = nullptr;
     }
-
-    inline constexpr bool is_tagged() const {
-        if constexpr(!std::is_same_v<T, PyObject>) return false;
-        return (bits & 0b11) != 0b00;
-    }
-    inline bool is_tag_00() const { return (bits & 0b11) == 0b00; }
-    inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
-    inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
-    inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
 };
 
 #undef _t
 #undef _inc_counter
 #undef _dec_counter
 
-    template <typename T, typename U, typename... Args>
-    shared_ptr<T> make_sp(Args&&... args) {
-        static_assert(std::is_base_of_v<T, U>, "U must be derived from T");
-        static_assert(std::has_virtual_destructor_v<T>, "T must have virtual destructor");
-        static_assert(!std::is_same_v<T, PyObject> || (!std::is_same_v<U, i64> && !std::is_same_v<U, f64>));
-        int* p = SpAllocator<T>::template alloc<U>(); *p = 1;
-        new(p+1) U(std::forward<Args>(args)...);
-        return shared_ptr<T>(p);
-    }
-
     template <typename T, typename... Args>
     shared_ptr<T> make_sp(Args&&... args) {
-        int* p = SpAllocator<T>::template alloc<T>(); *p = 1;
+        int* p = (int*)malloc(sizeof(int) + sizeof(T));
+        *p = 1;
         new(p+1) T(std::forward<Args>(args)...);
         return shared_ptr<T>(p);
     }
 
-static_assert(sizeof(i64) == sizeof(int*));
-static_assert(sizeof(f64) == sizeof(int*));
-static_assert(sizeof(shared_ptr<PyObject>) == sizeof(int*));
-static_assert(std::numeric_limits<float>::is_iec559);
-static_assert(std::numeric_limits<double>::is_iec559);
-
 template<typename T, int __Bucket, int __BucketSize=32>
 struct SmallArrayPool {
     std::vector<T*> buckets[__Bucket+1];
@@ -145,10 +101,4 @@ struct SmallArrayPool {
         }
     }
 };
-
-
-typedef shared_ptr<PyObject> PyVar;
-typedef PyVar PyVarOrNull;
-typedef PyVar PyVarRef;
-
 };  // namespace pkpy

+ 19 - 21
src/namedict.h

@@ -6,7 +6,7 @@
 
 namespace pkpy{
 
-const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyVar);
+const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyObject*);
 
 template<int __Bucket, int __BucketSize=32>
 struct DictArrayPool {
@@ -26,9 +26,7 @@ struct DictArrayPool {
     }
 
     void dealloc(StrName* head, uint16_t n){
-        PyVar* _values = (PyVar*)(head + n);
         if(n > __Bucket || buckets[n].size() >= __BucketSize){
-            for(int i=0; i<n; i++) _values[i].~PyVar();
             free(head);
         }else{
             buckets[n].push_back(head);
@@ -75,12 +73,12 @@ struct NameDict {
     uint16_t _mask;
     StrName* _keys;
 
-    inline PyVar& value(uint16_t i){
-        return reinterpret_cast<PyVar*>(_keys + _capacity)[i];
+    inline PyObject*& value(uint16_t i){
+        return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
     }
 
-    inline const PyVar& value(uint16_t i) const {
-        return reinterpret_cast<const PyVar*>(_keys + _capacity)[i];
+    inline PyObject* value(uint16_t i) const {
+        return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
     }
 
     NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]):
@@ -123,19 +121,19 @@ while(!_keys[i].empty()) { \
     i = (i + 1) & _mask; \
 }
 
-    const PyVar& operator[](StrName key) const {
+    PyObject* operator[](StrName key) const {
         bool ok; uint16_t i;
         HASH_PROBE(key, ok, i);
         if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
         return value(i);
     }
 
-    PyVar& get(StrName key){
-        bool ok; uint16_t i;
-        HASH_PROBE(key, ok, i);
-        if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
-        return value(i);
-    }
+    // PyObject*& get(StrName key){
+    //     bool ok; uint16_t i;
+    //     HASH_PROBE(key, ok, i);
+    //     if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
+    //     return value(i);
+    // }
 
     template<typename T>
     void set(StrName key, T&& val){
@@ -154,7 +152,7 @@ while(!_keys[i].empty()) { \
 
     void _rehash(bool resize){
         StrName* old_keys = _keys;
-        PyVar* old_values = &value(0);
+        PyObject** old_values = &value(0);
         uint16_t old_capacity = _capacity;
         if(resize){
             _capacity = find_next_capacity(_capacity * 2);
@@ -177,18 +175,18 @@ while(!_keys[i].empty()) { \
         _rehash(false); // do not resize
     }
 
-    inline PyVar* try_get(StrName key){
+    inline PyObject** try_get(StrName key){
         bool ok; uint16_t i;
         HASH_PROBE(key, ok, i);
         if(!ok) return nullptr;
         return &value(i);
     }
 
-    inline bool try_set(StrName key, PyVar&& val){
+    inline bool try_set(StrName key, PyObject* val){
         bool ok; uint16_t i;
         HASH_PROBE(key, ok, i);
         if(!ok) return false;
-        value(i) = std::move(val);
+        value(i) = val;
         return true;
     }
 
@@ -213,8 +211,8 @@ while(!_keys[i].empty()) { \
         _size--;
     }
 
-    std::vector<std::pair<StrName, PyVar>> items() const {
-        std::vector<std::pair<StrName, PyVar>> v;
+    std::vector<std::pair<StrName, PyObject*>> items() const {
+        std::vector<std::pair<StrName, PyObject*>> v;
         for(uint16_t i=0; i<_capacity; i++){
             if(_keys[i].empty()) continue;
             v.push_back(std::make_pair(_keys[i], value(i)));
@@ -231,7 +229,7 @@ while(!_keys[i].empty()) { \
         return v;
     }
 
-    void apply_v(void(*f)(PyVar)) {
+    void apply_v(void(*f)(PyObject*)) {
         for(uint16_t i=0; i<_capacity; i++){
             if(_keys[i].empty()) continue;
             f(value(i));

+ 38 - 50
src/obj.h

@@ -12,7 +12,7 @@ struct Frame;
 struct BaseRef;
 class VM;
 
-typedef std::function<PyVar(VM*, Args&)> NativeFuncRaw;
+typedef std::function<PyObject*(VM*, Args&)> NativeFuncRaw;
 typedef shared_ptr<CodeObject> CodeObject_;
 typedef shared_ptr<NameDict> NameDict_;
 
@@ -22,7 +22,7 @@ struct NativeFunc {
     bool method;
     
     NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
-    inline PyVar operator()(VM* vm, Args& args) const;
+    inline PyObject* operator()(VM* vm, Args& args) const;
 };
 
 struct Function {
@@ -34,7 +34,7 @@ struct Function {
     std::vector<StrName> kwargs_order;
 
     // runtime settings
-    PyVar _module = nullptr;
+    PyObject* _module = nullptr;
     NameDict_ _closure = nullptr;
 
     bool has_name(StrName val) const {
@@ -46,9 +46,9 @@ struct Function {
 };
 
 struct BoundMethod {
-    PyVar obj;
-    PyVar method;
-    BoundMethod(const PyVar& obj, const PyVar& method) : obj(obj), method(method) {}
+    PyObject* obj;
+    PyObject* method;
+    BoundMethod(PyObject* obj, PyObject* method) : obj(obj), method(method) {}
 };
 
 struct Range {
@@ -58,9 +58,9 @@ struct Range {
 };
 
 struct StarWrapper {
-    PyVar obj;
+    PyObject* obj;
     bool rvalue;
-    StarWrapper(const PyVar& obj, bool rvalue): obj(obj), rvalue(rvalue) {}
+    StarWrapper(PyObject* obj, bool rvalue): obj(obj), rvalue(rvalue) {}
 };
 
 struct Slice {
@@ -79,30 +79,34 @@ struct Slice {
 class BaseIter {
 protected:
     VM* vm;
-    PyVar _ref;     // keep a reference to the object so it will not be deleted while iterating
+    PyObject* _ref;     // keep a reference to the object so it will not be deleted while iterating
 public:
-    virtual PyVar next() = 0;
-    PyVarRef loop_var;
-    BaseIter(VM* vm, PyVar _ref) : vm(vm), _ref(_ref) {}
+    virtual PyObject* next() = 0;
+    PyObject* loop_var;
+    BaseIter(VM* vm, PyObject* _ref) : vm(vm), _ref(_ref) {}
     virtual ~BaseIter() = default;
 };
 
+struct GCHeader {
+    bool enabled;   // whether this object is managed by GC
+    bool marked;    // whether this object is marked
+    GCHeader() : enabled(false), marked(false) {}
+};
+
 struct PyObject {
-    bool need_gc;
-    bool marked;
-    /**********/
+    GCHeader gc;
     Type type;
     NameDict* _attr;
 
     inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
     inline NameDict& attr() noexcept { return *_attr; }
-    inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
+    inline PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; }
     virtual void* value() = 0;
 
     virtual void mark() {
-        if(!need_gc || marked) return;
-        marked = true;
-        if(is_attr_valid()) attr().apply_v([](PyVar v){ v->mark(); });
+        if(!gc.enabled || gc.marked) return;
+        gc.marked = true;
+        if(is_attr_valid()) attr().apply_v([](PyObject* v){ v->mark(); });
     }
 
     PyObject(Type type) : type(type) {}
@@ -141,67 +145,51 @@ struct Py_ : PyObject {
 const int kTpIntIndex = 2;
 const int kTpFloatIndex = 3;
 
-inline bool is_type(const PyVar& obj, Type type) noexcept {
+inline bool is_type(PyObject* obj, Type type) noexcept {
     switch(type.index){
-        case kTpIntIndex: return obj.is_tag_01();
-        case kTpFloatIndex: return obj.is_tag_10();
-        default: return !obj.is_tagged() && obj->type == type;
+        case kTpIntIndex: return is_tag_01(obj);
+        case kTpFloatIndex: return is_tag_10(obj);
+        default: return !is_tagged(obj) && obj->type == type;
     }
 }
 
-inline bool is_both_int_or_float(const PyVar& a, const PyVar& b) noexcept {
-    return a.is_tagged() && b.is_tagged();
-}
-
-inline bool is_both_int(const PyVar& a, const PyVar& b) noexcept {
-    return (a.bits & b.bits & 0b11) == 0b01;
-}
-
-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(T, mod, name) \
     static Type _type(VM* vm) {  \
         static const StrName __x0(#mod);      \
         static const StrName __x1(#name);     \
         return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1));               \
     }                                                                       \
-    static PyVar register_class(VM* vm, PyVar mod) {                        \
-        PyVar type = vm->new_type_object(mod, #name, vm->tp_object);        \
+    static PyObject* register_class(VM* vm, PyObject* mod) {                \
+        PyObject* type = vm->new_type_object(mod, #name, vm->tp_object);    \
         if(OBJ_NAME(mod) != #mod) UNREACHABLE();                            \
         T::_register(vm, mod, type);                                        \
         type->attr()._try_perfect_rehash();                                 \
         return type;                                                        \
     }                                                                       
 
-union __8B {
+union BitsCvt {
     i64 _int;
     f64 _float;
-    __8B(i64 val) : _int(val) {}
-    __8B(f64 val) : _float(val) {}
+    BitsCvt(i64 val) : _int(val) {}
+    BitsCvt(f64 val) : _float(val) {}
 };
 
 template <typename, typename = void> struct is_py_class : std::false_type {};
 template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {};
 
 template<typename T>
-void _check_py_class(VM* vm, const PyVar& var);
+void _check_py_class(VM* vm, PyObject* var);
 
 template<typename T>
-T py_pointer_cast(VM* vm, const PyVar& var);
+T py_pointer_cast(VM* vm, PyObject* var);
 
 template<typename T>
-T py_value_cast(VM* vm, const PyVar& var);
+T py_value_cast(VM* vm, PyObject* var);
 
 struct Discarded {};
 
 template<typename __T>
-__T py_cast(VM* vm, const PyVar& obj) {
+__T py_cast(VM* vm, PyObject* obj) {
     using T = std::decay_t<__T>;
     if constexpr(std::is_pointer_v<T>){
         return py_pointer_cast<T>(vm, obj);
@@ -216,7 +204,7 @@ __T py_cast(VM* vm, const PyVar& obj) {
 }
 
 template<typename __T>
-__T _py_cast(VM* vm, const PyVar& obj) {
+__T _py_cast(VM* vm, PyObject* obj) {
     using T = std::decay_t<__T>;
     if constexpr(std::is_pointer_v<__T>){
         return py_pointer_cast<__T>(vm, obj);
@@ -228,7 +216,7 @@ __T _py_cast(VM* vm, const PyVar& obj) {
 }
 
 #define VAR(x) py_var(vm, x)
-#define VAR_T(T, ...) vm->new_object(T::_type(vm), T(__VA_ARGS__))
+#define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__))
 #define CAST(T, x) py_cast<T>(vm, x)
 #define _CAST(T, x) _py_cast<T>(vm, x)
 

+ 2 - 2
src/parser.h

@@ -54,7 +54,7 @@ struct Token{
   const char* start;
   int length;
   int line;
-  PyVar value;
+  PyObject* value;
 
   Str str() const { return Str(start, length);}
 
@@ -271,7 +271,7 @@ struct Parser {
         return true;
     }
 
-    void set_next_token(TokenIndex type, PyVar value=nullptr) {
+    void set_next_token(TokenIndex type, PyObject* value=nullptr) {
         switch(type){
             case TK("{"): case TK("["): case TK("("): brackets_level++; break;
             case TK(")"): case TK("]"): case TK("}"): brackets_level--; break;

+ 25 - 25
src/pocketpy.h

@@ -69,7 +69,7 @@ void init_builtins(VM* _vm) {
             vm->TypeError("super(type, obj): obj must be an instance or subtype of type");
         }
         Type base = vm->_all_types[type.index].base;
-        return vm->new_object(vm->tp_super, Super(args[1], base));
+        return vm->heap.gcnew(vm->tp_super, Super(args[1], base));
     });
 
     _vm->bind_builtin_func<2>("isinstance", [](VM* vm, Args& args) {
@@ -79,16 +79,16 @@ void init_builtins(VM* _vm) {
     });
 
     _vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) {
-        const PyVar& obj = args[0];
-        if(obj.is_tagged()) return VAR((i64)0);
-        return VAR(obj.bits);
+        PyObject* obj = args[0];
+        if(is_tagged(obj)) return VAR((i64)0);
+        return VAR(BITS(obj));
     });
 
     _vm->bind_builtin_func<2>("divmod", [](VM* vm, Args& args) {
         i64 lhs = CAST(i64, args[0]);
         i64 rhs = CAST(i64, args[1]);
         if(rhs == 0) vm->ZeroDivisionError();
-        return VAR(two_args(VAR(lhs/rhs), VAR(lhs%rhs)));
+        return VAR(Tuple{VAR(lhs/rhs), VAR(lhs%rhs)});
     });
 
     _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
@@ -169,8 +169,8 @@ void init_builtins(VM* _vm) {
     });
 
     _vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
-        PyVar self = args[0];
-        std::uintptr_t addr = self.is_tagged() ? 0 : (uintptr_t)self.get();
+        PyObject* self = args[0];
+        std::uintptr_t addr = is_tagged(self) ? 0 : (uintptr_t)self;
         StrStream ss;
         ss << std::hex << addr;
         Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">";
@@ -405,7 +405,7 @@ void init_builtins(VM* _vm) {
     _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
         const Str& self = CAST(Str&, args[0]);
         StrStream ss;
-        PyVar obj = vm->asList(args[1]);
+        PyObject* obj = vm->asList(args[1]);
         const List& list = CAST(List&, obj);
         for (int i = 0; i < list.size(); ++i) {
             if (i > 0) ss << self;
@@ -423,7 +423,7 @@ void init_builtins(VM* _vm) {
 
     _vm->bind_method<1>("list", "extend", [](VM* vm, Args& args) {
         List& self = CAST(List&, args[0]);
-        PyVar obj = vm->asList(args[1]);
+        PyObject* obj = vm->asList(args[1]);
         const List& list = CAST(List&, obj);
         self.insert(self.end(), list.begin(), list.end());
         return vm->None;
@@ -575,7 +575,7 @@ void init_builtins(VM* _vm) {
 #endif
 
 void add_module_time(VM* vm){
-    PyVar mod = vm->new_module("time");
+    PyObject* mod = vm->new_module("time");
     vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
         auto now = std::chrono::high_resolution_clock::now();
         return VAR(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
@@ -583,7 +583,7 @@ void add_module_time(VM* vm){
 }
 
 void add_module_sys(VM* vm){
-    PyVar mod = vm->new_module("sys");
+    PyObject* mod = vm->new_module("sys");
     vm->setattr(mod, "version", VAR(PK_VERSION));
 
     vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(VAR(args[0].use_count())));
@@ -596,7 +596,7 @@ void add_module_sys(VM* vm){
 }
 
 void add_module_json(VM* vm){
-    PyVar mod = vm->new_module("json");
+    PyObject* mod = vm->new_module("json");
     vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) {
         const Str& expr = CAST(Str&, args[0]);
         CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE);
@@ -607,7 +607,7 @@ void add_module_json(VM* vm){
 }
 
 void add_module_math(VM* vm){
-    PyVar mod = vm->new_module("math");
+    PyObject* mod = vm->new_module("math");
     vm->setattr(mod, "pi", VAR(3.1415926535897932384));
     vm->setattr(mod, "e" , VAR(2.7182818284590452354));
 
@@ -626,9 +626,9 @@ void add_module_math(VM* vm){
 }
 
 void add_module_dis(VM* vm){
-    PyVar mod = vm->new_module("dis");
+    PyObject* mod = vm->new_module("dis");
     vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
-        PyVar f = args[0];
+        PyObject* f = args[0];
         if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).method;
         CodeObject_ code = CAST(Function, f).code;
         (*vm->_stdout) << vm->disassemble(code);
@@ -644,14 +644,14 @@ struct ReMatch {
     std::smatch m;
     ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {}
 
-    static void _register(VM* vm, PyVar mod, PyVar type){
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED());
         vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).start)));
         vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).end)));
 
         vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
             auto& self = CAST(ReMatch&, args[0]);
-            return VAR(two_args(VAR(self.start), VAR(self.end)));
+            return VAR(Tuple{VAR(self.start), VAR(self.end)});
         });
 
         vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
@@ -663,7 +663,7 @@ struct ReMatch {
     }
 };
 
-PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){
+PyObject* _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){
     std::regex re(pattern);
     std::smatch m;
     if(std::regex_search(string, m, re)){
@@ -676,7 +676,7 @@ PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* v
 };
 
 void add_module_re(VM* vm){
-    PyVar mod = vm->new_module("re");
+    PyObject* mod = vm->new_module("re");
     ReMatch::register_class(vm, mod);
 
     vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) {
@@ -740,7 +740,7 @@ struct Random{
         gen.seed(seed);
     }
 
-    static void _register(VM* vm, PyVar mod, PyVar type){
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random)));
         vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed));
         vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint));
@@ -750,7 +750,7 @@ struct Random{
 };
 
 void add_module_random(VM* vm){
-    PyVar mod = vm->new_module("random");
+    PyObject* mod = vm->new_module("random");
     Random::register_class(vm, mod);
     CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
     vm->_exec(code, mod);
@@ -851,7 +851,7 @@ extern "C" {
     /// Return `__repr__` of the result.
     /// If the variable is not found, return `nullptr`.
     char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){
-        pkpy::PyVar* val = vm->_main->attr().try_get(name);
+        pkpy::PyObject** val = vm->_main->attr().try_get(name);
         if(val == nullptr) return nullptr;
         try{
             pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val));
@@ -867,7 +867,7 @@ extern "C" {
     /// Return `__repr__` of the result.
     /// If there is any error, return `nullptr`.
     char* pkpy_vm_eval(pkpy::VM* vm, const char* source){
-        pkpy::PyVarOrNull ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE);
+        pkpy::PyObject* ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE);
         if(ret == nullptr) return nullptr;
         try{
             pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret));
@@ -950,13 +950,13 @@ extern "C" {
         for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr;
         for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr;
         std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
-        pkpy::PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
+        pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
         vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){
             pkpy::StrStream ss;
             ss << f_header;
             for(int i=0; i<args.size(); i++){
                 ss << ' ';
-                pkpy::PyVar x = vm->call(args[i], pkpy::__json__);
+                pkpy::PyObject* x = vm->call(args[i], pkpy::__json__);
                 ss << pkpy::CAST(pkpy::Str&, x);
             }
             char* packet = strdup(ss.str().c_str());

+ 27 - 27
src/ref.h

@@ -6,8 +6,8 @@
 namespace pkpy {
 
 struct BaseRef {
-    virtual PyVar get(VM*, Frame*) const = 0;
-    virtual void set(VM*, Frame*, PyVar) const = 0;
+    virtual PyObject* get(VM*, Frame*) const = 0;
+    virtual void set(VM*, Frame*, PyObject*) const = 0;
     virtual void del(VM*, Frame*) const = 0;
     virtual ~BaseRef() = default;
 };
@@ -18,8 +18,8 @@ struct NameRef : BaseRef {
     inline NameScope scope() const { return pair.second; }
     NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
 
-    PyVar get(VM* vm, Frame* frame) const{
-        PyVar* val;
+    PyObject* get(VM* vm, Frame* frame) const{
+        PyObject** val;
         val = frame->f_locals().try_get(name());
         if(val != nullptr) return *val;
         val = frame->f_closure_try_get(name());
@@ -32,12 +32,12 @@ struct NameRef : BaseRef {
         return nullptr;
     }
 
-    void set(VM* vm, Frame* frame, PyVar val) const{
+    void set(VM* vm, Frame* frame, PyObject* val) const{
         switch(scope()) {
-            case NAME_LOCAL: frame->f_locals().set(name(), std::move(val)); break;
+            case NAME_LOCAL: frame->f_locals().set(name(), val); break;
             case NAME_GLOBAL:
-                if(frame->f_locals().try_set(name(), std::move(val))) return;
-                frame->f_globals().set(name(), std::move(val));
+                if(frame->f_locals().try_set(name(), val)) return;
+                frame->f_globals().set(name(), val);
                 break;
             default: UNREACHABLE();
         }
@@ -70,15 +70,15 @@ struct NameRef : BaseRef {
 };
 
 struct AttrRef : BaseRef {
-    mutable PyVar obj;
+    mutable PyObject* obj;
     NameRef attr;
-    AttrRef(PyVar obj, NameRef attr) : obj(obj), attr(attr) {}
+    AttrRef(PyObject* obj, NameRef attr) : obj(obj), attr(attr) {}
 
-    PyVar get(VM* vm, Frame* frame) const{
+    PyObject* get(VM* vm, Frame* frame) const{
         return vm->getattr(obj, attr.name());
     }
 
-    void set(VM* vm, Frame* frame, PyVar val) const{
+    void set(VM* vm, Frame* frame, PyObject* val) const{
         vm->setattr(obj, attr.name(), std::move(val));
     }
 
@@ -90,22 +90,22 @@ struct AttrRef : BaseRef {
 };
 
 struct IndexRef : BaseRef {
-    mutable PyVar obj;
-    PyVar index;
-    IndexRef(PyVar obj, PyVar index) : obj(obj), index(index) {}
+    mutable PyObject* obj;
+    PyObject* index;
+    IndexRef(PyObject* obj, PyObject* index) : obj(obj), index(index) {}
 
-    PyVar get(VM* vm, Frame* frame) const{
-        return vm->fast_call(__getitem__, two_args(obj, index));
+    PyObject* get(VM* vm, Frame* frame) const{
+        return vm->fast_call(__getitem__, Args{obj, index});
     }
 
-    void set(VM* vm, Frame* frame, PyVar val) const{
+    void set(VM* vm, Frame* frame, PyObject* val) const{
         Args args(3);
         args[0] = obj; args[1] = index; args[2] = std::move(val);
         vm->fast_call(__setitem__, std::move(args));
     }
 
     void del(VM* vm, Frame* frame) const{
-        vm->fast_call(__delitem__, two_args(obj, index));
+        vm->fast_call(__delitem__, Args{obj, index});
     }
 };
 
@@ -113,7 +113,7 @@ struct TupleRef : BaseRef {
     Tuple objs;
     TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
 
-    PyVar get(VM* vm, Frame* frame) const{
+    PyObject* get(VM* vm, Frame* frame) const{
         Tuple args(objs.size());
         for (int i = 0; i < objs.size(); i++) {
             args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
@@ -121,11 +121,11 @@ struct TupleRef : BaseRef {
         return VAR(std::move(args));
     }
 
-    void set(VM* vm, Frame* frame, PyVar val) const{
+    void set(VM* vm, Frame* frame, PyObject* val) const{
         val = vm->asIter(val);
         BaseIter* iter = vm->PyIter_AS_C(val);
         for(int i=0; i<objs.size(); i++){
-            PyVarOrNull x;
+            PyObject* x;
             if(is_type(objs[i], vm->tp_star_wrapper)){
                 auto& star = _CAST(StarWrapper&, objs[i]);
                 if(star.rvalue) vm->ValueError("can't use starred expression here");
@@ -141,7 +141,7 @@ struct TupleRef : BaseRef {
                 vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
             }
         }
-        PyVarOrNull x = iter->next();
+        PyObject* x = iter->next();
         if(x != nullptr) vm->ValueError("too many values to unpack");
     }
 
@@ -152,19 +152,19 @@ struct TupleRef : BaseRef {
 
 
 template<typename P>
-PyVarRef VM::PyRef(P&& value) {
+PyObject* VM::PyRef(P&& value) {
     static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>);
-    return new_object(tp_ref, std::forward<P>(value));
+    return heap.gcnew<P>(tp_ref, std::forward<P>(value));
 }
 
-const BaseRef* VM::PyRef_AS_C(const PyVar& obj)
+const BaseRef* VM::PyRef_AS_C(PyObject* obj)
 {
     if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
     return static_cast<const BaseRef*>(obj->value());
 }
 
 /***** Frame's Impl *****/
-inline void Frame::try_deref(VM* vm, PyVar& v){
+inline void Frame::try_deref(VM* vm, PyObject*& v){
     if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
 }
 

+ 6 - 24
src/tuplelist.h

@@ -3,6 +3,7 @@
 #include "common.h"
 #include "memory.h"
 #include "str.h"
+#include <initializer_list>
 
 namespace pkpy {
     using List = std::vector<PyObject*>;
@@ -33,6 +34,11 @@ namespace pkpy {
             other._size = 0;
         }
 
+        Args(std::initializer_list<PyObject*> list) : Args(list.size()){
+            int i=0;
+            for(auto& p : list) _args[i++] = p;
+        }
+
         static pkpy::Args from_list(List&& other) noexcept {
             Args ret(other.size());
             memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size());
@@ -82,30 +88,6 @@ namespace pkpy {
         return _zero;
     }
 
-    template<typename T>
-    Args one_arg(T&& a) {
-        Args ret(1);
-        ret[0] = std::forward<T>(a);
-        return ret;
-    }
-
-    template<typename T1, typename T2>
-    Args two_args(T1&& a, T2&& b) {
-        Args ret(2);
-        ret[0] = std::forward<T1>(a);
-        ret[1] = std::forward<T2>(b);
-        return ret;
-    }
-
-    template<typename T1, typename T2, typename T3>
-    Args three_args(T1&& a, T2&& b, T3&& c) {
-        Args ret(3);
-        ret[0] = std::forward<T1>(a);
-        ret[1] = std::forward<T2>(b);
-        ret[2] = std::forward<T3>(c);
-        return ret;
-    }
-
     typedef Args Tuple;
     THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool;
 }   // namespace pkpy

+ 58 - 73
src/vm.h

@@ -1,7 +1,9 @@
 #pragma once
 
+#include "common.h"
 #include "frame.h"
 #include "error.h"
+#include "gc.h"
 
 namespace pkpy{
 
@@ -20,8 +22,8 @@ namespace pkpy{
     template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) {         \
         return OBJ_GET(ctype, obj);                                     \
     }                                                                   \
-    PyObject* py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);}     \
-    PyObject* py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));}
+    PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);}     \
+    PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));}
 
 class Generator: public BaseIter {
     std::unique_ptr<Frame> frame;
@@ -41,6 +43,7 @@ struct PyTypeInfo{
 
 class VM {
     VM* vm;     // self reference for simplify code
+    ManagedHeap heap;
 public:
     std::stack< std::unique_ptr<Frame> > callstack;
     std::vector<PyTypeInfo> _all_types;
@@ -78,11 +81,10 @@ public:
         }
 
         init_builtin_types();
-        // for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
     }
 
     PyObject* asStr(PyObject* obj){
-        PyVarOrNull f = getattr(obj, __str__, false, true);
+        PyObject* f = getattr(obj, __str__, false, true);
         if(f != nullptr) return call(f);
         return asRepr(obj);
     }
@@ -95,8 +97,8 @@ public:
     }
 
     PyObject* asIter(PyObject* obj){
-        if(is_type(obj, tp_native_iterator)) return obj;
-        PyVarOrNull iter_f = getattr(obj, __iter__, false, true);
+        if(is_type(obj, tp_iterator)) return obj;
+        PyObject* iter_f = getattr(obj, __iter__, false, true);
         if(iter_f != nullptr) return call(iter_f);
         TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
         return nullptr;
@@ -104,7 +106,7 @@ public:
 
     PyObject* asList(PyObject* iterable){
         if(is_type(iterable, tp_list)) return iterable;
-        return call(_t(tp_list), one_arg(iterable));
+        return call(_t(tp_list), Args{iterable});
     }
 
     PyObject** find_name_in_mro(PyObject* cls, StrName name){
@@ -191,13 +193,13 @@ public:
 
     PyObject* property(NativeFuncRaw fget){
         PyObject* p = builtins->attr("property");
-        PyObject* method = new_object(tp_native_function, NativeFunc(fget, 1, false));
-        return call(p, one_arg(method));
+        PyObject* method = heap.gcnew(tp_native_function, NativeFunc(fget, 1, false));
+        return call(p, Args{method});
     }
 
     PyObject* new_type_object(PyObject* mod, StrName name, Type base){
         // use gcnew
-        PyObject* obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
+        PyObject* obj = new Py_<Type>(tp_type, _all_types.size());
         PyTypeInfo info{
             .obj = obj,
             .base = base,
@@ -213,30 +215,6 @@ public:
         return OBJ_GET(Type, obj);
     }
 
-    template<typename T>
-    inline PyObject* new_object(PyObject* type, const T& _value) {
-#if PK_EXTRA_CHECK
-        if(!is_type(type, tp_type)) UNREACHABLE();
-#endif
-        return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
-    }
-    template<typename T>
-    inline PyObject* new_object(PyObject* type, T&& _value) {
-#if PK_EXTRA_CHECK
-        if(!is_type(type, tp_type)) UNREACHABLE();
-#endif
-        return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), std::move(_value));
-    }
-
-    template<typename T>
-    inline PyObject* new_object(Type type, const T& _value) {
-        return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value);
-    }
-    template<typename T>
-    inline PyObject* new_object(Type type, T&& _value) {
-        return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value));
-    }
-
     PyObject* _find_type(const Str& type){
         PyObject** obj = builtins->attr().try_get(type);
         if(!obj){
@@ -282,19 +260,19 @@ public:
     // for quick access
     Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str;
     Type tp_list, tp_tuple;
-    Type tp_function, tp_native_function, tp_native_iterator, tp_bound_method;
+    Type tp_function, tp_native_function, tp_iterator, tp_bound_method;
     Type tp_slice, tp_range, tp_module, tp_ref;
     Type tp_super, tp_exception, tp_star_wrapper;
 
     template<typename P>
     inline PyObject* PyIter(P&& value) {
         static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>);
-        return new_object(tp_native_iterator, std::forward<P>(value));
+        return heap.gcnew<P>(tp_iterator, std::forward<P>(value));
     }
 
     inline BaseIter* PyIter_AS_C(PyObject* obj)
     {
-        check_type(obj, tp_native_iterator);
+        check_type(obj, tp_iterator);
         return static_cast<BaseIter*>(obj->value());
     }
     
@@ -369,7 +347,7 @@ public:
     PyObject* _exec();
 
     template<typename P>
-    PyVarRef PyRef(P&& value);
+    PyObject* PyRef(P&& value);
     const BaseRef* PyRef_AS_C(PyObject* obj);
 };
 
@@ -458,23 +436,23 @@ template<> float py_cast<float>(VM* vm, PyObject* obj){
     vm->check_type(obj, vm->tp_float);
     i64 bits = obj.bits;
     bits = (bits >> 2) << 2;
-    return __8B(bits)._float;
+    return BitsCvt(bits)._float;
 }
 template<> float _py_cast<float>(VM* vm, PyObject* obj){
     i64 bits = obj.bits;
     bits = (bits >> 2) << 2;
-    return __8B(bits)._float;
+    return BitsCvt(bits)._float;
 }
 template<> double py_cast<double>(VM* vm, PyObject* obj){
     vm->check_type(obj, vm->tp_float);
     i64 bits = obj.bits;
     bits = (bits >> 2) << 2;
-    return __8B(bits)._float;
+    return BitsCvt(bits)._float;
 }
 template<> double _py_cast<double>(VM* vm, PyObject* obj){
     i64 bits = obj.bits;
     bits = (bits >> 2) << 2;
-    return __8B(bits)._float;
+    return BitsCvt(bits)._float;
 }
 
 
@@ -502,7 +480,7 @@ PY_VAR_INT(unsigned long long)
 #define PY_VAR_FLOAT(T)                             \
     PyObject* py_var(VM* vm, T _val){               \
         f64 val = static_cast<f64>(_val);           \
-        i64 bits = __8B(val)._int;                  \
+        i64 bits = BitsCvt(val)._int;                  \
         bits = (bits >> 2) << 2;                    \
         bits |= 0b10;                               \
         return reinterpret_cast<PyObject*>(bits);   \
@@ -561,7 +539,7 @@ PyObject* VM::asBool(PyObject* obj){
     if(obj == None) return False;
     if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0);
     if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0);
-    PyVarOrNull len_fn = getattr(obj, __len__, false, true);
+    PyObject* len_fn = getattr(obj, __len__, false, true);
     if(len_fn != nullptr){
         PyObject* ret = call(len_fn);
         return VAR(CAST(i64, ret) > 0);
@@ -596,8 +574,11 @@ PyObject* VM::asRepr(PyObject* obj){
 }
 
 PyObject* VM::new_module(StrName name) {
-    PyObject* obj = new_object(tp_module, DummyModule());
+    PyObject* obj = new Py_<DummyModule>(tp_module, DummyModule());
     obj->attr().set(__name__, VAR(name.str()));
+    // we do not allow override in order to avoid memory leak
+    // it is because Module objects are not garbage collected
+    if(_modules.contains(name)) UNREACHABLE();
     _modules.set(name, obj);
     return obj;
 }
@@ -672,9 +653,11 @@ Str VM::disassemble(CodeObject_ co){
 }
 
 void VM::init_builtin_types(){
-    // Py_(Type type, T&& val)
-    PyVar _tp_object = make_sp<PyObject, Py_<Type>>(Type(1), Type(0));
-    PyVar _tp_type = make_sp<PyObject, Py_<Type>>(Type(1), Type(1));
+    PyObject* _tp_object = new Py_<Type>(Type(1), Type(0));
+    PyObject* _tp_type = new Py_<Type>(Type(1), Type(1));
+    // PyTypeObject is managed by _all_types
+    // PyModuleObject is managed by _modules
+    // They are not managed by GC, so we use a simple "new"
     _all_types.push_back({.obj = _tp_object, .base = -1, .name = "object"});
     _all_types.push_back({.obj = _tp_type, .base = 0, .name = "type"});
     tp_object = 0; tp_type = 1;
@@ -695,17 +678,17 @@ void VM::init_builtin_types(){
     
     tp_function = _new_type_object("function");
     tp_native_function = _new_type_object("native_function");
-    tp_native_iterator = _new_type_object("native_iterator");
+    tp_iterator = _new_type_object("iterator");
     tp_bound_method = _new_type_object("bound_method");
     tp_super = _new_type_object("super");
     tp_exception = _new_type_object("Exception");
 
-    this->None = new_object(_new_type_object("NoneType"), DUMMY_VAL);
-    this->Ellipsis = new_object(_new_type_object("ellipsis"), DUMMY_VAL);
-    this->True = new_object(tp_bool, true);
-    this->False = new_object(tp_bool, false);
-    this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL);
-    this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL);
+    this->None = new Py_<Dummy>(_new_type_object("NoneType"), {});
+    this->Ellipsis = new Py_<Dummy>(_new_type_object("ellipsis"), {});
+    this->True = new Py_<Dummy>(tp_bool, {});
+    this->False = new Py_<Dummy>(tp_bool, {});
+    this->_py_op_call = new Py_<Dummy>(_new_type_object("_py_op_call"), {});
+    this->_py_op_yield = new Py_<Dummy>(_new_type_object("_py_op_yield"), {});
     this->builtins = new_module("builtins");
     this->_main = new_module("__main__");
     
@@ -735,8 +718,8 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal
         if(new_f != nullptr){
             obj = call(*new_f, std::move(args), kwargs, false);
         }else{
-            obj = new_object(_callable, DummyInstance());
-            PyVarOrNull init_f = getattr(obj, __init__, false, true);
+            obj = heap.gcnew<DummyInstance>(_callable, {});
+            PyObject* init_f = getattr(obj, __init__, false, true);
             if (init_f != nullptr) call(init_f, std::move(args), kwargs, false);
         }
         return obj;
@@ -801,7 +784,7 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal
         return _exec();
     }
 
-    PyVarOrNull call_f = getattr(_callable, __call__, false, true);
+    PyObject* call_f = getattr(_callable, __call__, false, true);
     if(call_f != nullptr){
         return call(call_f, std::move(args), kwargs, false);
     }
@@ -829,42 +812,44 @@ using Super = std::pair<PyObject*, Type>;
 
 // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
 PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){
-    PyObject* objtype = _t(*obj).get();
-    if(is_type(*obj, tp_super)){
-        const Super& super = OBJ_GET(Super, *obj);
-        obj = &super.first;
-        objtype = _t(super.second).get();
+    PyObject* objtype = _t(obj);
+    // handle super() proxy
+    if(is_type(obj, tp_super)){
+        const Super& super = OBJ_GET(Super, obj);
+        obj = super.first;
+        objtype = _t(super.second);
     }
     PyObject** cls_var = find_name_in_mro(objtype, name);
     if(cls_var != nullptr){
         // handle descriptor
         PyObject** descr_get = _t(*cls_var)->attr().try_get(__get__);
-        if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj));
+        if(descr_get != nullptr) return call(*descr_get, Args{*cls_var, obj});
     }
     // handle instance __dict__
-    if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){
-        PyObject** val = (*obj)->attr().try_get(name);
+    if(!class_only && !is_tagged(obj) && obj->is_attr_valid()){
+        PyObject** val = obj->attr().try_get(name);
         if(val != nullptr) return *val;
     }
     if(cls_var != nullptr){
         // bound method is non-data descriptor
         if(is_type(*cls_var, tp_function) || is_type(*cls_var, tp_native_function)){
-            return VAR(BoundMethod(*obj, *cls_var));
+            return VAR(BoundMethod(obj, *cls_var));
         }
         return *cls_var;
     }
-    if(throw_err) AttributeError(*obj, name);
+    if(throw_err) AttributeError(obj, name);
     return nullptr;
 }
 
 template<typename T>
 void VM::setattr(PyObject* obj, StrName name, T&& value){
-    static_assert(std::is_same_v<std::decay_t<T>, PyVar>);
-    PyObject* objtype = _t(obj).get();
+    static_assert(std::is_same_v<std::decay_t<T>, PyObject*>);
+    PyObject* objtype = _t(obj);
+    // handle super() proxy
     if(is_type(obj, tp_super)){
         Super& super = OBJ_GET(Super, *obj);
         obj = super.first;
-        objtype = _t(super.second).get();
+        objtype = _t(super.second);
     }
     PyObject** cls_var = find_name_in_mro(objtype, name);
     if(cls_var != nullptr){
@@ -873,7 +858,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){
         if(cls_var_t->attr().contains(__get__)){
             PyObject** descr_set = cls_var_t->attr().try_get(__set__);
             if(descr_set != nullptr){
-                call(*descr_set, three_args(*cls_var, obj, std::forward<T>(value)));
+                call(*descr_set, Args{*cls_var, obj, std::forward<T>(value)});
             }else{
                 TypeError("readonly attribute: " + name.str().escape(true));
             }
@@ -881,7 +866,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){
         }
     }
     // handle instance __dict__
-    if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute");
+    if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute");
     obj->attr().set(name, std::forward<T>(value));
 }