blueloveTH преди 2 години
родител
ревизия
6a9d220433
променени са 9 файла, в които са добавени 66 реда и са изтрити 36 реда
  1. 6 2
      python/_dict.py
  2. 7 4
      src/ceval.h
  3. 29 10
      src/gc.h
  4. 1 1
      src/iter.h
  5. 2 2
      src/obj.h
  6. 3 5
      src/pocketpy.h
  7. 8 5
      src/vm.h
  8. 4 1
      tests/07_dict.py
  9. 6 6
      tests/80_json.py

+ 6 - 2
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

+ 7 - 4
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; i<items.size(); i+=2){
-                call(obj, __setitem__, Args{items[i], items[i+1]});
+            List list(byte.arg);
+            for(int i=0; i<byte.arg; i++){
+                PyObject* value = frame->pop_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: {

+ 29 - 10
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<PyObject*> _no_gc;
     std::vector<PyObject*> gen;
-    int counter = 0;
+    
+    int gc_threshold = 700;
+    int gc_counter = 0;
 
     template<typename T>
     PyObject* gcnew(Type type, T&& val){
         PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
         gen.push_back(obj);
-        counter++;
+        gc_counter++;
         return obj;
     }
 
     template<typename T>
     PyObject* _new(Type type, T&& val){
-        return gcnew<T>(type, std::forward<T>(val));
+        PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(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<PyObject*> 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;

+ 1 - 1
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<typename T>

+ 2 - 2
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<T>(_value);   // handle PyObject* inside _value `T`

+ 3 - 5
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) {

+ 8 - 5
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

+ 4 - 1
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
+assert d1 != d3
+
+a = dict([(1, 2), (3, 4)])
+assert a == {1: 2, 3: 4}

+ 6 - 6
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