This commit is contained in:
blueloveTH 2023-04-15 15:19:04 +08:00
parent c2a9b77a18
commit 84d71762c2
7 changed files with 226 additions and 225 deletions

View File

@ -1,9 +1,9 @@
import sys import sys
sys.setrecursionlimit(10000) sys.setrecursionlimit(5000)
def f(n): def f(n):
if n == 8000: if n == 4000:
return -1 return -1
return f(n + 1) return f(n + 1)

View File

@ -13,7 +13,7 @@ inline PyObject* VM::_run_top_frame(){
while(true){ while(true){
#if DEBUG_EXTRA_CHECK #if DEBUG_EXTRA_CHECK
if(frame->id < base_id) FATAL_ERROR(); if(frame.index < base_id) FATAL_ERROR();
#endif #endif
try{ try{
if(need_raise){ need_raise = false; _raise(); } if(need_raise){ need_raise = false; _raise(); }
@ -21,11 +21,23 @@ inline PyObject* VM::_run_top_frame(){
/* NOTE: /* NOTE:
* Be aware of accidental gc! * Be aware of accidental gc!
* DO NOT leave any strong reference of PyObject* in the C stack * 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` * `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: __NEXT_FRAME:
Bytecode byte = frame->next_bytecode(); Bytecode byte = frame->next_bytecode();
// cache // cache
@ -57,25 +69,25 @@ __NEXT_STEP:;
#endif #endif
TARGET(NO_OP) DISPATCH(); TARGET(NO_OP) DISPATCH();
/*****************************************/ /*****************************************/
TARGET(POP_TOP) frame->pop(); DISPATCH(); TARGET(POP_TOP) POP(); DISPATCH();
TARGET(DUP_TOP) frame->push(frame->top()); DISPATCH(); TARGET(DUP_TOP) PUSH(TOP()); DISPATCH();
TARGET(ROT_TWO) std::swap(frame->top(), frame->top_1()); DISPATCH(); TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH();
TARGET(PRINT_EXPR) { 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'; if(obj != None) *_stdout << CAST(Str&, asRepr(obj)) << '\n';
frame->pop(); POP();
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(LOAD_CONST) TARGET(LOAD_CONST)
heap._auto_collect(); heap._auto_collect();
frame->push(co_consts[byte.arg]); PUSH(co_consts[byte.arg]);
DISPATCH(); DISPATCH();
TARGET(LOAD_NONE) frame->push(None); DISPATCH(); TARGET(LOAD_NONE) PUSH(None); DISPATCH();
TARGET(LOAD_TRUE) frame->push(True); DISPATCH(); TARGET(LOAD_TRUE) PUSH(True); DISPATCH();
TARGET(LOAD_FALSE) frame->push(False); DISPATCH(); TARGET(LOAD_FALSE) PUSH(False); DISPATCH();
TARGET(LOAD_INTEGER) frame->push(VAR(byte.arg)); DISPATCH(); TARGET(LOAD_INTEGER) PUSH(VAR(byte.arg)); DISPATCH();
TARGET(LOAD_ELLIPSIS) frame->push(Ellipsis); DISPATCH(); TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
TARGET(LOAD_BUILTIN_EVAL) frame->push(builtins->attr(m_eval)); DISPATCH(); TARGET(LOAD_BUILTIN_EVAL) PUSH(builtins->attr(m_eval)); DISPATCH();
TARGET(LOAD_FUNCTION) { TARGET(LOAD_FUNCTION) {
FuncDecl_ decl = co->func_decls[byte.arg]; FuncDecl_ decl = co->func_decls[byte.arg];
PyObject* obj; PyObject* obj;
@ -84,28 +96,28 @@ __NEXT_STEP:;
}else{ }else{
obj = VAR(Function({decl, frame->_module})); obj = VAR(Function({decl, frame->_module}));
} }
frame->push(obj); PUSH(obj);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_NULL) frame->push(_py_null); DISPATCH(); TARGET(LOAD_NULL) PUSH(_py_null); DISPATCH();
/*****************************************/ /*****************************************/
TARGET(LOAD_FAST) { TARGET(LOAD_FAST) {
heap._auto_collect(); heap._auto_collect();
PyObject* val = frame->_locals[byte.arg]; PyObject* val = frame->_locals[byte.arg];
if(val == nullptr) vm->NameError(co->varnames[byte.arg]); if(val == nullptr) vm->NameError(co->varnames[byte.arg]);
frame->push(val); PUSH(val);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_NAME) { TARGET(LOAD_NAME) {
heap._auto_collect(); heap._auto_collect();
StrName name(byte.arg); StrName name(byte.arg);
PyObject* val; PyObject* val;
val = frame->_locals.try_get(name); 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); 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); 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); val = vm->builtins->attr().try_get(name);
if(val != nullptr) { frame->push(val); DISPATCH(); } if(val != nullptr) { PUSH(val); DISPATCH(); }
vm->NameError(name); vm->NameError(name);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_NONLOCAL) { TARGET(LOAD_NONLOCAL) {
@ -113,59 +125,59 @@ __NEXT_STEP:;
StrName name(byte.arg); StrName name(byte.arg);
PyObject* val; PyObject* val;
val = frame->_closure.try_get(name); 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); 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); val = vm->builtins->attr().try_get(name);
if(val != nullptr) { frame->push(val); DISPATCH(); } if(val != nullptr) { PUSH(val); DISPATCH(); }
vm->NameError(name); vm->NameError(name);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_GLOBAL) { TARGET(LOAD_GLOBAL) {
heap._auto_collect(); heap._auto_collect();
StrName name(byte.arg); StrName name(byte.arg);
PyObject* val = frame->f_globals().try_get(name); 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); val = vm->builtins->attr().try_get(name);
if(val != nullptr) { frame->push(val); DISPATCH(); } if(val != nullptr) { PUSH(val); DISPATCH(); }
vm->NameError(name); vm->NameError(name);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_ATTR) { TARGET(LOAD_ATTR) {
PyObject* a = frame->top(); PyObject* a = TOP();
StrName name(byte.arg); StrName name(byte.arg);
frame->top() = getattr(a, name); TOP() = getattr(a, name);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_METHOD) { TARGET(LOAD_METHOD) {
PyObject* a = frame->top(); PyObject* a = TOP();
StrName name(byte.arg); StrName name(byte.arg);
PyObject* self; PyObject* self;
frame->top() = get_unbound_method(a, name, &self, true, true); TOP() = get_unbound_method(a, name, &self, true, true);
frame->push(self); PUSH(self);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_SUBSCR) { TARGET(LOAD_SUBSCR) {
Args args(2); Args args(2);
args[1] = frame->popx(); // b args[1] = POPX(); // b
args[0] = frame->top(); // a args[0] = TOP(); // a
frame->top() = fast_call(__getitem__, std::move(args)); TOP() = fast_call(__getitem__, std::move(args));
} DISPATCH(); } DISPATCH();
TARGET(STORE_FAST) TARGET(STORE_FAST)
frame->_locals[byte.arg] = frame->popx(); frame->_locals[byte.arg] = POPX();
DISPATCH(); DISPATCH();
TARGET(STORE_GLOBAL) { TARGET(STORE_GLOBAL) {
StrName name(byte.arg); StrName name(byte.arg);
frame->f_globals().set(name, frame->popx()); frame->f_globals().set(name, POPX());
} DISPATCH(); } DISPATCH();
TARGET(STORE_ATTR) { TARGET(STORE_ATTR) {
StrName name(byte.arg); StrName name(byte.arg);
PyObject* a = frame->top(); PyObject* a = TOP();
PyObject* val = frame->top_1(); PyObject* val = SECOND();
setattr(a, name, val); setattr(a, name, val);
frame->pop_n(2); STACK_SHRINK(2);
} DISPATCH(); } DISPATCH();
TARGET(STORE_SUBSCR) { TARGET(STORE_SUBSCR) {
Args args(3); Args args(3);
args[1] = frame->popx(); // b args[1] = POPX(); // b
args[0] = frame->popx(); // a args[0] = POPX(); // a
args[2] = frame->popx(); // val args[2] = POPX(); // val
fast_call(__setitem__, std::move(args)); fast_call(__setitem__, std::move(args));
} DISPATCH(); } DISPATCH();
TARGET(DELETE_FAST) { TARGET(DELETE_FAST) {
@ -182,70 +194,76 @@ __NEXT_STEP:;
} }
} DISPATCH(); } DISPATCH();
TARGET(DELETE_ATTR) { TARGET(DELETE_ATTR) {
PyObject* a = frame->popx(); PyObject* a = POPX();
StrName name(byte.arg); StrName name(byte.arg);
if(!a->is_attr_valid()) TypeError("cannot delete attribute"); if(!a->is_attr_valid()) TypeError("cannot delete attribute");
if(!a->attr().contains(name)) AttributeError(a, name); if(!a->attr().contains(name)) AttributeError(a, name);
a->attr().erase(name); a->attr().erase(name);
} DISPATCH(); } DISPATCH();
TARGET(DELETE_SUBSCR) { TARGET(DELETE_SUBSCR) {
PyObject* b = frame->popx(); PyObject* b = POPX();
PyObject* a = frame->popx(); PyObject* a = POPX();
fast_call(__delitem__, Args{a, b}); fast_call(__delitem__, Args{a, b});
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(BUILD_LIST) TARGET(BUILD_LIST) {
frame->push(VAR(frame->popx_n_reversed(byte.arg).to_list())); PyObject* obj = VAR(STACK_VIEW(byte.arg).to_list());
DISPATCH(); STACK_SHRINK(byte.arg);
PUSH(obj);
} DISPATCH();
TARGET(BUILD_DICT) { 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}); PyObject* obj = call(builtins->attr(m_dict), Args{t});
frame->push(obj); PUSH(obj);
} DISPATCH(); } DISPATCH();
TARGET(BUILD_SET) { 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}); PyObject* obj = call(builtins->attr(m_set), Args{t});
frame->push(obj); PUSH(obj);
} DISPATCH(); } DISPATCH();
TARGET(BUILD_SLICE) { TARGET(BUILD_SLICE) {
PyObject* step = frame->popx(); PyObject* step = POPX();
PyObject* stop = frame->popx(); PyObject* stop = POPX();
PyObject* start = frame->popx(); PyObject* start = POPX();
Slice s; Slice s;
if(start != None) s.start = CAST(int, start); if(start != None) s.start = CAST(int, start);
if(stop != None) s.stop = CAST(int, stop); if(stop != None) s.stop = CAST(int, stop);
if(step != None) s.step = CAST(int, step); if(step != None) s.step = CAST(int, step);
frame->push(VAR(s)); PUSH(VAR(s));
} DISPATCH(); } DISPATCH();
TARGET(BUILD_TUPLE) { TARGET(BUILD_TUPLE) {
Tuple items = frame->popx_n_reversed(byte.arg); PyObject* obj = VAR(STACK_VIEW(byte.arg).to_tuple());
frame->push(VAR(std::move(items))); STACK_SHRINK(byte.arg);
PUSH(obj);
} DISPATCH(); } DISPATCH();
TARGET(BUILD_STRING) { TARGET(BUILD_STRING) {
std::stringstream ss; // asStr() may run extra bytecode std::stringstream ss;
for(int i=byte.arg-1; i>=0; i--) ss << CAST(Str&, asStr(frame->top_n(i))); auto view = STACK_VIEW(byte.arg);
frame->pop_n(byte.arg); for(PyObject* obj : view) ss << CAST(Str&, asStr(obj));
frame->push(VAR(ss.str())); STACK_SHRINK(byte.arg);
PUSH(VAR(ss.str()));
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(BINARY_OP) { TARGET(BINARY_OP) {
Args args(2); Args args(2);
args[1] = frame->popx(); // lhs args[1] = POPX(); // lhs
args[0] = frame->top(); // rhs args[0] = TOP(); // rhs
frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); TOP() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
} DISPATCH(); } DISPATCH();
#define INT_BINARY_OP(op, func) \ #define INT_BINARY_OP(op, func) \
if(is_both_int(frame->top(), frame->top_1())){ \ if(is_both_int(TOP(), SECOND())){ \
i64 b = _CAST(i64, frame->top()); \ i64 b = _CAST(i64, TOP()); \
i64 a = _CAST(i64, frame->top_1()); \ i64 a = _CAST(i64, SECOND()); \
frame->pop(); \ POP(); \
frame->top() = VAR(a op b); \ TOP() = VAR(a op b); \
}else{ \ }else{ \
Args args(2); \ Args args(2); \
args[1] = frame->popx(); \ args[1] = POPX(); \
args[0] = frame->top(); \ args[0] = TOP(); \
frame->top() = fast_call(func, std::move(args));\ TOP() = fast_call(func, std::move(args)); \
} }
TARGET(BINARY_ADD) TARGET(BINARY_ADD)
@ -298,33 +316,33 @@ __NEXT_STEP:;
DISPATCH() DISPATCH()
#undef INT_BINARY_OP #undef INT_BINARY_OP
TARGET(IS_OP) { TARGET(IS_OP) {
PyObject* rhs = frame->popx(); PyObject* rhs = POPX();
PyObject* lhs = frame->top(); PyObject* lhs = TOP();
bool ret_c = lhs == rhs; bool ret_c = lhs == rhs;
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1) ret_c = !ret_c;
frame->top() = VAR(ret_c); TOP() = VAR(ret_c);
} DISPATCH(); } DISPATCH();
TARGET(CONTAINS_OP) { TARGET(CONTAINS_OP) {
Args args(2); Args args(2);
args[0] = frame->popx(); args[0] = POPX();
args[1] = frame->top(); args[1] = TOP();
PyObject* ret = fast_call(__contains__, std::move(args)); PyObject* ret = fast_call(__contains__, std::move(args));
bool ret_c = CAST(bool, ret); bool ret_c = CAST(bool, ret);
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1) ret_c = !ret_c;
frame->top() = VAR(ret_c); TOP() = VAR(ret_c);
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(JUMP_ABSOLUTE) frame->jump_abs(byte.arg); DISPATCH(); TARGET(JUMP_ABSOLUTE) frame->jump_abs(byte.arg); DISPATCH();
TARGET(POP_JUMP_IF_FALSE) TARGET(POP_JUMP_IF_FALSE)
if(!asBool(frame->popx())) frame->jump_abs(byte.arg); if(!asBool(POPX())) frame->jump_abs(byte.arg);
DISPATCH(); DISPATCH();
TARGET(JUMP_IF_TRUE_OR_POP) TARGET(JUMP_IF_TRUE_OR_POP)
if(asBool(frame->top()) == true) frame->jump_abs(byte.arg); if(asBool(TOP()) == true) frame->jump_abs(byte.arg);
else frame->pop(); else POP();
DISPATCH(); DISPATCH();
TARGET(JUMP_IF_FALSE_OR_POP) TARGET(JUMP_IF_FALSE_OR_POP)
if(asBool(frame->top()) == false) frame->jump_abs(byte.arg); if(asBool(TOP()) == false) frame->jump_abs(byte.arg);
else frame->pop(); else POP();
DISPATCH(); DISPATCH();
TARGET(LOOP_CONTINUE) { TARGET(LOOP_CONTINUE) {
int target = co_blocks[byte.block].start; int target = co_blocks[byte.block].start;
@ -344,92 +362,91 @@ __NEXT_STEP:;
TARGET(CALL) TARGET(CALL)
TARGET(CALL_UNPACK) { TARGET(CALL_UNPACK) {
int ARGC = byte.arg; int ARGC = byte.arg;
PyObject* callable = frame->top_n(ARGC+1); PyObject* callable = PEEK(ARGC+2);
bool method_call = frame->top_n(ARGC) != _py_null; bool method_call = PEEK(ARGC+1) != _py_null;
// fast path // fast path
if(byte.op==OP_CALL && is_type(callable, tp_function)){ 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, STACK_VIEW(ARGC + int(method_call)), {});
PyObject* ret = _py_call(callable, args, {}); STACK_SHRINK(ARGC + 2);
frame->pop_n(ARGC + 2);
if(ret == nullptr) { DISPATCH_OP_CALL(); } if(ret == nullptr) { DISPATCH_OP_CALL(); }
else frame->push(ret); // a generator else PUSH(ret); // a generator
DISPATCH(); DISPATCH();
} }
Args args = STACK_VIEW(ARGC + int(method_call)).to_tuple();
Args args = frame->popx_n_reversed(ARGC + int(method_call));
if(!method_call) frame->pop();
if(byte.op == OP_CALL_UNPACK) unpack_args(args); if(byte.op == OP_CALL_UNPACK) unpack_args(args);
frame->pop();
PyObject* ret = call(callable, std::move(args), no_arg(), true); PyObject* ret = call(callable, std::move(args), no_arg(), true);
STACK_SHRINK(ARGC + 2);
if(ret == _py_op_call) { DISPATCH_OP_CALL(); } if(ret == _py_op_call) { DISPATCH_OP_CALL(); }
frame->push(ret); PUSH(ret);
} DISPATCH(); } DISPATCH();
TARGET(CALL_KWARGS) TARGET(CALL_KWARGS)
TARGET(CALL_KWARGS_UNPACK) { TARGET(CALL_KWARGS_UNPACK) {
// TODO: poor performance, refactor needed
int ARGC = byte.arg & 0xFFFF; int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 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 if(method_call) ARGC++; // add self into args
Args args = frame->popx_n_reversed(ARGC); Args args = STACK_VIEW(ARGC).to_tuple();
if(!method_call) frame->pop(); STACK_SHRINK(ARGC);
if(!method_call) POP();
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args); 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); PyObject* ret = call(callable, std::move(args), kwargs, true);
if(ret == _py_op_call) { DISPATCH_OP_CALL(); } if(ret == _py_op_call) { DISPATCH_OP_CALL(); }
frame->push(ret); PUSH(ret);
} DISPATCH(); } DISPATCH();
TARGET(RETURN_VALUE) { TARGET(RETURN_VALUE) {
PyObject* __ret = frame->popx(); PyObject* __ret = POPX();
if(frame.index == base_id){ // [ frameBase<- ] if(frame.index == base_id){ // [ frameBase<- ]
callstack.pop(); callstack.pop();
return __ret; return __ret;
}else{ }else{
callstack.pop(); callstack.pop();
frame = top_frame(); frame = top_frame();
frame->push(__ret); PUSH(__ret);
goto __NEXT_FRAME; goto __NEXT_FRAME;
} }
} }
TARGET(YIELD_VALUE) return _py_op_yield; TARGET(YIELD_VALUE) return _py_op_yield;
/*****************************************/ /*****************************************/
TARGET(LIST_APPEND) { TARGET(LIST_APPEND) {
PyObject* obj = frame->popx(); PyObject* obj = POPX();
List& list = CAST(List&, frame->top_1()); List& list = CAST(List&, SECOND());
list.push_back(obj); list.push_back(obj);
} DISPATCH(); } DISPATCH();
TARGET(DICT_ADD) { TARGET(DICT_ADD) {
PyObject* kv = frame->popx(); PyObject* kv = POPX();
Tuple& t = CAST(Tuple& ,kv); 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(); } DISPATCH();
TARGET(SET_ADD) { TARGET(SET_ADD) {
PyObject* obj = frame->popx(); PyObject* obj = POPX();
fast_call(m_add, Args{frame->top_1(), obj}); fast_call(m_add, Args{SECOND(), obj});
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(UNARY_NEGATIVE) TARGET(UNARY_NEGATIVE)
frame->top() = num_negated(frame->top()); TOP() = num_negated(TOP());
DISPATCH(); DISPATCH();
TARGET(UNARY_NOT) TARGET(UNARY_NOT)
frame->top() = VAR(!asBool(frame->top())); TOP() = VAR(!asBool(TOP()));
DISPATCH(); DISPATCH();
TARGET(UNARY_STAR) TARGET(UNARY_STAR)
frame->top() = VAR(StarWrapper(frame->top())); TOP() = VAR(StarWrapper(TOP()));
DISPATCH(); DISPATCH();
/*****************************************/ /*****************************************/
TARGET(GET_ITER) TARGET(GET_ITER)
frame->top() = asIter(frame->top()); TOP() = asIter(TOP());
DISPATCH(); DISPATCH();
TARGET(FOR_ITER) { TARGET(FOR_ITER) {
BaseIter* it = PyIter_AS_C(frame->top()); BaseIter* it = PyIter_AS_C(TOP());
PyObject* obj = it->next(); PyObject* obj = it->next();
if(obj != nullptr){ if(obj != nullptr){
frame->push(obj); PUSH(obj);
}else{ }else{
int target = co_blocks[byte.block].end; int target = co_blocks[byte.block].end;
frame->jump_abs_break(target); frame->jump_abs_break(target);
@ -454,13 +471,13 @@ __NEXT_STEP:;
PyObject* new_mod = new_module(name); PyObject* new_mod = new_module(name);
_exec(code, new_mod); _exec(code, new_mod);
new_mod->attr()._try_perfect_rehash(); new_mod->attr()._try_perfect_rehash();
frame->push(new_mod); PUSH(new_mod);
}else{ }else{
frame->push(ext_mod); PUSH(ext_mod);
} }
} DISPATCH(); } DISPATCH();
TARGET(IMPORT_STAR) { TARGET(IMPORT_STAR) {
PyObject* obj = frame->popx(); PyObject* obj = POPX();
for(auto& [name, value]: obj->attr().items()){ for(auto& [name, value]: obj->attr().items()){
std::string_view s = name.sv(); std::string_view s = name.sv();
if(s.empty() || s[0] == '_') continue; if(s.empty() || s[0] == '_') continue;
@ -472,12 +489,12 @@ __NEXT_STEP:;
TARGET(UNPACK_EX) { TARGET(UNPACK_EX) {
// asIter or iter->next may run bytecode, accidential gc may happen // asIter or iter->next may run bytecode, accidential gc may happen
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! 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); BaseIter* iter = PyIter_AS_C(obj);
for(int i=0; i<byte.arg; i++){ for(int i=0; i<byte.arg; i++){
PyObject* item = iter->next(); PyObject* item = iter->next();
if(item == nullptr) ValueError("not enough values to unpack"); if(item == nullptr) ValueError("not enough values to unpack");
frame->push(item); PUSH(item);
} }
// handle extra items // handle extra items
if(byte.op == OP_UNPACK_EX){ if(byte.op == OP_UNPACK_EX){
@ -487,7 +504,7 @@ __NEXT_STEP:;
if(item == nullptr) break; if(item == nullptr) break;
extras.push_back(item); extras.push_back(item);
} }
frame->push(VAR(extras)); PUSH(VAR(extras));
}else{ }else{
if(iter->next() != nullptr) ValueError("too many values to unpack"); if(iter->next() != nullptr) ValueError("too many values to unpack");
} }
@ -495,20 +512,20 @@ __NEXT_STEP:;
/*****************************************/ /*****************************************/
TARGET(BEGIN_CLASS) { TARGET(BEGIN_CLASS) {
StrName name(byte.arg); StrName name(byte.arg);
PyObject* super_cls = frame->popx(); PyObject* super_cls = POPX();
if(super_cls == None) super_cls = _t(tp_object); if(super_cls == None) super_cls = _t(tp_object);
check_type(super_cls, tp_type); check_type(super_cls, tp_type);
PyObject* cls = new_type_object(frame->_module, name, OBJ_GET(Type, super_cls)); PyObject* cls = new_type_object(frame->_module, name, OBJ_GET(Type, super_cls));
frame->push(cls); PUSH(cls);
} DISPATCH(); } DISPATCH();
TARGET(END_CLASS) { TARGET(END_CLASS) {
PyObject* cls = frame->popx(); PyObject* cls = POPX();
cls->attr()._try_perfect_rehash(); cls->attr()._try_perfect_rehash();
}; DISPATCH(); }; DISPATCH();
TARGET(STORE_CLASS_ATTR) { TARGET(STORE_CLASS_ATTR) {
StrName name(byte.arg); StrName name(byte.arg);
PyObject* obj = frame->popx(); PyObject* obj = POPX();
PyObject* cls = frame->top(); PyObject* cls = TOP();
cls->attr().set(name, obj); cls->attr().set(name, obj);
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
@ -517,7 +534,7 @@ __NEXT_STEP:;
// TARGET(WITH_EXIT) call(frame->pop_value(this), __exit__, no_arg()); DISPATCH(); // TARGET(WITH_EXIT) call(frame->pop_value(this), __exit__, no_arg()); DISPATCH();
/*****************************************/ /*****************************************/
TARGET(ASSERT) { TARGET(ASSERT) {
PyObject* obj = frame->top(); PyObject* obj = TOP();
Str msg; Str msg;
if(is_type(obj, tp_tuple)){ if(is_type(obj, tp_tuple)){
auto& t = CAST(Tuple&, obj); auto& t = CAST(Tuple&, obj);
@ -526,16 +543,16 @@ __NEXT_STEP:;
msg = CAST(Str&, asStr(t[1])); msg = CAST(Str&, asStr(t[1]));
} }
bool ok = asBool(obj); bool ok = asBool(obj);
frame->pop(); POP();
if(!ok) _error("AssertionError", msg); if(!ok) _error("AssertionError", msg);
} DISPATCH(); } DISPATCH();
TARGET(EXCEPTION_MATCH) { TARGET(EXCEPTION_MATCH) {
const auto& e = CAST(Exception&, frame->top()); const auto& e = CAST(Exception&, TOP());
StrName name(byte.arg); StrName name(byte.arg);
frame->push(VAR(e.match_type(name))); PUSH(VAR(e.match_type(name)));
} DISPATCH(); } DISPATCH();
TARGET(RAISE) { TARGET(RAISE) {
PyObject* obj = frame->popx(); PyObject* obj = POPX();
Str msg = obj == None ? "" : CAST(Str, asStr(obj)); Str msg = obj == None ? "" : CAST(Str, asStr(obj));
_error(StrName(byte.arg), msg); _error(StrName(byte.arg), msg);
} DISPATCH(); } DISPATCH();
@ -558,7 +575,7 @@ __NEXT_STEP:;
}catch(HandledException& e){ }catch(HandledException& e){
continue; continue;
}catch(UnhandledException& e){ }catch(UnhandledException& e){
PyObject* obj = frame->popx(); PyObject* obj = POPX();
Exception& _e = CAST(Exception&, obj); Exception& _e = CAST(Exception&, obj);
_e.st_push(frame->snapshot()); _e.st_push(frame->snapshot());
callstack.pop(); callstack.pop();
@ -569,7 +586,7 @@ __NEXT_STEP:;
throw _e; throw _e;
} }
frame = top_frame(); frame = top_frame();
frame->push(obj); PUSH(obj);
if(frame.index < base_id) throw ToBeRaisedException(); if(frame.index < base_id) throw ToBeRaisedException();
need_raise = true; need_raise = true;
}catch(ToBeRaisedException& e){ }catch(ToBeRaisedException& e){

View File

@ -6,23 +6,26 @@
namespace pkpy{ namespace pkpy{
using ValueStack = pod_vector<PyObject*>;
struct FastLocals{ struct FastLocals{
NameDictInt_ varnames_inv; NameDictInt_ varnames_inv;
PyObject** a; 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){ return a[i]; }
PyObject* operator[](int i) const { 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){ 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); int* counter = (int*)pool128.alloc(sizeof(int) + size);
*counter = 1; *counter = 1;
a = (PyObject**)(counter + 1); a = (PyObject**)(counter + 1);
memset(a, 0, size); memset(a, 0, this->size() * sizeof(void*));
} }
PyObject* try_get(StrName name){ PyObject* try_get(StrName name){
@ -40,9 +43,6 @@ struct FastLocals{
return true; return true;
} }
FastLocals(): varnames_inv(nullptr), a(nullptr) {}
FastLocals(std::nullptr_t): varnames_inv(nullptr), a(nullptr) {}
FastLocals(const FastLocals& other){ FastLocals(const FastLocals& other){
varnames_inv = other.varnames_inv; varnames_inv = other.varnames_inv;
a = other.a; a = other.a;
@ -112,8 +112,47 @@ template<> inline void gc_mark<Function>(Function& t){
t._closure._gc_mark(); 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 { struct Frame {
ValueStack _data;
int _ip = -1; int _ip = -1;
int _next_ip = 0; int _next_ip = 0;
const CodeObject* co; const CodeObject* co;
@ -121,6 +160,7 @@ struct Frame {
FastLocals _locals; FastLocals _locals;
FastLocals _closure; FastLocals _closure;
ValueStack _s;
NameDict& f_globals() noexcept { return _module->attr(); } NameDict& f_globals() noexcept { return _module->attr(); }
@ -150,60 +190,15 @@ struct Frame {
std::string stack_info(){ std::string stack_info(){
std::stringstream ss; std::stringstream ss;
ss << " ["; ss << this << ": [";
for(int i=0; i<_data.size(); i++){ for(PyObject** t=_s.begin(); t<_s.end(); t++){
ss << (i64)_data[i]; ss << *t;
if(i != _data.size()-1) ss << ", "; if(t != _s.end()-1) ss << ", ";
} }
ss << "]"; ss << "]";
return ss.str(); 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_abs(int i){ _next_ip = i; }
void jump_rel(int i){ _next_ip += i; } void jump_rel(int i){ _next_ip += i; }
@ -215,19 +210,18 @@ struct Frame {
block = co->blocks[block].parent; block = co->blocks[block].parent;
} }
if(block < 0) return false; 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) // get the stack size of the try block (depth of for loops)
int stack_size = co->blocks[block].for_loop_depth; int stack_size = co->blocks[block].for_loop_depth;
// std::cout << "stack_size: " << stack_size << std::endl; if(_s.size() < stack_size) throw std::runtime_error("invalid stack size");
if(_data.size() < stack_size) throw std::runtime_error("invalid stack size"); _s.resize(stack_size); // rollback the stack
_data.resize(stack_size); // rollback the stack _s.push(obj); // push exception object
_data.push_back(obj); // push exception object
_next_ip = co->blocks[block].end; _next_ip = co->blocks[block].end;
return true; return true;
} }
int _exit_block(int i){ 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; 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 { void _gc_mark() const {
// do return if this frame has been moved // do return if this frame has been moved
if(_data._data == nullptr) return; if(!_locals.is_valid()) return;
for(PyObject* obj : _data) OBJ_MARK(obj); for(PyObject* obj: _s) OBJ_MARK(obj);
OBJ_MARK(_module); OBJ_MARK(_module);
_locals._gc_mark(); _locals._gc_mark();
_closure._gc_mark(); _closure._gc_mark();

View File

@ -69,8 +69,7 @@ inline PyObject* Generator::next(){
frame = std::move(vm->callstack.top()); frame = std::move(vm->callstack.top());
vm->callstack.pop(); vm->callstack.pop();
state = 1; state = 1;
PyObject** _sp = frame._sp; return frame._s.popx();
return POPX();
}else{ }else{
state = 2; state = 2;
return nullptr; return nullptr;

View File

@ -143,7 +143,7 @@ struct Py_ final: PyObject {
Str obj_type_name(VM* vm, Type type); 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("<?>") #define OBJ_NAME(obj) Str("<?>")
#else #else
#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) #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) { \ static PyObject* register_class(VM* vm, PyObject* mod) { \
PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \ 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); \ T::_register(vm, mod, type); \
type->attr()._try_perfect_rehash(); \ type->attr()._try_perfect_rehash(); \
return type; \ return type; \

View File

@ -133,6 +133,7 @@ public:
T& top(){ return vec.back(); } T& top(){ return vec.back(); }
const T& top() const { return vec.back(); } const T& top() const { return vec.back(); }
T popx(){ T t = std::move(vec.back()); vec.pop_back(); return t; } T popx(){ T t = std::move(vec.back()); vec.pop_back(); return t; }
void reserve(int n){ vec.reserve(n); }
Container& data() { return vec; } Container& data() { return vec; }
}; };

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "codeobject.h"
#include "common.h" #include "common.h"
#include "frame.h" #include "frame.h"
#include "error.h" #include "error.h"
@ -897,8 +898,8 @@ inline void VM::_error(Exception e){
e.is_re = false; e.is_re = false;
throw e; throw e;
} }
PyObject** _sp = top_frame()->_sp; Frame* frame = &callstack.top();
PUSH(VAR(e)); frame->_s.push(VAR(e));
_raise(); _raise();
} }