diff --git a/src/ceval.h b/src/ceval.h index 60557718..a6c266c8 100644 --- a/src/ceval.h +++ b/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; inext(); + 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: { diff --git a/src/compiler.h b/src/compiler.h index 81a453af..4f214360 100644 --- a/src/compiler.h +++ b/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 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(); + e->a = ctx()->s_expr.popx(); std::vector 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()); diff --git a/src/expr.h b/src/expr.h index 21df0215..da0bc366 100644 --- a/src/expr.h +++ b/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 ""; } - + LambdaExpr(NameScope scope){ this->decl = make_sp(); this->decl->name = ""; diff --git a/src/gc.h b/src/gc.h index 89286c5d..f0619150 100644 --- a/src/gc.h +++ b/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 PyObject* gcnew(Type type, T&& val){ PyObject* obj = new Py_>(type, std::forward(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;