#pragma once #include "vm.h" PyVar VM::run_frame(Frame* frame){ while(frame->has_next_bytecode()){ const Bytecode& byte = frame->next_bytecode(); // if(true || frame->_module != builtins){ // printf("%d: %s (%d) %s\n", frame->_ip, OP_NAMES[byte.op], byte.arg, frame->stack_info().c_str()); // } switch (byte.op) { case OP_NO_OP: continue; case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue; case OP_LOAD_FUNCTION: { const PyVar obj = frame->co->consts[byte.arg]; pkpy::Function f = PyFunction_AS_C(obj); // copy f._module = frame->_module; frame->push(PyFunction(f)); } continue; case OP_SETUP_CLOSURE: { pkpy::Function& f = PyFunction_AS_C(frame->top()); // reference f._closure = frame->_locals; } continue; case OP_LOAD_NAME_REF: { frame->push(PyRef(NameRef(frame->co->names[byte.arg]))); } continue; case OP_LOAD_NAME: { frame->push(NameRef(frame->co->names[byte.arg]).get(this, frame)); } continue; case OP_STORE_NAME: { auto& p = frame->co->names[byte.arg]; NameRef(p).set(this, frame, frame->pop()); } continue; case OP_BUILD_ATTR: { int name = byte.arg >> 1; bool _rvalue = byte.arg % 2 == 1; auto& attr = frame->co->names[name]; PyVar obj = frame->pop_value(this); AttrRef ref = AttrRef(obj, NameRef(attr)); if(_rvalue) frame->push(ref.get(this, frame)); else frame->push(PyRef(ref)); } continue; case OP_BUILD_INDEX: { PyVar index = frame->pop_value(this); auto ref = IndexRef(frame->pop_value(this), index); if(byte.arg > 0) frame->push(ref.get(this, frame)); else frame->push(PyRef(ref)); } continue; case OP_FAST_INDEX: case OP_FAST_INDEX_REF: { auto& a = frame->co->names[byte.arg & 0xFFFF]; auto& x = frame->co->names[(byte.arg >> 16) & 0xFFFF]; auto ref = IndexRef(NameRef(a).get(this, frame), NameRef(x).get(this, frame)); if(byte.op == OP_FAST_INDEX) frame->push(ref.get(this, frame)); else frame->push(PyRef(ref)); } continue; case OP_STORE_REF: { // PyVar obj = frame->pop_value(this); // PyVarRef r = frame->pop(); // PyRef_AS_C(r)->set(this, frame, std::move(obj)); PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this)); frame->_pop(); frame->_pop(); } continue; case OP_DELETE_REF: PyRef_AS_C(frame->top())->del(this, frame); frame->_pop(); continue; case OP_BUILD_TUPLE: { pkpy::Args items = frame->pop_n_reversed(byte.arg); frame->push(PyTuple(std::move(items))); } continue; case OP_BUILD_TUPLE_REF: { pkpy::Args items = frame->pop_n_reversed(byte.arg); frame->push(PyRef(TupleRef(std::move(items)))); } continue; case OP_BUILD_STRING: { pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg); StrStream ss; for(int i=0; ipush(PyStr(ss.str())); } continue; case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue; case OP_LIST_APPEND: { PyVar obj = frame->pop_value(this); pkpy::List& list = PyList_AS_C(frame->top_1()); list.push_back(std::move(obj)); } continue; case OP_BUILD_CLASS: { const Str& clsName = frame->co->names[byte.arg].first.str(); PyVar clsBase = frame->pop_value(this); if(clsBase == None) clsBase = _t(tp_object); check_type(clsBase, tp_type); PyVar cls = new_type_object(frame->_module, clsName, clsBase); while(true){ PyVar fn = frame->pop_value(this); if(fn == None) break; const pkpy::Function& f = PyFunction_AS_C(fn); setattr(cls, f.name, fn); } cls->attr()._try_perfect_rehash(); } continue; case OP_RETURN_VALUE: return frame->pop_value(this); case OP_PRINT_EXPR: { const PyVar expr = frame->top_value(this); if(expr == None) continue; *_stdout << PyStr_AS_C(asRepr(expr)) << '\n'; } continue; case OP_POP_TOP: frame->_pop(); continue; case OP_BINARY_OP: { pkpy::Args args(2); args[1] = frame->pop_value(this); args[0] = frame->top_value(this); frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); } continue; case OP_BITWISE_OP: { pkpy::Args args(2); args[1] = frame->pop_value(this); args[0] = frame->top_value(this); frame->top() = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args)); } continue; case OP_INPLACE_BINARY_OP: { pkpy::Args args(2); args[1] = frame->pop(); args[0] = frame->top_value(this); PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); PyRef_AS_C(frame->top())->set(this, frame, std::move(ret)); frame->_pop(); } continue; case OP_INPLACE_BITWISE_OP: { pkpy::Args args(2); args[1] = frame->pop_value(this); args[0] = frame->top_value(this); PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args)); PyRef_AS_C(frame->top())->set(this, frame, std::move(ret)); frame->_pop(); } continue; case OP_COMPARE_OP: { pkpy::Args args(2); args[1] = frame->pop(); args[0] = frame->top(); frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args)); } continue; case OP_IS_OP: { PyVar rhs = frame->pop_value(this); bool ret_c = rhs == frame->top_value(this); if(byte.arg == 1) ret_c = !ret_c; frame->top() = PyBool(ret_c); } continue; case OP_CONTAINS_OP: { PyVar rhs = frame->pop_value(this); bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::one_arg(frame->pop_value(this)))); if(byte.arg == 1) ret_c = !ret_c; frame->push(PyBool(ret_c)); } continue; case OP_UNARY_NEGATIVE: frame->top() = num_negated(frame->top_value(this)); continue; case OP_UNARY_NOT: { PyVar obj = frame->pop_value(this); const PyVar& obj_bool = asBool(obj); frame->push(PyBool(!PyBool_AS_C(obj_bool))); } continue; case OP_POP_JUMP_IF_FALSE: if(!PyBool_AS_C(asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg); continue; case OP_LOAD_NONE: frame->push(None); continue; case OP_LOAD_TRUE: frame->push(True); continue; case OP_LOAD_FALSE: frame->push(False); continue; case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue; case OP_ASSERT: { PyVar _msg = frame->pop_value(this); Str msg = PyStr_AS_C(asStr(_msg)); PyVar expr = frame->pop_value(this); if(asBool(expr) != True) _error("AssertionError", msg); } continue; case OP_EXCEPTION_MATCH: { const auto& e = PyException_AS_C(frame->top()); StrName name = frame->co->names[byte.arg].first; frame->push(PyBool(e.match_type(name))); } continue; case OP_RAISE: { PyVar obj = frame->pop_value(this); Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj)); StrName type = frame->co->names[byte.arg].first; _error(type, msg); } continue; case OP_RE_RAISE: _raise(); continue; case OP_BUILD_LIST: frame->push(PyList(frame->pop_n_values_reversed(this, byte.arg).move_to_list())); continue; case OP_BUILD_MAP: { pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg*2); PyVar obj = call(builtins->attr("dict")); for(int i=0; ipush(obj); } continue; case OP_BUILD_SET: { PyVar list = PyList( frame->pop_n_values_reversed(this, byte.arg).move_to_list() ); PyVar obj = call(builtins->attr("set"), pkpy::one_arg(list)); frame->push(obj); } continue; case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue; case OP_UNARY_STAR: { if(byte.arg > 0){ // rvalue frame->top() = PyStarWrapper({frame->top_value(this), true}); }else{ PyRef_AS_C(frame->top()); // check ref frame->top() = PyStarWrapper({frame->top(), false}); } } continue; case OP_CALL_KWARGS_UNPACK: case OP_CALL_KWARGS: { int ARGC = byte.arg & 0xFFFF; int KWARGC = (byte.arg >> 16) & 0xFFFF; pkpy::Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2); pkpy::Args args = frame->pop_n_values_reversed(this, ARGC); if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args); PyVar callable = frame->pop_value(this); PyVar ret = call(callable, std::move(args), kwargs, true); if(ret == _py_op_call) return ret; frame->push(std::move(ret)); } continue; case OP_CALL_UNPACK: case OP_CALL: { pkpy::Args args = frame->pop_n_values_reversed(this, byte.arg); if(byte.op == OP_CALL_UNPACK) unpack_args(args); PyVar callable = frame->pop_value(this); PyVar ret = call(callable, std::move(args), pkpy::no_arg(), true); if(ret == _py_op_call) return ret; frame->push(std::move(ret)); } continue; case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); continue; case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); continue; case OP_GOTO: { StrName label = frame->co->names[byte.arg].first; auto it = frame->co->labels.find(label); if(it == frame->co->labels.end()) _error("KeyError", "label " + label.str().escape(true) + " not found"); frame->jump_abs_safe(it->second); } continue; case OP_GET_ITER: { PyVar obj = frame->pop_value(this); PyVar iter = asIter(obj); check_type(frame->top(), tp_ref); PyIter_AS_C(iter)->loop_var = frame->pop(); frame->push(std::move(iter)); } continue; case OP_FOR_ITER: { auto& it = PyIter_AS_C(frame->top()); PyVar obj = it->next(); if(obj != nullptr){ PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj)); }else{ int blockEnd = frame->co->blocks[byte.block].end; frame->jump_abs_safe(blockEnd); } } continue; case OP_LOOP_CONTINUE: { int blockStart = frame->co->blocks[byte.block].start; frame->jump_abs(blockStart); } continue; case OP_LOOP_BREAK: { int blockEnd = frame->co->blocks[byte.block].end; frame->jump_abs_safe(blockEnd); } continue; case OP_JUMP_IF_FALSE_OR_POP: { const PyVar expr = frame->top_value(this); if(asBool(expr)==False) frame->jump_abs(byte.arg); else frame->pop_value(this); } continue; case OP_JUMP_IF_TRUE_OR_POP: { const PyVar expr = frame->top_value(this); if(asBool(expr)==True) frame->jump_abs(byte.arg); else frame->pop_value(this); } continue; case OP_BUILD_SLICE: { PyVar stop = frame->pop_value(this); PyVar start = frame->pop_value(this); pkpy::Slice s; if(start != None) {check_type(start, tp_int); s.start = (int)PyInt_AS_C(start);} if(stop != None) {check_type(stop, tp_int); s.stop = (int)PyInt_AS_C(stop);} frame->push(PySlice(s)); } continue; case OP_IMPORT_NAME: { StrName name = frame->co->names[byte.arg].first; PyVar* ext_mod = _modules.try_get(name); if(ext_mod == nullptr){ auto it2 = _lazy_modules.find(name); if(it2 == _lazy_modules.end()){ _error("ImportError", "module " + name.str().escape(true) + " not found"); }else{ const Str& source = it2->second; CodeObject_ code = compile(source, name.str(), EXEC_MODE); PyVar new_mod = new_module(name); _exec(code, new_mod); frame->push(new_mod); _lazy_modules.erase(it2); } }else{ frame->push(*ext_mod); } } continue; case OP_YIELD_VALUE: return _py_op_yield; // TODO: using "goto" inside with block may cause __exit__ not called case OP_WITH_ENTER: call(frame->pop_value(this), __enter__); continue; case OP_WITH_EXIT: call(frame->pop_value(this), __exit__); continue; case OP_TRY_BLOCK_ENTER: frame->on_try_block_enter(); continue; case OP_TRY_BLOCK_EXIT: frame->on_try_block_exit(); continue; default: throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); } } if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){ if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE"); return frame->pop_value(this); } if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE"); return None; }