diff --git a/src/ceval.h b/src/ceval.h index b14877ea..289a86a8 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -145,7 +145,9 @@ __NEXT_STEP:; PUSH(self); } DISPATCH(); TARGET(LOAD_SUBSCR) { - TOP() = fast_call_method(SECOND(), __getitem__, 2); + PyObject* b = POPX(); + PyObject* a = TOP(); + TOP() = call_method(a, __getitem__, b); } DISPATCH(); TARGET(STORE_FAST) frame->_locals[byte.arg] = POPX(); @@ -171,12 +173,13 @@ __NEXT_STEP:; setattr(a, name, val); STACK_SHRINK(2); } DISPATCH(); - TARGET(STORE_SUBSCR) - // val a b -> a b val - std::swap(SECOND(), THIRD()); - std::swap(TOP(), SECOND()); - fast_call_method(THIRD(), __setitem__, 3); - DISPATCH(); + TARGET(STORE_SUBSCR) { + // val a b + PyObject* b = POPX(); + PyObject* a = POPX(); + PyObject* val = POPX(); + call_method(a, __setitem__, b, val); + } DISPATCH(); TARGET(DELETE_FAST) { PyObject* val = frame->_locals[byte.arg]; if(val == nullptr) vm->NameError(co->varnames[byte.arg]); @@ -207,9 +210,11 @@ __NEXT_STEP:; if(!a->attr().contains(name)) AttributeError(a, name); a->attr().erase(name); } DISPATCH(); - TARGET(DELETE_SUBSCR) - fast_call_method(SECOND(), __delitem__, 2); - DISPATCH(); + TARGET(DELETE_SUBSCR) { + PyObject* b = POPX(); + PyObject* a = POPX(); + call_method(a, __delitem__, b); + } DISPATCH(); /*****************************************/ TARGET(BUILD_LIST) { PyObject* obj = VAR(STACK_VIEW(byte.arg).to_list()); @@ -251,9 +256,11 @@ __NEXT_STEP:; PUSH(VAR(ss.str())); } DISPATCH(); /*****************************************/ - TARGET(BINARY_OP) - TOP() = fast_call_method(SECOND(), BINARY_SPECIAL_METHODS[byte.arg], 2); - DISPATCH(); + TARGET(BINARY_OP) { + PyObject* b = POPX(); + PyObject* a = TOP(); + TOP() = call_method(a, BINARY_SPECIAL_METHODS[byte.arg], b); + } DISPATCH(); #define INT_BINARY_OP(op, func) \ if(is_both_int(TOP(), SECOND())){ \ @@ -262,7 +269,9 @@ __NEXT_STEP:; POP(); \ TOP() = VAR(a op b); \ }else{ \ - TOP() = fast_call_method(SECOND(), func, 2); \ + PyObject* b = POPX(); \ + PyObject* a = TOP(); \ + TOP() = call_method(a, func, b); \ } TARGET(BINARY_ADD) @@ -323,8 +332,7 @@ __NEXT_STEP:; } DISPATCH(); TARGET(CONTAINS_OP) { // a in b -> b __contains__ a - std::swap(TOP(), SECOND()); - PyObject* ret = fast_call_method(SECOND(), __contains__, 2); + PyObject* ret = call_method(TOP(), __contains__, SECOND()); bool ret_c = CAST(bool, ret); if(byte.arg == 1) ret_c = !ret_c; TOP() = VAR(ret_c); @@ -357,6 +365,9 @@ __NEXT_STEP:; frame->jump_abs_break(index); } DISPATCH(); /*****************************************/ + TARGET(BEGIN_CALL) + PUSH(_py_begin_call); + DISPATCH(); TARGET(CALL) { int ARGC = byte.arg & 0xFFFF; int KWARGC = (byte.arg >> 16) & 0xFFFF; @@ -406,9 +417,6 @@ __NEXT_STEP:; TARGET(UNARY_NOT) TOP() = VAR(!asBool(TOP())); DISPATCH(); - TARGET(UNARY_STAR) - TOP() = VAR(StarWrapper(TOP())); - DISPATCH(); /*****************************************/ TARGET(GET_ITER) TOP() = asIter(TOP()); @@ -479,7 +487,18 @@ __NEXT_STEP:; }else{ if(iter->next() != nullptr) ValueError("too many values to unpack"); } - }; DISPATCH(); + } DISPATCH(); + TARGET(UNPACK_UNLIMITED) { + auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! + PyObject* obj = asIter(POPX()); + BaseIter* iter = PyIter_AS_C(obj); + obj = iter->next(); + while(obj != nullptr){ + PUSH(obj); + // if(s_data.is_overflow()) StackOverflowError(); + obj = iter->next(); + } + } DISPATCH(); /*****************************************/ TARGET(BEGIN_CLASS) { StrName name(byte.arg); diff --git a/src/expr.h b/src/expr.h index 461d9a26..6a7902dc 100644 --- a/src/expr.h +++ b/src/expr.h @@ -189,7 +189,7 @@ struct StarredExpr: Expr{ void emit(CodeEmitContext* ctx) override { child->emit(ctx); - ctx->emit(OP_UNARY_STAR, BC_NOARG, line); + ctx->emit(OP_UNPACK_UNLIMITED, BC_NOARG, line); } bool emit_store(CodeEmitContext* ctx) override { @@ -627,6 +627,7 @@ struct CallExpr: Expr{ void emit(CodeEmitContext* ctx) override { VM* vm = ctx->vm; + if(need_unpack()) ctx->emit(OP_BEGIN_CALL, BC_NOARG, line); // if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy if(callable->is_attrib()){ auto p = static_cast(callable.get()); @@ -645,11 +646,8 @@ struct CallExpr: Expr{ } int KWARGC = (int)kwargs.size(); int ARGC = (int)args.size(); - if(KWARGC > 0){ - ctx->emit(need_unpack() ? OP_CALL_KWARGS_UNPACK : OP_CALL_KWARGS, (KWARGC<<16)|ARGC, line); - }else{ - ctx->emit(need_unpack() ? OP_CALL_UNPACK : OP_CALL, ARGC, line); - } + if(need_unpack()) ARGC = 0xFFFF; + ctx->emit(OP_CALL, (KWARGC<<16)|ARGC, line); } }; diff --git a/src/frame.h b/src/frame.h index e45e0f46..d7ae9130 100644 --- a/src/frame.h +++ b/src/frame.h @@ -212,6 +212,8 @@ struct Frame { int stack_size() const { return _s->_sp - _sp_base; } + ArgsView stack_view() const { return ArgsView(_sp_base, _s->_sp); } + std::string stack_info(){ std::stringstream ss; ss << this << ": ["; diff --git a/src/gc.h b/src/gc.h index 1a883210..5ef2d38e 100644 --- a/src/gc.h +++ b/src/gc.h @@ -141,10 +141,6 @@ template<> inline void gc_mark(BoundMethod& t){ OBJ_MARK(t.method); } -template<> inline void gc_mark(StarWrapper& t){ - OBJ_MARK(t.obj); -} - template<> inline void gc_mark(Super& t){ OBJ_MARK(t.first); } diff --git a/src/iter.h b/src/iter.h index 4ba31cad..4427e2b4 100644 --- a/src/iter.h +++ b/src/iter.h @@ -63,10 +63,15 @@ public: inline PyObject* Generator::next(){ if(state == 2) return nullptr; - vm->_push_new_frame(std::move(frame)); + // restore the context + for(PyObject* obj: s_data) frame._s->push(obj); + s_data.clear(); + vm->callstack.push(std::move(frame)); PyObject* ret = vm->_run_top_frame(); if(ret == vm->_py_op_yield){ + // backup the context frame = std::move(vm->callstack.top()); + for(PyObject* obj: frame.stack_view()) s_data.push_back(obj); vm->callstack.pop(); state = 1; return frame._s->popx(); diff --git a/src/obj.h b/src/obj.h index 5b822e9b..b502b991 100644 --- a/src/obj.h +++ b/src/obj.h @@ -50,11 +50,6 @@ struct Range { i64 step = 1; }; -struct StarWrapper { - PyObject* obj; - StarWrapper(PyObject* obj): obj(obj) {} -}; - using Super = std::pair; // TODO: re-examine the design of Slice diff --git a/src/opcodes.h b/src/opcodes.h index 2b253fb9..c14f17fd 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -76,6 +76,7 @@ OPCODE(LOOP_CONTINUE) OPCODE(LOOP_BREAK) OPCODE(GOTO) /**************************/ +OPCODE(BEGIN_CALL) OPCODE(CALL) OPCODE(RETURN_VALUE) OPCODE(YIELD_VALUE) @@ -86,7 +87,6 @@ OPCODE(SET_ADD) /**************************/ OPCODE(UNARY_NEGATIVE) OPCODE(UNARY_NOT) -OPCODE(UNARY_STAR) /**************************/ OPCODE(GET_ITER) OPCODE(FOR_ITER) @@ -96,6 +96,7 @@ OPCODE(IMPORT_STAR) /**************************/ OPCODE(UNPACK_SEQUENCE) OPCODE(UNPACK_EX) +OPCODE(UNPACK_UNLIMITED) /**************************/ OPCODE(BEGIN_CLASS) OPCODE(END_CLASS) diff --git a/src/vm.h b/src/vm.h index afbd35e6..990f51d9 100644 --- a/src/vm.h +++ b/src/vm.h @@ -48,11 +48,10 @@ Str _read_file_cwd(const Str& name, bool* ok); class Generator final: public BaseIter { Frame frame; - int state; // 0,1,2 + int state; // 0,1,2 + List s_data; // backup public: - template - Generator(VM* vm, Frame&& frame) - : BaseIter(vm), frame(std::move(frame)), state(0) {} + Generator(VM* vm, Frame&& frame): BaseIter(vm), frame(std::move(frame)), state(0) {} PyObject* next() override; void _gc_mark() const override; @@ -103,7 +102,7 @@ public: Type tp_list, tp_tuple; Type tp_function, tp_native_function, tp_iterator, tp_bound_method; Type tp_slice, tp_range, tp_module; - Type tp_super, tp_exception, tp_star_wrapper; + Type tp_super, tp_exception; VM(bool use_stdio) : heap(this){ this->vm = this; @@ -167,20 +166,6 @@ public: return false; } - PyObject* fast_call_method(PyObject* obj, StrName name, int ARGC){ - PyObject* callable = find_name_in_mro(_t(obj), name); - if(callable == nullptr) AttributeError(obj, name); - // [a, b] - // [......., a, b] - // [unbound, a, b] - // ^^^^^^^ - s_data._sp++; - PyObject** t = s_data._sp; - for(; t>s_data._sp-ARGC; t--) *t = t[-1]; - *t = obj; - return _vectorcall(ARGC-1); - } - PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){ if(_module == nullptr) _module = _main; try { @@ -333,6 +318,7 @@ public: } void RecursionError() { _error("RecursionError", "maximum recursion depth exceeded"); } + void StackOverflowError() { _error("StackOverflowError", ""); } void IOError(const Str& msg) { _error("IOError", msg); } void NotImplementedError(){ _error("NotImplementedError", ""); } void TypeError(const Str& msg){ _error("TypeError", msg); } @@ -417,7 +403,6 @@ DEF_NATIVE_2(BoundMethod, tp_bound_method) DEF_NATIVE_2(Range, tp_range) DEF_NATIVE_2(Slice, tp_slice) DEF_NATIVE_2(Exception, tp_exception) -DEF_NATIVE_2(StarWrapper, tp_star_wrapper) #define PY_CAST_INT(T) \ template<> inline T py_cast(VM* vm, PyObject* obj){ \ @@ -586,8 +571,7 @@ inline i64 VM::hash(PyObject* obj){ } inline PyObject* VM::asRepr(PyObject* obj){ - // TODO: fastcall does not take care of super() proxy! - return fast_call_method(obj, __repr__, 0); + return call_method(obj, __repr__); } inline PyObject* VM::new_module(StrName name) { @@ -682,7 +666,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_star_wrapper = _new_type_object("_star_wrapper"); tp_function = _new_type_object("function"); tp_native_function = _new_type_object("native_function"); tp_iterator = _new_type_object("iterator");