diff --git a/python/_dict.py b/python/_dict.py index 2a3b8137..24adfc9b 100644 --- a/python/_dict.py +++ b/python/_dict.py @@ -1,8 +1,12 @@ class dict: - def __init__(self, capacity=13): - self._capacity = capacity + def __init__(self, mapping=None): + self._capacity = 16 self._a = [None] * self._capacity self._len = 0 + + if mapping is not None: + for k,v in mapping: + self[k] = v def __len__(self): return self._len diff --git a/src/ceval.h b/src/ceval.h index 51033f99..b4893812 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -186,11 +186,14 @@ inline PyObject* VM::run_frame(Frame* frame){ frame->push(VAR(frame->pop_n_values_reversed(this, byte.arg).to_list())); continue; case OP_BUILD_MAP: { - Args items = frame->pop_n_values_reversed(this, byte.arg*2); - PyObject* obj = call(builtins->attr("dict"), no_arg()); - for(int i=0; ipop_value(this); + PyObject* key = frame->pop_value(this); + list[i] = VAR(Tuple({key, value})); } + PyObject* d_arg = VAR(std::move(list)); + PyObject* obj = call(builtins->attr("dict"), Args{d_arg}); frame->push(obj); } continue; case OP_BUILD_SET: { diff --git a/src/gc.h b/src/gc.h index a897ff8f..b4e0643f 100644 --- a/src/gc.h +++ b/src/gc.h @@ -1,59 +1,78 @@ #pragma once +#include "common.h" #include "obj.h" #include "codeobject.h" #include "namedict.h" namespace pkpy { struct ManagedHeap{ + std::vector _no_gc; std::vector gen; - int counter = 0; + + int gc_threshold = 700; + int gc_counter = 0; template PyObject* gcnew(Type type, T&& val){ PyObject* obj = new Py_>(type, std::forward(val)); gen.push_back(obj); - counter++; + gc_counter++; return obj; } template PyObject* _new(Type type, T&& val){ - return gcnew(type, std::forward(val)); + PyObject* obj = new Py_>(type, std::forward(val)); + obj->gc.enabled = false; + _no_gc.push_back(obj); + return obj; } - int sweep(){ + ~ManagedHeap(){ + for(PyObject* obj: _no_gc) delete obj; + } + + int sweep(VM* vm){ std::vector alive; for(PyObject* obj: gen){ if(obj->gc.marked){ obj->gc.marked = false; alive.push_back(obj); }else{ + // _delete_hook(vm, obj); delete obj; } } + + // clear _no_gc marked flag + for(PyObject* obj: _no_gc) obj->gc.marked = false; + int freed = gen.size() - alive.size(); gen.clear(); gen.swap(alive); return freed; } + void _delete_hook(VM* vm, PyObject* obj); + void _auto_collect(VM* vm){ - if(counter > 1000){ - counter = 0; - collect(vm); - } + if(gc_counter < gc_threshold) return; + gc_counter = 0; + collect(vm); + gc_threshold = gen.size() * 2; } int collect(VM* vm){ mark(vm); - return sweep(); + int freed = sweep(vm); + // std::cout << "GC: " << freed << " objects freed" << std::endl; + return freed; } void mark(VM* vm); }; - inline void NameDict::_mark(){ for(uint16_t i=0; i<_capacity; i++){ if(_items[i].first.empty()) continue; diff --git a/src/iter.h b/src/iter.h index 464b48de..f8ecdb5c 100644 --- a/src/iter.h +++ b/src/iter.h @@ -72,7 +72,7 @@ inline void BaseIter::_mark() { inline void Generator::_mark(){ BaseIter::_mark(); - frame->_mark(); + if(frame!=nullptr) frame->_mark(); } template diff --git a/src/obj.h b/src/obj.h index b65e3215..c7c38a90 100644 --- a/src/obj.h +++ b/src/obj.h @@ -91,8 +91,9 @@ public: }; struct GCHeader { + bool enabled; // whether this object is managed by GC bool marked; // whether this object is marked - GCHeader() : marked(false) {} + GCHeader() : enabled(true), marked(false) {} }; struct PyObject { @@ -135,7 +136,6 @@ struct Py_ : PyObject { void _mark() override { if(gc.marked) return; - // std::cout << "marking " << type << std::endl; gc.marked = true; if(_attr != nullptr) _attr->_mark(); pkpy::_mark(_value); // handle PyObject* inside _value `T` diff --git a/src/pocketpy.h b/src/pocketpy.h index 78442bab..bc6a8109 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -88,8 +88,7 @@ inline void init_builtins(VM* _vm) { i64 lhs = CAST(i64, args[0]); i64 rhs = CAST(i64, args[1]); if(rhs == 0) vm->ZeroDivisionError(); - Tuple t = Tuple{VAR(lhs/rhs), VAR(lhs%rhs)}; - return VAR(std::move(t)); + return VAR(Tuple({VAR(lhs/rhs), VAR(lhs%rhs)})); }); _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) { @@ -146,7 +145,7 @@ inline void init_builtins(VM* _vm) { }); _vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) { - std::stringstream ss; + StrStream ss; ss << std::hex << CAST(i64, args[0]); return VAR("0x" + ss.str()); }); @@ -649,8 +648,7 @@ struct ReMatch { vm->bind_method<0>(type, "span", [](VM* vm, Args& args) { auto& self = CAST(ReMatch&, args[0]); - Tuple t = Tuple{VAR(self.start), VAR(self.end)}; - return VAR(std::move(t)); + return VAR(Tuple({VAR(self.start), VAR(self.end)})); }); vm->bind_method<1>(type, "group", [](VM* vm, Args& args) { diff --git a/src/vm.h b/src/vm.h index a49ea8e2..bfb73a8f 100644 --- a/src/vm.h +++ b/src/vm.h @@ -881,15 +881,14 @@ inline void VM::_error(Exception e){ inline PyObject* VM::_exec(){ Frame* frame = top_frame(); - i64 base_id = frame->id; - PyObject* ret = nullptr; + const i64 base_id = frame->id; bool need_raise = false; while(true){ if(frame->id < base_id) UNREACHABLE(); try{ if(need_raise){ need_raise = false; _raise(); } - ret = run_frame(frame); + PyObject* ret = run_frame(frame); if(ret == _py_op_yield) return _py_op_yield; if(ret != _py_op_call){ if(frame->id == base_id){ // [ frameBase<- ] @@ -922,11 +921,15 @@ inline PyObject* VM::_exec(){ } inline void ManagedHeap::mark(VM *vm) { - vm->_modules._mark(); - for(auto& t: vm->_all_types) t.obj->_mark(); + for(PyObject* obj: _no_gc) OBJ_MARK(obj); for(auto& frame : vm->callstack.data()){ frame->_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; +} + } // namespace pkpy \ No newline at end of file diff --git a/tests/07_dict.py b/tests/07_dict.py index 9c3826fc..50f21cff 100644 --- a/tests/07_dict.py +++ b/tests/07_dict.py @@ -42,4 +42,7 @@ d1 = {1:2, 3:4} d2 = {3:4, 1:2} d3 = {1:2, 3:4, 5:6} assert d1 == d2 -assert d1 != d3 \ No newline at end of file +assert d1 != d3 + +a = dict([(1, 2), (3, 4)]) +assert a == {1: 2, 3: 4} \ No newline at end of file diff --git a/tests/80_json.py b/tests/80_json.py index b285faed..6a589c32 100644 --- a/tests/80_json.py +++ b/tests/80_json.py @@ -3,12 +3,12 @@ a = { 'b': 2, 'c': None, 'd': [1, 2, 3], - # 'e': { - # 'a': 1, - # 'b': 2, - # 'c': None, - # 'd': [1, 2, 3], - # }, + 'e': { + 'a': 1, + 'b': 2, + 'c': None, + 'd': [1, 2, 3], + }, "f": 'This is a string', 'g': [True, False, None], 'h': False