From 0a44220f66ed9f88ec25198b2a5ba9590e06d4f4 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 30 Jun 2025 01:46:28 +0800 Subject: [PATCH] Update ceval.c --- src/interpreter/ceval.c | 2133 +++++++++++++++++++-------------------- 1 file changed, 1064 insertions(+), 1069 deletions(-) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index b19b3e34..673acab7 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -88,524 +88,523 @@ FrameResult VM__run_top_frame(VM* self) { py_Frame* frame = self->top_frame; Bytecode* co_codes; py_Name* co_names; + Bytecode byte; const py_Frame* base_frame = frame; - while(true) { - Bytecode byte; - __NEXT_FRAME: - if(self->recursion_depth >= self->max_recursion_depth) { - py_exception(tp_RecursionError, "maximum recursion depth exceeded"); - goto __ERROR; - } - RESET_CO_CACHE(); - frame->ip++; +__NEXT_FRAME: + if(self->recursion_depth >= self->max_recursion_depth) { + py_exception(tp_RecursionError, "maximum recursion depth exceeded"); + goto __ERROR; + } + RESET_CO_CACHE(); + frame->ip++; - __NEXT_STEP: - byte = co_codes[frame->ip]; +__NEXT_STEP: + byte = co_codes[frame->ip]; - if(self->trace_info.func) { - SourceLocation loc = Frame__source_location(frame); - SourceLocation prev_loc = self->trace_info.prev_loc; - if(loc.lineno != prev_loc.lineno || loc.src != prev_loc.src) { - if(prev_loc.src) PK_DECREF(prev_loc.src); - PK_INCREF(loc.src); - self->trace_info.prev_loc = loc; - self->trace_info.func(frame, TRACE_EVENT_LINE); - } + if(self->trace_info.func) { + SourceLocation loc = Frame__source_location(frame); + SourceLocation prev_loc = self->trace_info.prev_loc; + if(loc.lineno != prev_loc.lineno || loc.src != prev_loc.src) { + if(prev_loc.src) PK_DECREF(prev_loc.src); + PK_INCREF(loc.src); + self->trace_info.prev_loc = loc; + self->trace_info.func(frame, TRACE_EVENT_LINE); } + } #if PK_ENABLE_WATCHDOG - if(self->watchdog_info.max_reset_time > 0) { - clock_t now = clock(); - if(now > self->watchdog_info.max_reset_time) { - self->watchdog_info.max_reset_time = 0; - TimeoutError("watchdog timeout"); - goto __ERROR; - } + if(self->watchdog_info.max_reset_time > 0) { + clock_t now = clock(); + if(now > self->watchdog_info.max_reset_time) { + self->watchdog_info.max_reset_time = 0; + TimeoutError("watchdog timeout"); + goto __ERROR; } + } #endif #ifndef NDEBUG - pk_print_stack(self, frame, byte); + pk_print_stack(self, frame, byte); #endif - switch((Opcode)byte.op) { - case OP_NO_OP: DISPATCH(); - /*****************************************/ - case OP_POP_TOP: POP(); DISPATCH(); - case OP_DUP_TOP: PUSH(TOP()); DISPATCH(); - case OP_DUP_TOP_TWO: - // [a, b] - PUSH(SECOND()); // [a, b, a] - PUSH(SECOND()); // [a, b, a, b] - DISPATCH(); - case OP_ROT_TWO: { - py_TValue tmp = *TOP(); - *TOP() = *SECOND(); - *SECOND() = tmp; - DISPATCH(); + switch((Opcode)byte.op) { + case OP_NO_OP: DISPATCH(); + /*****************************************/ + case OP_POP_TOP: POP(); DISPATCH(); + case OP_DUP_TOP: PUSH(TOP()); DISPATCH(); + case OP_DUP_TOP_TWO: + // [a, b] + PUSH(SECOND()); // [a, b, a] + PUSH(SECOND()); // [a, b, a, b] + DISPATCH(); + case OP_ROT_TWO: { + py_TValue tmp = *TOP(); + *TOP() = *SECOND(); + *SECOND() = tmp; + DISPATCH(); + } + case OP_ROT_THREE: { + // [a, b, c] -> [c, a, b] + py_TValue tmp = *TOP(); + *TOP() = *SECOND(); + *SECOND() = *THIRD(); + *THIRD() = tmp; + DISPATCH(); + } + case OP_PRINT_EXPR: + if(TOP()->type != tp_NoneType) { + bool ok = py_repr(TOP()); + if(!ok) goto __ERROR; + self->callbacks.print(py_tostr(&self->last_retval)); + self->callbacks.print("\n"); } - case OP_ROT_THREE: { - // [a, b, c] -> [c, a, b] - py_TValue tmp = *TOP(); - *TOP() = *SECOND(); - *SECOND() = *THIRD(); - *THIRD() = tmp; - DISPATCH(); - } - case OP_PRINT_EXPR: - if(TOP()->type != tp_NoneType) { - bool ok = py_repr(TOP()); - if(!ok) goto __ERROR; - self->callbacks.print(py_tostr(&self->last_retval)); - self->callbacks.print("\n"); + POP(); + DISPATCH(); + /*****************************************/ + case OP_LOAD_CONST: { + PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg)); + DISPATCH(); + } + case OP_LOAD_NONE: { + py_newnone(SP()++); + DISPATCH(); + } + case OP_LOAD_TRUE: { + py_newbool(SP()++, true); + DISPATCH(); + } + case OP_LOAD_FALSE: { + py_newbool(SP()++, false); + DISPATCH(); + } + /*****************************************/ + case OP_LOAD_SMALL_INT: { + py_newint(SP()++, (int16_t)byte.arg); + DISPATCH(); + } + /*****************************************/ + case OP_LOAD_ELLIPSIS: { + py_newellipsis(SP()++); + DISPATCH(); + } + case OP_LOAD_FUNCTION: { + FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg); + Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function)); + Function__ctor(ud, decl, frame->module, frame->globals); + if(decl->nested) { + if(frame->is_locals_special) { + RuntimeError("cannot create closure from special locals"); + goto __ERROR; } - POP(); - DISPATCH(); + ud->closure = FastLocals__to_namedict(frame->locals, frame->co); + py_Name name = py_name(decl->code.name->data); + // capture itself to allow recursion + NameDict__set(ud->closure, name, SP()); + } + SP()++; + DISPATCH(); + } + case OP_LOAD_NULL: + py_newnil(SP()++); + DISPATCH(); /*****************************************/ - case OP_LOAD_CONST: { - PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg)); + case OP_LOAD_FAST: { + assert(!frame->is_locals_special); + py_Ref val = &frame->locals[byte.arg]; + if(!py_isnil(val)) { + PUSH(val); DISPATCH(); } - case OP_LOAD_NONE: { - py_newnone(SP()++); - DISPATCH(); - } - case OP_LOAD_TRUE: { - py_newbool(SP()++, true); - DISPATCH(); - } - case OP_LOAD_FALSE: { - py_newbool(SP()++, false); - DISPATCH(); - } - /*****************************************/ - case OP_LOAD_SMALL_INT: { - py_newint(SP()++, (int16_t)byte.arg); - DISPATCH(); - } - /*****************************************/ - case OP_LOAD_ELLIPSIS: { - py_newellipsis(SP()++); - DISPATCH(); - } - case OP_LOAD_FUNCTION: { - FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg); - Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function)); - Function__ctor(ud, decl, frame->module, frame->globals); - if(decl->nested) { - if(frame->is_locals_special) { - RuntimeError("cannot create closure from special locals"); + py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg); + UnboundLocalError(name); + goto __ERROR; + } + case OP_LOAD_NAME: { + assert(frame->is_locals_special); + py_Name name = co_names[byte.arg]; + // locals + switch(frame->locals->type) { + case tp_locals: { + py_Frame* noproxy = frame->locals->_ptr; + py_Ref slot = Frame__getlocal_noproxy(noproxy, name); + if(slot == NULL) break; + if(py_isnil(slot)) { + UnboundLocalError(name); goto __ERROR; } - ud->closure = FastLocals__to_namedict(frame->locals, frame->co); - py_Name name = py_name(decl->code.name->data); - // capture itself to allow recursion - NameDict__set(ud->closure, name, SP()); - } - SP()++; - DISPATCH(); - } - case OP_LOAD_NULL: - py_newnil(SP()++); - DISPATCH(); - /*****************************************/ - case OP_LOAD_FAST: { - assert(!frame->is_locals_special); - py_Ref val = &frame->locals[byte.arg]; - if(!py_isnil(val)) { - PUSH(val); + PUSH(slot); DISPATCH(); } + case tp_dict: { + int res = py_dict_getitem(frame->locals, py_name2ref(name)); + if(res == 1) { + PUSH(&self->last_retval); + DISPATCH(); + } + if(res == 0) break; + assert(res == -1); + goto __ERROR; + } + case tp_nil: break; + default: c11__unreachable(); + } + // globals + int res = Frame__getglobal(frame, name); + if(res == 1) { + PUSH(&self->last_retval); + DISPATCH(); + } + if(res == -1) goto __ERROR; + // builtins + py_Ref tmp = py_getdict(self->builtins, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_NONLOCAL: { + py_Name name = co_names[byte.arg]; + py_Ref tmp = Frame__getclosure(frame, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); + } + int res = Frame__getglobal(frame, name); + if(res == 1) { + PUSH(&self->last_retval); + DISPATCH(); + } + if(res == -1) goto __ERROR; + + tmp = py_getdict(self->builtins, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_GLOBAL: { + py_Name name = co_names[byte.arg]; + int res = Frame__getglobal(frame, name); + if(res == 1) { + PUSH(&self->last_retval); + DISPATCH(); + } + if(res == -1) goto __ERROR; + py_Ref tmp = py_getdict(self->builtins, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_ATTR: { + py_Name name = co_names[byte.arg]; + if(py_getattr(TOP(), name)) { + py_assign(TOP(), py_retval()); + } else { + goto __ERROR; + } + DISPATCH(); + } + case OP_LOAD_CLASS_GLOBAL: { + assert(self->curr_class); + py_Name name = co_names[byte.arg]; + py_Ref tmp = py_getdict(self->curr_class, name); + if(tmp) { + PUSH(tmp); + DISPATCH(); + } + // load global if attribute not found + int res = Frame__getglobal(frame, name); + if(res == 1) { + PUSH(&self->last_retval); + DISPATCH(); + } + if(res == -1) goto __ERROR; + tmp = py_getdict(self->builtins, name); + if(tmp) { + PUSH(tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_METHOD: { + // [self] -> [unbound, self] + py_Name name = co_names[byte.arg]; + bool ok = py_pushmethod(name); + if(!ok) { + // fallback to getattr + if(py_getattr(TOP(), name)) { + py_assign(TOP(), py_retval()); + py_newnil(SP()++); + } else { + goto __ERROR; + } + } + DISPATCH(); + } + case OP_LOAD_SUBSCR: { + // [a, b] -> a[b] + py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__); + if(magic) { + if(magic->type == tp_nativefunc) { + if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR; + POP(); + py_assign(TOP(), py_retval()); + } else { + INSERT_THIRD(); // [?, a, b] + *THIRD() = *magic; // [__getitem__, a, b] + vectorcall_opcall(1, 0); + } + DISPATCH(); + } + TypeError("'%t' object is not subscriptable", SECOND()->type); + goto __ERROR; + } + case OP_STORE_FAST: { + assert(!frame->is_locals_special); + frame->locals[byte.arg] = POPX(); + DISPATCH(); + } + case OP_STORE_NAME: { + assert(frame->is_locals_special); + py_Name name = co_names[byte.arg]; + switch(frame->locals->type) { + case tp_locals: { + py_Frame* noproxy = frame->locals->_ptr; + py_Ref slot = Frame__getlocal_noproxy(noproxy, name); + if(slot == NULL) { + UnboundLocalError(name); + goto __ERROR; + } + *slot = POPX(); + DISPATCH(); + } + case tp_dict: { + if(!py_dict_setitem(frame->locals, py_name2ref(name), TOP())) goto __ERROR; + POP(); + DISPATCH(); + } + case tp_nil: { + // globals + if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; + POP(); + DISPATCH(); + } + default: c11__unreachable(); + } + } + case OP_STORE_GLOBAL: { + py_Name name = co_names[byte.arg]; + if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; + POP(); + DISPATCH(); + } + case OP_STORE_ATTR: { + // [val, a] -> a.b = val + py_Name name = co_names[byte.arg]; + if(!py_setattr(TOP(), name, SECOND())) goto __ERROR; + STACK_SHRINK(2); + DISPATCH(); + } + case OP_STORE_SUBSCR: { + // [val, a, b] -> a[b] = val + py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__); + if(magic) { + PUSH(THIRD()); // [val, a, b, val] + if(magic->type == tp_nativefunc) { + if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR; + STACK_SHRINK(4); + } else { + *FOURTH() = *magic; // [__setitem__, a, b, val] + if(!py_vectorcall(2, 0)) goto __ERROR; + } + DISPATCH(); + } + TypeError("'%t' object does not support item assignment", SECOND()->type); + goto __ERROR; + } + case OP_DELETE_FAST: { + assert(!frame->is_locals_special); + py_Ref tmp = &frame->locals[byte.arg]; + if(py_isnil(tmp)) { py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg); UnboundLocalError(name); goto __ERROR; } - case OP_LOAD_NAME: { - assert(frame->is_locals_special); - py_Name name = co_names[byte.arg]; - // locals - switch(frame->locals->type) { - case tp_locals: { - py_Frame* noproxy = frame->locals->_ptr; - py_Ref slot = Frame__getlocal_noproxy(noproxy, name); - if(slot == NULL) break; - if(py_isnil(slot)) { - UnboundLocalError(name); - goto __ERROR; - } - PUSH(slot); - DISPATCH(); - } - case tp_dict: { - int res = py_dict_getitem(frame->locals, py_name2ref(name)); - if(res == 1) { - PUSH(&self->last_retval); - DISPATCH(); - } - if(res == 0) break; - assert(res == -1); + py_newnil(tmp); + DISPATCH(); + } + case OP_DELETE_NAME: { + assert(frame->is_locals_special); + py_Name name = co_names[byte.arg]; + switch(frame->locals->type) { + case tp_locals: { + py_Frame* noproxy = frame->locals->_ptr; + py_Ref slot = Frame__getlocal_noproxy(noproxy, name); + if(slot == NULL || py_isnil(slot)) { + UnboundLocalError(name); goto __ERROR; } - case tp_nil: break; - default: c11__unreachable(); - } - // globals - int res = Frame__getglobal(frame, name); - if(res == 1) { - PUSH(&self->last_retval); + py_newnil(slot); DISPATCH(); } - if(res == -1) goto __ERROR; - // builtins - py_Ref tmp = py_getdict(self->builtins, name); - if(tmp != NULL) { - PUSH(tmp); - DISPATCH(); + case tp_dict: { + int res = py_dict_delitem(frame->locals, py_name2ref(name)); + if(res == 1) DISPATCH(); + if(res == 0) UnboundLocalError(name); + goto __ERROR; } - NameError(name); - goto __ERROR; + case tp_nil: { + // globals + int res = Frame__delglobal(frame, name); + if(res == 1) DISPATCH(); + if(res == 0) NameError(name); + goto __ERROR; + } + default: c11__unreachable(); } - case OP_LOAD_NONLOCAL: { - py_Name name = co_names[byte.arg]; - py_Ref tmp = Frame__getclosure(frame, name); - if(tmp != NULL) { - PUSH(tmp); - DISPATCH(); - } - int res = Frame__getglobal(frame, name); - if(res == 1) { - PUSH(&self->last_retval); - DISPATCH(); - } - if(res == -1) goto __ERROR; + } + case OP_DELETE_GLOBAL: { + py_Name name = co_names[byte.arg]; + int res = Frame__delglobal(frame, name); + if(res == 1) DISPATCH(); + if(res == -1) goto __ERROR; + NameError(name); + goto __ERROR; + } - tmp = py_getdict(self->builtins, name); - if(tmp != NULL) { - PUSH(tmp); - DISPATCH(); - } - NameError(name); - goto __ERROR; - } - case OP_LOAD_GLOBAL: { - py_Name name = co_names[byte.arg]; - int res = Frame__getglobal(frame, name); - if(res == 1) { - PUSH(&self->last_retval); - DISPATCH(); - } - if(res == -1) goto __ERROR; - py_Ref tmp = py_getdict(self->builtins, name); - if(tmp != NULL) { - PUSH(tmp); - DISPATCH(); - } - NameError(name); - goto __ERROR; - } - case OP_LOAD_ATTR: { - py_Name name = co_names[byte.arg]; - if(py_getattr(TOP(), name)) { - py_assign(TOP(), py_retval()); + case OP_DELETE_ATTR: { + py_Name name = co_names[byte.arg]; + if(!py_delattr(TOP(), name)) goto __ERROR; + DISPATCH(); + } + + case OP_DELETE_SUBSCR: { + // [a, b] -> del a[b] + py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__); + if(magic) { + if(magic->type == tp_nativefunc) { + if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR; + STACK_SHRINK(2); } else { - goto __ERROR; - } - DISPATCH(); - } - case OP_LOAD_CLASS_GLOBAL: { - assert(self->curr_class); - py_Name name = co_names[byte.arg]; - py_Ref tmp = py_getdict(self->curr_class, name); - if(tmp) { - PUSH(tmp); - DISPATCH(); - } - // load global if attribute not found - int res = Frame__getglobal(frame, name); - if(res == 1) { - PUSH(&self->last_retval); - DISPATCH(); - } - if(res == -1) goto __ERROR; - tmp = py_getdict(self->builtins, name); - if(tmp) { - PUSH(tmp); - DISPATCH(); - } - NameError(name); - goto __ERROR; - } - case OP_LOAD_METHOD: { - // [self] -> [unbound, self] - py_Name name = co_names[byte.arg]; - bool ok = py_pushmethod(name); - if(!ok) { - // fallback to getattr - if(py_getattr(TOP(), name)) { - py_assign(TOP(), py_retval()); - py_newnil(SP()++); - } else { - goto __ERROR; - } - } - DISPATCH(); - } - case OP_LOAD_SUBSCR: { - // [a, b] -> a[b] - py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__); - if(magic) { - if(magic->type == tp_nativefunc) { - if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR; - POP(); - py_assign(TOP(), py_retval()); - } else { - INSERT_THIRD(); // [?, a, b] - *THIRD() = *magic; // [__getitem__, a, b] - vectorcall_opcall(1, 0); - } - DISPATCH(); - } - TypeError("'%t' object is not subscriptable", SECOND()->type); - goto __ERROR; - } - case OP_STORE_FAST: { - assert(!frame->is_locals_special); - frame->locals[byte.arg] = POPX(); - DISPATCH(); - } - case OP_STORE_NAME: { - assert(frame->is_locals_special); - py_Name name = co_names[byte.arg]; - switch(frame->locals->type) { - case tp_locals: { - py_Frame* noproxy = frame->locals->_ptr; - py_Ref slot = Frame__getlocal_noproxy(noproxy, name); - if(slot == NULL) { - UnboundLocalError(name); - goto __ERROR; - } - *slot = POPX(); - DISPATCH(); - } - case tp_dict: { - if(!py_dict_setitem(frame->locals, py_name2ref(name), TOP())) goto __ERROR; - POP(); - DISPATCH(); - } - case tp_nil: { - // globals - if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; - POP(); - DISPATCH(); - } - default: c11__unreachable(); - } - } - case OP_STORE_GLOBAL: { - py_Name name = co_names[byte.arg]; - if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; - POP(); - DISPATCH(); - } - case OP_STORE_ATTR: { - // [val, a] -> a.b = val - py_Name name = co_names[byte.arg]; - if(!py_setattr(TOP(), name, SECOND())) goto __ERROR; - STACK_SHRINK(2); - DISPATCH(); - } - case OP_STORE_SUBSCR: { - // [val, a, b] -> a[b] = val - py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__); - if(magic) { - PUSH(THIRD()); // [val, a, b, val] - if(magic->type == tp_nativefunc) { - if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR; - STACK_SHRINK(4); - } else { - *FOURTH() = *magic; // [__setitem__, a, b, val] - if(!py_vectorcall(2, 0)) goto __ERROR; - } - DISPATCH(); - } - TypeError("'%t' object does not support item assignment", SECOND()->type); - goto __ERROR; - } - case OP_DELETE_FAST: { - assert(!frame->is_locals_special); - py_Ref tmp = &frame->locals[byte.arg]; - if(py_isnil(tmp)) { - py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg); - UnboundLocalError(name); - goto __ERROR; - } - py_newnil(tmp); - DISPATCH(); - } - case OP_DELETE_NAME: { - assert(frame->is_locals_special); - py_Name name = co_names[byte.arg]; - switch(frame->locals->type) { - case tp_locals: { - py_Frame* noproxy = frame->locals->_ptr; - py_Ref slot = Frame__getlocal_noproxy(noproxy, name); - if(slot == NULL || py_isnil(slot)) { - UnboundLocalError(name); - goto __ERROR; - } - py_newnil(slot); - DISPATCH(); - } - case tp_dict: { - int res = py_dict_delitem(frame->locals, py_name2ref(name)); - if(res == 1) DISPATCH(); - if(res == 0) UnboundLocalError(name); - goto __ERROR; - } - case tp_nil: { - // globals - int res = Frame__delglobal(frame, name); - if(res == 1) DISPATCH(); - if(res == 0) NameError(name); - goto __ERROR; - } - default: c11__unreachable(); - } - } - case OP_DELETE_GLOBAL: { - py_Name name = co_names[byte.arg]; - int res = Frame__delglobal(frame, name); - if(res == 1) DISPATCH(); - if(res == -1) goto __ERROR; - NameError(name); - goto __ERROR; - } - - case OP_DELETE_ATTR: { - py_Name name = co_names[byte.arg]; - if(!py_delattr(TOP(), name)) goto __ERROR; - DISPATCH(); - } - - case OP_DELETE_SUBSCR: { - // [a, b] -> del a[b] - py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__); - if(magic) { - if(magic->type == tp_nativefunc) { - if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR; - STACK_SHRINK(2); - } else { - INSERT_THIRD(); // [?, a, b] - *THIRD() = *magic; // [__delitem__, a, b] - if(!py_vectorcall(1, 0)) goto __ERROR; - } - DISPATCH(); - } - TypeError("'%t' object does not support item deletion", SECOND()->type); - goto __ERROR; - } - /*****************************************/ - case OP_BUILD_IMAG: { - // [x] - py_Ref f = py_getdict(self->builtins, py_name("complex")); - assert(f != NULL); - py_TValue tmp = *TOP(); - *TOP() = *f; // [complex] - py_newnil(SP()++); // [complex, NULL] - py_newint(SP()++, 0); // [complex, NULL, 0] - *SP()++ = tmp; // [complex, NULL, 0, x] - vectorcall_opcall(2, 0); - DISPATCH(); - } - case OP_BUILD_BYTES: { - int size; - py_Ref string = c11__at(py_TValue, &frame->co->consts, byte.arg); - const char* data = py_tostrn(string, &size); - unsigned char* p = py_newbytes(SP()++, size); - memcpy(p, data, size); - DISPATCH(); - } - case OP_BUILD_TUPLE: { - py_TValue tmp; - py_Ref p = py_newtuple(&tmp, byte.arg); - py_TValue* begin = SP() - byte.arg; - for(int i = 0; i < byte.arg; i++) - p[i] = begin[i]; - SP() = begin; - PUSH(&tmp); - DISPATCH(); - } - case OP_BUILD_LIST: { - py_TValue tmp; - py_newlistn(&tmp, byte.arg); - py_TValue* begin = SP() - byte.arg; - for(int i = 0; i < byte.arg; i++) { - py_list_setitem(&tmp, i, begin + i); - } - SP() = begin; - PUSH(&tmp); - DISPATCH(); - } - case OP_BUILD_DICT: { - py_TValue* begin = SP() - byte.arg * 2; - py_Ref tmp = py_pushtmp(); - py_newdict(tmp); - for(int i = 0; i < byte.arg * 2; i += 2) { - bool ok = py_dict_setitem(tmp, begin + i, begin + i + 1); - if(!ok) goto __ERROR; - } - SP() = begin; - PUSH(tmp); - DISPATCH(); - } - case OP_BUILD_SET: { - py_TValue* begin = SP() - byte.arg; - py_Ref typeobject_set = py_getdict(self->builtins, py_name("set")); - assert(typeobject_set != NULL); - py_push(typeobject_set); - py_pushnil(); - if(!py_vectorcall(0, 0)) goto __ERROR; - py_push(py_retval()); // empty set - py_Name id_add = py_name("add"); - for(int i = 0; i < byte.arg; i++) { - py_push(TOP()); - if(!py_pushmethod(id_add)) { - c11__abort("OP_BUILD_SET: failed to load method 'add'"); - } - py_push(begin + i); + INSERT_THIRD(); // [?, a, b] + *THIRD() = *magic; // [__delitem__, a, b] if(!py_vectorcall(1, 0)) goto __ERROR; } - py_TValue tmp = *TOP(); - SP() = begin; - PUSH(&tmp); DISPATCH(); } - case OP_BUILD_SLICE: { - // [start, stop, step] - py_TValue tmp; - py_newslice(&tmp); - py_setslot(&tmp, 0, THIRD()); - py_setslot(&tmp, 1, SECOND()); - py_setslot(&tmp, 2, TOP()); - STACK_SHRINK(3); - PUSH(&tmp); - DISPATCH(); + TypeError("'%t' object does not support item deletion", SECOND()->type); + goto __ERROR; + } + /*****************************************/ + case OP_BUILD_IMAG: { + // [x] + py_Ref f = py_getdict(self->builtins, py_name("complex")); + assert(f != NULL); + py_TValue tmp = *TOP(); + *TOP() = *f; // [complex] + py_newnil(SP()++); // [complex, NULL] + py_newint(SP()++, 0); // [complex, NULL, 0] + *SP()++ = tmp; // [complex, NULL, 0, x] + vectorcall_opcall(2, 0); + DISPATCH(); + } + case OP_BUILD_BYTES: { + int size; + py_Ref string = c11__at(py_TValue, &frame->co->consts, byte.arg); + const char* data = py_tostrn(string, &size); + unsigned char* p = py_newbytes(SP()++, size); + memcpy(p, data, size); + DISPATCH(); + } + case OP_BUILD_TUPLE: { + py_TValue tmp; + py_Ref p = py_newtuple(&tmp, byte.arg); + py_TValue* begin = SP() - byte.arg; + for(int i = 0; i < byte.arg; i++) + p[i] = begin[i]; + SP() = begin; + PUSH(&tmp); + DISPATCH(); + } + case OP_BUILD_LIST: { + py_TValue tmp; + py_newlistn(&tmp, byte.arg); + py_TValue* begin = SP() - byte.arg; + for(int i = 0; i < byte.arg; i++) { + py_list_setitem(&tmp, i, begin + i); } - case OP_BUILD_STRING: { - py_TValue* begin = SP() - byte.arg; - c11_sbuf ss; - c11_sbuf__ctor(&ss); - for(int i = 0; i < byte.arg; i++) { - if(!py_str(begin + i)) goto __ERROR; - c11_sbuf__write_sv(&ss, py_tosv(&self->last_retval)); + SP() = begin; + PUSH(&tmp); + DISPATCH(); + } + case OP_BUILD_DICT: { + py_TValue* begin = SP() - byte.arg * 2; + py_Ref tmp = py_pushtmp(); + py_newdict(tmp); + for(int i = 0; i < byte.arg * 2; i += 2) { + bool ok = py_dict_setitem(tmp, begin + i, begin + i + 1); + if(!ok) goto __ERROR; + } + SP() = begin; + PUSH(tmp); + DISPATCH(); + } + case OP_BUILD_SET: { + py_TValue* begin = SP() - byte.arg; + py_Ref typeobject_set = py_getdict(self->builtins, py_name("set")); + assert(typeobject_set != NULL); + py_push(typeobject_set); + py_pushnil(); + if(!py_vectorcall(0, 0)) goto __ERROR; + py_push(py_retval()); // empty set + py_Name id_add = py_name("add"); + for(int i = 0; i < byte.arg; i++) { + py_push(TOP()); + if(!py_pushmethod(id_add)) { + c11__abort("OP_BUILD_SET: failed to load method 'add'"); } - SP() = begin; - c11_sbuf__py_submit(&ss, SP()++); - DISPATCH(); + py_push(begin + i); + if(!py_vectorcall(1, 0)) goto __ERROR; } - /*****************************/ + py_TValue tmp = *TOP(); + SP() = begin; + PUSH(&tmp); + DISPATCH(); + } + case OP_BUILD_SLICE: { + // [start, stop, step] + py_TValue tmp; + py_newslice(&tmp); + py_setslot(&tmp, 0, THIRD()); + py_setslot(&tmp, 1, SECOND()); + py_setslot(&tmp, 2, TOP()); + STACK_SHRINK(3); + PUSH(&tmp); + DISPATCH(); + } + case OP_BUILD_STRING: { + py_TValue* begin = SP() - byte.arg; + c11_sbuf ss; + c11_sbuf__ctor(&ss); + for(int i = 0; i < byte.arg; i++) { + if(!py_str(begin + i)) goto __ERROR; + c11_sbuf__write_sv(&ss, py_tosv(&self->last_retval)); + } + SP() = begin; + c11_sbuf__py_submit(&ss, SP()++); + DISPATCH(); + } + /*****************************/ #define CASE_BINARY_OP(label, op, rop) \ case label: { \ if(!pk_stack_binaryop(self, op, rop)) goto __ERROR; \ @@ -613,642 +612,638 @@ FrameResult VM__run_top_frame(VM* self) { *TOP() = self->last_retval; \ DISPATCH(); \ } - CASE_BINARY_OP(OP_BINARY_ADD, __add__, __radd__) - CASE_BINARY_OP(OP_BINARY_SUB, __sub__, __rsub__) - CASE_BINARY_OP(OP_BINARY_MUL, __mul__, __rmul__) - CASE_BINARY_OP(OP_BINARY_TRUEDIV, __truediv__, __rtruediv__) - CASE_BINARY_OP(OP_BINARY_FLOORDIV, __floordiv__, __rfloordiv__) - CASE_BINARY_OP(OP_BINARY_MOD, __mod__, __rmod__) - CASE_BINARY_OP(OP_BINARY_POW, __pow__, __rpow__) - CASE_BINARY_OP(OP_BINARY_LSHIFT, __lshift__, 0) - CASE_BINARY_OP(OP_BINARY_RSHIFT, __rshift__, 0) - CASE_BINARY_OP(OP_BINARY_AND, __and__, 0) - CASE_BINARY_OP(OP_BINARY_OR, __or__, 0) - CASE_BINARY_OP(OP_BINARY_XOR, __xor__, 0) - CASE_BINARY_OP(OP_BINARY_MATMUL, __matmul__, 0) - CASE_BINARY_OP(OP_COMPARE_LT, __lt__, __gt__) - CASE_BINARY_OP(OP_COMPARE_LE, __le__, __ge__) - CASE_BINARY_OP(OP_COMPARE_EQ, __eq__, __eq__) - CASE_BINARY_OP(OP_COMPARE_NE, __ne__, __ne__) - CASE_BINARY_OP(OP_COMPARE_GT, __gt__, __lt__) - CASE_BINARY_OP(OP_COMPARE_GE, __ge__, __le__) + CASE_BINARY_OP(OP_BINARY_ADD, __add__, __radd__) + CASE_BINARY_OP(OP_BINARY_SUB, __sub__, __rsub__) + CASE_BINARY_OP(OP_BINARY_MUL, __mul__, __rmul__) + CASE_BINARY_OP(OP_BINARY_TRUEDIV, __truediv__, __rtruediv__) + CASE_BINARY_OP(OP_BINARY_FLOORDIV, __floordiv__, __rfloordiv__) + CASE_BINARY_OP(OP_BINARY_MOD, __mod__, __rmod__) + CASE_BINARY_OP(OP_BINARY_POW, __pow__, __rpow__) + CASE_BINARY_OP(OP_BINARY_LSHIFT, __lshift__, 0) + CASE_BINARY_OP(OP_BINARY_RSHIFT, __rshift__, 0) + CASE_BINARY_OP(OP_BINARY_AND, __and__, 0) + CASE_BINARY_OP(OP_BINARY_OR, __or__, 0) + CASE_BINARY_OP(OP_BINARY_XOR, __xor__, 0) + CASE_BINARY_OP(OP_BINARY_MATMUL, __matmul__, 0) + CASE_BINARY_OP(OP_COMPARE_LT, __lt__, __gt__) + CASE_BINARY_OP(OP_COMPARE_LE, __le__, __ge__) + CASE_BINARY_OP(OP_COMPARE_EQ, __eq__, __eq__) + CASE_BINARY_OP(OP_COMPARE_NE, __ne__, __ne__) + CASE_BINARY_OP(OP_COMPARE_GT, __gt__, __lt__) + CASE_BINARY_OP(OP_COMPARE_GE, __ge__, __le__) #undef CASE_BINARY_OP - case OP_IS_OP: { - bool res = py_isidentical(SECOND(), TOP()); - POP(); + case OP_IS_OP: { + bool res = py_isidentical(SECOND(), TOP()); + POP(); + if(byte.arg) res = !res; + py_newbool(TOP(), res); + DISPATCH(); + } + case OP_CONTAINS_OP: { + // [b, a] -> b __contains__ a (a in b) -> [retval] + py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__); + if(magic) { + if(magic->type == tp_nativefunc) { + if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR; + STACK_SHRINK(2); + } else { + INSERT_THIRD(); // [?, b, a] + *THIRD() = *magic; // [__contains__, a, b] + if(!py_vectorcall(1, 0)) goto __ERROR; + } + bool res = py_tobool(py_retval()); if(byte.arg) res = !res; - py_newbool(TOP(), res); + py_newbool(SP()++, res); DISPATCH(); } - case OP_CONTAINS_OP: { - // [b, a] -> b __contains__ a (a in b) -> [retval] - py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__); - if(magic) { - if(magic->type == tp_nativefunc) { - if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR; - STACK_SHRINK(2); - } else { - INSERT_THIRD(); // [?, b, a] - *THIRD() = *magic; // [__contains__, a, b] - if(!py_vectorcall(1, 0)) goto __ERROR; - } - bool res = py_tobool(py_retval()); - if(byte.arg) res = !res; - py_newbool(SP()++, res); - DISPATCH(); - } - TypeError("'%t' type does not support '__contains__'", SECOND()->type); - goto __ERROR; - } - /*****************************************/ - case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg); - case OP_POP_JUMP_IF_NOT_MATCH: { - int res = py_equal(SECOND(), TOP()); - if(res < 0) goto __ERROR; - STACK_SHRINK(2); - if(!res) DISPATCH_JUMP((int16_t)byte.arg); - DISPATCH(); - } - case OP_POP_JUMP_IF_FALSE: { - int res = py_bool(TOP()); - if(res < 0) goto __ERROR; - POP(); - if(!res) DISPATCH_JUMP((int16_t)byte.arg); - DISPATCH(); - } - case OP_POP_JUMP_IF_TRUE: { - int res = py_bool(TOP()); - if(res < 0) goto __ERROR; - POP(); - if(res) DISPATCH_JUMP((int16_t)byte.arg); - DISPATCH(); - } - case OP_JUMP_IF_TRUE_OR_POP: { - int res = py_bool(TOP()); - if(res < 0) goto __ERROR; - if(res) { - DISPATCH_JUMP((int16_t)byte.arg); - } else { - POP(); - DISPATCH(); - } - } - case OP_JUMP_IF_FALSE_OR_POP: { - int res = py_bool(TOP()); - if(res < 0) goto __ERROR; - if(!res) { - DISPATCH_JUMP((int16_t)byte.arg); - } else { - POP(); - DISPATCH(); - } - } - case OP_SHORTCUT_IF_FALSE_OR_POP: { - int res = py_bool(TOP()); - if(res < 0) goto __ERROR; - if(!res) { // [b, False] - STACK_SHRINK(2); // [] - py_newbool(SP()++, false); // [False] - DISPATCH_JUMP((int16_t)byte.arg); - } else { - POP(); // [b] - DISPATCH(); - } - } - case OP_LOOP_CONTINUE: { - DISPATCH_JUMP((int16_t)byte.arg); - } - case OP_LOOP_BREAK: { - DISPATCH_JUMP((int16_t)byte.arg); - } + TypeError("'%t' type does not support '__contains__'", SECOND()->type); + goto __ERROR; + } /*****************************************/ - case OP_CALL: { - ManagedHeap__collect_if_needed(&self->heap); - vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8); + case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg); + case OP_POP_JUMP_IF_NOT_MATCH: { + int res = py_equal(SECOND(), TOP()); + if(res < 0) goto __ERROR; + STACK_SHRINK(2); + if(!res) DISPATCH_JUMP((int16_t)byte.arg); + DISPATCH(); + } + case OP_POP_JUMP_IF_FALSE: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + POP(); + if(!res) DISPATCH_JUMP((int16_t)byte.arg); + DISPATCH(); + } + case OP_POP_JUMP_IF_TRUE: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + POP(); + if(res) DISPATCH_JUMP((int16_t)byte.arg); + DISPATCH(); + } + case OP_JUMP_IF_TRUE_OR_POP: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + if(res) { + DISPATCH_JUMP((int16_t)byte.arg); + } else { + POP(); DISPATCH(); } - case OP_CALL_VARGS: { - // [_0, _1, _2 | k1, v1, k2, v2] - uint16_t argc = byte.arg & 0xFF; - uint16_t kwargc = byte.arg >> 8; + } + case OP_JUMP_IF_FALSE_OR_POP: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + if(!res) { + DISPATCH_JUMP((int16_t)byte.arg); + } else { + POP(); + DISPATCH(); + } + } + case OP_SHORTCUT_IF_FALSE_OR_POP: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + if(!res) { // [b, False] + STACK_SHRINK(2); // [] + py_newbool(SP()++, false); // [False] + DISPATCH_JUMP((int16_t)byte.arg); + } else { + POP(); // [b] + DISPATCH(); + } + } + case OP_LOOP_CONTINUE: { + DISPATCH_JUMP((int16_t)byte.arg); + } + case OP_LOOP_BREAK: { + DISPATCH_JUMP((int16_t)byte.arg); + } + /*****************************************/ + case OP_CALL: { + ManagedHeap__collect_if_needed(&self->heap); + vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8); + DISPATCH(); + } + case OP_CALL_VARGS: { + // [_0, _1, _2 | k1, v1, k2, v2] + uint16_t argc = byte.arg & 0xFF; + uint16_t kwargc = byte.arg >> 8; - int n = 0; - py_TValue* sp = SP(); - py_TValue* p1 = sp - kwargc * 2; - py_TValue* base = p1 - argc; - py_TValue* buf = self->vectorcall_buffer; + int n = 0; + py_TValue* sp = SP(); + py_TValue* p1 = sp - kwargc * 2; + py_TValue* base = p1 - argc; + py_TValue* buf = self->vectorcall_buffer; - for(py_TValue* curr = base; curr != p1; curr++) { - if(curr->type != tp_star_wrapper) { - buf[n++] = *curr; - } else { - py_TValue* args = py_getslot(curr, 0); - py_TValue* p; - int length = pk_arrayview(args, &p); - if(length != -1) { - for(int j = 0; j < length; j++) { - buf[n++] = p[j]; - } - argc += length - 1; - } else { - TypeError("*args must be a list or tuple, got '%t'", args->type); - goto __ERROR; + for(py_TValue* curr = base; curr != p1; curr++) { + if(curr->type != tp_star_wrapper) { + buf[n++] = *curr; + } else { + py_TValue* args = py_getslot(curr, 0); + py_TValue* p; + int length = pk_arrayview(args, &p); + if(length != -1) { + for(int j = 0; j < length; j++) { + buf[n++] = p[j]; } + argc += length - 1; + } else { + TypeError("*args must be a list or tuple, got '%t'", args->type); + goto __ERROR; } } + } - for(py_TValue* curr = p1; curr != sp; curr += 2) { - if(curr[1].type != tp_star_wrapper) { - buf[n++] = curr[0]; - buf[n++] = curr[1]; + for(py_TValue* curr = p1; curr != sp; curr += 2) { + if(curr[1].type != tp_star_wrapper) { + buf[n++] = curr[0]; + buf[n++] = curr[1]; + } else { + assert(py_toint(&curr[0]) == 0); + py_TValue* kwargs = py_getslot(&curr[1], 0); + if(kwargs->type == tp_dict) { + py_TValue* p = buf + n; + if(!py_dict_apply(kwargs, unpack_dict_to_buffer, &p)) goto __ERROR; + n = p - buf; + kwargc += py_dict_len(kwargs) - 1; } else { - assert(py_toint(&curr[0]) == 0); - py_TValue* kwargs = py_getslot(&curr[1], 0); - if(kwargs->type == tp_dict) { - py_TValue* p = buf + n; - if(!py_dict_apply(kwargs, unpack_dict_to_buffer, &p)) goto __ERROR; - n = p - buf; - kwargc += py_dict_len(kwargs) - 1; - } else { - TypeError("**kwargs must be a dict, got '%t'", kwargs->type); - goto __ERROR; - } + TypeError("**kwargs must be a dict, got '%t'", kwargs->type); + goto __ERROR; } } - - memcpy(base, buf, n * sizeof(py_TValue)); - SP() = base + n; - - vectorcall_opcall(argc, kwargc); - DISPATCH(); } - case OP_RETURN_VALUE: { - CHECK_RETURN_FROM_EXCEPT_OR_FINALLY(); - if(byte.arg == BC_NOARG) { - self->last_retval = POPX(); - } else { - py_newnone(&self->last_retval); - } - VM__pop_frame(self); - if(frame == base_frame) { // [ frameBase<- ] - return RES_RETURN; - } else { - frame = self->top_frame; - PUSH(&self->last_retval); - goto __NEXT_FRAME; - } - DISPATCH(); + + memcpy(base, buf, n * sizeof(py_TValue)); + SP() = base + n; + + vectorcall_opcall(argc, kwargc); + DISPATCH(); + } + case OP_RETURN_VALUE: { + CHECK_RETURN_FROM_EXCEPT_OR_FINALLY(); + if(byte.arg == BC_NOARG) { + self->last_retval = POPX(); + } else { + py_newnone(&self->last_retval); } - case OP_YIELD_VALUE: { - CHECK_RETURN_FROM_EXCEPT_OR_FINALLY(); - if(byte.arg == 1) { - py_newnone(py_retval()); - } else { - py_assign(py_retval(), TOP()); - POP(); - } + VM__pop_frame(self); + if(frame == base_frame) { // [ frameBase<- ] + return RES_RETURN; + } else { + frame = self->top_frame; + PUSH(&self->last_retval); + goto __NEXT_FRAME; + } + DISPATCH(); + } + case OP_YIELD_VALUE: { + CHECK_RETURN_FROM_EXCEPT_OR_FINALLY(); + if(byte.arg == 1) { + py_newnone(py_retval()); + } else { + py_assign(py_retval(), TOP()); + POP(); + } + return RES_YIELD; + } + case OP_FOR_ITER_YIELD_VALUE: { + CHECK_RETURN_FROM_EXCEPT_OR_FINALLY(); + int res = py_next(TOP()); + if(res == -1) goto __ERROR; + if(res) { return RES_YIELD; + } else { + assert(self->last_retval.type == tp_StopIteration); + py_ObjectRef value = py_getslot(&self->last_retval, 0); + if(py_isnil(value)) value = py_None(); + *TOP() = *value; // [iter] -> [retval] + DISPATCH_JUMP((int16_t)byte.arg); } - case OP_FOR_ITER_YIELD_VALUE: { - CHECK_RETURN_FROM_EXCEPT_OR_FINALLY(); - int res = py_next(TOP()); - if(res == -1) goto __ERROR; - if(res) { - return RES_YIELD; - } else { - assert(self->last_retval.type == tp_StopIteration); - py_ObjectRef value = py_getslot(&self->last_retval, 0); - if(py_isnil(value)) value = py_None(); - *TOP() = *value; // [iter] -> [retval] - DISPATCH_JUMP((int16_t)byte.arg); - } - } - ///////// - case OP_LIST_APPEND: { - // [list, iter, value] - py_list_append(THIRD(), TOP()); - POP(); - DISPATCH(); - } - case OP_DICT_ADD: { - // [dict, iter, key, value] - bool ok = py_dict_setitem(FOURTH(), SECOND(), TOP()); - if(!ok) goto __ERROR; - STACK_SHRINK(2); - DISPATCH(); - } - case OP_SET_ADD: { - // [set, iter, value] - py_push(THIRD()); // [| set] - if(!py_pushmethod(py_name("add"))) { - c11__abort("OP_SET_ADD: failed to load method 'add'"); - } // [|add() set] - py_push(THIRD()); - if(!py_vectorcall(1, 0)) goto __ERROR; - POP(); - DISPATCH(); - } - ///////// - case OP_UNARY_NEGATIVE: { - if(!pk_callmagic(__neg__, 1, TOP())) goto __ERROR; - *TOP() = self->last_retval; - DISPATCH(); - } - case OP_UNARY_NOT: { - int res = py_bool(TOP()); - if(res < 0) goto __ERROR; - py_newbool(TOP(), !res); - DISPATCH(); - } - case OP_UNARY_STAR: { - py_TValue value = POPX(); - int* level = py_newobject(SP()++, tp_star_wrapper, 1, sizeof(int)); - *level = byte.arg; - py_setslot(TOP(), 0, &value); - DISPATCH(); - } - case OP_UNARY_INVERT: { - if(!pk_callmagic(__invert__, 1, TOP())) goto __ERROR; - *TOP() = self->last_retval; - DISPATCH(); - } - //////////////// - case OP_GET_ITER: { - if(!py_iter(TOP())) goto __ERROR; - *TOP() = *py_retval(); - DISPATCH(); - } - case OP_FOR_ITER: { - int res = py_next(TOP()); - if(res == -1) goto __ERROR; - if(res) { - PUSH(py_retval()); - DISPATCH(); - } else { - assert(self->last_retval.type == tp_StopIteration); - POP(); // [iter] -> [] - DISPATCH_JUMP((int16_t)byte.arg); - } - } - //////// - case OP_IMPORT_PATH: { - py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg); - const char* path = py_tostr(path_object); - int res = py_import(path); - if(res == -1) goto __ERROR; - if(res == 0) { - ImportError("No module named '%s'", path); - goto __ERROR; - } + } + ///////// + case OP_LIST_APPEND: { + // [list, iter, value] + py_list_append(THIRD(), TOP()); + POP(); + DISPATCH(); + } + case OP_DICT_ADD: { + // [dict, iter, key, value] + bool ok = py_dict_setitem(FOURTH(), SECOND(), TOP()); + if(!ok) goto __ERROR; + STACK_SHRINK(2); + DISPATCH(); + } + case OP_SET_ADD: { + // [set, iter, value] + py_push(THIRD()); // [| set] + if(!py_pushmethod(py_name("add"))) { + c11__abort("OP_SET_ADD: failed to load method 'add'"); + } // [|add() set] + py_push(THIRD()); + if(!py_vectorcall(1, 0)) goto __ERROR; + POP(); + DISPATCH(); + } + ///////// + case OP_UNARY_NEGATIVE: { + if(!pk_callmagic(__neg__, 1, TOP())) goto __ERROR; + *TOP() = self->last_retval; + DISPATCH(); + } + case OP_UNARY_NOT: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + py_newbool(TOP(), !res); + DISPATCH(); + } + case OP_UNARY_STAR: { + py_TValue value = POPX(); + int* level = py_newobject(SP()++, tp_star_wrapper, 1, sizeof(int)); + *level = byte.arg; + py_setslot(TOP(), 0, &value); + DISPATCH(); + } + case OP_UNARY_INVERT: { + if(!pk_callmagic(__invert__, 1, TOP())) goto __ERROR; + *TOP() = self->last_retval; + DISPATCH(); + } + //////////////// + case OP_GET_ITER: { + if(!py_iter(TOP())) goto __ERROR; + *TOP() = *py_retval(); + DISPATCH(); + } + case OP_FOR_ITER: { + int res = py_next(TOP()); + if(res == -1) goto __ERROR; + if(res) { PUSH(py_retval()); DISPATCH(); + } else { + assert(self->last_retval.type == tp_StopIteration); + POP(); // [iter] -> [] + DISPATCH_JUMP((int16_t)byte.arg); } - case OP_POP_IMPORT_STAR: { - // [module] - NameDict* dict = PyObject__dict(TOP()->_obj); - py_ItemRef all = NameDict__try_get(dict, __all__); - if(all) { - py_TValue* p; - int length = pk_arrayview(all, &p); - if(length == -1) { - TypeError("'__all__' must be a list or tuple, got '%t'", all->type); - goto __ERROR; - } - for(int i = 0; i < length; i++) { - py_Name name = py_namev(py_tosv(p + i)); - py_ItemRef value = NameDict__try_get(dict, name); - if(value == NULL) { - ImportError("cannot import name '%n'", name); - goto __ERROR; - } else { - if(!Frame__setglobal(frame, name, value)) goto __ERROR; - } - } - } else { - for(int i = 0; i < dict->capacity; i++) { - NameDict_KV* kv = &dict->items[i]; - if(kv->key == NULL) continue; - c11_sv name = py_name2sv(kv->key); - if(name.size == 0 || name.data[0] == '_') continue; - if(!Frame__setglobal(frame, kv->key, &kv->value)) goto __ERROR; - } - } - POP(); - DISPATCH(); + } + //////// + case OP_IMPORT_PATH: { + py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg); + const char* path = py_tostr(path_object); + int res = py_import(path); + if(res == -1) goto __ERROR; + if(res == 0) { + ImportError("No module named '%s'", path); + goto __ERROR; } - //////// - case OP_UNPACK_SEQUENCE: { + PUSH(py_retval()); + DISPATCH(); + } + case OP_POP_IMPORT_STAR: { + // [module] + NameDict* dict = PyObject__dict(TOP()->_obj); + py_ItemRef all = NameDict__try_get(dict, __all__); + if(all) { py_TValue* p; - int length; - - switch(TOP()->type) { - case tp_tuple: { - length = py_tuple_len(TOP()); - p = py_tuple_data(TOP()); - break; - } - case tp_list: { - length = py_list_len(TOP()); - p = py_list_data(TOP()); - break; - } - case tp_vec2i: { - length = 2; - if(byte.arg != length) break; - c11_vec2i val = py_tovec2i(TOP()); - POP(); - py_newint(SP()++, val.x); - py_newint(SP()++, val.y); - DISPATCH(); - } - case tp_vec2: { - length = 2; - if(byte.arg != length) break; - c11_vec2 val = py_tovec2(TOP()); - POP(); - py_newfloat(SP()++, val.x); - py_newfloat(SP()++, val.y); - DISPATCH(); - } - case tp_vec3i: { - length = 3; - if(byte.arg != length) break; - c11_vec3i val = py_tovec3i(TOP()); - POP(); - py_newint(SP()++, val.x); - py_newint(SP()++, val.y); - py_newint(SP()++, val.z); - DISPATCH(); - } - case tp_vec3: { - length = 3; - if(byte.arg != length) break; - c11_vec3 val = py_tovec3(TOP()); - POP(); - py_newfloat(SP()++, val.x); - py_newfloat(SP()++, val.y); - py_newfloat(SP()++, val.z); - DISPATCH(); - } - default: { - TypeError("expected list or tuple to unpack, got %t", TOP()->type); - goto __ERROR; - } - } - if(length != byte.arg) { - ValueError("expected %d values to unpack, got %d", byte.arg, length); + int length = pk_arrayview(all, &p); + if(length == -1) { + TypeError("'__all__' must be a list or tuple, got '%t'", all->type); goto __ERROR; } - POP(); for(int i = 0; i < length; i++) { - PUSH(p + i); + py_Name name = py_namev(py_tosv(p + i)); + py_ItemRef value = NameDict__try_get(dict, name); + if(value == NULL) { + ImportError("cannot import name '%n'", name); + goto __ERROR; + } else { + if(!Frame__setglobal(frame, name, value)) goto __ERROR; + } + } + } else { + for(int i = 0; i < dict->capacity; i++) { + NameDict_KV* kv = &dict->items[i]; + if(kv->key == NULL) continue; + c11_sv name = py_name2sv(kv->key); + if(name.size == 0 || name.data[0] == '_') continue; + if(!Frame__setglobal(frame, kv->key, &kv->value)) goto __ERROR; } - DISPATCH(); } - case OP_UNPACK_EX: { - py_TValue* p; - int length = pk_arrayview(TOP(), &p); - if(length == -1) { + POP(); + DISPATCH(); + } + //////// + case OP_UNPACK_SEQUENCE: { + py_TValue* p; + int length; + + switch(TOP()->type) { + case tp_tuple: { + length = py_tuple_len(TOP()); + p = py_tuple_data(TOP()); + break; + } + case tp_list: { + length = py_list_len(TOP()); + p = py_list_data(TOP()); + break; + } + case tp_vec2i: { + length = 2; + if(byte.arg != length) break; + c11_vec2i val = py_tovec2i(TOP()); + POP(); + py_newint(SP()++, val.x); + py_newint(SP()++, val.y); + DISPATCH(); + } + case tp_vec2: { + length = 2; + if(byte.arg != length) break; + c11_vec2 val = py_tovec2(TOP()); + POP(); + py_newfloat(SP()++, val.x); + py_newfloat(SP()++, val.y); + DISPATCH(); + } + case tp_vec3i: { + length = 3; + if(byte.arg != length) break; + c11_vec3i val = py_tovec3i(TOP()); + POP(); + py_newint(SP()++, val.x); + py_newint(SP()++, val.y); + py_newint(SP()++, val.z); + DISPATCH(); + } + case tp_vec3: { + length = 3; + if(byte.arg != length) break; + c11_vec3 val = py_tovec3(TOP()); + POP(); + py_newfloat(SP()++, val.x); + py_newfloat(SP()++, val.y); + py_newfloat(SP()++, val.z); + DISPATCH(); + } + default: { TypeError("expected list or tuple to unpack, got %t", TOP()->type); goto __ERROR; } - int exceed = length - byte.arg; - if(exceed < 0) { - ValueError("not enough values to unpack"); - goto __ERROR; - } - POP(); - for(int i = 0; i < byte.arg; i++) { - PUSH(p + i); - } - py_newlistn(SP()++, exceed); - for(int i = 0; i < exceed; i++) { - py_list_setitem(TOP(), i, p + byte.arg + i); - } - DISPATCH(); } - /////////// - case OP_BEGIN_CLASS: { - // [base] - py_Name name = co_names[byte.arg]; - py_Type base; - if(py_isnone(TOP())) { - base = tp_object; - } else { - if(!py_checktype(TOP(), tp_type)) goto __ERROR; - base = py_totype(TOP()); - } - POP(); - - py_TypeInfo* base_ti = pk_typeinfo(base); - if(base_ti->is_sealed) { - TypeError("type '%t' is not an acceptable base type", base); - goto __ERROR; - } - - py_Type type = pk_newtypewithmode(name, - base, - frame->module, - NULL, - base_ti->is_python, - false, - frame->co->src->mode); - PUSH(py_tpobject(type)); - self->curr_class = TOP(); - DISPATCH(); - } - case OP_END_CLASS: { - // [cls or decorated] - py_Name name = co_names[byte.arg]; - if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; - - if(py_istype(TOP(), tp_type)) { - // call on_end_subclass - py_TypeInfo* ti = py_touserdata(TOP()); - if(ti->base != tp_object) { - py_TypeInfo* base_ti = ti->base_ti; - if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti); - } - py_TValue* slot_eq = py_getdict(&ti->self, __eq__); - py_TValue* slot_ne = py_getdict(&ti->self, __ne__); - if(slot_eq && !slot_ne) { - TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name); - goto __ERROR; - } - } - // class with decorator is unsafe currently - // it skips the above check - POP(); - self->curr_class = NULL; - DISPATCH(); - } - case OP_STORE_CLASS_ATTR: { - assert(self->curr_class); - py_Name name = co_names[byte.arg]; - // TOP() can be a function, classmethod or custom decorator - py_Ref actual_func = TOP(); - if(actual_func->type == tp_classmethod) { - actual_func = py_getslot(actual_func, 0); - } - if(actual_func->type == tp_function) { - Function* ud = py_touserdata(actual_func); - ud->clazz = self->curr_class->_obj; - } - py_setdict(self->curr_class, name, TOP()); - POP(); - DISPATCH(); - } - case OP_ADD_CLASS_ANNOTATION: { - assert(self->curr_class); - // [type_hint string] - py_TypeInfo* ti = py_touserdata(self->curr_class); - if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations); - py_Name name = co_names[byte.arg]; - bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP()); - if(!ok) goto __ERROR; - POP(); - DISPATCH(); - } - /////////// - case OP_WITH_ENTER: { - // [expr] - py_push(TOP()); - if(!py_pushmethod(__enter__)) { - TypeError("'%t' object does not support the context manager protocol", - TOP()->type); - goto __ERROR; - } - vectorcall_opcall(0, 0); - DISPATCH(); - } - case OP_WITH_EXIT: { - // [expr] - py_push(TOP()); - if(!py_pushmethod(__exit__)) { - TypeError("'%t' object does not support the context manager protocol", - TOP()->type); - goto __ERROR; - } - if(!py_vectorcall(0, 0)) goto __ERROR; - POP(); - DISPATCH(); - } - /////////// - case OP_TRY_ENTER: { - Frame__set_unwind_target(frame, SP()); - DISPATCH(); - } - case OP_EXCEPTION_MATCH: { - if(!py_checktype(TOP(), tp_type)) goto __ERROR; - bool ok = py_isinstance(&self->curr_exception, py_totype(TOP())); - py_newbool(TOP(), ok); - DISPATCH(); - } - case OP_RAISE: { - // [exception] - if(py_istype(TOP(), tp_type)) { - if(!py_tpcall(py_totype(TOP()), 0, NULL)) goto __ERROR; - py_assign(TOP(), py_retval()); - } - if(!py_isinstance(TOP(), tp_BaseException)) { - TypeError("exceptions must derive from BaseException"); - goto __ERROR; - } - py_raise(TOP()); + if(length != byte.arg) { + ValueError("expected %d values to unpack, got %d", byte.arg, length); goto __ERROR; } - case OP_RAISE_ASSERT: { - if(byte.arg) { - if(!py_str(TOP())) goto __ERROR; - POP(); - py_exception(tp_AssertionError, "%s", py_tostr(py_retval())); - } else { - py_exception(tp_AssertionError, ""); - } - goto __ERROR; + POP(); + for(int i = 0; i < length; i++) { + PUSH(p + i); } - case OP_RE_RAISE: { - if(self->curr_exception.type) { - assert(!self->is_curr_exc_handled); - goto __ERROR_RE_RAISE; - } - DISPATCH(); - } - case OP_PUSH_EXCEPTION: { - assert(self->curr_exception.type); - PUSH(&self->curr_exception); - DISPATCH(); - } - case OP_BEGIN_EXC_HANDLING: { - assert(self->curr_exception.type); - self->is_curr_exc_handled = true; - DISPATCH(); - } - case OP_END_EXC_HANDLING: { - assert(self->curr_exception.type); - py_clearexc(NULL); - DISPATCH(); - } - case OP_BEGIN_FINALLY: { - if(self->curr_exception.type) { - assert(!self->is_curr_exc_handled); - // temporarily handle the exception if any - self->is_curr_exc_handled = true; - } - DISPATCH(); - } - case OP_END_FINALLY: { - if(byte.arg == BC_NOARG) { - if(self->curr_exception.type) { - assert(self->is_curr_exc_handled); - // revert the exception handling if needed - self->is_curr_exc_handled = false; - } - } else { - // break or continue inside finally block - py_clearexc(NULL); - } - DISPATCH(); - } - ////////////////// - case OP_FORMAT_STRING: { - py_Ref spec = c11__at(py_TValue, &frame->co->consts, byte.arg); - bool ok = stack_format_object(self, py_tosv(spec)); - if(!ok) goto __ERROR; - DISPATCH(); - } - default: c11__unreachable(); + DISPATCH(); } - - c11__unreachable(); - - __ERROR: - py_BaseException__stpush(&self->curr_exception, - frame->co->src, - Frame__lineno(frame), - !frame->is_locals_special ? frame->co->name->data : NULL); - __ERROR_RE_RAISE: - do { - } while(0); - int target = Frame__prepare_jump_exception_handler(frame, &self->stack); - if(target >= 0) { - // 1. Exception can be handled inside the current frame - DISPATCH_JUMP_ABSOLUTE(target); - } else { - // 2. Exception need to be propagated to the upper frame - bool is_base_frame_to_be_popped = frame == base_frame; - VM__pop_frame(self); - if(self->top_frame == NULL || is_base_frame_to_be_popped) { - // propagate to the top level - return RES_ERROR; + case OP_UNPACK_EX: { + py_TValue* p; + int length = pk_arrayview(TOP(), &p); + if(length == -1) { + TypeError("expected list or tuple to unpack, got %t", TOP()->type); + goto __ERROR; } - frame = self->top_frame; - RESET_CO_CACHE(); + int exceed = length - byte.arg; + if(exceed < 0) { + ValueError("not enough values to unpack"); + goto __ERROR; + } + POP(); + for(int i = 0; i < byte.arg; i++) { + PUSH(p + i); + } + py_newlistn(SP()++, exceed); + for(int i = 0; i < exceed; i++) { + py_list_setitem(TOP(), i, p + byte.arg + i); + } + DISPATCH(); + } + /////////// + case OP_BEGIN_CLASS: { + // [base] + py_Name name = co_names[byte.arg]; + py_Type base; + if(py_isnone(TOP())) { + base = tp_object; + } else { + if(!py_checktype(TOP(), tp_type)) goto __ERROR; + base = py_totype(TOP()); + } + POP(); + + py_TypeInfo* base_ti = pk_typeinfo(base); + if(base_ti->is_sealed) { + TypeError("type '%t' is not an acceptable base type", base); + goto __ERROR; + } + + py_Type type = pk_newtypewithmode(name, + base, + frame->module, + NULL, + base_ti->is_python, + false, + frame->co->src->mode); + PUSH(py_tpobject(type)); + self->curr_class = TOP(); + DISPATCH(); + } + case OP_END_CLASS: { + // [cls or decorated] + py_Name name = co_names[byte.arg]; + if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; + + if(py_istype(TOP(), tp_type)) { + // call on_end_subclass + py_TypeInfo* ti = py_touserdata(TOP()); + if(ti->base != tp_object) { + py_TypeInfo* base_ti = ti->base_ti; + if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti); + } + py_TValue* slot_eq = py_getdict(&ti->self, __eq__); + py_TValue* slot_ne = py_getdict(&ti->self, __ne__); + if(slot_eq && !slot_ne) { + TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name); + goto __ERROR; + } + } + // class with decorator is unsafe currently + // it skips the above check + POP(); + self->curr_class = NULL; + DISPATCH(); + } + case OP_STORE_CLASS_ATTR: { + assert(self->curr_class); + py_Name name = co_names[byte.arg]; + // TOP() can be a function, classmethod or custom decorator + py_Ref actual_func = TOP(); + if(actual_func->type == tp_classmethod) { actual_func = py_getslot(actual_func, 0); } + if(actual_func->type == tp_function) { + Function* ud = py_touserdata(actual_func); + ud->clazz = self->curr_class->_obj; + } + py_setdict(self->curr_class, name, TOP()); + POP(); + DISPATCH(); + } + case OP_ADD_CLASS_ANNOTATION: { + assert(self->curr_class); + // [type_hint string] + py_TypeInfo* ti = py_touserdata(self->curr_class); + if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations); + py_Name name = co_names[byte.arg]; + bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP()); + if(!ok) goto __ERROR; + POP(); + DISPATCH(); + } + /////////// + case OP_WITH_ENTER: { + // [expr] + py_push(TOP()); + if(!py_pushmethod(__enter__)) { + TypeError("'%t' object does not support the context manager protocol", TOP()->type); + goto __ERROR; + } + vectorcall_opcall(0, 0); + DISPATCH(); + } + case OP_WITH_EXIT: { + // [expr] + py_push(TOP()); + if(!py_pushmethod(__exit__)) { + TypeError("'%t' object does not support the context manager protocol", TOP()->type); + goto __ERROR; + } + if(!py_vectorcall(0, 0)) goto __ERROR; + POP(); + DISPATCH(); + } + /////////// + case OP_TRY_ENTER: { + Frame__set_unwind_target(frame, SP()); + DISPATCH(); + } + case OP_EXCEPTION_MATCH: { + if(!py_checktype(TOP(), tp_type)) goto __ERROR; + bool ok = py_isinstance(&self->curr_exception, py_totype(TOP())); + py_newbool(TOP(), ok); + DISPATCH(); + } + case OP_RAISE: { + // [exception] + if(py_istype(TOP(), tp_type)) { + if(!py_tpcall(py_totype(TOP()), 0, NULL)) goto __ERROR; + py_assign(TOP(), py_retval()); + } + if(!py_isinstance(TOP(), tp_BaseException)) { + TypeError("exceptions must derive from BaseException"); + goto __ERROR; + } + py_raise(TOP()); goto __ERROR; } + case OP_RAISE_ASSERT: { + if(byte.arg) { + if(!py_str(TOP())) goto __ERROR; + POP(); + py_exception(tp_AssertionError, "%s", py_tostr(py_retval())); + } else { + py_exception(tp_AssertionError, ""); + } + goto __ERROR; + } + case OP_RE_RAISE: { + if(self->curr_exception.type) { + assert(!self->is_curr_exc_handled); + goto __ERROR_RE_RAISE; + } + DISPATCH(); + } + case OP_PUSH_EXCEPTION: { + assert(self->curr_exception.type); + PUSH(&self->curr_exception); + DISPATCH(); + } + case OP_BEGIN_EXC_HANDLING: { + assert(self->curr_exception.type); + self->is_curr_exc_handled = true; + DISPATCH(); + } + case OP_END_EXC_HANDLING: { + assert(self->curr_exception.type); + py_clearexc(NULL); + DISPATCH(); + } + case OP_BEGIN_FINALLY: { + if(self->curr_exception.type) { + assert(!self->is_curr_exc_handled); + // temporarily handle the exception if any + self->is_curr_exc_handled = true; + } + DISPATCH(); + } + case OP_END_FINALLY: { + if(byte.arg == BC_NOARG) { + if(self->curr_exception.type) { + assert(self->is_curr_exc_handled); + // revert the exception handling if needed + self->is_curr_exc_handled = false; + } + } else { + // break or continue inside finally block + py_clearexc(NULL); + } + DISPATCH(); + } + ////////////////// + case OP_FORMAT_STRING: { + py_Ref spec = c11__at(py_TValue, &frame->co->consts, byte.arg); + bool ok = stack_format_object(self, py_tosv(spec)); + if(!ok) goto __ERROR; + DISPATCH(); + } + default: c11__unreachable(); } - return RES_RETURN; + c11__unreachable(); + +__ERROR: + py_BaseException__stpush(&self->curr_exception, + frame->co->src, + Frame__lineno(frame), + !frame->is_locals_special ? frame->co->name->data : NULL); +__ERROR_RE_RAISE: + do { + } while(0); + + int target = Frame__prepare_jump_exception_handler(frame, &self->stack); + if(target >= 0) { + // 1. Exception can be handled inside the current frame + DISPATCH_JUMP_ABSOLUTE(target); + } else { + // 2. Exception need to be propagated to the upper frame + bool is_base_frame_to_be_popped = frame == base_frame; + VM__pop_frame(self); + if(self->top_frame == NULL || is_base_frame_to_be_popped) { + // propagate to the top level + return RES_ERROR; + } + frame = self->top_frame; + RESET_CO_CACHE(); + goto __ERROR; + } + + c11__unreachable(); } const char* pk_op2str(py_Name op) {