blueloveTH 2 лет назад
Родитель
Сommit
66e6a6b559
4 измененных файлов с 53 добавлено и 5 удалено
  1. 14 0
      src/ceval.h
  2. 6 1
      src/compiler.h
  3. 14 4
      src/expr.h
  4. 19 0
      src/gc.h

+ 14 - 0
src/ceval.h

@@ -309,6 +309,20 @@ __NEXT_STEP:;
         }
     }; DISPATCH();
     /*****************************************/
+    case OP_UNPACK_SEQUENCE: {
+        // asIter or iter->next may run bytecode
+        // accidential gc may happen
+        // lock the gc via RAII
+        auto _lock = heap.gc_scope_lock();
+        PyObject* obj = asIter(frame->popx());
+        BaseIter* iter = PyIter_AS_C(obj);
+        for(int i=0; i<byte.arg; i++){
+            PyObject* item = iter->next();
+            if(item == nullptr) ValueError("not enough values to unpack");
+            frame->push(item);
+        }
+        if(iter->next() != nullptr) ValueError("too many values to unpack");
+    }; DISPATCH();
     /*****************************************/
     // case OP_SETUP_DECORATOR: DISPATCH();
     // case OP_BEGIN_CLASS: {

+ 6 - 1
src/compiler.h

@@ -40,7 +40,9 @@ class Compiler {
     }
 
     void pop_context(){
-        if(!ctx()->s_expr.empty()) UNREACHABLE();
+        if(!ctx()->s_expr.empty()){
+            throw std::runtime_error("!ctx()->s_expr.empty()\n" + ctx()->_log_s_expr());
+        }
         // if the last op does not return, add a default return None
         if(ctx()->co->codes.empty() || ctx()->co->codes.back().op != OP_RETURN_VALUE){
             ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
@@ -184,6 +186,7 @@ class Compiler {
     // PASS
     void exprTuple(){
         std::vector<Expr_> items;
+        items.push_back(ctx()->s_expr.popx());
         do {
             EXPR();         // NOTE: "1," will fail, "1,2" will be ok
             items.push_back(ctx()->s_expr.popx());
@@ -385,6 +388,7 @@ class Compiler {
     // PASS
     void exprSubscr() {
         auto e = make_expr<SubscrExpr>();
+        e->a = ctx()->s_expr.popx();
         std::vector<Expr_> items;
         do {
             EXPR_TUPLE();
@@ -605,6 +609,7 @@ class Compiler {
                 break;
             default: return false;
         }
+        std::cout << ctx()->_log_s_expr() << std::endl;
         Expr_ rhs = ctx()->s_expr.popx();
         rhs->emit(ctx());
         bool ok = lhs_p->emit_store(ctx());

+ 14 - 4
src/expr.h

@@ -5,6 +5,7 @@
 #include "lexer.h"
 #include "error.h"
 #include "ceval.h"
+#include "str.h"
 
 namespace pkpy{
 
@@ -55,11 +56,19 @@ struct CodeEmitContext{
 
     // clear the expression stack and generate bytecode
     void emit_expr(){
-        if(s_expr.size() != 1) UNREACHABLE();
+        if(s_expr.size() != 1){
+            throw std::runtime_error("s_expr.size() != 1\n" + _log_s_expr());
+        }
         Expr_ expr = s_expr.popx();
         expr->emit(this);
     }
 
+    Str _log_s_expr(){
+        StrStream ss;
+        for(auto& e: s_expr.data()) ss << e->str() << " ";
+        return ss.str();
+    }
+
     int emit(Opcode opcode, int arg, int line) {
         co->codes.push_back(
             Bytecode{(uint16_t)opcode, (uint16_t)curr_block_i, arg, line}
@@ -411,8 +420,9 @@ struct TupleExpr: SequenceExpr{
             if(starred_i != items.size()-1) return false;
             ctx->emit(OP_UNPACK_EX, items.size()-1, line);
         }
-        for(auto& e: items){
-            bool ok = e->emit_store(ctx);
+        // do reverse emit
+        for(int i=items.size()-1; i>=0; i--){
+            bool ok = items[i]->emit_store(ctx);
             if(!ok) return false;
         }
         return true;
@@ -480,7 +490,7 @@ struct LambdaExpr: Expr{
     FuncDecl_ decl;
     NameScope scope;
     Str str() const override { return "<lambda>"; }
-    
+
     LambdaExpr(NameScope scope){
         this->decl = make_sp<FuncDecl>();
         this->decl->name = "<lambda>";

+ 19 - 0
src/gc.h

@@ -47,6 +47,23 @@ struct ManagedHeap{
     int gc_threshold = kMinGCThreshold;
     int gc_counter = 0;
 
+    /********************/
+    int _gc_lock_counter = 0;
+    struct ScopeLock{
+        ManagedHeap* heap;
+        ScopeLock(ManagedHeap* heap): heap(heap){
+            heap->_gc_lock_counter++;
+        }
+        ~ScopeLock(){
+            heap->_gc_lock_counter--;
+        }
+    };
+
+    ScopeLock gc_scope_lock(){
+        return ScopeLock(this);
+    }
+    /********************/
+
     template<typename T>
     PyObject* gcnew(Type type, T&& val){
         PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
@@ -98,6 +115,7 @@ struct ManagedHeap{
     void _delete_hook(VM* vm, PyObject* obj);
 
     void _auto_collect(VM* vm){
+        if(_gc_lock_counter > 0) return;
         if(gc_counter < gc_threshold) return;
         gc_counter = 0;
         collect(vm);
@@ -106,6 +124,7 @@ struct ManagedHeap{
     }
 
     int collect(VM* vm){
+        if(_gc_lock_counter > 0) UNREACHABLE();
         mark(vm);
         int freed = sweep(vm);
         return freed;