diff --git a/src/ceval.h b/src/ceval.h index d50cf46b..6893f83d 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -15,7 +15,7 @@ __NEXT_STEP:; * For example, frame->popx() returns a strong reference which may be dangerous * `Args` containing strong references is safe if it is passed to `call` or `fast_call` */ -#if !DEBUG_NO_GC +#if !DEBUG_NO_AUTO_GC heap._auto_collect(this); #endif diff --git a/src/common.h b/src/common.h index 771f79d8..a14023c1 100644 --- a/src/common.h +++ b/src/common.h @@ -33,11 +33,12 @@ // debug macros #define DEBUG_NO_BUILTIN_MODULES 0 #define DEBUG_EXTRA_CHECK 0 -#define DEBUG_DIS_EXEC 0 +#define DEBUG_DIS_EXEC 1 #define DEBUG_DIS_EXEC_MIN 1 #define DEBUG_CEVAL_STEP 0 #define DEBUG_FULL_EXCEPTION 0 -#define DEBUG_NO_GC 0 +#define DEBUG_NO_AUTO_GC 1 +#define DEBUG_GC_STATS 0 #if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__) #define PK_ENABLE_FILEIO 0 diff --git a/src/compiler.h b/src/compiler.h index e18db025..37ed7c59 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -726,7 +726,6 @@ __SUBSCR_END: /*************************************************/ case TK("assert"): EXPR_TUPLE(false); - // TODO: change OP_ASSERT impl in ceval.h ctx()->emit(OP_ASSERT, BC_NOARG, kw_line); consume_end_stmt(); break; @@ -860,7 +859,6 @@ __SUBSCR_END: } void compile_function(const std::vector& decorators={}){ - // TODO: bug, if there are multiple decorators, will cause error FuncDecl_ decl = make_sp(); StrName obj_name; consume(TK("@id")); diff --git a/src/expr.h b/src/expr.h index e8ccced3..58ba7cb9 100644 --- a/src/expr.h +++ b/src/expr.h @@ -632,6 +632,8 @@ struct CallExpr: Expr{ void emit(CodeEmitContext* ctx) override { VM* vm = ctx->vm; + // TODO: if callable is a AttrExpr, we should try to use `fast_call` + // instead of use `boundmethod` proxy callable->emit(ctx); // emit args for(auto& item: args) item->emit(ctx); diff --git a/src/gc.h b/src/gc.h index 311f6b5f..dbb22d23 100644 --- a/src/gc.h +++ b/src/gc.h @@ -5,45 +5,15 @@ #include "codeobject.h" #include "namedict.h" -/* -0: object -1: type -2: int -3: float -4: bool -5: str -6: list -7: tuple -8: slice -9: range -10: module -11: _ref -12: _star_wrapper -13: function -14: native_function -15: iterator -16: bound_method -17: super -18: Exception -19: NoneType -20: ellipsis -21: _py_op_call -22: _py_op_yield -23: re.Match -24: random.Random -25: io.FileIO -26: property -27: staticmethod -28: dict -29: set -*/ - namespace pkpy { struct ManagedHeap{ std::vector _no_gc; std::vector gen; + VM* vm; + + ManagedHeap(VM* vm): vm(vm) {} - static const int kMinGCThreshold = 700; + static const int kMinGCThreshold = 4096; int gc_threshold = kMinGCThreshold; int gc_counter = 0; @@ -84,19 +54,20 @@ struct ManagedHeap{ ~ManagedHeap(){ for(PyObject* obj: _no_gc) delete obj; - // for(auto& [type, count]: deleted){ - // std::cout << "GC: " << type << "=" << count << std::endl; - // } +#if DEBUG_GC_STATS + for(auto& [type, count]: deleted){ + std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl; + } +#endif } - int sweep(VM* vm){ + int sweep(){ std::vector alive; for(PyObject* obj: gen){ if(obj->gc.marked){ obj->gc.marked = false; alive.push_back(obj); }else{ - // _delete_hook(vm, obj); deleted[obj->type] += 1; delete obj; } @@ -112,25 +83,23 @@ struct ManagedHeap{ return freed; } - void _delete_hook(VM* vm, PyObject* obj); - - void _auto_collect(VM* vm){ + void _auto_collect(){ if(_gc_lock_counter > 0) return; if(gc_counter < gc_threshold) return; gc_counter = 0; - collect(vm); + collect(); gc_threshold = gen.size() * 2; if(gc_threshold < kMinGCThreshold) gc_threshold = kMinGCThreshold; } - int collect(VM* vm){ + int collect(){ if(_gc_lock_counter > 0) UNREACHABLE(); - mark(vm); - int freed = sweep(vm); + mark(); + int freed = sweep(); return freed; } - void mark(VM* vm); + void mark(); }; inline void NameDict::_gc_mark() const{ diff --git a/src/obj.h b/src/obj.h index 2362bf95..d5cbca40 100644 --- a/src/obj.h +++ b/src/obj.h @@ -149,6 +149,8 @@ struct Py_ : PyObject { #define OBJ_GET(T, obj) (((Py_*)(obj))->_value) #define OBJ_MARK(obj) if(!is_tagged(obj)) obj->_obj_gc_mark() +Str obj_type_name(VM* vm, Type type); + #if DEBUG_NO_BUILTIN_MODULES #define OBJ_NAME(obj) Str("") #else diff --git a/src/pocketpy.h b/src/pocketpy.h index b67257b5..2b125f56 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -756,7 +756,7 @@ inline void add_module_random(VM* vm){ inline void add_module_gc(VM* vm){ PyObject* mod = vm->new_module("gc"); - vm->bind_func<0>(mod, "collect", CPP_LAMBDA(VAR(vm->heap.collect(vm)))); + vm->bind_func<0>(mod, "collect", CPP_LAMBDA(VAR(vm->heap.collect()))); } inline void VM::post_init(){ diff --git a/src/vm.h b/src/vm.h index bd946aea..b28cd20a 100644 --- a/src/vm.h +++ b/src/vm.h @@ -4,6 +4,7 @@ #include "frame.h" #include "error.h" #include "gc.h" +#include "obj.h" namespace pkpy{ @@ -75,10 +76,10 @@ public: 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_iterator, tp_bound_method; - Type tp_slice, tp_range, tp_module, tp_ref; + Type tp_slice, tp_range, tp_module; Type tp_super, tp_exception, tp_star_wrapper; - VM(bool use_stdio){ + VM(bool use_stdio) : heap(this){ this->vm = this; this->use_stdio = use_stdio; if(use_stdio){ @@ -317,7 +318,7 @@ public: } ~VM() { - heap.collect(this); + heap.collect(); if(!use_stdio){ delete _stdout; delete _stderr; @@ -344,8 +345,6 @@ public: void bind_func(PyObject*, Str, NativeFuncRaw); void _error(Exception); PyObject* _exec(); - template PyObject* PyRef(P&&); - const BaseRef* PyRef_AS_C(PyObject* obj); void post_init(); }; @@ -652,7 +651,6 @@ inline void VM::init_builtin_types(){ tp_slice = _new_type_object("slice"); tp_range = _new_type_object("range"); tp_module = _new_type_object("module"); - tp_ref = _new_type_object("_ref"); tp_star_wrapper = _new_type_object("_star_wrapper"); tp_function = _new_type_object("function"); tp_native_function = _new_type_object("native_function"); @@ -690,7 +688,7 @@ inline void VM::init_builtin_types(){ for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash(); } -// TODO: args here may be garbage collected accidentally +// TODO: callable/args here may be garbage collected accidentally inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCall){ if(is_type(callable, tp_type)){ PyObject* new_f = callable->attr().try_get(__new__); @@ -907,14 +905,13 @@ inline PyObject* VM::_exec(){ } } -inline void ManagedHeap::mark(VM *vm) { +inline void ManagedHeap::mark() { for(PyObject* obj: _no_gc) OBJ_MARK(obj); for(auto& frame : vm->callstack.data()) frame->_gc_mark(); } -inline void ManagedHeap::_delete_hook(VM *vm, PyObject *obj){ - Type t = OBJ_GET(Type, vm->_t(obj)); - std::cout << "delete " << vm->_all_types[t].name << " at " << obj << std::endl; +inline Str obj_type_name(VM *vm, Type type){ + return vm->_all_types[type].name; } } // namespace pkpy \ No newline at end of file