From 84d71762c268428f807e96faec733f6950a2c7fa Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 15 Apr 2023 15:19:04 +0800 Subject: [PATCH] up --- benchmarks/recursive.py | 4 +- src/ceval.h | 291 +++++++++++++++++++++------------------- src/frame.h | 140 +++++++++---------- src/iter.h | 3 +- src/obj.h | 7 +- src/vector.h | 1 + src/vm.h | 5 +- 7 files changed, 226 insertions(+), 225 deletions(-) diff --git a/benchmarks/recursive.py b/benchmarks/recursive.py index df99c0a2..f0dd6334 100644 --- a/benchmarks/recursive.py +++ b/benchmarks/recursive.py @@ -1,9 +1,9 @@ import sys -sys.setrecursionlimit(10000) +sys.setrecursionlimit(5000) def f(n): - if n == 8000: + if n == 4000: return -1 return f(n + 1) diff --git a/src/ceval.h b/src/ceval.h index e4cd3ba9..31d6de95 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -13,7 +13,7 @@ inline PyObject* VM::_run_top_frame(){ while(true){ #if DEBUG_EXTRA_CHECK - if(frame->id < base_id) FATAL_ERROR(); + if(frame.index < base_id) FATAL_ERROR(); #endif try{ if(need_raise){ need_raise = false; _raise(); } @@ -21,11 +21,23 @@ inline PyObject* VM::_run_top_frame(){ /* NOTE: * Be aware of accidental gc! * DO NOT leave any strong reference of PyObject* in the C stack - * For example, frame->popx() returns a strong reference which may be dangerous + * For example, POPX() returns a strong reference which may be dangerous * `Args` containing strong references is safe if it is passed to `call` or `fast_call` */ { - #define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; } + +/* Stack manipulation macros */ +// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123 +#define TOP() (frame->_s.top()) +#define SECOND() (frame->_s.second()) +#define PEEK(n) (frame->_s.peek(n)) +#define STACK_SHRINK(n) (frame->_s.shrink(n)) +#define PUSH(v) (frame->_s.push(v)) +#define POP() (frame->_s.pop()) +#define POPX() (frame->_s.popx()) +#define STACK_VIEW(n) (frame->_s.view(n)) + +#define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; } __NEXT_FRAME: Bytecode byte = frame->next_bytecode(); // cache @@ -57,25 +69,25 @@ __NEXT_STEP:; #endif TARGET(NO_OP) DISPATCH(); /*****************************************/ - TARGET(POP_TOP) frame->pop(); DISPATCH(); - TARGET(DUP_TOP) frame->push(frame->top()); DISPATCH(); - TARGET(ROT_TWO) std::swap(frame->top(), frame->top_1()); DISPATCH(); + TARGET(POP_TOP) POP(); DISPATCH(); + TARGET(DUP_TOP) PUSH(TOP()); DISPATCH(); + TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH(); TARGET(PRINT_EXPR) { - PyObject* obj = frame->top(); // use top() to avoid accidental gc + PyObject* obj = TOP(); // use top() to avoid accidental gc if(obj != None) *_stdout << CAST(Str&, asRepr(obj)) << '\n'; - frame->pop(); + POP(); } DISPATCH(); /*****************************************/ TARGET(LOAD_CONST) heap._auto_collect(); - frame->push(co_consts[byte.arg]); + PUSH(co_consts[byte.arg]); DISPATCH(); - TARGET(LOAD_NONE) frame->push(None); DISPATCH(); - TARGET(LOAD_TRUE) frame->push(True); DISPATCH(); - TARGET(LOAD_FALSE) frame->push(False); DISPATCH(); - TARGET(LOAD_INTEGER) frame->push(VAR(byte.arg)); DISPATCH(); - TARGET(LOAD_ELLIPSIS) frame->push(Ellipsis); DISPATCH(); - TARGET(LOAD_BUILTIN_EVAL) frame->push(builtins->attr(m_eval)); DISPATCH(); + TARGET(LOAD_NONE) PUSH(None); DISPATCH(); + TARGET(LOAD_TRUE) PUSH(True); DISPATCH(); + TARGET(LOAD_FALSE) PUSH(False); DISPATCH(); + TARGET(LOAD_INTEGER) PUSH(VAR(byte.arg)); DISPATCH(); + TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH(); + TARGET(LOAD_BUILTIN_EVAL) PUSH(builtins->attr(m_eval)); DISPATCH(); TARGET(LOAD_FUNCTION) { FuncDecl_ decl = co->func_decls[byte.arg]; PyObject* obj; @@ -84,28 +96,28 @@ __NEXT_STEP:; }else{ obj = VAR(Function({decl, frame->_module})); } - frame->push(obj); + PUSH(obj); } DISPATCH(); - TARGET(LOAD_NULL) frame->push(_py_null); DISPATCH(); + TARGET(LOAD_NULL) PUSH(_py_null); DISPATCH(); /*****************************************/ TARGET(LOAD_FAST) { heap._auto_collect(); PyObject* val = frame->_locals[byte.arg]; if(val == nullptr) vm->NameError(co->varnames[byte.arg]); - frame->push(val); + PUSH(val); } DISPATCH(); TARGET(LOAD_NAME) { heap._auto_collect(); StrName name(byte.arg); PyObject* val; val = frame->_locals.try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } val = frame->_closure.try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } val = frame->f_globals().try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } val = vm->builtins->attr().try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } vm->NameError(name); } DISPATCH(); TARGET(LOAD_NONLOCAL) { @@ -113,59 +125,59 @@ __NEXT_STEP:; StrName name(byte.arg); PyObject* val; val = frame->_closure.try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } val = frame->f_globals().try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } val = vm->builtins->attr().try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } vm->NameError(name); } DISPATCH(); TARGET(LOAD_GLOBAL) { heap._auto_collect(); StrName name(byte.arg); PyObject* val = frame->f_globals().try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } val = vm->builtins->attr().try_get(name); - if(val != nullptr) { frame->push(val); DISPATCH(); } + if(val != nullptr) { PUSH(val); DISPATCH(); } vm->NameError(name); } DISPATCH(); TARGET(LOAD_ATTR) { - PyObject* a = frame->top(); + PyObject* a = TOP(); StrName name(byte.arg); - frame->top() = getattr(a, name); + TOP() = getattr(a, name); } DISPATCH(); TARGET(LOAD_METHOD) { - PyObject* a = frame->top(); + PyObject* a = TOP(); StrName name(byte.arg); PyObject* self; - frame->top() = get_unbound_method(a, name, &self, true, true); - frame->push(self); + TOP() = get_unbound_method(a, name, &self, true, true); + PUSH(self); } DISPATCH(); TARGET(LOAD_SUBSCR) { Args args(2); - args[1] = frame->popx(); // b - args[0] = frame->top(); // a - frame->top() = fast_call(__getitem__, std::move(args)); + args[1] = POPX(); // b + args[0] = TOP(); // a + TOP() = fast_call(__getitem__, std::move(args)); } DISPATCH(); TARGET(STORE_FAST) - frame->_locals[byte.arg] = frame->popx(); + frame->_locals[byte.arg] = POPX(); DISPATCH(); TARGET(STORE_GLOBAL) { StrName name(byte.arg); - frame->f_globals().set(name, frame->popx()); + frame->f_globals().set(name, POPX()); } DISPATCH(); TARGET(STORE_ATTR) { StrName name(byte.arg); - PyObject* a = frame->top(); - PyObject* val = frame->top_1(); + PyObject* a = TOP(); + PyObject* val = SECOND(); setattr(a, name, val); - frame->pop_n(2); + STACK_SHRINK(2); } DISPATCH(); TARGET(STORE_SUBSCR) { Args args(3); - args[1] = frame->popx(); // b - args[0] = frame->popx(); // a - args[2] = frame->popx(); // val + args[1] = POPX(); // b + args[0] = POPX(); // a + args[2] = POPX(); // val fast_call(__setitem__, std::move(args)); } DISPATCH(); TARGET(DELETE_FAST) { @@ -182,70 +194,76 @@ __NEXT_STEP:; } } DISPATCH(); TARGET(DELETE_ATTR) { - PyObject* a = frame->popx(); + PyObject* a = POPX(); StrName name(byte.arg); if(!a->is_attr_valid()) TypeError("cannot delete attribute"); if(!a->attr().contains(name)) AttributeError(a, name); a->attr().erase(name); } DISPATCH(); TARGET(DELETE_SUBSCR) { - PyObject* b = frame->popx(); - PyObject* a = frame->popx(); + PyObject* b = POPX(); + PyObject* a = POPX(); fast_call(__delitem__, Args{a, b}); } DISPATCH(); /*****************************************/ - TARGET(BUILD_LIST) - frame->push(VAR(frame->popx_n_reversed(byte.arg).to_list())); - DISPATCH(); + TARGET(BUILD_LIST) { + PyObject* obj = VAR(STACK_VIEW(byte.arg).to_list()); + STACK_SHRINK(byte.arg); + PUSH(obj); + } DISPATCH(); TARGET(BUILD_DICT) { - PyObject* t = VAR(frame->popx_n_reversed(byte.arg)); + PyObject* t = VAR(STACK_VIEW(byte.arg).to_tuple()); + STACK_SHRINK(byte.arg); PyObject* obj = call(builtins->attr(m_dict), Args{t}); - frame->push(obj); + PUSH(obj); } DISPATCH(); TARGET(BUILD_SET) { - PyObject* t = VAR(frame->popx_n_reversed(byte.arg)); + PyObject* t = VAR(STACK_VIEW(byte.arg).to_tuple()); + STACK_SHRINK(byte.arg); PyObject* obj = call(builtins->attr(m_set), Args{t}); - frame->push(obj); + PUSH(obj); } DISPATCH(); TARGET(BUILD_SLICE) { - PyObject* step = frame->popx(); - PyObject* stop = frame->popx(); - PyObject* start = frame->popx(); + PyObject* step = POPX(); + PyObject* stop = POPX(); + PyObject* start = POPX(); Slice s; if(start != None) s.start = CAST(int, start); if(stop != None) s.stop = CAST(int, stop); if(step != None) s.step = CAST(int, step); - frame->push(VAR(s)); + PUSH(VAR(s)); } DISPATCH(); TARGET(BUILD_TUPLE) { - Tuple items = frame->popx_n_reversed(byte.arg); - frame->push(VAR(std::move(items))); + PyObject* obj = VAR(STACK_VIEW(byte.arg).to_tuple()); + STACK_SHRINK(byte.arg); + PUSH(obj); } DISPATCH(); TARGET(BUILD_STRING) { - std::stringstream ss; // asStr() may run extra bytecode - for(int i=byte.arg-1; i>=0; i--) ss << CAST(Str&, asStr(frame->top_n(i))); - frame->pop_n(byte.arg); - frame->push(VAR(ss.str())); + std::stringstream ss; + auto view = STACK_VIEW(byte.arg); + for(PyObject* obj : view) ss << CAST(Str&, asStr(obj)); + STACK_SHRINK(byte.arg); + PUSH(VAR(ss.str())); } DISPATCH(); /*****************************************/ TARGET(BINARY_OP) { Args args(2); - args[1] = frame->popx(); // lhs - args[0] = frame->top(); // rhs - frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); + args[1] = POPX(); // lhs + args[0] = TOP(); // rhs + TOP() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); } DISPATCH(); #define INT_BINARY_OP(op, func) \ - if(is_both_int(frame->top(), frame->top_1())){ \ - i64 b = _CAST(i64, frame->top()); \ - i64 a = _CAST(i64, frame->top_1()); \ - frame->pop(); \ - frame->top() = VAR(a op b); \ - }else{ \ - Args args(2); \ - args[1] = frame->popx(); \ - args[0] = frame->top(); \ - frame->top() = fast_call(func, std::move(args));\ + if(is_both_int(TOP(), SECOND())){ \ + i64 b = _CAST(i64, TOP()); \ + i64 a = _CAST(i64, SECOND()); \ + POP(); \ + TOP() = VAR(a op b); \ + }else{ \ + Args args(2); \ + args[1] = POPX(); \ + args[0] = TOP(); \ + TOP() = fast_call(func, std::move(args)); \ } TARGET(BINARY_ADD) @@ -298,33 +316,33 @@ __NEXT_STEP:; DISPATCH() #undef INT_BINARY_OP TARGET(IS_OP) { - PyObject* rhs = frame->popx(); - PyObject* lhs = frame->top(); + PyObject* rhs = POPX(); + PyObject* lhs = TOP(); bool ret_c = lhs == rhs; if(byte.arg == 1) ret_c = !ret_c; - frame->top() = VAR(ret_c); + TOP() = VAR(ret_c); } DISPATCH(); TARGET(CONTAINS_OP) { Args args(2); - args[0] = frame->popx(); - args[1] = frame->top(); + args[0] = POPX(); + args[1] = TOP(); PyObject* ret = fast_call(__contains__, std::move(args)); bool ret_c = CAST(bool, ret); if(byte.arg == 1) ret_c = !ret_c; - frame->top() = VAR(ret_c); + TOP() = VAR(ret_c); } DISPATCH(); /*****************************************/ TARGET(JUMP_ABSOLUTE) frame->jump_abs(byte.arg); DISPATCH(); TARGET(POP_JUMP_IF_FALSE) - if(!asBool(frame->popx())) frame->jump_abs(byte.arg); + if(!asBool(POPX())) frame->jump_abs(byte.arg); DISPATCH(); TARGET(JUMP_IF_TRUE_OR_POP) - if(asBool(frame->top()) == true) frame->jump_abs(byte.arg); - else frame->pop(); + if(asBool(TOP()) == true) frame->jump_abs(byte.arg); + else POP(); DISPATCH(); TARGET(JUMP_IF_FALSE_OR_POP) - if(asBool(frame->top()) == false) frame->jump_abs(byte.arg); - else frame->pop(); + if(asBool(TOP()) == false) frame->jump_abs(byte.arg); + else POP(); DISPATCH(); TARGET(LOOP_CONTINUE) { int target = co_blocks[byte.block].start; @@ -344,92 +362,91 @@ __NEXT_STEP:; TARGET(CALL) TARGET(CALL_UNPACK) { int ARGC = byte.arg; - PyObject* callable = frame->top_n(ARGC+1); - bool method_call = frame->top_n(ARGC) != _py_null; + PyObject* callable = PEEK(ARGC+2); + bool method_call = PEEK(ARGC+1) != _py_null; // fast path if(byte.op==OP_CALL && is_type(callable, tp_function)){ - ArgsView args = frame->top_n_view(ARGC + int(method_call)); - PyObject* ret = _py_call(callable, args, {}); - frame->pop_n(ARGC + 2); + PyObject* ret = _py_call(callable, STACK_VIEW(ARGC + int(method_call)), {}); + STACK_SHRINK(ARGC + 2); if(ret == nullptr) { DISPATCH_OP_CALL(); } - else frame->push(ret); // a generator + else PUSH(ret); // a generator DISPATCH(); } - - Args args = frame->popx_n_reversed(ARGC + int(method_call)); - if(!method_call) frame->pop(); - + Args args = STACK_VIEW(ARGC + int(method_call)).to_tuple(); if(byte.op == OP_CALL_UNPACK) unpack_args(args); - frame->pop(); PyObject* ret = call(callable, std::move(args), no_arg(), true); + STACK_SHRINK(ARGC + 2); if(ret == _py_op_call) { DISPATCH_OP_CALL(); } - frame->push(ret); + PUSH(ret); } DISPATCH(); TARGET(CALL_KWARGS) TARGET(CALL_KWARGS_UNPACK) { + // TODO: poor performance, refactor needed int ARGC = byte.arg & 0xFFFF; int KWARGC = (byte.arg >> 16) & 0xFFFF; - Args kwargs = frame->popx_n_reversed(KWARGC*2); + Args kwargs = STACK_VIEW(KWARGC*2).to_tuple(); + STACK_SHRINK(KWARGC*2); - bool method_call = frame->top_n(ARGC) != _py_null; + bool method_call = PEEK(ARGC+1) != _py_null; if(method_call) ARGC++; // add self into args - Args args = frame->popx_n_reversed(ARGC); - if(!method_call) frame->pop(); + Args args = STACK_VIEW(ARGC).to_tuple(); + STACK_SHRINK(ARGC); + if(!method_call) POP(); if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args); - PyObject* callable = frame->popx(); + PyObject* callable = POPX(); PyObject* ret = call(callable, std::move(args), kwargs, true); if(ret == _py_op_call) { DISPATCH_OP_CALL(); } - frame->push(ret); + PUSH(ret); } DISPATCH(); TARGET(RETURN_VALUE) { - PyObject* __ret = frame->popx(); + PyObject* __ret = POPX(); if(frame.index == base_id){ // [ frameBase<- ] callstack.pop(); return __ret; }else{ callstack.pop(); frame = top_frame(); - frame->push(__ret); + PUSH(__ret); goto __NEXT_FRAME; } } TARGET(YIELD_VALUE) return _py_op_yield; /*****************************************/ TARGET(LIST_APPEND) { - PyObject* obj = frame->popx(); - List& list = CAST(List&, frame->top_1()); + PyObject* obj = POPX(); + List& list = CAST(List&, SECOND()); list.push_back(obj); } DISPATCH(); TARGET(DICT_ADD) { - PyObject* kv = frame->popx(); + PyObject* kv = POPX(); Tuple& t = CAST(Tuple& ,kv); - fast_call(__setitem__, Args{frame->top_1(), t[0], t[1]}); + fast_call(__setitem__, Args{SECOND(), t[0], t[1]}); } DISPATCH(); TARGET(SET_ADD) { - PyObject* obj = frame->popx(); - fast_call(m_add, Args{frame->top_1(), obj}); + PyObject* obj = POPX(); + fast_call(m_add, Args{SECOND(), obj}); } DISPATCH(); /*****************************************/ TARGET(UNARY_NEGATIVE) - frame->top() = num_negated(frame->top()); + TOP() = num_negated(TOP()); DISPATCH(); TARGET(UNARY_NOT) - frame->top() = VAR(!asBool(frame->top())); + TOP() = VAR(!asBool(TOP())); DISPATCH(); TARGET(UNARY_STAR) - frame->top() = VAR(StarWrapper(frame->top())); + TOP() = VAR(StarWrapper(TOP())); DISPATCH(); /*****************************************/ TARGET(GET_ITER) - frame->top() = asIter(frame->top()); + TOP() = asIter(TOP()); DISPATCH(); TARGET(FOR_ITER) { - BaseIter* it = PyIter_AS_C(frame->top()); + BaseIter* it = PyIter_AS_C(TOP()); PyObject* obj = it->next(); if(obj != nullptr){ - frame->push(obj); + PUSH(obj); }else{ int target = co_blocks[byte.block].end; frame->jump_abs_break(target); @@ -454,13 +471,13 @@ __NEXT_STEP:; PyObject* new_mod = new_module(name); _exec(code, new_mod); new_mod->attr()._try_perfect_rehash(); - frame->push(new_mod); + PUSH(new_mod); }else{ - frame->push(ext_mod); + PUSH(ext_mod); } } DISPATCH(); TARGET(IMPORT_STAR) { - PyObject* obj = frame->popx(); + PyObject* obj = POPX(); for(auto& [name, value]: obj->attr().items()){ std::string_view s = name.sv(); if(s.empty() || s[0] == '_') continue; @@ -472,12 +489,12 @@ __NEXT_STEP:; TARGET(UNPACK_EX) { // asIter or iter->next may run bytecode, accidential gc may happen auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! - PyObject* obj = asIter(frame->popx()); + PyObject* obj = asIter(POPX()); BaseIter* iter = PyIter_AS_C(obj); for(int i=0; inext(); if(item == nullptr) ValueError("not enough values to unpack"); - frame->push(item); + PUSH(item); } // handle extra items if(byte.op == OP_UNPACK_EX){ @@ -487,7 +504,7 @@ __NEXT_STEP:; if(item == nullptr) break; extras.push_back(item); } - frame->push(VAR(extras)); + PUSH(VAR(extras)); }else{ if(iter->next() != nullptr) ValueError("too many values to unpack"); } @@ -495,20 +512,20 @@ __NEXT_STEP:; /*****************************************/ TARGET(BEGIN_CLASS) { StrName name(byte.arg); - PyObject* super_cls = frame->popx(); + PyObject* super_cls = POPX(); if(super_cls == None) super_cls = _t(tp_object); check_type(super_cls, tp_type); PyObject* cls = new_type_object(frame->_module, name, OBJ_GET(Type, super_cls)); - frame->push(cls); + PUSH(cls); } DISPATCH(); TARGET(END_CLASS) { - PyObject* cls = frame->popx(); + PyObject* cls = POPX(); cls->attr()._try_perfect_rehash(); }; DISPATCH(); TARGET(STORE_CLASS_ATTR) { StrName name(byte.arg); - PyObject* obj = frame->popx(); - PyObject* cls = frame->top(); + PyObject* obj = POPX(); + PyObject* cls = TOP(); cls->attr().set(name, obj); } DISPATCH(); /*****************************************/ @@ -517,7 +534,7 @@ __NEXT_STEP:; // TARGET(WITH_EXIT) call(frame->pop_value(this), __exit__, no_arg()); DISPATCH(); /*****************************************/ TARGET(ASSERT) { - PyObject* obj = frame->top(); + PyObject* obj = TOP(); Str msg; if(is_type(obj, tp_tuple)){ auto& t = CAST(Tuple&, obj); @@ -526,16 +543,16 @@ __NEXT_STEP:; msg = CAST(Str&, asStr(t[1])); } bool ok = asBool(obj); - frame->pop(); + POP(); if(!ok) _error("AssertionError", msg); } DISPATCH(); TARGET(EXCEPTION_MATCH) { - const auto& e = CAST(Exception&, frame->top()); + const auto& e = CAST(Exception&, TOP()); StrName name(byte.arg); - frame->push(VAR(e.match_type(name))); + PUSH(VAR(e.match_type(name))); } DISPATCH(); TARGET(RAISE) { - PyObject* obj = frame->popx(); + PyObject* obj = POPX(); Str msg = obj == None ? "" : CAST(Str, asStr(obj)); _error(StrName(byte.arg), msg); } DISPATCH(); @@ -558,7 +575,7 @@ __NEXT_STEP:; }catch(HandledException& e){ continue; }catch(UnhandledException& e){ - PyObject* obj = frame->popx(); + PyObject* obj = POPX(); Exception& _e = CAST(Exception&, obj); _e.st_push(frame->snapshot()); callstack.pop(); @@ -569,7 +586,7 @@ __NEXT_STEP:; throw _e; } frame = top_frame(); - frame->push(obj); + PUSH(obj); if(frame.index < base_id) throw ToBeRaisedException(); need_raise = true; }catch(ToBeRaisedException& e){ diff --git a/src/frame.h b/src/frame.h index 048efaa2..65296a3d 100644 --- a/src/frame.h +++ b/src/frame.h @@ -6,23 +6,26 @@ namespace pkpy{ -using ValueStack = pod_vector; - struct FastLocals{ NameDictInt_ varnames_inv; PyObject** a; - int size() const{ return varnames_inv->size(); } + int size() const{ + return varnames_inv->size(); + } PyObject*& operator[](int i){ return a[i]; } PyObject* operator[](int i) const { return a[i]; } + FastLocals(): varnames_inv(nullptr), a(nullptr) {} + FastLocals(std::nullptr_t): varnames_inv(nullptr), a(nullptr) {} + FastLocals(const CodeObject* co): varnames_inv(co->varnames_inv){ - size_t size = co->varnames.size() * sizeof(void*); + size_t size = this->size() * sizeof(void*); int* counter = (int*)pool128.alloc(sizeof(int) + size); *counter = 1; a = (PyObject**)(counter + 1); - memset(a, 0, size); + memset(a, 0, this->size() * sizeof(void*)); } PyObject* try_get(StrName name){ @@ -40,9 +43,6 @@ struct FastLocals{ return true; } - FastLocals(): varnames_inv(nullptr), a(nullptr) {} - FastLocals(std::nullptr_t): varnames_inv(nullptr), a(nullptr) {} - FastLocals(const FastLocals& other){ varnames_inv = other.varnames_inv; a = other.a; @@ -112,8 +112,47 @@ template<> inline void gc_mark(Function& t){ t._closure._gc_mark(); } +struct ValueStack { + PyObject** _begin; + PyObject** _sp; + + ValueStack(int n=16): _begin((PyObject**)pool128.alloc(n * sizeof(void*))), _sp(_begin) { } + + PyObject*& top(){ return _sp[-1]; } + PyObject* top() const { return _sp[-1]; } + PyObject*& second(){ return _sp[-2]; } + PyObject* second() const { return _sp[-2]; } + PyObject*& peek(int n){ return _sp[-n]; } + PyObject* peek(int n) const { return _sp[-n]; } + void push(PyObject* v){ *_sp++ = v; } + void pop(){ --_sp; } + PyObject* popx(){ return *--_sp; } + ArgsView view(int n){ return ArgsView(_sp-n, _sp); } + void shrink(int n){ _sp -= n; } + int size() const { return _sp - _begin; } + bool empty() const { return _sp == _begin; } + PyObject** begin() const { return _begin; } + PyObject** end() const { return _sp; } + void resize(int n) { _sp = _begin + n; } + + ValueStack(ValueStack&& other) noexcept{ + _begin = other._begin; + _sp = other._sp; + other._begin = nullptr; + } + + ValueStack& operator=(ValueStack&& other) noexcept{ + if(_begin != nullptr) pool128.dealloc(_begin); + _begin = other._begin; + _sp = other._sp; + other._begin = nullptr; + return *this; + } + + ~ValueStack(){ if(_begin!=nullptr) pool128.dealloc(_begin); } +}; + struct Frame { - ValueStack _data; int _ip = -1; int _next_ip = 0; const CodeObject* co; @@ -121,6 +160,7 @@ struct Frame { FastLocals _locals; FastLocals _closure; + ValueStack _s; NameDict& f_globals() noexcept { return _module->attr(); } @@ -150,60 +190,15 @@ struct Frame { std::string stack_info(){ std::stringstream ss; - ss << " ["; - for(int i=0; i<_data.size(); i++){ - ss << (i64)_data[i]; - if(i != _data.size()-1) ss << ", "; + ss << this << ": ["; + for(PyObject** t=_s.begin(); t<_s.end(); t++){ + ss << *t; + if(t != _s.end()-1) ss << ", "; } ss << "]"; return ss.str(); } - void pop(){ -#if DEBUG_EXTRA_CHECK - if(_data.empty()) throw std::runtime_error("_data.empty() is true"); -#endif - _data.pop_back(); - } - - PyObject* popx(){ -#if DEBUG_EXTRA_CHECK - if(_data.empty()) throw std::runtime_error("_data.empty() is true"); -#endif - PyObject* ret = _data.back(); - _data.pop_back(); - return ret; - } - - PyObject*& top(){ -#if DEBUG_EXTRA_CHECK - if(_data.empty()) throw std::runtime_error("_data.empty() is true"); -#endif - return _data.back(); - } - - PyObject*& top_1(){ -#if DEBUG_EXTRA_CHECK - if(_data.size() < 2) throw std::runtime_error("_data.size() < 2"); -#endif - return _data[_data.size()-2]; - } - - PyObject*& top_n(int n){ - n += 1; -#if DEBUG_EXTRA_CHECK - if(_data.size() < n) throw std::runtime_error("_data.size() < n"); -#endif - return _data[_data.size()-n]; - } - - void push(PyObject* obj){ -#if DEBUG_EXTRA_CHECK - if(obj == nullptr) throw std::runtime_error("obj == nullptr"); -#endif - _data.push_back(obj); - } - void jump_abs(int i){ _next_ip = i; } void jump_rel(int i){ _next_ip += i; } @@ -215,19 +210,18 @@ struct Frame { block = co->blocks[block].parent; } if(block < 0) return false; - PyObject* obj = popx(); // pop exception object + PyObject* obj = _s.popx(); // pop exception object // get the stack size of the try block (depth of for loops) int stack_size = co->blocks[block].for_loop_depth; - // std::cout << "stack_size: " << stack_size << std::endl; - if(_data.size() < stack_size) throw std::runtime_error("invalid stack size"); - _data.resize(stack_size); // rollback the stack - _data.push_back(obj); // push exception object + if(_s.size() < stack_size) throw std::runtime_error("invalid stack size"); + _s.resize(stack_size); // rollback the stack + _s.push(obj); // push exception object _next_ip = co->blocks[block].end; return true; } int _exit_block(int i){ - if(co->blocks[i].type == FOR_LOOP) pop(); + if(co->blocks[i].type == FOR_LOOP) _s.pop(); return co->blocks[i].parent; } @@ -244,24 +238,10 @@ struct Frame { } } - Args popx_n_reversed(int n){ - Args v(n); - for(int i=n-1; i>=0; i--) v[i] = popx(); - return v; - } - - void pop_n(int n){ - _data.pop_back_n(n); - } - - ArgsView top_n_view(int n){ - return ArgsView(_data.end()-n, _data.end()); - } - void _gc_mark() const { // do return if this frame has been moved - if(_data._data == nullptr) return; - for(PyObject* obj : _data) OBJ_MARK(obj); + if(!_locals.is_valid()) return; + for(PyObject* obj: _s) OBJ_MARK(obj); OBJ_MARK(_module); _locals._gc_mark(); _closure._gc_mark(); diff --git a/src/iter.h b/src/iter.h index f2348366..2e208db5 100644 --- a/src/iter.h +++ b/src/iter.h @@ -69,8 +69,7 @@ inline PyObject* Generator::next(){ frame = std::move(vm->callstack.top()); vm->callstack.pop(); state = 1; - PyObject** _sp = frame._sp; - return POPX(); + return frame._s.popx(); }else{ state = 2; return nullptr; diff --git a/src/obj.h b/src/obj.h index 74ba417e..6e16fe5f 100644 --- a/src/obj.h +++ b/src/obj.h @@ -143,7 +143,7 @@ struct Py_ final: PyObject { Str obj_type_name(VM* vm, Type type); -#if DEBUG_NO_BUILTIN_MODULES || DEBUG_NO_NAME_GETTER +#if DEBUG_NO_BUILTIN_MODULES #define OBJ_NAME(obj) Str("") #else #define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) @@ -171,7 +171,10 @@ inline bool is_type(PyObject* obj, Type type) { } \ static PyObject* register_class(VM* vm, PyObject* mod) { \ PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \ - if(OBJ_NAME(mod) != #mod) FATAL_ERROR(); \ + if(OBJ_NAME(mod) != #mod) { \ + auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \ + throw std::runtime_error(msg); \ + } \ T::_register(vm, mod, type); \ type->attr()._try_perfect_rehash(); \ return type; \ diff --git a/src/vector.h b/src/vector.h index efffc63f..aebcd354 100644 --- a/src/vector.h +++ b/src/vector.h @@ -133,6 +133,7 @@ public: T& top(){ return vec.back(); } const T& top() const { return vec.back(); } T popx(){ T t = std::move(vec.back()); vec.pop_back(); return t; } + void reserve(int n){ vec.reserve(n); } Container& data() { return vec; } }; diff --git a/src/vm.h b/src/vm.h index 2aad0679..083dc420 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1,5 +1,6 @@ #pragma once +#include "codeobject.h" #include "common.h" #include "frame.h" #include "error.h" @@ -897,8 +898,8 @@ inline void VM::_error(Exception e){ e.is_re = false; throw e; } - PyObject** _sp = top_frame()->_sp; - PUSH(VAR(e)); + Frame* frame = &callstack.top(); + frame->_s.push(VAR(e)); _raise(); }