This commit is contained in:
blueloveTH 2023-04-17 17:48:13 +08:00
parent bccabaa872
commit 697c2b0922

View File

@ -11,6 +11,10 @@ inline PyObject* VM::_run_top_frame(){
const int base_id = frame.index; const int base_id = frame.index;
bool need_raise = false; bool need_raise = false;
// shared registers
PyObject *_0, *_1, *_2;
StrName _name;
while(true){ while(true){
#if DEBUG_EXTRA_CHECK #if DEBUG_EXTRA_CHECK
if(frame.index < base_id) FATAL_ERROR(); if(frame.index < base_id) FATAL_ERROR();
@ -21,8 +25,6 @@ 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, 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; } #define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; }
@ -63,11 +65,10 @@ __NEXT_STEP:;
TARGET(POP_TOP) POP(); DISPATCH(); TARGET(POP_TOP) POP(); DISPATCH();
TARGET(DUP_TOP) PUSH(TOP()); DISPATCH(); TARGET(DUP_TOP) PUSH(TOP()); DISPATCH();
TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH(); TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH();
TARGET(PRINT_EXPR) { TARGET(PRINT_EXPR)
PyObject* obj = TOP(); // use top() to avoid accidental gc if(TOP() != None) *_stdout << CAST(Str&, asRepr(TOP())) << '\n';
if(obj != None) *_stdout << CAST(Str&, asRepr(obj)) << '\n';
POP(); POP();
} DISPATCH(); DISPATCH();
/*****************************************/ /*****************************************/
TARGET(LOAD_CONST) TARGET(LOAD_CONST)
heap._auto_collect(); heap._auto_collect();
@ -93,134 +94,127 @@ __NEXT_STEP:;
/*****************************************/ /*****************************************/
TARGET(LOAD_FAST) { TARGET(LOAD_FAST) {
heap._auto_collect(); heap._auto_collect();
PyObject* val = frame->_locals[byte.arg]; _0 = frame->_locals[byte.arg];
if(val == nullptr) vm->NameError(co->varnames[byte.arg]); if(_0 == nullptr) vm->NameError(co->varnames[byte.arg]);
PUSH(val); PUSH(_0);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_NAME) { TARGET(LOAD_NAME)
heap._auto_collect(); heap._auto_collect();
StrName name(byte.arg); _name = StrName(byte.arg);
PyObject* val; _0 = frame->_locals.try_get(_name);
val = frame->_locals.try_get(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } _0 = frame->_closure.try_get(_name);
val = frame->_closure.try_get(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } _0 = frame->f_globals().try_get(_name);
val = frame->f_globals().try_get(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } _0 = vm->builtins->attr().try_get(_name);
val = vm->builtins->attr().try_get(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } vm->NameError(_name);
vm->NameError(name); DISPATCH();
} DISPATCH();
TARGET(LOAD_NONLOCAL) { TARGET(LOAD_NONLOCAL) {
heap._auto_collect(); heap._auto_collect();
StrName name(byte.arg); _name = StrName(byte.arg);
PyObject* val; // _0 = frame->_locals.try_get(_name);
val = frame->_closure.try_get(name); // if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } _0 = frame->_closure.try_get(_name);
val = frame->f_globals().try_get(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } _0 = frame->f_globals().try_get(_name);
val = vm->builtins->attr().try_get(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
if(val != nullptr) { PUSH(val); DISPATCH(); } _0 = vm->builtins->attr().try_get(_name);
vm->NameError(name); if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
vm->NameError(_name);
DISPATCH();
} DISPATCH(); } DISPATCH();
TARGET(LOAD_GLOBAL) { TARGET(LOAD_GLOBAL)
heap._auto_collect(); heap._auto_collect();
StrName name(byte.arg); _name = StrName(byte.arg);
PyObject* val = frame->f_globals().try_get(name); _0 = frame->f_globals().try_get(_name);
if(val != nullptr) { PUSH(val); DISPATCH(); } if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
val = vm->builtins->attr().try_get(name); _0 = vm->builtins->attr().try_get(_name);
if(val != nullptr) { PUSH(val); DISPATCH(); } if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
vm->NameError(name); vm->NameError(_name);
} DISPATCH(); DISPATCH();
TARGET(LOAD_ATTR) { TARGET(LOAD_ATTR)
PyObject* a = TOP(); TOP() = getattr(TOP(), StrName(byte.arg));
StrName name(byte.arg); DISPATCH();
TOP() = getattr(a, name); TARGET(LOAD_METHOD)
} DISPATCH(); TOP() = get_unbound_method(TOP(), StrName(byte.arg), &_0, true, true);
TARGET(LOAD_METHOD) { PUSH(_0);
PyObject* a = TOP(); DISPATCH();
StrName name(byte.arg); TARGET(LOAD_SUBSCR)
PyObject* self; _1 = POPX();
TOP() = get_unbound_method(a, name, &self, true, true); _0 = TOP();
PUSH(self); TOP() = call_method(_0, __getitem__, _1);
} DISPATCH(); DISPATCH();
TARGET(LOAD_SUBSCR) {
PyObject* b = POPX();
PyObject* a = TOP();
TOP() = call_method(a, __getitem__, b);
} DISPATCH();
TARGET(STORE_FAST) TARGET(STORE_FAST)
frame->_locals[byte.arg] = POPX(); frame->_locals[byte.arg] = POPX();
DISPATCH(); DISPATCH();
TARGET(STORE_NAME) { TARGET(STORE_NAME)
StrName name(byte.arg); _name = StrName(byte.arg);
PyObject* val = POPX(); _0 = POPX();
if(frame->_locals.is_valid()){ if(frame->_locals.is_valid()){
bool ok = frame->_locals.try_set(name, val); bool ok = frame->_locals.try_set(_name, _0);
if(!ok) vm->NameError(name); if(!ok) vm->NameError(_name);
}else{ }else{
frame->f_globals().set(name, val); frame->f_globals().set(_name, _0);
} }
} DISPATCH(); DISPATCH();
TARGET(STORE_GLOBAL) { TARGET(STORE_GLOBAL)
StrName name(byte.arg); frame->f_globals().set(StrName(byte.arg), POPX());
frame->f_globals().set(name, POPX()); DISPATCH();
} DISPATCH();
TARGET(STORE_ATTR) { TARGET(STORE_ATTR) {
StrName name(byte.arg); _0 = TOP(); // a
PyObject* a = TOP(); _1 = SECOND(); // val
PyObject* val = SECOND(); setattr(_0, StrName(byte.arg), _1);
setattr(a, name, val);
STACK_SHRINK(2); STACK_SHRINK(2);
} DISPATCH(); } DISPATCH();
TARGET(STORE_SUBSCR) { TARGET(STORE_SUBSCR)
// val a b _2 = POPX(); // b
PyObject* b = POPX(); _1 = POPX(); // a
PyObject* a = POPX(); _0 = POPX(); // val
PyObject* val = POPX(); call_method(_1, __setitem__, _2, _0);
call_method(a, __setitem__, b, val); DISPATCH();
} DISPATCH(); TARGET(DELETE_FAST)
TARGET(DELETE_FAST) { _0 = frame->_locals[byte.arg];
PyObject* val = frame->_locals[byte.arg]; if(_0 == nullptr) vm->NameError(co->varnames[byte.arg]);
if(val == nullptr) vm->NameError(co->varnames[byte.arg]);
frame->_locals[byte.arg] = nullptr; frame->_locals[byte.arg] = nullptr;
} DISPATCH(); DISPATCH();
TARGET(DELETE_NAME) { TARGET(DELETE_NAME)
StrName name(byte.arg); _name = StrName(byte.arg);
if(frame->_locals.is_valid()){ if(frame->_locals.is_valid()){
if(!frame->_locals.contains(name)) vm->NameError(name); if(!frame->_locals.contains(_name)) vm->NameError(_name);
frame->_locals.erase(name); frame->_locals.erase(_name);
}else{ }else{
if(!frame->f_globals().contains(name)) vm->NameError(name); if(!frame->f_globals().contains(_name)) vm->NameError(_name);
frame->f_globals().erase(name); frame->f_globals().erase(_name);
} }
} DISPATCH(); DISPATCH();
TARGET(DELETE_GLOBAL) { TARGET(DELETE_GLOBAL)
StrName name(byte.arg); _name = StrName(byte.arg);
if(frame->f_globals().contains(name)){ if(frame->f_globals().contains(_name)){
frame->f_globals().erase(name); frame->f_globals().erase(_name);
}else{ }else{
NameError(name); NameError(_name);
} }
} DISPATCH(); DISPATCH();
TARGET(DELETE_ATTR) { TARGET(DELETE_ATTR)
PyObject* a = POPX(); _0 = POPX();
StrName name(byte.arg); _name = StrName(byte.arg);
if(!a->is_attr_valid()) TypeError("cannot delete attribute"); if(!_0->is_attr_valid()) TypeError("cannot delete attribute");
if(!a->attr().contains(name)) AttributeError(a, name); if(!_0->attr().contains(_name)) AttributeError(_0, _name);
a->attr().erase(name); _0->attr().erase(_name);
} DISPATCH(); DISPATCH();
TARGET(DELETE_SUBSCR) { TARGET(DELETE_SUBSCR)
PyObject* b = POPX(); _1 = POPX();
PyObject* a = POPX(); _0 = POPX();
call_method(a, __delitem__, b); call_method(_0, __delitem__, _1);
} DISPATCH(); DISPATCH();
/*****************************************/ /*****************************************/
TARGET(BUILD_LIST) { TARGET(BUILD_LIST)
PyObject* obj = VAR(STACK_VIEW(byte.arg).to_list()); _0 = VAR(STACK_VIEW(byte.arg).to_list());
STACK_SHRINK(byte.arg); STACK_SHRINK(byte.arg);
PUSH(obj); PUSH(_0);
} DISPATCH(); DISPATCH();
TARGET(BUILD_DICT) { TARGET(BUILD_DICT) {
PyObject* t = VAR(STACK_VIEW(byte.arg).to_tuple()); PyObject* t = VAR(STACK_VIEW(byte.arg).to_tuple());
PyObject* obj = call_(builtins->attr(m_dict), t); PyObject* obj = call_(builtins->attr(m_dict), t);
@ -234,20 +228,20 @@ __NEXT_STEP:;
PUSH(obj); PUSH(obj);
} DISPATCH(); } DISPATCH();
TARGET(BUILD_SLICE) { TARGET(BUILD_SLICE) {
PyObject* step = POPX(); _2 = POPX();
PyObject* stop = POPX(); _1 = POPX();
PyObject* start = POPX(); _0 = POPX();
Slice s; Slice s;
if(start != None) s.start = CAST(int, start); if(_0 != None) s.start = CAST(int, _0);
if(stop != None) s.stop = CAST(int, stop); if(_1 != None) s.stop = CAST(int, _1);
if(step != None) s.step = CAST(int, step); if(_2 != None) s.step = CAST(int, _2);
PUSH(VAR(s)); PUSH(VAR(s));
} DISPATCH(); } DISPATCH();
TARGET(BUILD_TUPLE) { TARGET(BUILD_TUPLE)
PyObject* obj = VAR(STACK_VIEW(byte.arg).to_tuple()); _0 = VAR(STACK_VIEW(byte.arg).to_tuple());
STACK_SHRINK(byte.arg); STACK_SHRINK(byte.arg);
PUSH(obj); PUSH(_0);
} DISPATCH(); DISPATCH();
TARGET(BUILD_STRING) { TARGET(BUILD_STRING) {
std::stringstream ss; std::stringstream ss;
auto view = STACK_VIEW(byte.arg); auto view = STACK_VIEW(byte.arg);
@ -256,11 +250,11 @@ __NEXT_STEP:;
PUSH(VAR(ss.str())); PUSH(VAR(ss.str()));
} DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(BINARY_OP) { TARGET(BINARY_OP)
PyObject* b = POPX(); _1 = POPX(); // b
PyObject* a = TOP(); _0 = TOP(); // a
TOP() = call_method(a, BINARY_SPECIAL_METHODS[byte.arg], b); TOP() = call_method(_0, BINARY_SPECIAL_METHODS[byte.arg], _1);
} DISPATCH(); DISPATCH();
#define INT_BINARY_OP(op, func) \ #define INT_BINARY_OP(op, func) \
if(is_both_int(TOP(), SECOND())){ \ if(is_both_int(TOP(), SECOND())){ \
@ -269,9 +263,9 @@ __NEXT_STEP:;
POP(); \ POP(); \
TOP() = VAR(a op b); \ TOP() = VAR(a op b); \
}else{ \ }else{ \
PyObject* b = POPX(); \ _1 = POPX(); \
PyObject* a = TOP(); \ _0 = TOP(); \
TOP() = call_method(a, func, b); \ TOP() = call_method(_0, func, _1); \
} }
TARGET(BINARY_ADD) TARGET(BINARY_ADD)
@ -323,22 +317,29 @@ __NEXT_STEP:;
INT_BINARY_OP(^, __xor__) INT_BINARY_OP(^, __xor__)
DISPATCH() DISPATCH()
#undef INT_BINARY_OP #undef INT_BINARY_OP
TARGET(IS_OP) {
PyObject* rhs = POPX(); TARGET(IS_OP)
PyObject* lhs = TOP(); _1 = POPX(); // rhs
bool ret_c = lhs == rhs; _0 = TOP(); // lhs
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1){
TOP() = VAR(ret_c); TOP() = VAR(_0 != _1);
} DISPATCH(); }else{
TARGET(CONTAINS_OP) { TOP() = VAR(_0 == _1);
}
DISPATCH();
TARGET(CONTAINS_OP)
// a in b -> b __contains__ a // a in b -> b __contains__ a
PyObject* ret = call_method(TOP(), __contains__, SECOND()); _0 = call_method(TOP(), __contains__, SECOND());
bool ret_c = CAST(bool, ret); if(byte.arg == 1){
if(byte.arg == 1) ret_c = !ret_c; TOP() = VAR(!CAST(bool, _0));
TOP() = VAR(ret_c); }else{
} DISPATCH(); TOP() = VAR(CAST(bool, _0));
}
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(POPX())) frame->jump_abs(byte.arg); if(!asBool(POPX())) frame->jump_abs(byte.arg);
DISPATCH(); DISPATCH();
@ -354,10 +355,11 @@ __NEXT_STEP:;
int target = co_blocks[byte.block].start; int target = co_blocks[byte.block].start;
frame->jump_abs(target); frame->jump_abs(target);
} DISPATCH(); } DISPATCH();
TARGET(LOOP_BREAK) { TARGET(LOOP_BREAK)
int target = co_blocks[byte.block].end; frame->jump_abs_break(
frame->jump_abs_break(target); co_blocks[byte.block].end
} DISPATCH(); );
DISPATCH();
TARGET(GOTO) { TARGET(GOTO) {
StrName name(byte.arg); StrName name(byte.arg);
int index = co->labels->try_get(name); int index = co->labels->try_get(name);
@ -368,27 +370,27 @@ __NEXT_STEP:;
TARGET(BEGIN_CALL) TARGET(BEGIN_CALL)
PUSH(_py_begin_call); PUSH(_py_begin_call);
DISPATCH(); DISPATCH();
TARGET(CALL) { TARGET(CALL)
int ARGC = byte.arg & 0xFFFF; _0 = _vectorcall(
int KWARGC = (byte.arg >> 16) & 0xFFFF; byte.arg & 0xFFFF, // ARGC
PyObject* ret = _vectorcall(ARGC, KWARGC, true); (byte.arg>>16) & 0xFFFF, // KWARGC
if(ret == _py_op_call) { DISPATCH_OP_CALL(); } true
PUSH(ret); );
if(_0 == _py_op_call) DISPATCH_OP_CALL();
PUSH(_0);
DISPATCH(); DISPATCH();
} TARGET(RETURN_VALUE)
TARGET(RETURN_VALUE) { _0 = POPX();
PyObject* __ret = POPX();
// cleanup the stack on return // cleanup the stack on return
callstack.pop(); callstack.pop();
s_data.reset(frame->_sp_base); s_data.reset(frame->_sp_base);
if(frame.index == base_id){ // [ frameBase<- ] if(frame.index == base_id){ // [ frameBase<- ]
return __ret; return _0;
}else{ }else{
frame = top_frame(); frame = top_frame();
PUSH(__ret); PUSH(_0);
goto __NEXT_FRAME; goto __NEXT_FRAME;
} }
}
TARGET(YIELD_VALUE) TARGET(YIELD_VALUE)
return _py_op_yield; return _py_op_yield;
/*****************************************/ /*****************************************/
@ -423,9 +425,9 @@ __NEXT_STEP:;
DISPATCH(); DISPATCH();
TARGET(FOR_ITER) { TARGET(FOR_ITER) {
BaseIter* it = PyIter_AS_C(TOP()); BaseIter* it = PyIter_AS_C(TOP());
PyObject* obj = it->next(); _0 = it->next();
if(obj != nullptr){ if(_0 != nullptr){
PUSH(obj); PUSH(_0);
}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);