diff --git a/include/pocketpy/common/config.h b/include/pocketpy/common/config.h index 7e126bdc..65305e9e 100644 --- a/include/pocketpy/common/config.h +++ b/include/pocketpy/common/config.h @@ -43,8 +43,8 @@ /*************** internal settings ***************/ -// This is the maximum size of the value stack in PyVar units -// The actual size in bytes equals `sizeof(PyVar) * PK_VM_STACK_SIZE` +// This is the maximum size of the value stack in py_TValue units +// The actual size in bytes equals `sizeof(py_TValue) * PK_VM_STACK_SIZE` #define PK_VM_STACK_SIZE 16384 // This is the maximum number of local variables in a function diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 692893f6..b51fb1a8 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -11,14 +11,14 @@ extern "C" { #endif -PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, py_Name name); -pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co); +py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name); +pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co); typedef struct ValueStack { // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`. - PyVar* sp; - PyVar* end; - PyVar begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128]; + py_TValue* sp; + py_TValue* end; + py_TValue begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128]; } ValueStack; void ValueStack__ctor(ValueStack* self); @@ -39,14 +39,14 @@ typedef struct Frame { const CodeObject* co; PyObject* module; PyObject* function; // a function object or NULL (global scope) - PyVar* p0; // unwinding base - PyVar* locals; // locals base + py_TValue* p0; // unwinding base + py_TValue* locals; // locals base const CodeObject* locals_co; UnwindTarget* uw_list; } Frame; -Frame* Frame__new(const CodeObject* co, const PyVar* module, const PyVar* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co); +Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co); void Frame__delete(Frame* self); PK_INLINE int Frame__ip(const Frame* self){ @@ -67,11 +67,11 @@ PK_INLINE pk_NameDict* Frame__f_globals(Frame* self){ return PyObject__dict(self->module); } -PK_INLINE PyVar* Frame__f_globals_try_get(Frame* self, py_Name name){ +PK_INLINE py_TValue* Frame__f_globals_try_get(Frame* self, py_Name name){ return pk_NameDict__try_get(Frame__f_globals(self), name); } -PyVar* Frame__f_closure_try_get(Frame* self, py_Name name); +py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name); int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*); void Frame__prepare_jump_break(Frame* self, ValueStack*, int); @@ -80,7 +80,7 @@ int Frame__exit_block(Frame* self, ValueStack*, int); void Frame__gc_mark(Frame* self); UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock); -void Frame__set_unwind_target(Frame* self, PyVar* sp); +void Frame__set_unwind_target(Frame* self, py_TValue* sp); #ifdef __cplusplus } @@ -92,7 +92,7 @@ void Frame__set_unwind_target(Frame* self, PyVar* sp); #include "pocketpy/objects/codeobject.hpp" extern "C"{ - inline PyVar* Frame__f_closure_try_get(Frame* self, StrName name){ + inline py_TValue* Frame__f_closure_try_get(Frame* self, StrName name){ if(self->function == NULL) return NULL; pkpy::Function* fn = PyObject__as(pkpy::Function, self->function); if(fn->_closure == nullptr) return nullptr; diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index ecdfeb22..b7056193 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -12,8 +12,8 @@ typedef struct pk_TypeInfo{ py_Name name; py_Type base; - PyVar self; // the type object itself - PyVar module; // the module where the type is defined + py_TValue self; // the type object itself + py_TValue module; // the module where the type is defined bool subclass_enabled; void (*dtor)(void*); @@ -38,7 +38,7 @@ typedef struct pk_TypeInfo{ py_CFunction on_end_subclass; // for enum module } pk_TypeInfo; -void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const PyVar* module, bool subclass_enabled); +void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled); void pk_TypeInfo__dtor(pk_TypeInfo* self); typedef struct pk_VM { @@ -47,24 +47,24 @@ typedef struct pk_VM { pk_NameDict modules; c11_vector/*T=pk_TypeInfo*/ types; - PyVar StopIteration; // a special Exception class - PyVar builtins; // builtins module - PyVar main; // __main__ module + py_TValue StopIteration; // a special Exception class + py_TValue builtins; // builtins module + py_TValue main; // __main__ module void (*_ceval_on_step)(Frame*, Bytecode); unsigned char* (*_import_file)(const char*); - void (*_stdout)(const char*); - void (*_stderr)(const char*); + void (*_stdout)(const char*, ...); + void (*_stderr)(const char*, ...); // singleton objects - PyVar True, False, None, NotImplemented, Ellipsis; + py_TValue True, False, None, NotImplemented, Ellipsis; // last error py_Error* last_error; PyObject* __curr_class; PyObject* __cached_object_new; FuncDecl_ __dynamic_func_decl; - PyVar __vectorcall_buffer[PK_MAX_CO_VARNAMES]; + py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES]; pk_ManagedHeap heap; ValueStack stack; // put `stack` at the end for better cache locality @@ -87,7 +87,7 @@ typedef enum pk_FrameResult{ pk_FrameResult pk_VM__run_top_frame(pk_VM* self); -py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const PyVar* module, bool subclass_enabled); +py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled); #ifdef __cplusplus } diff --git a/include/pocketpy/objects/base.h b/include/pocketpy/objects/base.h index 94436cc0..1cd86034 100644 --- a/include/pocketpy/objects/base.h +++ b/include/pocketpy/objects/base.h @@ -14,8 +14,9 @@ extern "C" { #endif typedef int16_t py_Type; +typedef struct PyObject PyObject; -typedef struct PyVar{ +typedef struct py_TValue{ py_Type type; bool is_ptr; int extra; @@ -26,9 +27,9 @@ typedef struct PyVar{ void* _ptr; // Vec2 }; -} PyVar; +} py_TValue; -static_assert(sizeof(PyVar) <= 16, "!sizeof(PyVar) <= 16"); +static_assert(sizeof(py_TValue) <= 16, "!sizeof(py_TValue) <= 16"); /* predefined vars */ static const py_Type tp_object = {1}, tp_type = {2}; @@ -44,7 +45,7 @@ static const py_Type tp_ellipsis = {26}; static const py_Type tp_op_call = {27}, tp_op_yield = {28}; static const py_Type tp_syntax_error = {29}, tp_stop_iteration = {30}; -extern PyVar PY_NULL, PY_OP_CALL, PY_OP_YIELD; +extern py_TValue PY_NULL, PY_OP_CALL, PY_OP_YIELD; #ifdef __cplusplus } diff --git a/include/pocketpy/objects/codeobject.h b/include/pocketpy/objects/codeobject.h index 0264e6d6..c7c487cb 100644 --- a/include/pocketpy/objects/codeobject.h +++ b/include/pocketpy/objects/codeobject.h @@ -74,7 +74,7 @@ typedef struct CodeObject { c11_vector/*T=Bytecode*/ codes; c11_vector/*T=CodeObjectByteCodeEx*/ codes_ex; - c11_vector/*T=PyVar*/ consts; // constants + c11_vector/*T=py_TValue*/ consts; // constants c11_vector/*T=StrName*/ varnames; // local variables int nlocals; // cached varnames.size() @@ -95,7 +95,7 @@ void CodeObject__gc_mark(const CodeObject* self); typedef struct FuncDeclKwArg{ int index; // index in co->varnames uint16_t key; // name of this argument - PyVar value; // default value + py_TValue value; // default value } FuncDeclKwArg; typedef struct FuncDecl { @@ -119,7 +119,7 @@ typedef FuncDecl* FuncDecl_; FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_string name); void FuncDecl__dtor(FuncDecl* self); -void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const PyVar* value); +void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value); void FuncDecl__gc_mark(const FuncDecl* self); #ifdef __cplusplus diff --git a/include/pocketpy/objects/dict.h b/include/pocketpy/objects/dict.h index fc8f9483..ae0a829b 100644 --- a/include/pocketpy/objects/dict.h +++ b/include/pocketpy/objects/dict.h @@ -49,7 +49,7 @@ pkpy_Dict pkpy_Dict__copy(const pkpy_Dict* self); * @param val value to set * @return `true` if the key is newly added, `false` if the key already exists */ -bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val); +bool pkpy_Dict__set(pkpy_Dict* self, py_TValue key, py_TValue val); /** * @brief Check if a key exists in the `pkpy_Dict` @@ -58,7 +58,7 @@ bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val); * @param key key to check * @return `true` if the key exists, `false` otherwise */ -bool pkpy_Dict__contains(const pkpy_Dict* self, PyVar key); +bool pkpy_Dict__contains(const pkpy_Dict* self, py_TValue key); /** * @brief Remove a key from the `pkpy_Dict` @@ -67,7 +67,7 @@ bool pkpy_Dict__contains(const pkpy_Dict* self, PyVar key); * @param key key to remove * @return `true` if the key was found and removed, `false` if the key doesn't exist */ -bool pkpy_Dict__del(pkpy_Dict* self, PyVar key); +bool pkpy_Dict__del(pkpy_Dict* self, py_TValue key); /** * @brief Try to get a value from the `pkpy_Dict` @@ -76,7 +76,7 @@ bool pkpy_Dict__del(pkpy_Dict* self, PyVar key); * @param key key to get * @return the value associated with the key, `NULL` if the key doesn't exist */ -const PyVar* pkpy_Dict__try_get(const pkpy_Dict* self, PyVar key); +const py_TValue* pkpy_Dict__try_get(const pkpy_Dict* self, py_TValue key); /** * @brief Update the `pkpy_Dict` with another one @@ -106,7 +106,7 @@ pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict* self); * @param value value will be filled with the current value, can be `NULL` if not needed * @return `true` if the iteration is still valid, `false` otherwise */ -bool pkpy_DictIter__next(pkpy_DictIter* self, PyVar* key, PyVar* value); +bool pkpy_DictIter__next(pkpy_DictIter* self, py_TValue* key, py_TValue* value); #ifdef __cplusplus } diff --git a/include/pocketpy/objects/namedict.h b/include/pocketpy/objects/namedict.h index 4e3966c9..fd2d1b78 100644 --- a/include/pocketpy/objects/namedict.h +++ b/include/pocketpy/objects/namedict.h @@ -11,7 +11,7 @@ extern "C" { #define SMALLMAP_T__HEADER #define K uint16_t -#define V PyVar +#define V py_TValue #define NAME pk_NameDict #include "pocketpy/xmacros/smallmap.h" #undef SMALLMAP_T__HEADER diff --git a/include/pocketpy/objects/object.h b/include/pocketpy/objects/object.h index afa61c35..99f3d6b0 100644 --- a/include/pocketpy/objects/object.h +++ b/include/pocketpy/objects/object.h @@ -22,18 +22,18 @@ typedef struct PyObject{ static_assert(sizeof(PyObject) <= 8, "!(sizeof(PyObject) <= 8)"); -PyVar* PyObject__slots(PyObject* self); +py_TValue* PyObject__slots(PyObject* self); pk_NameDict* PyObject__dict(PyObject* self); void* PyObject__value(PyObject* self); -#define PK_OBJ_HEADER_SIZE(slots) ((slots)>=0 ? 8+sizeof(PyVar)*(slots) : 8+sizeof(pk_NameDict)) +#define PK_OBJ_HEADER_SIZE(slots) ((slots)>=0 ? 8+sizeof(py_TValue)*(slots) : 8+sizeof(pk_NameDict)) PyObject* PyObject__new(py_Type type, int slots, int size); void PyObject__delete(PyObject* self); -PK_INLINE PyVar PyVar__fromobj(PyObject* obj){ +PK_INLINE py_TValue PyVar__fromobj(PyObject* obj){ if(!obj) return PY_NULL; - PyVar retval = { + py_TValue retval = { .type = obj->type, .is_ptr = true, ._obj = obj diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 3e1fc3b0..d3d30950 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -4,12 +4,12 @@ #include /************* Public Types *************/ -typedef struct PyObject PyObject; -typedef struct PyVar PyVar; +typedef struct py_TValue py_TValue; typedef struct pk_VM pk_VM; typedef uint16_t py_Name; typedef int16_t py_Type; -typedef PyVar* py_Ref; +typedef py_TValue* py_Ref; +typedef struct py_Str py_Str; typedef int (*py_CFunction)(int argc, py_Ref argv); typedef struct py_Error{ @@ -175,8 +175,8 @@ void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val); void py_dict__delitem(py_Ref self, const py_Ref key); void py_dict__clear(py_Ref self); -int py_str(const py_Ref, char* out); -int py_repr(const py_Ref, char* out); +int py_str(const py_Ref, py_Str* out); +int py_repr(const py_Ref, py_Str* out); #ifdef __cplusplus } diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 96503805..3328efba 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -251,7 +251,7 @@ typedef struct ImagExpr { void ImagExpr__emit_(Expr* self_, Ctx* ctx) { ImagExpr* self = (ImagExpr*)self_; - PyVar value; + py_TValue value; py_newfloat(&value, self->value); int index = Ctx__add_const(ctx, &value); Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line); @@ -282,7 +282,7 @@ void LiteralExpr__emit_(Expr* self_, Ctx* ctx) { break; } case TokenValue_F64: { - PyVar value; + py_TValue value; py_newfloat(&value, self->value->_f64); int index = Ctx__add_const(ctx, &value); Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line); @@ -1331,7 +1331,7 @@ int Ctx__emit_int(Ctx* self, int64_t value, int line) { if(is_small_int(value)) { return Ctx__emit_(self, OP_LOAD_SMALL_INT, (uint16_t)value, line); } else { - PyVar tmp; + py_TValue tmp; py_newint(&tmp, value); return Ctx__emit_(self, OP_LOAD_CONST, Ctx__add_const(self, &tmp), line); } @@ -1366,9 +1366,9 @@ int Ctx__add_const_string(Ctx* self, c11_string key) { if(val) { return *val; } else { - PyVar tmp; + py_TValue tmp; py_newstrn(&tmp, key.data, key.size); - c11_vector__push(PyVar, &self->co->consts, tmp); + c11_vector__push(py_TValue, &self->co->consts, tmp); int index = self->co->consts.count - 1; c11_smallmap_s2n__set(&self->co_consts_string_dedup_map, py_Str__sv(PyObject__value(tmp._obj)), @@ -1379,7 +1379,7 @@ int Ctx__add_const_string(Ctx* self, c11_string key) { int Ctx__add_const(Ctx* self, py_Ref v) { assert(v->type != tp_str); - c11_vector__push(PyVar, &self->co->consts, *v); + c11_vector__push(py_TValue, &self->co->consts, *v); return self->co->consts.count - 1; } diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 489243ef..0810a505 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -1,1151 +1,140 @@ -// #include "pocketpy/interpreter/ceval.h" -// #include "pocketpy/objects/base.h" +#include "pocketpy/interpreter/vm.h" +#include "pocketpy/common/memorypool.h" +#include "pocketpy/common/sstream.h" +#include "pocketpy/objects/codeobject.h" +#include "pocketpy/pocketpy.h" -// namespace pkpy { +#define DISPATCH() \ + do { \ + frame->ip++; \ + goto __NEXT_STEP; \ + } while(0) +#define DISPATCH_JUMP(__offset) \ + do { \ + frame->ip += __offset; \ + goto __NEXT_STEP; \ + } while(0) +#define DISPATCH_JUMP_ABSOLUTE(__target) \ + do { \ + frame->ip = c11__at(Bytecode, &frame->co->codes, __target); \ + goto __NEXT_STEP; \ + } while(0) -// #define PREDICT_INT_OP(op) \ -// if(is_int(_0) && is_int(_1)) { \ -// TOP() = VAR(_0._i64 op _1._i64); \ -// DISPATCH() \ -// } +/* Stack manipulation macros */ +// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123 +#define TOP() self->stack.sp[-1] +#define SECOND() self->stack.sp[-2] +#define THIRD() self->stack.sp[-3] +#define STACK_SHRINK(n) (self->stack.sp -= n) +#define PUSH(v) (*self->stack.sp++ = v) +#define POP() (--self->stack.sp) +#define POPX() (*--self->stack.sp) +#define SP() (self->stack.sp) -// #define PREDICT_INT_DIV_OP(op) \ -// if(is_int(_0) && is_int(_1)) { \ -// i64 divisor = _1._i64; \ -// if(divisor == 0) ZeroDivisionError(); \ -// TOP() = VAR(_0._i64 op divisor); \ -// DISPATCH() \ -// } +pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { + Frame* frame = self->top_frame; + const Frame* base_frame = frame; -// #define BINARY_F_COMPARE(func, op, rfunc) \ -// PyVar ret; \ -// const PyTypeInfo* _ti = _tp_info(_0); \ -// if(_ti->m##func) { \ -// ret = _ti->m##func(this, _0, _1); \ -// } else { \ -// PyVar self; \ -// PyVar _2 = get_unbound_method(_0, func, &self, false); \ -// if(_2.type) \ -// ret = call_method(self, _2, _1); \ -// else \ -// ret = NotImplemented; \ -// } \ -// if(is_not_implemented(ret)) { \ -// PyVar self; \ -// PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \ -// if(_2.type) \ -// ret = call_method(self, _2, _0); \ -// else \ -// BinaryOptError(op, _0, _1); \ -// if(is_not_implemented(ret)) BinaryOptError(op, _0, _1); \ -// } + while(true) { + Bytecode byte; + __NEXT_FRAME: + // if(__internal_exception.type == InternalExceptionType::Null) { + // // None + // frame->_ip++; + // } else if(__internal_exception.type == InternalExceptionType::Handled) { + // // HandledException + continue + // frame->_ip = c11__at(Bytecode, &frame->co->codes, __internal_exception.arg); + // __internal_exception = {}; + // } else { + // // UnhandledException + continue (need_raise = true) + // // ToBeRaisedException + continue (need_raise = true) + // __internal_exception = {}; + // __raise_exc(); // no return + // } -// void VM::__op_unpack_sequence(uint16_t arg) { -// PyVar _0 = POPX(); -// if(is_type(_0, VM::tp_tuple)) { -// // fast path for tuple -// Tuple& tuple = PK_OBJ_GET(Tuple, _0); -// if(tuple.size() == arg) { -// for(PyVar obj: tuple) -// PUSH(obj); -// } else { -// ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size())); -// } -// } else { -// auto _lock = gc_scope_lock(); // lock the gc via RAII!! -// _0 = py_iter(_0); -// const PyTypeInfo* ti = _tp_info(_0); -// for(int i = 0; i < arg; i++) { -// PyVar _1 = _py_next(ti, _0); -// if(_1 == StopIteration) ValueError("not enough values to unpack"); -// PUSH(_1); -// } -// if(_py_next(ti, _0) != StopIteration) ValueError("too many values to unpack"); -// } -// } + frame->ip++; -// bool VM::py_lt(PyVar _0, PyVar _1) { -// BINARY_F_COMPARE(__lt__, "<", __gt__); -// assert(ret.type == tp_bool); -// return ret.extra; -// } + __NEXT_STEP: + byte = *frame->ip; -// bool VM::py_le(PyVar _0, PyVar _1) { -// BINARY_F_COMPARE(__le__, "<=", __ge__); -// assert(ret.type == tp_bool); -// return ret.extra; -// } + 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 _0 = TOP(); + TOP() = SECOND(); + SECOND() = THIRD(); + THIRD() = _0; + DISPATCH(); + } + case OP_PRINT_EXPR: + if(TOP().type != tp_none_type) { + py_Str out; + int err = py_repr(&TOP(), &out); + if(err) goto __ERROR; + self->_stdout("%s\n", py_Str__data(&out)); + py_Str__dtor(&out); + } + POP(); + DISPATCH(); + /*****************************************/ + case OP_LOAD_CONST: PUSH(c11__getitem(py_TValue, &frame->co->consts, byte.arg)); DISPATCH(); + case OP_LOAD_NONE: PUSH(self->None); DISPATCH(); + case OP_LOAD_TRUE: PUSH(self->True); DISPATCH(); + case OP_LOAD_FALSE: PUSH(self->False); DISPATCH(); + /*****************************************/ + case OP_LOAD_SMALL_INT: + py_newint(SP(), (int64_t)(int16_t)byte.arg); + SP()++; + DISPATCH(); + /*****************************************/ + case OP_LOAD_ELLIPSIS: PUSH(self->Ellipsis); DISPATCH(); + case OP_LOAD_FUNCTION: { + // FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg); + // py_TValue obj; + // if(decl->nested) { + // NameDict* captured = frame->_locals.to_namedict(); + // obj = + // new_object(tp_function, decl, frame->_module, nullptr, + // captured); + // uint16_t name = pk_StrName__map2(py_Str__sv(&decl->code->name)); + // captured->set(name, obj); + // } else { + // obj = new_object(tp_function, decl, frame->_module, nullptr, + // nullptr); + // } + // PUSH(obj);DISPATCH(); + } + case OP_LOAD_NULL: + py_newnull(SP()); + SP()++; + DISPATCH(); + /*****************************************/ + default: PK_UNREACHABLE(); + } -// bool VM::py_gt(PyVar _0, PyVar _1) { -// BINARY_F_COMPARE(__gt__, ">", __lt__); -// assert(ret.type == tp_bool); -// return ret.extra; -// } + assert(false); // should never reach here -// bool VM::py_ge(PyVar _0, PyVar _1) { -// BINARY_F_COMPARE(__ge__, ">=", __le__); -// assert(ret.type == tp_bool); -// return ret.extra; -// } + __ERROR: + // 1. Exception can be handled inside the current frame + // 2. Exception need to be propagated to the upper frame + assert(false); + return RES_ERROR; + } -// #undef BINARY_F_COMPARE - -// #if PK_ENABLE_PROFILER -// #define CEVAL_STEP_CALLBACK() \ -// if(_ceval_on_step) _ceval_on_step(this, frame, byte); \ -// if(_profiler) _profiler->_step(callstack.size(), frame); \ -// if(!_next_breakpoint.empty()) { _next_breakpoint._step(this); } -// #else -// #define CEVAL_STEP_CALLBACK() \ -// if(_ceval_on_step && _ceval_on_step) { \ -// if(_ceval_on_step) \ -// if(_ceval_on_step) _ceval_on_step(this, frame, byte); \ -// } -// #endif - -// #define DISPATCH() \ -// { \ -// frame->_ip++; \ -// goto __NEXT_STEP; \ -// } -// #define DISPATCH_JUMP(__offset) \ -// { \ -// frame->_ip += __offset; \ -// goto __NEXT_STEP; \ -// } -// #define DISPATCH_JUMP_ABSOLUTE(__target) \ -// { \ -// frame->_ip = c11__at(Bytecode, &frame->co->codes, __target); \ -// goto __NEXT_STEP; \ -// } - -// PyVar VM::__run_top_frame() { -// Frame* frame = &callstack.top(); -// const Frame* base_frame = frame; -// InternalException __internal_exception; - -// while(true) { -// try { -// /**********************************************************************/ -// { -// __NEXT_FRAME: -// Bytecode byte; - -// if(__internal_exception.type == InternalExceptionType::Null) { -// // None -// frame->_ip++; -// } else if(__internal_exception.type == InternalExceptionType::Handled) { -// // HandledException + continue -// frame->_ip = c11__at(Bytecode, &frame->co->codes, __internal_exception.arg); -// __internal_exception = {}; -// } else { -// // UnhandledException + continue (need_raise = true) -// // ToBeRaisedException + continue (need_raise = true) -// __internal_exception = {}; -// __raise_exc(); // no return -// } - -// __NEXT_STEP: -// byte = *frame->_ip; -// CEVAL_STEP_CALLBACK() - -// #if PK_DEBUG_CEVAL_STEP -// __log_s_data(); -// #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: std::swap(TOP(), SECOND()); DISPATCH() -// case OP_ROT_THREE: { -// // [a, b, c] -> [c, a, b] -// PyVar _0 = TOP(); -// TOP() = SECOND(); -// SECOND() = THIRD(); -// THIRD() = _0; -// } -// DISPATCH() -// case OP_PRINT_EXPR: -// if(!is_none(TOP())) stdout_write(py_repr(TOP()) + "\n"); -// POP(); -// DISPATCH() -// /*****************************************/ -// case OP_LOAD_CONST: -// PUSH(c11__getitem(PyVar, &frame->co->consts, byte.arg)); -// DISPATCH() -// case OP_LOAD_NONE: PUSH(None); DISPATCH() -// case OP_LOAD_TRUE: PUSH(True); DISPATCH() -// case OP_LOAD_FALSE: PUSH(False); DISPATCH() -// /*****************************************/ -// case OP_LOAD_SMALL_INT: s_data.emplace(tp_int, (i64)(int16_t)byte.arg); DISPATCH() -// /*****************************************/ -// case OP_LOAD_ELLIPSIS: PUSH(Ellipsis); DISPATCH() -// case OP_LOAD_FUNCTION: { -// FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg); -// PyVar obj; -// if(decl->nested) { -// NameDict* captured = frame->_locals.to_namedict(); -// obj = new_object(tp_function, decl, frame->_module, nullptr, captured); -// uint16_t name = pk_StrName__map2(py_Str__sv(&decl->code->name)); -// captured->set(name, obj); -// } else { -// obj = new_object(tp_function, decl, frame->_module, nullptr, nullptr); -// } -// PUSH(obj); -// } -// DISPATCH() -// case OP_LOAD_NULL: PUSH(PY_NULL); DISPATCH() -// /*****************************************/ -// case OP_LOAD_FAST: { -// PyVar _0 = frame->_locals[byte.arg]; -// if(_0 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); -// PUSH(_0); -// } -// DISPATCH() -// case OP_LOAD_NAME: { -// StrName _name(byte.arg); -// PyVar* slot = frame->_locals.try_get_name(_name); -// if(slot != nullptr) { -// if(*slot == PY_NULL) vm->UnboundLocalError(_name); -// PUSH(*slot); -// DISPATCH() -// } -// PyVar* _0 = frame->f_closure_try_get(_name); -// if(_0 != nullptr) { -// PUSH(*_0); -// DISPATCH() -// } -// _0 = frame->f_globals().try_get_2_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(*_0); -// DISPATCH() -// } -// _0 = vm->builtins->attr().try_get_2_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(*_0); -// DISPATCH() -// } -// vm->NameError(_name); -// } -// DISPATCH() -// case OP_LOAD_NONLOCAL: { -// StrName _name(byte.arg); -// PyVar* _0 = frame->f_closure_try_get(_name); -// if(_0 != nullptr) { -// PUSH(*_0); -// DISPATCH() -// } -// _0 = frame->f_globals().try_get_2_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(*_0); -// DISPATCH() -// } -// _0 = vm->builtins->attr().try_get_2_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(*_0); -// DISPATCH() -// } -// vm->NameError(_name); -// } -// DISPATCH() -// case OP_LOAD_GLOBAL: { -// StrName _name(byte.arg); -// PyVar _0 = frame->f_globals().try_get_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(_0); -// DISPATCH() -// } -// _0 = vm->builtins->attr().try_get_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(_0); -// DISPATCH() -// } -// vm->NameError(_name); -// } -// DISPATCH() -// case OP_LOAD_ATTR: { -// TOP() = getattr(TOP(), StrName(byte.arg)); -// } -// DISPATCH() -// case OP_LOAD_CLASS_GLOBAL: { -// assert(__curr_class != nullptr); -// StrName _name(byte.arg); -// PyVar _0 = getattr(__curr_class, _name, false); -// if(_0 != nullptr) { -// PUSH(_0); -// DISPATCH() -// } -// // load global if attribute not found -// _0 = frame->f_globals().try_get_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(_0); -// DISPATCH() -// } -// _0 = vm->builtins->attr().try_get_likely_found(_name); -// if(_0 != nullptr) { -// PUSH(_0); -// DISPATCH() -// } -// vm->NameError(_name); -// } -// DISPATCH() -// case OP_LOAD_METHOD: { -// PyVar _0; -// TOP() = get_unbound_method(TOP(), StrName(byte.arg), &_0, true, true); -// PUSH(_0); -// } -// DISPATCH() -// case OP_LOAD_SUBSCR: { -// PyVar _1 = POPX(); // b -// PyVar _0 = TOP(); // a -// auto _ti = _tp_info(_0); -// if(_ti->m__getitem__) { -// TOP() = _ti->m__getitem__(this, _0, _1); -// } else { -// TOP() = call_method(_0, __getitem__, _1); -// } -// } -// DISPATCH() -// case OP_LOAD_SUBSCR_FAST: { -// PyVar _1 = frame->_locals[byte.arg]; -// if(_1 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); -// PyVar _0 = TOP(); // a -// auto _ti = _tp_info(_0); -// if(_ti->m__getitem__) { -// TOP() = _ti->m__getitem__(this, _0, _1); -// } else { -// TOP() = call_method(_0, __getitem__, _1); -// } -// } -// DISPATCH() -// case OP_LOAD_SUBSCR_SMALL_INT: { -// PyVar _1 = VAR((int16_t)byte.arg); -// PyVar _0 = TOP(); // a -// auto _ti = _tp_info(_0); -// if(_ti->m__getitem__) { -// TOP() = _ti->m__getitem__(this, _0, _1); -// } else { -// TOP() = call_method(_0, __getitem__, _1); -// } -// } -// DISPATCH() -// case OP_STORE_FAST: frame->_locals[byte.arg] = POPX(); DISPATCH() -// case OP_STORE_NAME: { -// StrName _name(byte.arg); -// PyVar _0 = POPX(); -// if(frame->_callable != nullptr) { -// PyVar* slot = frame->_locals.try_get_name(_name); -// if(slot != nullptr) { -// *slot = _0; // store in locals if possible -// } else { -// Function& func = frame->_callable->as(); -// if(func.decl == __dynamic_func_decl) { -// assert(func._closure != nullptr); -// func._closure->set(_name, _0); -// } else { -// vm->NameError(_name); -// } -// } -// } else { -// frame->f_globals().set(_name, _0); -// } -// } -// DISPATCH() -// case OP_STORE_GLOBAL: frame->f_globals().set(StrName(byte.arg), POPX()); DISPATCH() -// case OP_STORE_ATTR: { -// PyVar _0 = TOP(); // a -// PyVar _1 = SECOND(); // val -// setattr(_0, StrName(byte.arg), _1); -// STACK_SHRINK(2); -// } -// DISPATCH() -// case OP_STORE_SUBSCR: { -// PyVar _2 = POPX(); // b -// PyVar _1 = POPX(); // a -// PyVar _0 = POPX(); // val -// auto _ti = _tp_info(_1); -// if(_ti->m__setitem__) { -// _ti->m__setitem__(this, _1, _2, _0); -// } else { -// call_method(_1, __setitem__, _2, _0); -// } -// } -// DISPATCH() -// case OP_STORE_SUBSCR_FAST: { -// PyVar _2 = frame->_locals[byte.arg]; // b -// if(_2 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); -// PyVar _1 = POPX(); // a -// PyVar _0 = POPX(); // val -// auto _ti = _tp_info(_1); -// if(_ti->m__setitem__) { -// _ti->m__setitem__(this, _1, _2, _0); -// } else { -// call_method(_1, __setitem__, _2, _0); -// } -// } -// DISPATCH() -// case OP_DELETE_FAST: { -// PyVar _0 = frame->_locals[byte.arg]; -// if(_0 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); -// frame->_locals[byte.arg].set_null(); -// } -// DISPATCH() -// case OP_DELETE_NAME: { -// StrName _name(byte.arg); -// if(frame->_callable != nullptr) { -// PyVar* slot = frame->_locals.try_get_name(_name); -// if(slot != nullptr) { -// slot->set_null(); -// } else { -// Function& func = frame->_callable->as(); -// if(func.decl == __dynamic_func_decl) { -// assert(func._closure != nullptr); -// bool ok = func._closure->del(_name); -// if(!ok) vm->NameError(_name); -// } else { -// vm->NameError(_name); -// } -// } -// } else { -// if(!frame->f_globals().del(_name)) vm->NameError(_name); -// } -// } -// DISPATCH() -// case OP_DELETE_GLOBAL: { -// StrName _name(byte.arg); -// if(!frame->f_globals().del(_name)) vm->NameError(_name); -// } -// DISPATCH() -// case OP_DELETE_ATTR: { -// PyVar _0 = POPX(); -// delattr(_0, StrName(byte.arg)); -// } -// DISPATCH() -// case OP_DELETE_SUBSCR: { -// PyVar _1 = POPX(); -// PyVar _0 = POPX(); -// auto _ti = _tp_info(_0); -// if(_ti->m__delitem__) { -// _ti->m__delitem__(this, _0, _1); -// } else { -// call_method(_0, __delitem__, _1); -// } -// } -// DISPATCH() -// /*****************************************/ -// case OP_BUILD_LONG: { -// PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long); -// if(_0 == nullptr) AttributeError(builtins, pk_id_long); -// TOP() = call(_0, TOP()); -// } -// DISPATCH() -// case OP_BUILD_IMAG: { -// PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex); -// if(_0 == nullptr) AttributeError(builtins, pk_id_long); -// TOP() = call(_0, VAR(0), TOP()); -// } -// DISPATCH() -// case OP_BUILD_BYTES: { -// const Str& s = CAST(Str&, TOP()); -// unsigned char* p = (unsigned char*)std::malloc(s.size); -// std::memcpy(p, s.c_str(), s.size); -// TOP() = VAR(Bytes(p, s.size)); -// } -// DISPATCH() -// case OP_BUILD_TUPLE: { -// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_tuple()); -// STACK_SHRINK(byte.arg); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_LIST: { -// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list()); -// STACK_SHRINK(byte.arg); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_DICT: { -// if(byte.arg == 0) { -// PUSH(VAR(Dict())); -// DISPATCH() -// } -// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list()); -// _0 = call(_t(tp_dict), _0); -// STACK_SHRINK(byte.arg); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_SET: { -// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list()); -// _0 = call(builtins->attr()[pk_id_set], _0); -// STACK_SHRINK(byte.arg); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_SLICE: { -// PyVar _2 = POPX(); // step -// PyVar _1 = POPX(); // stop -// PyVar _0 = POPX(); // start -// PUSH(VAR(Slice(_0, _1, _2))); -// } -// DISPATCH() -// case OP_BUILD_STRING: { -// SStream ss; -// ArgsView view = STACK_VIEW(byte.arg); -// for(PyVar obj: view) -// ss << py_str(obj); -// STACK_SHRINK(byte.arg); -// PUSH(VAR(ss.str())); -// } -// DISPATCH() -// /*****************************************/ -// case OP_BUILD_TUPLE_UNPACK: { -// List list; -// __unpack_as_list(STACK_VIEW(byte.arg), list); -// STACK_SHRINK(byte.arg); -// PyVar _0 = VAR(list.to_tuple()); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_LIST_UNPACK: { -// List list; -// __unpack_as_list(STACK_VIEW(byte.arg), list); -// STACK_SHRINK(byte.arg); -// PyVar _0 = VAR(std::move(list)); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_DICT_UNPACK: { -// Dict dict; -// __unpack_as_dict(STACK_VIEW(byte.arg), dict); -// STACK_SHRINK(byte.arg); -// PyVar _0 = VAR(std::move(dict)); -// PUSH(_0); -// } -// DISPATCH() -// case OP_BUILD_SET_UNPACK: { -// List list; -// __unpack_as_list(STACK_VIEW(byte.arg), list); -// STACK_SHRINK(byte.arg); -// PyVar _0 = VAR(std::move(list)); -// _0 = call(builtins->attr()[pk_id_set], _0); -// PUSH(_0); -// } -// DISPATCH() -// /*****************************************/ -// #define BINARY_OP_SPECIAL(func) \ -// _ti = _tp_info(_0); \ -// if(_ti->m##func) { \ -// TOP() = _ti->m##func(this, _0, _1); \ -// } else { \ -// PyVar self; \ -// PyVar _2 = get_unbound_method(_0, func, &self, false); \ -// if(_2 != nullptr) \ -// TOP() = call_method(self, _2, _1); \ -// else \ -// TOP() = NotImplemented; \ -// } - -// #define BINARY_OP_RSPECIAL(op, func) \ -// if(is_not_implemented(TOP())) { \ -// PyVar self; \ -// PyVar _2 = get_unbound_method(_1, func, &self, false); \ -// if(_2 != nullptr) \ -// TOP() = call_method(self, _2, _0); \ -// else \ -// BinaryOptError(op, _0, _1); \ -// if(is_not_implemented(TOP())) BinaryOptError(op, _0, _1); \ -// } - -// case OP_BINARY_TRUEDIV: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__truediv__); -// if(is_not_implemented(TOP())) BinaryOptError("/", _0, _1); -// } -// DISPATCH() -// case OP_BINARY_POW: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__pow__); -// if(is_not_implemented(TOP())) BinaryOptError("**", _0, _1); -// } -// DISPATCH() -// case OP_BINARY_ADD: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(+) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__add__); -// BINARY_OP_RSPECIAL("+", __radd__); -// } -// DISPATCH() -// case OP_BINARY_SUB: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(-) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__sub__); -// BINARY_OP_RSPECIAL("-", __rsub__); -// } -// DISPATCH() -// case OP_BINARY_MUL: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(*) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__mul__); -// BINARY_OP_RSPECIAL("*", __rmul__); -// } -// DISPATCH() -// case OP_BINARY_FLOORDIV: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_DIV_OP(/) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__floordiv__); -// if(is_not_implemented(TOP())) BinaryOptError("//", _0, _1); -// } -// DISPATCH() -// case OP_BINARY_MOD: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_DIV_OP(%) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__mod__); -// if(is_not_implemented(TOP())) BinaryOptError("%", _0, _1); -// } -// DISPATCH() -// case OP_COMPARE_LT: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(<) -// TOP() = VAR(py_lt(_0, _1)); -// } -// DISPATCH() -// case OP_COMPARE_LE: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(<=) -// TOP() = VAR(py_le(_0, _1)); -// } -// DISPATCH() -// case OP_COMPARE_EQ: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// TOP() = VAR(py_eq(_0, _1)); -// } -// DISPATCH() -// case OP_COMPARE_NE: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// TOP() = VAR(py_ne(_0, _1)); -// } -// DISPATCH() -// case OP_COMPARE_GT: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(>) -// TOP() = VAR(py_gt(_0, _1)); -// } -// DISPATCH() -// case OP_COMPARE_GE: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(>=) -// TOP() = VAR(py_ge(_0, _1)); -// } -// DISPATCH() -// case OP_BITWISE_LSHIFT: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(<<) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__lshift__); -// if(is_not_implemented(TOP())) BinaryOptError("<<", _0, _1); -// } -// DISPATCH() -// case OP_BITWISE_RSHIFT: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(>>) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__rshift__); -// if(is_not_implemented(TOP())) BinaryOptError(">>", _0, _1); -// } -// DISPATCH() -// case OP_BITWISE_AND: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(&) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__and__); -// if(is_not_implemented(TOP())) BinaryOptError("&", _0, _1); -// } -// DISPATCH() -// case OP_BITWISE_OR: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(|) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__or__); -// if(is_not_implemented(TOP())) BinaryOptError("|", _0, _1); -// } -// DISPATCH() -// case OP_BITWISE_XOR: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// PREDICT_INT_OP(^) -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__xor__); -// if(is_not_implemented(TOP())) BinaryOptError("^", _0, _1); -// } -// DISPATCH() -// case OP_BINARY_MATMUL: { -// PyVar _1 = POPX(); -// PyVar _0 = TOP(); -// const PyTypeInfo* _ti; -// BINARY_OP_SPECIAL(__matmul__); -// if(is_not_implemented(TOP())) BinaryOptError("@", _0, _1); -// } -// DISPATCH() - -// #undef BINARY_OP_SPECIAL -// #undef BINARY_OP_RSPECIAL -// #undef PREDICT_INT_OP - -// case OP_IS_OP: { -// PyVar _1 = POPX(); // rhs -// PyVar _0 = TOP(); // lhs -// TOP() = PyVar__IS_OP(&_0, &_1) ? True : False; -// } -// DISPATCH() -// case OP_IS_NOT_OP: { -// PyVar _1 = POPX(); // rhs -// PyVar _0 = TOP(); // lhs -// TOP() = PyVar__IS_OP(&_0, &_1) ? False : True; -// } -// DISPATCH() -// case OP_CONTAINS_OP: { -// // a in b -> b __contains__ a -// auto _ti = _tp_info(TOP()); -// PyVar _0; -// if(_ti->m__contains__) { -// _0 = _ti->m__contains__(this, TOP(), SECOND()); -// } else { -// _0 = call_method(TOP(), __contains__, SECOND()); -// } -// POP(); -// TOP() = VAR(static_cast((int)CAST(bool, _0) ^ byte.arg)); -// } -// DISPATCH() -// /*****************************************/ -// case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg) -// case OP_POP_JUMP_IF_FALSE: -// if(!py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg) -// DISPATCH() -// case OP_POP_JUMP_IF_TRUE: -// if(py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg) -// DISPATCH() -// case OP_JUMP_IF_TRUE_OR_POP: -// if(py_bool(TOP())) { -// DISPATCH_JUMP((int16_t)byte.arg) -// } else { -// POP(); -// DISPATCH() -// } -// case OP_JUMP_IF_FALSE_OR_POP: -// if(!py_bool(TOP())) { -// DISPATCH_JUMP((int16_t)byte.arg) -// } else { -// POP(); -// DISPATCH() -// } -// case OP_SHORTCUT_IF_FALSE_OR_POP: -// if(!py_bool(TOP())) { // [b, False] -// STACK_SHRINK(2); // [] -// PUSH(vm->False); // [False] -// DISPATCH_JUMP((int16_t)byte.arg) -// } else { -// POP(); // [b] -// DISPATCH() -// } -// case OP_LOOP_CONTINUE: -// // just an alias of OP_JUMP_FORWARD -// DISPATCH_JUMP((int16_t)byte.arg) -// case OP_LOOP_BREAK: { -// frame->prepare_jump_break(&s_data, frame->ip() + byte.arg); -// DISPATCH_JUMP((int16_t)byte.arg) -// } -// case OP_JUMP_ABSOLUTE_TOP: DISPATCH_JUMP_ABSOLUTE(_CAST(int, POPX())) -// case OP_GOTO: { -// StrName _name(byte.arg); -// int target = c11_smallmap_n2i__get(&frame->co->labels, byte.arg, -1); -// if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found")); -// frame->prepare_jump_break(&s_data, target); -// DISPATCH_JUMP_ABSOLUTE(target) -// } -// /*****************************************/ -// case OP_FSTRING_EVAL: { -// PyVar _0 = c11__getitem(PyVar, &frame->co->consts, byte.arg); -// std::string_view string = CAST(Str&, _0).sv(); -// // TODO: optimize this -// CodeObject* code = vm->compile(string, "", EVAL_MODE, true); -// _0 = vm->_exec(code, frame->_module, frame->_callable, frame->_locals); -// CodeObject__delete(code); -// PUSH(_0); -// } -// DISPATCH() -// case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH() -// case OP_CALL: { -// pk_ManagedHeap__collect_if_needed(&heap); -// PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC -// (byte.arg >> 8) & 0xFF, // KWARGC -// true); -// if(_0.type == tp_op_call) { -// frame = &callstack.top(); -// goto __NEXT_FRAME; -// } -// PUSH(_0); -// } -// DISPATCH() -// case OP_CALL_TP: { -// pk_ManagedHeap__collect_if_needed(&heap); -// PyVar _0; -// PyVar _1; -// PyVar _2; -// // [callable, , args: tuple, kwargs: dict | NULL] -// if(byte.arg) { -// _2 = POPX(); -// _1 = POPX(); -// for(PyVar obj: _CAST(Tuple&, _1)) -// PUSH(obj); -// _CAST(Dict&, _2).apply([this](PyVar k, PyVar v) { -// PUSH(VAR(StrName(CAST(Str&, k)).index)); -// PUSH(v); -// }); -// _0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC -// _CAST(Dict&, _2).size(), // KWARGC -// true); -// } else { -// // no **kwargs -// _1 = POPX(); -// for(PyVar obj: _CAST(Tuple&, _1)) -// PUSH(obj); -// _0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC -// 0, // KWARGC -// true); -// } -// if(_0.type == tp_op_call) { -// frame = &callstack.top(); -// goto __NEXT_FRAME; -// } -// PUSH(_0); -// } -// DISPATCH() -// case OP_RETURN_VALUE: { -// PyVar _0 = byte.arg == BC_NOARG ? POPX() : None; -// __pop_frame(); -// if(frame == base_frame) { // [ frameBase<- ] -// return _0; -// } else { -// frame = &callstack.top(); -// PUSH(_0); -// goto __NEXT_FRAME; -// } -// } -// DISPATCH() -// case OP_YIELD_VALUE: return PY_OP_YIELD; -// /*****************************************/ -// case OP_LIST_APPEND: { -// PyVar _0 = POPX(); -// PK_OBJ_GET(List, SECOND()).push_back(_0); -// } -// DISPATCH() -// case OP_DICT_ADD: { -// PyVar _0 = POPX(); -// const Tuple& t = PK_OBJ_GET(Tuple, _0); -// PK_OBJ_GET(Dict, SECOND()).set(this, t[0], t[1]); -// } -// DISPATCH() -// case OP_SET_ADD: { -// PyVar _0 = POPX(); -// call_method(SECOND(), pk_id_add, _0); -// } -// DISPATCH() -// /*****************************************/ -// case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH() -// case OP_UNARY_NOT: TOP() = VAR(!py_bool(TOP())); DISPATCH() -// case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH() -// case OP_UNARY_INVERT: { -// PyVar _0; -// auto _ti = _tp_info(TOP()); -// if(_ti->m__invert__) -// _0 = _ti->m__invert__(this, TOP()); -// else -// _0 = call_method(TOP(), __invert__); -// TOP() = _0; -// } -// DISPATCH() -// /*****************************************/ -// case OP_GET_ITER: TOP() = py_iter(TOP()); DISPATCH() -// case OP_GET_ITER_NEW: TOP() = py_iter(TOP()); DISPATCH() -// case OP_FOR_ITER: { -// PyVar _0 = py_next(TOP()); -// if(_0 == StopIteration) { -// int target = frame->prepare_loop_break(&s_data); -// DISPATCH_JUMP_ABSOLUTE(target) -// } else { -// PUSH(_0); -// DISPATCH() -// } -// } -// case OP_FOR_ITER_STORE_FAST: { -// PyVar _0 = py_next(TOP()); -// if(_0 == StopIteration) { -// int target = frame->prepare_loop_break(&s_data); -// DISPATCH_JUMP_ABSOLUTE(target) -// } else { -// frame->_locals[byte.arg] = _0; -// DISPATCH() -// } -// } -// case OP_FOR_ITER_STORE_GLOBAL: { -// PyVar _0 = py_next(TOP()); -// if(_0 == StopIteration) { -// int target = frame->prepare_loop_break(&s_data); -// DISPATCH_JUMP_ABSOLUTE(target) -// } else { -// frame->f_globals().set(StrName(byte.arg), _0); -// DISPATCH() -// } -// } -// case OP_FOR_ITER_YIELD_VALUE: { -// PyVar _0 = py_next(TOP()); -// if(_0 == StopIteration) { -// int target = frame->prepare_loop_break(&s_data); -// DISPATCH_JUMP_ABSOLUTE(target) -// } else { -// PUSH(_0); -// return PY_OP_YIELD; -// } -// } -// case OP_FOR_ITER_UNPACK: { -// PyVar _0 = TOP(); -// const PyTypeInfo* _ti = _tp_info(_0); -// if(_ti->op__next__) { -// unsigned n = _ti->op__next__(this, _0); -// if(n == 0) { -// // StopIteration -// int target = frame->prepare_loop_break(&s_data); -// DISPATCH_JUMP_ABSOLUTE(target) -// } else if(n == 1) { -// // UNPACK_SEQUENCE -// __op_unpack_sequence(byte.arg); -// } else { -// if(n != byte.arg) { -// ValueError(_S("expected ", (int)byte.arg, " values to unpack, got ", (int)n)); -// } -// } -// } else { -// // FOR_ITER -// _0 = call_method(_0, __next__); -// if(_0 != StopIteration) { -// PUSH(_0); -// // UNPACK_SEQUENCE -// __op_unpack_sequence(byte.arg); -// } else { -// int target = frame->prepare_loop_break(&s_data); -// DISPATCH_JUMP_ABSOLUTE(target) -// } -// } -// } -// DISPATCH() -// /*****************************************/ -// case OP_IMPORT_PATH: { -// PyVar _0 = c11__getitem(PyVar, &frame->co->consts, byte.arg); -// PUSH(py_import(CAST(Str&, _0))); -// } -// DISPATCH() -// case OP_POP_IMPORT_STAR: { -// PyVar _0 = POPX(); // pop the module -// PyVar _1 = _0->attr().try_get(__all__); -// StrName _name; -// if(_1 != nullptr) { -// for(PyVar key: CAST(List&, _1)) { -// _name = StrName::get(CAST(Str&, key).sv()); -// PyVar value = _0->attr().try_get_likely_found(_name); -// if(value == nullptr) { -// ImportError(_S("cannot import name ", _name.escape())); -// } else { -// frame->f_globals().set(_name, value); -// } -// } -// } else { -// for(auto& [name, value]: _0->attr().items()) { -// std::string_view s = name.sv(); -// if(s.empty() || s[0] == '_') continue; -// frame->f_globals().set(name, value); -// } -// } -// } -// DISPATCH() -// /*****************************************/ -// case OP_UNPACK_SEQUENCE: { -// __op_unpack_sequence(byte.arg); -// } -// DISPATCH() -// case OP_UNPACK_EX: { -// auto _lock = gc_scope_lock(); // lock the gc via RAII!! -// PyVar _0 = py_iter(POPX()); -// const PyTypeInfo* _ti = _tp_info(_0); -// PyVar _1; -// for(int i = 0; i < byte.arg; i++) { -// _1 = _py_next(_ti, _0); -// if(_1 == StopIteration) ValueError("not enough values to unpack"); -// PUSH(_1); -// } -// List extras; -// while(true) { -// _1 = _py_next(_ti, _0); -// if(_1 == StopIteration) break; -// extras.push_back(_1); -// } -// PUSH(VAR(std::move(extras))); -// } -// DISPATCH() -// /*****************************************/ -// case OP_BEGIN_CLASS: { -// StrName _name(byte.arg); -// PyVar _0 = POPX(); // super -// if(is_none(_0)) _0 = _t(tp_object); -// check_type(_0, tp_type); -// __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true); -// } -// DISPATCH() -// case OP_END_CLASS: { -// assert(__curr_class != nullptr); -// StrName _name(byte.arg); -// frame->_module->attr().set(_name, __curr_class); -// // call on_end_subclass -// PyTypeInfo* ti = &_all_types[__curr_class->as()]; -// if(ti->base != tp_object) { -// PyTypeInfo* base_ti = &_all_types[ti->base]; -// if(base_ti->on_end_subclass) base_ti->on_end_subclass(this, ti); -// } -// __curr_class = nullptr; -// } -// DISPATCH() -// case OP_STORE_CLASS_ATTR: { -// assert(__curr_class != nullptr); -// StrName _name(byte.arg); -// PyVar _0 = POPX(); -// if(is_type(_0, tp_function)) { PK_OBJ_GET(Function, _0)._class = __curr_class; } -// __curr_class->attr().set(_name, _0); -// } -// DISPATCH() -// case OP_BEGIN_CLASS_DECORATION: { -// PUSH(__curr_class); -// } -// DISPATCH() -// case OP_END_CLASS_DECORATION: { -// __curr_class = POPX().get(); -// } -// DISPATCH() -// case OP_ADD_CLASS_ANNOTATION: { -// assert(__curr_class != nullptr); -// StrName _name(byte.arg); -// Type type = __curr_class->as(); -// _all_types[type].annotated_fields.push_back(_name); -// } -// DISPATCH() -// /*****************************************/ -// case OP_WITH_ENTER: PUSH(call_method(TOP(), __enter__)); DISPATCH() -// case OP_WITH_EXIT: -// call_method(TOP(), __exit__); -// POP(); -// DISPATCH() -// /*****************************************/ -// case OP_TRY_ENTER: { -// frame->set_unwind_target(s_data.sp); -// DISPATCH() -// } -// case OP_EXCEPTION_MATCH: { -// PyVar assumed_type = POPX(); -// check_type(assumed_type, tp_type); -// PyVar e_obj = TOP(); -// bool ok = isinstance(e_obj, PK_OBJ_GET(Type, assumed_type)); -// PUSH(VAR(ok)); -// } -// DISPATCH() -// case OP_RAISE: { -// if(is_type(TOP(), tp_type)) { TOP() = call(TOP()); } -// if(!isinstance(TOP(), tp_exception)) { TypeError("exceptions must derive from Exception"); } -// _error(POPX()); -// } -// DISPATCH() -// case OP_RAISE_ASSERT: -// if(byte.arg) { -// Str msg = py_str(TOP()); -// POP(); -// AssertionError(msg); -// } else { -// AssertionError(); -// } -// DISPATCH() -// case OP_RE_RAISE: __raise_exc(true); DISPATCH() -// case OP_POP_EXCEPTION: __last_exception = POPX().get(); DISPATCH() -// /*****************************************/ -// case OP_FORMAT_STRING: { -// PyVar _0 = POPX(); -// const Str& spec = CAST(Str&, c11__getitem(PyVar, &frame->co->consts, byte.arg)); -// PUSH(__format_object(_0, spec)); -// } -// DISPATCH() -// /*****************************************/ -// default: PK_UNREACHABLE() -// } -// } -// /**********************************************************************/ -// PK_UNREACHABLE() -// } catch(InternalException internal) { -// __internal_exception = internal; -// if(internal.type == InternalExceptionType::Unhandled) { -// __last_exception = POPX().get(); -// Exception& _e = __last_exception->as(); -// bool is_base_frame_to_be_popped = frame == base_frame; -// __pop_frame(); -// if(callstack.empty()) { -// // propagate to the top level -// throw TopLevelException(this, &_e); -// } -// frame = &callstack.top(); -// PUSH(__last_exception); -// if(is_base_frame_to_be_popped) { throw InternalException(InternalExceptionType::ToBeRaised); } -// } -// } -// } -// } - -// #undef TOP -// #undef SECOND -// #undef THIRD -// #undef STACK_SHRINK -// #undef PUSH -// #undef POP -// #undef POPX -// #undef STACK_VIEW - -// #undef DISPATCH -// #undef DISPATCH_JUMP -// #undef CEVAL_STEP_CALLBACK - -// } // namespace pkpy + return RES_RETURN; +} diff --git a/src/interpreter/ceval.cpp b/src/interpreter/ceval.cpp new file mode 100644 index 00000000..868e0a43 --- /dev/null +++ b/src/interpreter/ceval.cpp @@ -0,0 +1,1151 @@ +#include "pocketpy/interpreter/ceval.h" +#include "pocketpy/objects/base.h" + +namespace pkpy { + +#define PREDICT_INT_OP(op) \ + if(is_int(_0) && is_int(_1)) { \ + TOP() = VAR(_0._i64 op _1._i64); \ + DISPATCH() \ + } + +#define PREDICT_INT_DIV_OP(op) \ + if(is_int(_0) && is_int(_1)) { \ + i64 divisor = _1._i64; \ + if(divisor == 0) ZeroDivisionError(); \ + TOP() = VAR(_0._i64 op divisor); \ + DISPATCH() \ + } + +#define BINARY_F_COMPARE(func, op, rfunc) \ + PyVar ret; \ + const PyTypeInfo* _ti = _tp_info(_0); \ + if(_ti->m##func) { \ + ret = _ti->m##func(this, _0, _1); \ + } else { \ + PyVar self; \ + PyVar _2 = get_unbound_method(_0, func, &self, false); \ + if(_2.type) \ + ret = call_method(self, _2, _1); \ + else \ + ret = NotImplemented; \ + } \ + if(is_not_implemented(ret)) { \ + PyVar self; \ + PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \ + if(_2.type) \ + ret = call_method(self, _2, _0); \ + else \ + BinaryOptError(op, _0, _1); \ + if(is_not_implemented(ret)) BinaryOptError(op, _0, _1); \ + } + +void VM::__op_unpack_sequence(uint16_t arg) { + PyVar _0 = POPX(); + if(is_type(_0, VM::tp_tuple)) { + // fast path for tuple + Tuple& tuple = PK_OBJ_GET(Tuple, _0); + if(tuple.size() == arg) { + for(PyVar obj: tuple) + PUSH(obj); + } else { + ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size())); + } + } else { + auto _lock = gc_scope_lock(); // lock the gc via RAII!! + _0 = py_iter(_0); + const PyTypeInfo* ti = _tp_info(_0); + for(int i = 0; i < arg; i++) { + PyVar _1 = _py_next(ti, _0); + if(_1 == StopIteration) ValueError("not enough values to unpack"); + PUSH(_1); + } + if(_py_next(ti, _0) != StopIteration) ValueError("too many values to unpack"); + } +} + +bool VM::py_lt(PyVar _0, PyVar _1) { + BINARY_F_COMPARE(__lt__, "<", __gt__); + assert(ret.type == tp_bool); + return ret.extra; +} + +bool VM::py_le(PyVar _0, PyVar _1) { + BINARY_F_COMPARE(__le__, "<=", __ge__); + assert(ret.type == tp_bool); + return ret.extra; +} + +bool VM::py_gt(PyVar _0, PyVar _1) { + BINARY_F_COMPARE(__gt__, ">", __lt__); + assert(ret.type == tp_bool); + return ret.extra; +} + +bool VM::py_ge(PyVar _0, PyVar _1) { + BINARY_F_COMPARE(__ge__, ">=", __le__); + assert(ret.type == tp_bool); + return ret.extra; +} + +#undef BINARY_F_COMPARE + +#if PK_ENABLE_PROFILER +#define CEVAL_STEP_CALLBACK() \ + if(_ceval_on_step) _ceval_on_step(this, frame, byte); \ + if(_profiler) _profiler->_step(callstack.size(), frame); \ + if(!_next_breakpoint.empty()) { _next_breakpoint._step(this); } +#else +#define CEVAL_STEP_CALLBACK() \ + if(_ceval_on_step && _ceval_on_step) { \ + if(_ceval_on_step) \ + if(_ceval_on_step) _ceval_on_step(this, frame, byte); \ + } +#endif + +#define DISPATCH() \ + { \ + frame->_ip++; \ + goto __NEXT_STEP; \ + } +#define DISPATCH_JUMP(__offset) \ + { \ + frame->_ip += __offset; \ + goto __NEXT_STEP; \ + } +#define DISPATCH_JUMP_ABSOLUTE(__target) \ + { \ + frame->_ip = c11__at(Bytecode, &frame->co->codes, __target); \ + goto __NEXT_STEP; \ + } + +PyVar VM::__run_top_frame() { + Frame* frame = &callstack.top(); + const Frame* base_frame = frame; + InternalException __internal_exception; + + while(true) { + try { + /**********************************************************************/ + { + __NEXT_FRAME: + Bytecode byte; + + if(__internal_exception.type == InternalExceptionType::Null) { + // None + frame->_ip++; + } else if(__internal_exception.type == InternalExceptionType::Handled) { + // HandledException + continue + frame->_ip = c11__at(Bytecode, &frame->co->codes, __internal_exception.arg); + __internal_exception = {}; + } else { + // UnhandledException + continue (need_raise = true) + // ToBeRaisedException + continue (need_raise = true) + __internal_exception = {}; + __raise_exc(); // no return + } + + __NEXT_STEP: + byte = *frame->_ip; + CEVAL_STEP_CALLBACK() + +#if PK_DEBUG_CEVAL_STEP + __log_s_data(); +#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: std::swap(TOP(), SECOND()); DISPATCH() + case OP_ROT_THREE: { + // [a, b, c] -> [c, a, b] + PyVar _0 = TOP(); + TOP() = SECOND(); + SECOND() = THIRD(); + THIRD() = _0; + } + DISPATCH() + case OP_PRINT_EXPR: + if(!is_none(TOP())) stdout_write(py_repr(TOP()) + "\n"); + POP(); + DISPATCH() + /*****************************************/ + case OP_LOAD_CONST: + PUSH(c11__getitem(PyVar, &frame->co->consts, byte.arg)); + DISPATCH() + case OP_LOAD_NONE: PUSH(None); DISPATCH() + case OP_LOAD_TRUE: PUSH(True); DISPATCH() + case OP_LOAD_FALSE: PUSH(False); DISPATCH() + /*****************************************/ + case OP_LOAD_SMALL_INT: s_data.emplace(tp_int, (i64)(int16_t)byte.arg); DISPATCH() + /*****************************************/ + case OP_LOAD_ELLIPSIS: PUSH(Ellipsis); DISPATCH() + case OP_LOAD_FUNCTION: { + FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg); + PyVar obj; + if(decl->nested) { + NameDict* captured = frame->_locals.to_namedict(); + obj = new_object(tp_function, decl, frame->_module, nullptr, captured); + uint16_t name = pk_StrName__map2(py_Str__sv(&decl->code->name)); + captured->set(name, obj); + } else { + obj = new_object(tp_function, decl, frame->_module, nullptr, nullptr); + } + PUSH(obj); + } + DISPATCH() + case OP_LOAD_NULL: PUSH(PY_NULL); DISPATCH() + /*****************************************/ + case OP_LOAD_FAST: { + PyVar _0 = frame->_locals[byte.arg]; + if(_0 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); + PUSH(_0); + } + DISPATCH() + case OP_LOAD_NAME: { + StrName _name(byte.arg); + PyVar* slot = frame->_locals.try_get_name(_name); + if(slot != nullptr) { + if(*slot == PY_NULL) vm->UnboundLocalError(_name); + PUSH(*slot); + DISPATCH() + } + PyVar* _0 = frame->f_closure_try_get(_name); + if(_0 != nullptr) { + PUSH(*_0); + DISPATCH() + } + _0 = frame->f_globals().try_get_2_likely_found(_name); + if(_0 != nullptr) { + PUSH(*_0); + DISPATCH() + } + _0 = vm->builtins->attr().try_get_2_likely_found(_name); + if(_0 != nullptr) { + PUSH(*_0); + DISPATCH() + } + vm->NameError(_name); + } + DISPATCH() + case OP_LOAD_NONLOCAL: { + StrName _name(byte.arg); + PyVar* _0 = frame->f_closure_try_get(_name); + if(_0 != nullptr) { + PUSH(*_0); + DISPATCH() + } + _0 = frame->f_globals().try_get_2_likely_found(_name); + if(_0 != nullptr) { + PUSH(*_0); + DISPATCH() + } + _0 = vm->builtins->attr().try_get_2_likely_found(_name); + if(_0 != nullptr) { + PUSH(*_0); + DISPATCH() + } + vm->NameError(_name); + } + DISPATCH() + case OP_LOAD_GLOBAL: { + StrName _name(byte.arg); + PyVar _0 = frame->f_globals().try_get_likely_found(_name); + if(_0 != nullptr) { + PUSH(_0); + DISPATCH() + } + _0 = vm->builtins->attr().try_get_likely_found(_name); + if(_0 != nullptr) { + PUSH(_0); + DISPATCH() + } + vm->NameError(_name); + } + DISPATCH() + case OP_LOAD_ATTR: { + TOP() = getattr(TOP(), StrName(byte.arg)); + } + DISPATCH() + case OP_LOAD_CLASS_GLOBAL: { + assert(__curr_class != nullptr); + StrName _name(byte.arg); + PyVar _0 = getattr(__curr_class, _name, false); + if(_0 != nullptr) { + PUSH(_0); + DISPATCH() + } + // load global if attribute not found + _0 = frame->f_globals().try_get_likely_found(_name); + if(_0 != nullptr) { + PUSH(_0); + DISPATCH() + } + _0 = vm->builtins->attr().try_get_likely_found(_name); + if(_0 != nullptr) { + PUSH(_0); + DISPATCH() + } + vm->NameError(_name); + } + DISPATCH() + case OP_LOAD_METHOD: { + PyVar _0; + TOP() = get_unbound_method(TOP(), StrName(byte.arg), &_0, true, true); + PUSH(_0); + } + DISPATCH() + case OP_LOAD_SUBSCR: { + PyVar _1 = POPX(); // b + PyVar _0 = TOP(); // a + auto _ti = _tp_info(_0); + if(_ti->m__getitem__) { + TOP() = _ti->m__getitem__(this, _0, _1); + } else { + TOP() = call_method(_0, __getitem__, _1); + } + } + DISPATCH() + case OP_LOAD_SUBSCR_FAST: { + PyVar _1 = frame->_locals[byte.arg]; + if(_1 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); + PyVar _0 = TOP(); // a + auto _ti = _tp_info(_0); + if(_ti->m__getitem__) { + TOP() = _ti->m__getitem__(this, _0, _1); + } else { + TOP() = call_method(_0, __getitem__, _1); + } + } + DISPATCH() + case OP_LOAD_SUBSCR_SMALL_INT: { + PyVar _1 = VAR((int16_t)byte.arg); + PyVar _0 = TOP(); // a + auto _ti = _tp_info(_0); + if(_ti->m__getitem__) { + TOP() = _ti->m__getitem__(this, _0, _1); + } else { + TOP() = call_method(_0, __getitem__, _1); + } + } + DISPATCH() + case OP_STORE_FAST: frame->_locals[byte.arg] = POPX(); DISPATCH() + case OP_STORE_NAME: { + StrName _name(byte.arg); + PyVar _0 = POPX(); + if(frame->_callable != nullptr) { + PyVar* slot = frame->_locals.try_get_name(_name); + if(slot != nullptr) { + *slot = _0; // store in locals if possible + } else { + Function& func = frame->_callable->as(); + if(func.decl == __dynamic_func_decl) { + assert(func._closure != nullptr); + func._closure->set(_name, _0); + } else { + vm->NameError(_name); + } + } + } else { + frame->f_globals().set(_name, _0); + } + } + DISPATCH() + case OP_STORE_GLOBAL: frame->f_globals().set(StrName(byte.arg), POPX()); DISPATCH() + case OP_STORE_ATTR: { + PyVar _0 = TOP(); // a + PyVar _1 = SECOND(); // val + setattr(_0, StrName(byte.arg), _1); + STACK_SHRINK(2); + } + DISPATCH() + case OP_STORE_SUBSCR: { + PyVar _2 = POPX(); // b + PyVar _1 = POPX(); // a + PyVar _0 = POPX(); // val + auto _ti = _tp_info(_1); + if(_ti->m__setitem__) { + _ti->m__setitem__(this, _1, _2, _0); + } else { + call_method(_1, __setitem__, _2, _0); + } + } + DISPATCH() + case OP_STORE_SUBSCR_FAST: { + PyVar _2 = frame->_locals[byte.arg]; // b + if(_2 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); + PyVar _1 = POPX(); // a + PyVar _0 = POPX(); // val + auto _ti = _tp_info(_1); + if(_ti->m__setitem__) { + _ti->m__setitem__(this, _1, _2, _0); + } else { + call_method(_1, __setitem__, _2, _0); + } + } + DISPATCH() + case OP_DELETE_FAST: { + PyVar _0 = frame->_locals[byte.arg]; + if(_0 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg)); + frame->_locals[byte.arg].set_null(); + } + DISPATCH() + case OP_DELETE_NAME: { + StrName _name(byte.arg); + if(frame->_callable != nullptr) { + PyVar* slot = frame->_locals.try_get_name(_name); + if(slot != nullptr) { + slot->set_null(); + } else { + Function& func = frame->_callable->as(); + if(func.decl == __dynamic_func_decl) { + assert(func._closure != nullptr); + bool ok = func._closure->del(_name); + if(!ok) vm->NameError(_name); + } else { + vm->NameError(_name); + } + } + } else { + if(!frame->f_globals().del(_name)) vm->NameError(_name); + } + } + DISPATCH() + case OP_DELETE_GLOBAL: { + StrName _name(byte.arg); + if(!frame->f_globals().del(_name)) vm->NameError(_name); + } + DISPATCH() + case OP_DELETE_ATTR: { + PyVar _0 = POPX(); + delattr(_0, StrName(byte.arg)); + } + DISPATCH() + case OP_DELETE_SUBSCR: { + PyVar _1 = POPX(); + PyVar _0 = POPX(); + auto _ti = _tp_info(_0); + if(_ti->m__delitem__) { + _ti->m__delitem__(this, _0, _1); + } else { + call_method(_0, __delitem__, _1); + } + } + DISPATCH() + /*****************************************/ + case OP_BUILD_LONG: { + PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long); + if(_0 == nullptr) AttributeError(builtins, pk_id_long); + TOP() = call(_0, TOP()); + } + DISPATCH() + case OP_BUILD_IMAG: { + PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex); + if(_0 == nullptr) AttributeError(builtins, pk_id_long); + TOP() = call(_0, VAR(0), TOP()); + } + DISPATCH() + case OP_BUILD_BYTES: { + const Str& s = CAST(Str&, TOP()); + unsigned char* p = (unsigned char*)std::malloc(s.size); + std::memcpy(p, s.c_str(), s.size); + TOP() = VAR(Bytes(p, s.size)); + } + DISPATCH() + case OP_BUILD_TUPLE: { + PyVar _0 = VAR(STACK_VIEW(byte.arg).to_tuple()); + STACK_SHRINK(byte.arg); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_LIST: { + PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list()); + STACK_SHRINK(byte.arg); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_DICT: { + if(byte.arg == 0) { + PUSH(VAR(Dict())); + DISPATCH() + } + PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list()); + _0 = call(_t(tp_dict), _0); + STACK_SHRINK(byte.arg); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_SET: { + PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list()); + _0 = call(builtins->attr()[pk_id_set], _0); + STACK_SHRINK(byte.arg); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_SLICE: { + PyVar _2 = POPX(); // step + PyVar _1 = POPX(); // stop + PyVar _0 = POPX(); // start + PUSH(VAR(Slice(_0, _1, _2))); + } + DISPATCH() + case OP_BUILD_STRING: { + SStream ss; + ArgsView view = STACK_VIEW(byte.arg); + for(PyVar obj: view) + ss << py_str(obj); + STACK_SHRINK(byte.arg); + PUSH(VAR(ss.str())); + } + DISPATCH() + /*****************************************/ + case OP_BUILD_TUPLE_UNPACK: { + List list; + __unpack_as_list(STACK_VIEW(byte.arg), list); + STACK_SHRINK(byte.arg); + PyVar _0 = VAR(list.to_tuple()); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_LIST_UNPACK: { + List list; + __unpack_as_list(STACK_VIEW(byte.arg), list); + STACK_SHRINK(byte.arg); + PyVar _0 = VAR(std::move(list)); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_DICT_UNPACK: { + Dict dict; + __unpack_as_dict(STACK_VIEW(byte.arg), dict); + STACK_SHRINK(byte.arg); + PyVar _0 = VAR(std::move(dict)); + PUSH(_0); + } + DISPATCH() + case OP_BUILD_SET_UNPACK: { + List list; + __unpack_as_list(STACK_VIEW(byte.arg), list); + STACK_SHRINK(byte.arg); + PyVar _0 = VAR(std::move(list)); + _0 = call(builtins->attr()[pk_id_set], _0); + PUSH(_0); + } + DISPATCH() + /*****************************************/ +#define BINARY_OP_SPECIAL(func) \ + _ti = _tp_info(_0); \ + if(_ti->m##func) { \ + TOP() = _ti->m##func(this, _0, _1); \ + } else { \ + PyVar self; \ + PyVar _2 = get_unbound_method(_0, func, &self, false); \ + if(_2 != nullptr) \ + TOP() = call_method(self, _2, _1); \ + else \ + TOP() = NotImplemented; \ + } + +#define BINARY_OP_RSPECIAL(op, func) \ + if(is_not_implemented(TOP())) { \ + PyVar self; \ + PyVar _2 = get_unbound_method(_1, func, &self, false); \ + if(_2 != nullptr) \ + TOP() = call_method(self, _2, _0); \ + else \ + BinaryOptError(op, _0, _1); \ + if(is_not_implemented(TOP())) BinaryOptError(op, _0, _1); \ + } + + case OP_BINARY_TRUEDIV: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__truediv__); + if(is_not_implemented(TOP())) BinaryOptError("/", _0, _1); + } + DISPATCH() + case OP_BINARY_POW: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__pow__); + if(is_not_implemented(TOP())) BinaryOptError("**", _0, _1); + } + DISPATCH() + case OP_BINARY_ADD: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(+) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__add__); + BINARY_OP_RSPECIAL("+", __radd__); + } + DISPATCH() + case OP_BINARY_SUB: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(-) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__sub__); + BINARY_OP_RSPECIAL("-", __rsub__); + } + DISPATCH() + case OP_BINARY_MUL: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(*) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__mul__); + BINARY_OP_RSPECIAL("*", __rmul__); + } + DISPATCH() + case OP_BINARY_FLOORDIV: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_DIV_OP(/) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__floordiv__); + if(is_not_implemented(TOP())) BinaryOptError("//", _0, _1); + } + DISPATCH() + case OP_BINARY_MOD: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_DIV_OP(%) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__mod__); + if(is_not_implemented(TOP())) BinaryOptError("%", _0, _1); + } + DISPATCH() + case OP_COMPARE_LT: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(<) + TOP() = VAR(py_lt(_0, _1)); + } + DISPATCH() + case OP_COMPARE_LE: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(<=) + TOP() = VAR(py_le(_0, _1)); + } + DISPATCH() + case OP_COMPARE_EQ: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + TOP() = VAR(py_eq(_0, _1)); + } + DISPATCH() + case OP_COMPARE_NE: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + TOP() = VAR(py_ne(_0, _1)); + } + DISPATCH() + case OP_COMPARE_GT: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(>) + TOP() = VAR(py_gt(_0, _1)); + } + DISPATCH() + case OP_COMPARE_GE: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(>=) + TOP() = VAR(py_ge(_0, _1)); + } + DISPATCH() + case OP_BITWISE_LSHIFT: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(<<) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__lshift__); + if(is_not_implemented(TOP())) BinaryOptError("<<", _0, _1); + } + DISPATCH() + case OP_BITWISE_RSHIFT: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(>>) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__rshift__); + if(is_not_implemented(TOP())) BinaryOptError(">>", _0, _1); + } + DISPATCH() + case OP_BITWISE_AND: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(&) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__and__); + if(is_not_implemented(TOP())) BinaryOptError("&", _0, _1); + } + DISPATCH() + case OP_BITWISE_OR: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(|) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__or__); + if(is_not_implemented(TOP())) BinaryOptError("|", _0, _1); + } + DISPATCH() + case OP_BITWISE_XOR: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + PREDICT_INT_OP(^) + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__xor__); + if(is_not_implemented(TOP())) BinaryOptError("^", _0, _1); + } + DISPATCH() + case OP_BINARY_MATMUL: { + PyVar _1 = POPX(); + PyVar _0 = TOP(); + const PyTypeInfo* _ti; + BINARY_OP_SPECIAL(__matmul__); + if(is_not_implemented(TOP())) BinaryOptError("@", _0, _1); + } + DISPATCH() + +#undef BINARY_OP_SPECIAL +#undef BINARY_OP_RSPECIAL +#undef PREDICT_INT_OP + + case OP_IS_OP: { + PyVar _1 = POPX(); // rhs + PyVar _0 = TOP(); // lhs + TOP() = PyVar__IS_OP(&_0, &_1) ? True : False; + } + DISPATCH() + case OP_IS_NOT_OP: { + PyVar _1 = POPX(); // rhs + PyVar _0 = TOP(); // lhs + TOP() = PyVar__IS_OP(&_0, &_1) ? False : True; + } + DISPATCH() + case OP_CONTAINS_OP: { + // a in b -> b __contains__ a + auto _ti = _tp_info(TOP()); + PyVar _0; + if(_ti->m__contains__) { + _0 = _ti->m__contains__(this, TOP(), SECOND()); + } else { + _0 = call_method(TOP(), __contains__, SECOND()); + } + POP(); + TOP() = VAR(static_cast((int)CAST(bool, _0) ^ byte.arg)); + } + DISPATCH() + /*****************************************/ + case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg) + case OP_POP_JUMP_IF_FALSE: + if(!py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg) + DISPATCH() + case OP_POP_JUMP_IF_TRUE: + if(py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg) + DISPATCH() + case OP_JUMP_IF_TRUE_OR_POP: + if(py_bool(TOP())) { + DISPATCH_JUMP((int16_t)byte.arg) + } else { + POP(); + DISPATCH() + } + case OP_JUMP_IF_FALSE_OR_POP: + if(!py_bool(TOP())) { + DISPATCH_JUMP((int16_t)byte.arg) + } else { + POP(); + DISPATCH() + } + case OP_SHORTCUT_IF_FALSE_OR_POP: + if(!py_bool(TOP())) { // [b, False] + STACK_SHRINK(2); // [] + PUSH(vm->False); // [False] + DISPATCH_JUMP((int16_t)byte.arg) + } else { + POP(); // [b] + DISPATCH() + } + case OP_LOOP_CONTINUE: + // just an alias of OP_JUMP_FORWARD + DISPATCH_JUMP((int16_t)byte.arg) + case OP_LOOP_BREAK: { + frame->prepare_jump_break(&s_data, frame->ip() + byte.arg); + DISPATCH_JUMP((int16_t)byte.arg) + } + case OP_JUMP_ABSOLUTE_TOP: DISPATCH_JUMP_ABSOLUTE(_CAST(int, POPX())) + case OP_GOTO: { + StrName _name(byte.arg); + int target = c11_smallmap_n2i__get(&frame->co->labels, byte.arg, -1); + if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found")); + frame->prepare_jump_break(&s_data, target); + DISPATCH_JUMP_ABSOLUTE(target) + } + /*****************************************/ + case OP_FSTRING_EVAL: { + PyVar _0 = c11__getitem(PyVar, &frame->co->consts, byte.arg); + std::string_view string = CAST(Str&, _0).sv(); + // TODO: optimize this + CodeObject* code = vm->compile(string, "", EVAL_MODE, true); + _0 = vm->_exec(code, frame->_module, frame->_callable, frame->_locals); + CodeObject__delete(code); + PUSH(_0); + } + DISPATCH() + case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH() + case OP_CALL: { + pk_ManagedHeap__collect_if_needed(&heap); + PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC + (byte.arg >> 8) & 0xFF, // KWARGC + true); + if(_0.type == tp_op_call) { + frame = &callstack.top(); + goto __NEXT_FRAME; + } + PUSH(_0); + } + DISPATCH() + case OP_CALL_TP: { + pk_ManagedHeap__collect_if_needed(&heap); + PyVar _0; + PyVar _1; + PyVar _2; + // [callable, , args: tuple, kwargs: dict | NULL] + if(byte.arg) { + _2 = POPX(); + _1 = POPX(); + for(PyVar obj: _CAST(Tuple&, _1)) + PUSH(obj); + _CAST(Dict&, _2).apply([this](PyVar k, PyVar v) { + PUSH(VAR(StrName(CAST(Str&, k)).index)); + PUSH(v); + }); + _0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC + _CAST(Dict&, _2).size(), // KWARGC + true); + } else { + // no **kwargs + _1 = POPX(); + for(PyVar obj: _CAST(Tuple&, _1)) + PUSH(obj); + _0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC + 0, // KWARGC + true); + } + if(_0.type == tp_op_call) { + frame = &callstack.top(); + goto __NEXT_FRAME; + } + PUSH(_0); + } + DISPATCH() + case OP_RETURN_VALUE: { + PyVar _0 = byte.arg == BC_NOARG ? POPX() : None; + __pop_frame(); + if(frame == base_frame) { // [ frameBase<- ] + return _0; + } else { + frame = &callstack.top(); + PUSH(_0); + goto __NEXT_FRAME; + } + } + DISPATCH() + case OP_YIELD_VALUE: return PY_OP_YIELD; + /*****************************************/ + case OP_LIST_APPEND: { + PyVar _0 = POPX(); + PK_OBJ_GET(List, SECOND()).push_back(_0); + } + DISPATCH() + case OP_DICT_ADD: { + PyVar _0 = POPX(); + const Tuple& t = PK_OBJ_GET(Tuple, _0); + PK_OBJ_GET(Dict, SECOND()).set(this, t[0], t[1]); + } + DISPATCH() + case OP_SET_ADD: { + PyVar _0 = POPX(); + call_method(SECOND(), pk_id_add, _0); + } + DISPATCH() + /*****************************************/ + case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH() + case OP_UNARY_NOT: TOP() = VAR(!py_bool(TOP())); DISPATCH() + case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH() + case OP_UNARY_INVERT: { + PyVar _0; + auto _ti = _tp_info(TOP()); + if(_ti->m__invert__) + _0 = _ti->m__invert__(this, TOP()); + else + _0 = call_method(TOP(), __invert__); + TOP() = _0; + } + DISPATCH() + /*****************************************/ + case OP_GET_ITER: TOP() = py_iter(TOP()); DISPATCH() + case OP_GET_ITER_NEW: TOP() = py_iter(TOP()); DISPATCH() + case OP_FOR_ITER: { + PyVar _0 = py_next(TOP()); + if(_0 == StopIteration) { + int target = frame->prepare_loop_break(&s_data); + DISPATCH_JUMP_ABSOLUTE(target) + } else { + PUSH(_0); + DISPATCH() + } + } + case OP_FOR_ITER_STORE_FAST: { + PyVar _0 = py_next(TOP()); + if(_0 == StopIteration) { + int target = frame->prepare_loop_break(&s_data); + DISPATCH_JUMP_ABSOLUTE(target) + } else { + frame->_locals[byte.arg] = _0; + DISPATCH() + } + } + case OP_FOR_ITER_STORE_GLOBAL: { + PyVar _0 = py_next(TOP()); + if(_0 == StopIteration) { + int target = frame->prepare_loop_break(&s_data); + DISPATCH_JUMP_ABSOLUTE(target) + } else { + frame->f_globals().set(StrName(byte.arg), _0); + DISPATCH() + } + } + case OP_FOR_ITER_YIELD_VALUE: { + PyVar _0 = py_next(TOP()); + if(_0 == StopIteration) { + int target = frame->prepare_loop_break(&s_data); + DISPATCH_JUMP_ABSOLUTE(target) + } else { + PUSH(_0); + return PY_OP_YIELD; + } + } + case OP_FOR_ITER_UNPACK: { + PyVar _0 = TOP(); + const PyTypeInfo* _ti = _tp_info(_0); + if(_ti->op__next__) { + unsigned n = _ti->op__next__(this, _0); + if(n == 0) { + // StopIteration + int target = frame->prepare_loop_break(&s_data); + DISPATCH_JUMP_ABSOLUTE(target) + } else if(n == 1) { + // UNPACK_SEQUENCE + __op_unpack_sequence(byte.arg); + } else { + if(n != byte.arg) { + ValueError(_S("expected ", (int)byte.arg, " values to unpack, got ", (int)n)); + } + } + } else { + // FOR_ITER + _0 = call_method(_0, __next__); + if(_0 != StopIteration) { + PUSH(_0); + // UNPACK_SEQUENCE + __op_unpack_sequence(byte.arg); + } else { + int target = frame->prepare_loop_break(&s_data); + DISPATCH_JUMP_ABSOLUTE(target) + } + } + } + DISPATCH() + /*****************************************/ + case OP_IMPORT_PATH: { + PyVar _0 = c11__getitem(PyVar, &frame->co->consts, byte.arg); + PUSH(py_import(CAST(Str&, _0))); + } + DISPATCH() + case OP_POP_IMPORT_STAR: { + PyVar _0 = POPX(); // pop the module + PyVar _1 = _0->attr().try_get(__all__); + StrName _name; + if(_1 != nullptr) { + for(PyVar key: CAST(List&, _1)) { + _name = StrName::get(CAST(Str&, key).sv()); + PyVar value = _0->attr().try_get_likely_found(_name); + if(value == nullptr) { + ImportError(_S("cannot import name ", _name.escape())); + } else { + frame->f_globals().set(_name, value); + } + } + } else { + for(auto& [name, value]: _0->attr().items()) { + std::string_view s = name.sv(); + if(s.empty() || s[0] == '_') continue; + frame->f_globals().set(name, value); + } + } + } + DISPATCH() + /*****************************************/ + case OP_UNPACK_SEQUENCE: { + __op_unpack_sequence(byte.arg); + } + DISPATCH() + case OP_UNPACK_EX: { + auto _lock = gc_scope_lock(); // lock the gc via RAII!! + PyVar _0 = py_iter(POPX()); + const PyTypeInfo* _ti = _tp_info(_0); + PyVar _1; + for(int i = 0; i < byte.arg; i++) { + _1 = _py_next(_ti, _0); + if(_1 == StopIteration) ValueError("not enough values to unpack"); + PUSH(_1); + } + List extras; + while(true) { + _1 = _py_next(_ti, _0); + if(_1 == StopIteration) break; + extras.push_back(_1); + } + PUSH(VAR(std::move(extras))); + } + DISPATCH() + /*****************************************/ + case OP_BEGIN_CLASS: { + StrName _name(byte.arg); + PyVar _0 = POPX(); // super + if(is_none(_0)) _0 = _t(tp_object); + check_type(_0, tp_type); + __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true); + } + DISPATCH() + case OP_END_CLASS: { + assert(__curr_class != nullptr); + StrName _name(byte.arg); + frame->_module->attr().set(_name, __curr_class); + // call on_end_subclass + PyTypeInfo* ti = &_all_types[__curr_class->as()]; + if(ti->base != tp_object) { + PyTypeInfo* base_ti = &_all_types[ti->base]; + if(base_ti->on_end_subclass) base_ti->on_end_subclass(this, ti); + } + __curr_class = nullptr; + } + DISPATCH() + case OP_STORE_CLASS_ATTR: { + assert(__curr_class != nullptr); + StrName _name(byte.arg); + PyVar _0 = POPX(); + if(is_type(_0, tp_function)) { PK_OBJ_GET(Function, _0)._class = __curr_class; } + __curr_class->attr().set(_name, _0); + } + DISPATCH() + case OP_BEGIN_CLASS_DECORATION: { + PUSH(__curr_class); + } + DISPATCH() + case OP_END_CLASS_DECORATION: { + __curr_class = POPX().get(); + } + DISPATCH() + case OP_ADD_CLASS_ANNOTATION: { + assert(__curr_class != nullptr); + StrName _name(byte.arg); + Type type = __curr_class->as(); + _all_types[type].annotated_fields.push_back(_name); + } + DISPATCH() + /*****************************************/ + case OP_WITH_ENTER: PUSH(call_method(TOP(), __enter__)); DISPATCH() + case OP_WITH_EXIT: + call_method(TOP(), __exit__); + POP(); + DISPATCH() + /*****************************************/ + case OP_TRY_ENTER: { + frame->set_unwind_target(s_data.sp); + DISPATCH() + } + case OP_EXCEPTION_MATCH: { + PyVar assumed_type = POPX(); + check_type(assumed_type, tp_type); + PyVar e_obj = TOP(); + bool ok = isinstance(e_obj, PK_OBJ_GET(Type, assumed_type)); + PUSH(VAR(ok)); + } + DISPATCH() + case OP_RAISE: { + if(is_type(TOP(), tp_type)) { TOP() = call(TOP()); } + if(!isinstance(TOP(), tp_exception)) { TypeError("exceptions must derive from Exception"); } + _error(POPX()); + } + DISPATCH() + case OP_RAISE_ASSERT: + if(byte.arg) { + Str msg = py_str(TOP()); + POP(); + AssertionError(msg); + } else { + AssertionError(); + } + DISPATCH() + case OP_RE_RAISE: __raise_exc(true); DISPATCH() + case OP_POP_EXCEPTION: __last_exception = POPX().get(); DISPATCH() + /*****************************************/ + case OP_FORMAT_STRING: { + PyVar _0 = POPX(); + const Str& spec = CAST(Str&, c11__getitem(PyVar, &frame->co->consts, byte.arg)); + PUSH(__format_object(_0, spec)); + } + DISPATCH() + /*****************************************/ + default: PK_UNREACHABLE() + } + } + /**********************************************************************/ + PK_UNREACHABLE() + } catch(InternalException internal) { + __internal_exception = internal; + if(internal.type == InternalExceptionType::Unhandled) { + __last_exception = POPX().get(); + Exception& _e = __last_exception->as(); + bool is_base_frame_to_be_popped = frame == base_frame; + __pop_frame(); + if(callstack.empty()) { + // propagate to the top level + throw TopLevelException(this, &_e); + } + frame = &callstack.top(); + PUSH(__last_exception); + if(is_base_frame_to_be_popped) { throw InternalException(InternalExceptionType::ToBeRaised); } + } + } + } +} + +#undef TOP +#undef SECOND +#undef THIRD +#undef STACK_SHRINK +#undef PUSH +#undef POP +#undef POPX +#undef STACK_VIEW + +#undef DISPATCH +#undef DISPATCH_JUMP +#undef CEVAL_STEP_CALLBACK + +} // namespace pkpy diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index ab807db6..1e178e5e 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -10,16 +10,16 @@ void ValueStack__clear(ValueStack* self) { self->sp = self->begin; } -PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, py_Name name){ +py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name){ int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1); if(index == -1) return NULL; return &locals[index]; } -pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) { +pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) { pk_NameDict* dict = pk_NameDict__new(); c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) { - PyVar value = locals[entry->value]; + py_TValue value = locals[entry->value]; if(!py_isnull(&value)){ pk_NameDict__set(dict, entry->key, value); } @@ -39,7 +39,7 @@ void UnwindTarget__delete(UnwindTarget* self){ free(self); } -Frame* Frame__new(const CodeObject* co, const PyVar* module, const PyVar* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co){ +Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co){ static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)"); Frame* self = PoolFrame_alloc(); self->f_back = NULL; @@ -72,7 +72,7 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){ iblock = block->parent; } if(iblock < 0) return -1; - PyVar obj = *--_s->sp; // pop exception object + py_TValue obj = *--_s->sp; // pop exception object UnwindTarget* uw = Frame__find_unwind_target(self, iblock); _s->sp = (self->locals + uw->offset); // unwind the stack *(_s->sp++) = obj; // push it back @@ -121,7 +121,7 @@ UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock){ return NULL; } -void Frame__set_unwind_target(Frame* self, PyVar* sp) { +void Frame__set_unwind_target(Frame* self, py_TValue* sp) { int iblock = Frame__iblock(self); UnwindTarget* existing = Frame__find_unwind_target(self, iblock); if(existing) { diff --git a/src/interpreter/gc.c b/src/interpreter/gc.c index 181dcb71..7a0888ef 100644 --- a/src/interpreter/gc.c +++ b/src/interpreter/gc.c @@ -119,7 +119,7 @@ PyObject* PyObject__new(py_Type type, int slots, int size){ // initialize slots or dict void* p = (char*)self + 8; if(slots >= 0){ - memset(p, 0, slots*sizeof(PyVar)); + memset(p, 0, slots*sizeof(py_TValue)); }else{ pk_NameDict__ctor(p); } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index f5049dca..0ba0fa32 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -7,17 +7,23 @@ static unsigned char* pk_default_import_file(const char* path){ return NULL; } -static void pk_default_stdout(const char* s){ - fprintf(stdout, "%s", s); +static void pk_default_stdout(const char* fmt, ...){ + va_list args; + va_start(args, fmt); + vfprintf(stdout, fmt, args); + va_end(args); fflush(stdout); } -static void pk_default_stderr(const char* s){ - fprintf(stderr, "%s", s); +static void pk_default_stderr(const char* fmt, ...){ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); fflush(stderr); } -void pk_TypeInfo__ctor(pk_TypeInfo *self, py_Name name, py_Type base, PyObject* obj, const PyVar* module, bool subclass_enabled){ +void pk_TypeInfo__ctor(pk_TypeInfo *self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled){ memset(self, 0, sizeof(pk_TypeInfo)); self->name = name; @@ -58,19 +64,19 @@ void pk_VM__ctor(pk_VM* self){ pk_ManagedHeap__ctor(&self->heap, self); ValueStack__ctor(&self->stack); - self->True = (PyVar){.type=tp_bool, .is_ptr=true, .extra=1, + self->True = (py_TValue){.type=tp_bool, .is_ptr=true, .extra=1, ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0), }; - self->False = (PyVar){.type=tp_bool, .is_ptr=true, .extra=0, + self->False = (py_TValue){.type=tp_bool, .is_ptr=true, .extra=0, ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0), }; - self->None = (PyVar){.type=tp_none_type, .is_ptr=true, + self->None = (py_TValue){.type=tp_none_type, .is_ptr=true, ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 0, 0), }; - self->NotImplemented = (PyVar){.type=tp_not_implemented_type, .is_ptr=true, + self->NotImplemented = (py_TValue){.type=tp_not_implemented_type, .is_ptr=true, ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 0, 0), }; - self->Ellipsis = (PyVar){.type=tp_ellipsis, .is_ptr=true, + self->Ellipsis = (py_TValue){.type=tp_ellipsis, .is_ptr=true, ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 0, 0), }; @@ -169,11 +175,7 @@ void pk_VM__pop_frame(pk_VM* self){ Frame__delete(frame); } -pk_FrameResult pk_VM__run_top_frame(pk_VM* self){ - return RES_RETURN; -} - -py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const PyVar* module, bool subclass_enabled){ +py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled){ py_Type type = self->types.count; pk_TypeInfo* ti = c11_vector__emplace(&self->types); PyObject* typeobj = pk_ManagedHeap__gcnew(&self->heap, tp_type, -1, sizeof(py_Type)); diff --git a/src/objects/base.c b/src/objects/base.c index 0e9745d5..9116256d 100644 --- a/src/objects/base.c +++ b/src/objects/base.c @@ -1,6 +1,6 @@ #include "pocketpy/objects/base.h" -PyVar PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0}; -PyVar PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0}; -PyVar PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0}; +py_TValue PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0}; +py_TValue PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0}; +py_TValue PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0}; diff --git a/src/objects/codeobject.c b/src/objects/codeobject.c index 5dc63019..6487d45c 100644 --- a/src/objects/codeobject.c +++ b/src/objects/codeobject.c @@ -40,7 +40,7 @@ void FuncDecl__dtor(FuncDecl* self) { c11_smallmap_n2i__dtor(&self->kw_to_index); } -void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const PyVar* value) { +void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value) { c11_smallmap_n2i__set(&self->kw_to_index, key, index); FuncDeclKwArg item = {index, key, *value}; c11_vector__push(FuncDeclKwArg, &self->kwargs, item); @@ -54,7 +54,7 @@ void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_string name) { c11_vector__ctor(&self->codes, sizeof(Bytecode)); c11_vector__ctor(&self->codes_ex, sizeof(BytecodeEx)); - c11_vector__ctor(&self->consts, sizeof(PyVar)); + c11_vector__ctor(&self->consts, sizeof(py_TValue)); c11_vector__ctor(&self->varnames, sizeof(uint16_t)); self->nlocals = 0; diff --git a/src/objects/dict.c b/src/objects/dict.c index 3488c5fe..5cac91fb 100644 --- a/src/objects/dict.c +++ b/src/objects/dict.c @@ -13,8 +13,8 @@ #define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0) struct pkpy_DictEntry { - PyVar key; - PyVar val; + py_TValue key; + py_TValue val; }; inline extern int pkpy_Dict__idx_size(const pkpy_Dict* self) { @@ -79,7 +79,7 @@ static void pkpy_Dict__htset(pkpy_Dict* self, int h, int v) { #endif } -static int pkpy_Dict__probe0(const pkpy_Dict* self, PyVar key, int hash) { +static int pkpy_Dict__probe0(const pkpy_Dict* self, py_TValue key, int hash) { const int null = pkpy_Dict__idx_null(self); const int mask = self->_htcap - 1; for(int h = hash & mask;; h = DICT_HASH_NEXT(h) & mask) { @@ -92,7 +92,7 @@ static int pkpy_Dict__probe0(const pkpy_Dict* self, PyVar key, int hash) { PK_UNREACHABLE(); } -static int pkpy_Dict__probe1(const pkpy_Dict* self, PyVar key, int hash) { +static int pkpy_Dict__probe1(const pkpy_Dict* self, py_TValue key, int hash) { const int null = pkpy_Dict__idx_null(self); const int mask = self->_htcap - 1; for(int h = hash & mask;; h = DICT_HASH_NEXT(h) & mask) { @@ -124,7 +124,7 @@ static void pkpy_Dict__extendht(pkpy_Dict* self) { } } -bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val) { +bool pkpy_Dict__set(pkpy_Dict* self, py_TValue key, py_TValue val) { int64_t out; int err = py_hash(&key, &out); int hash = DICT_HASH_TRANS(out); @@ -161,7 +161,7 @@ bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val) { return false; } -bool pkpy_Dict__contains(const pkpy_Dict* self, PyVar key) { +bool pkpy_Dict__contains(const pkpy_Dict* self, py_TValue key) { int64_t out; int err = py_hash(&key, &out); int hash = DICT_HASH_TRANS(out); @@ -205,7 +205,7 @@ static bool pkpy_Dict__refactor(pkpy_Dict* self) { return true; } -bool pkpy_Dict__del(pkpy_Dict* self, PyVar key) { +bool pkpy_Dict__del(pkpy_Dict* self, py_TValue key) { int64_t out; int err = py_hash(&key, &out); int hash = DICT_HASH_TRANS(out); @@ -220,7 +220,7 @@ bool pkpy_Dict__del(pkpy_Dict* self, PyVar key) { return true; } -const PyVar *pkpy_Dict__try_get(const pkpy_Dict* self, PyVar key) { +const py_TValue *pkpy_Dict__try_get(const pkpy_Dict* self, py_TValue key) { int64_t out; int err = py_hash(&key, &out); int hash = DICT_HASH_TRANS(out); @@ -263,7 +263,7 @@ pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict *self) { }; } -bool pkpy_DictIter__next(pkpy_DictIter *self, PyVar *key, PyVar *val) { +bool pkpy_DictIter__next(pkpy_DictIter *self, py_TValue *key, py_TValue *val) { if(self->_index >= self->_dict->_entries.count) return false; struct pkpy_DictEntry* entry = &c11__getitem(struct pkpy_DictEntry, &self->_dict->_entries, self->_index); diff --git a/src/objects/namedict.c b/src/objects/namedict.c index f66ef7ab..2c170f49 100644 --- a/src/objects/namedict.c +++ b/src/objects/namedict.c @@ -2,7 +2,7 @@ #define SMALLMAP_T__SOURCE #define K uint16_t -#define V PyVar +#define V py_TValue #define NAME pk_NameDict #include "pocketpy/xmacros/smallmap.h" #undef SMALLMAP_T__SOURCE diff --git a/src/objects/object.c b/src/objects/object.c index db09679a..37dd801b 100644 --- a/src/objects/object.c +++ b/src/objects/object.c @@ -11,7 +11,7 @@ pk_NameDict* PyObject__dict(PyObject* self){ return (pk_NameDict*)((char*)self + 8); } -PyVar* PyObject__slots(PyObject* self){ +py_TValue* PyObject__slots(PyObject* self){ assert(self->slots >= 0); - return (PyVar*)((char*)self + 8); + return (py_TValue*)((char*)self + 8); } \ No newline at end of file