This commit is contained in:
blueloveTH 2023-04-02 16:38:51 +08:00
parent 8364adef70
commit d1f5d31849
5 changed files with 181 additions and 180 deletions

View File

@ -13,19 +13,28 @@ inline PyObject* VM::run_frame(Frame* frame){
switch (byte.op)
{
case OP_NO_OP: continue;
case OP_SETUP_DECORATOR: continue;
/*****************************************/
case OP_POP_TOP: frame->pop(); continue;
case OP_DUP_TOP: frame->push(frame->top()); continue;
case OP_ROT_TWO: std::swap(frame->top(), frame->top_1()); continue;
case OP_PRINT_EXPR: {
PyObject* obj = frame->top(); // use top() here to avoid accidental gc
if(obj != None) *_stdout << CAST(Str, asRepr(obj)) << '\n';
frame->pop();
} continue;
/*****************************************/
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
case OP_LOAD_NONE: frame->push(None); continue;
case OP_LOAD_TRUE: frame->push(True); continue;
case OP_LOAD_FALSE: frame->push(False); continue;
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue;
case OP_LOAD_BUILTINS_EVAL: frame->push(builtins->attr(m_eval)); continue;
case OP_LOAD_FUNCTION: {
PyObject* obj = frame->co->consts[byte.arg];
Function f = CAST(Function, obj); // copy
f._module = frame->_module;
frame->push(VAR(f));
Function f = CAST(Function, obj); // copy it!
f._module = frame->_module; // setup module
frame->push(VAR(std::move(f)));
} continue;
case OP_SETUP_CLOSURE: {
Function& f = CAST(Function&, frame->top()); // reference
f._closure = frame->_locals;
} continue;
case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue;
/*****************************************/
case OP_LOAD_NAME: {
StrName name = frame->co->names[byte.arg];
@ -116,9 +125,9 @@ inline PyObject* VM::run_frame(Frame* frame){
PyObject* stop = frame->popx();
PyObject* start = frame->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);}
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));
} continue;
case OP_BUILD_TUPLE: {
@ -132,7 +141,99 @@ inline PyObject* VM::run_frame(Frame* frame){
frame->push(VAR(ss.str()));
} continue;
/*****************************************/
case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
case OP_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));
} continue;
case OP_COMPARE_OP: {
Args args(2);
args[1] = frame->popx(); // lhs
args[0] = frame->top(); // rhs
frame->top() = fast_call(COMPARE_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_BITWISE_OP: {
Args args(2);
args[1] = frame->popx(); // lhs
args[0] = frame->top(); // rhs
frame->top() = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_IS_OP: {
PyObject* rhs = frame->popx();
PyObject* lhs = frame->top();
bool ret_c = lhs == rhs;
if(byte.arg == 1) ret_c = !ret_c;
frame->top() = VAR(ret_c);
} continue;
case OP_CONTAINS_OP: {
Args args(2);
args[0] = frame->popx();
args[1] = frame->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);
} continue;
/*****************************************/
case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); continue;
case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); continue;
case OP_POP_JUMP_IF_FALSE:
if(!asBool(frame->popx())) frame->jump_abs(byte.arg);
continue;
case OP_JUMP_IF_TRUE_OR_POP:
if(asBool(frame->top()) == true) frame->jump_abs(byte.arg);
else frame->pop();
continue;
case OP_JUMP_IF_FALSE_OR_POP:
if(asBool(frame->top()) == false) frame->jump_abs(byte.arg);
else frame->pop();
continue;
case OP_LOOP_CONTINUE: {
int target = frame->co->blocks[byte.block].start;
frame->jump_abs(target);
} continue;
case OP_LOOP_BREAK: {
int target = frame->co->blocks[byte.block].end;
frame->jump_abs_safe(target);
} continue;
case OP_GOTO: {
StrName label = frame->co->names[byte.arg];
auto it = frame->co->labels.find(label);
if(it == frame->co->labels.end()) _error("KeyError", "label " + label.str().escape(true) + " not found");
frame->jump_abs_safe(it->second);
} continue;
/*****************************************/
// TODO: examine this later
case OP_CALL: case OP_CALL_UNPACK: {
Args args = frame->popx_n_reversed(byte.arg);
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
PyObject* callable = frame->popx();
PyObject* ret = call(callable, std::move(args), no_arg(), true);
if(ret == _py_op_call) return ret;
frame->push(std::move(ret));
} continue;
case OP_CALL_KWARGS: case OP_CALL_KWARGS_UNPACK: {
int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF;
Args kwargs = frame->popx_n_reversed(KWARGC*2);
Args args = frame->popx_n_reversed(ARGC);
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
PyObject* callable = frame->popx();
PyObject* ret = call(callable, std::move(args), kwargs, true);
if(ret == _py_op_call) return ret;
frame->push(std::move(ret));
} continue;
case OP_RETURN_VALUE: return frame->popx();
/*****************************************/
/*****************************************/
case OP_SETUP_DECORATOR: continue;
case OP_SETUP_CLOSURE: {
Function& f = CAST(Function&, frame->top()); // reference
f._closure = frame->_locals;
} continue;
case OP_BEGIN_CLASS: {
StrName name = frame->co->names[byte.arg];
PyObject* clsBase = frame->popx();
@ -151,43 +252,7 @@ inline PyObject* VM::run_frame(Frame* frame){
PyObject* cls = frame->top();
cls->attr().set(name, obj);
} continue;
case OP_RETURN_VALUE: return frame->popx();
case OP_PRINT_EXPR: {
PyObject* expr = frame->top(); // use top() here to avoid accidental gc
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
frame->pop();
} continue;
case OP_POP_TOP: frame->_pop(); continue;
case OP_BINARY_OP: {
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_BITWISE_OP: {
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
frame->top() = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_COMPARE_OP: {
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_IS_OP: {
PyObject* rhs = frame->pop_value(this);
bool ret_c = rhs == frame->top_value(this);
if(byte.arg == 1) ret_c = !ret_c;
frame->top() = VAR(ret_c);
} continue;
case OP_CONTAINS_OP: {
PyObject* rhs = frame->pop_value(this);
bool ret_c = CAST(bool, call(rhs, __contains__, Args{frame->pop_value(this)}));
if(byte.arg == 1) ret_c = !ret_c;
frame->push(VAR(ret_c));
} continue;
case OP_UNARY_NEGATIVE:
frame->top() = num_negated(frame->top_value(this));
continue;
@ -196,13 +261,7 @@ inline PyObject* VM::run_frame(Frame* frame){
PyObject* obj_bool = asBool(obj);
frame->push(VAR(!_CAST(bool, obj_bool)));
} continue;
case OP_POP_JUMP_IF_FALSE:
if(!_CAST(bool, asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg);
continue;
case OP_LOAD_NONE: frame->push(None); continue;
case OP_LOAD_TRUE: frame->push(True); continue;
case OP_LOAD_FALSE: frame->push(False); continue;
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue;
case OP_ASSERT: {
PyObject* _msg = frame->pop_value(this);
Str msg = CAST(Str, asStr(_msg));
@ -236,7 +295,6 @@ inline PyObject* VM::run_frame(Frame* frame){
PyObject* obj = frame->pop_value(this);
call(frame->top_1(), "add", Args{obj});
} continue;
case OP_DUP_TOP: frame->push(frame->top()); continue;
case OP_UNARY_STAR: {
if(byte.arg > 0){ // rvalue
frame->top() = VAR(StarWrapper(frame->top_value(this), true));
@ -245,33 +303,6 @@ inline PyObject* VM::run_frame(Frame* frame){
frame->top() = VAR(StarWrapper(frame->top(), false));
}
} continue;
case OP_CALL_KWARGS_UNPACK: case OP_CALL_KWARGS: {
int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF;
Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
Args args = frame->pop_n_values_reversed(this, ARGC);
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
PyObject* callable = frame->pop_value(this);
PyObject* ret = call(callable, std::move(args), kwargs, true);
if(ret == _py_op_call) return ret;
frame->push(std::move(ret));
} continue;
case OP_CALL_UNPACK: case OP_CALL: {
Args args = frame->pop_n_values_reversed(this, byte.arg);
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
PyObject* callable = frame->pop_value(this);
PyObject* ret = call(callable, std::move(args), no_arg(), true);
if(ret == _py_op_call) return ret;
frame->push(std::move(ret));
} continue;
case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); continue;
case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); continue;
case OP_GOTO: {
StrName label = frame->co->names[byte.arg].first;
auto it = frame->co->labels.find(label);
if(it == frame->co->labels.end()) _error("KeyError", "label " + label.str().escape(true) + " not found");
frame->jump_abs_safe(it->second);
} continue;
case OP_GET_ITER: {
PyObject* obj = frame->pop_value(this);
PyObject* iter = asIter(obj);
@ -289,24 +320,7 @@ inline PyObject* VM::run_frame(Frame* frame){
frame->jump_abs_safe(blockEnd);
}
} continue;
case OP_LOOP_CONTINUE: {
int blockStart = frame->co->blocks[byte.block].start;
frame->jump_abs(blockStart);
} continue;
case OP_LOOP_BREAK: {
int blockEnd = frame->co->blocks[byte.block].end;
frame->jump_abs_safe(blockEnd);
} continue;
case OP_JUMP_IF_FALSE_OR_POP: {
PyObject* expr = frame->top_value(this);
if(asBool(expr)==False) frame->jump_abs(byte.arg);
else frame->pop_value(this);
} continue;
case OP_JUMP_IF_TRUE_OR_POP: {
PyObject* expr = frame->top_value(this);
if(asBool(expr)==True) frame->jump_abs(byte.arg);
else frame->pop_value(this);
} continue;
case OP_IMPORT_NAME: {
StrName name = frame->co->names[byte.arg].first;

View File

@ -425,7 +425,7 @@ struct FStringExpr: Expr{
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line);
size++;
}
ctx->emit(OP_LOAD_EVAL_FN, BC_NOARG, line);
ctx->emit(OP_LOAD_BUILTINS_EVAL, BC_NOARG, line);
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(m[1].str())), line);
ctx->emit(OP_CALL, 1, line);
size++;
@ -514,7 +514,16 @@ struct CallExpr: Expr{
}
void emit(CodeEmitContext* ctx) override {
VM* vm = ctx->vm;
callable->emit(ctx);
// emit args
for(auto& item: args) item->emit(ctx);
// emit kwargs
for(auto& item: kwargs){
// TODO: optimize this
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(item.first)), line);
item.second->emit(ctx);
}
int KWARGC = (int)kwargs.size();
int ARGC = (int)args.size();
if(KWARGC > 0){

View File

@ -1,21 +1,5 @@
#ifdef OPCODE
OPCODE(NO_OP)
OPCODE(POP_TOP)
OPCODE(DUP_TOP)
OPCODE(CALL)
OPCODE(CALL_UNPACK)
OPCODE(CALL_KWARGS)
OPCODE(CALL_KWARGS_UNPACK)
OPCODE(RETURN_VALUE)
OPCODE(ROT_TWO)
OPCODE(BINARY_OP)
OPCODE(COMPARE_OP)
OPCODE(BITWISE_OP)
OPCODE(IS_OP)
OPCODE(CONTAINS_OP)
OPCODE(UNARY_NEGATIVE)
OPCODE(UNARY_NOT)
OPCODE(UNARY_STAR)
@ -23,32 +7,14 @@ OPCODE(UNARY_STAR)
OPCODE(LIST_APPEND)
OPCODE(MAP_ADD)
OPCODE(SET_ADD)
OPCODE(IMPORT_NAME)
OPCODE(PRINT_EXPR)
OPCODE(GET_ITER)
OPCODE(FOR_ITER)
OPCODE(WITH_ENTER)
OPCODE(WITH_EXIT)
OPCODE(LOOP_BREAK)
OPCODE(LOOP_CONTINUE)
OPCODE(POP_JUMP_IF_FALSE)
OPCODE(JUMP_ABSOLUTE)
OPCODE(SAFE_JUMP_ABSOLUTE)
OPCODE(JUMP_IF_TRUE_OR_POP)
OPCODE(JUMP_IF_FALSE_OR_POP)
OPCODE(GOTO)
OPCODE(LOAD_CONST)
OPCODE(LOAD_NONE)
OPCODE(LOAD_TRUE)
OPCODE(LOAD_FALSE)
OPCODE(LOAD_EVAL_FN)
OPCODE(LOAD_FUNCTION)
OPCODE(LOAD_ELLIPSIS)
OPCODE(ASSERT)
OPCODE(EXCEPTION_MATCH)
@ -62,9 +28,6 @@ OPCODE(TRY_BLOCK_EXIT)
OPCODE(YIELD_VALUE)
OPCODE(FAST_INDEX) // a[x]
OPCODE(FAST_INDEX_REF) // a[x]
OPCODE(SETUP_CLOSURE)
OPCODE(SETUP_DECORATOR)
OPCODE(STORE_ALL_NAMES)
@ -73,6 +36,22 @@ OPCODE(BEGIN_CLASS)
OPCODE(END_CLASS)
OPCODE(STORE_CLASS_ATTR)
/**************************/
OPCODE(NO_OP)
/**************************/
OPCODE(POP_TOP)
OPCODE(DUP_TOP)
OPCODE(ROT_TWO)
OPCODE(PRINT_EXPR)
/**************************/
OPCODE(LOAD_CONST)
OPCODE(LOAD_NONE)
OPCODE(LOAD_TRUE)
OPCODE(LOAD_FALSE)
OPCODE(LOAD_ELLIPSIS)
OPCODE(LOAD_BUILTINS_EVAL)
OPCODE(LOAD_FUNCTION)
/**************************/
OPCODE(LOAD_NAME)
OPCODE(LOAD_ATTR)
@ -95,5 +74,26 @@ OPCODE(BUILD_SLICE)
OPCODE(BUILD_TUPLE)
OPCODE(BUILD_STRING)
/**************************/
OPCODE(BINARY_OP)
OPCODE(COMPARE_OP)
OPCODE(BITWISE_OP)
OPCODE(IS_OP)
OPCODE(CONTAINS_OP)
/**************************/
OPCODE(JUMP_ABSOLUTE)
OPCODE(SAFE_JUMP_ABSOLUTE)
OPCODE(POP_JUMP_IF_FALSE)
OPCODE(JUMP_IF_TRUE_OR_POP)
OPCODE(JUMP_IF_FALSE_OR_POP)
OPCODE(LOOP_CONTINUE)
OPCODE(LOOP_BREAK)
OPCODE(GOTO)
/**************************/
OPCODE(CALL)
OPCODE(CALL_UNPACK)
OPCODE(CALL_KWARGS)
OPCODE(CALL_KWARGS_UNPACK)
OPCODE(RETURN_VALUE)
/**************************/
#endif

View File

@ -214,7 +214,7 @@ const StrName m_set = StrName::get("set");
const StrName __enter__ = StrName::get("__enter__");
const StrName __exit__ = StrName::get("__exit__");
const StrName CMP_SPECIAL_METHODS[] = {
const StrName COMPARE_SPECIAL_METHODS[] = {
StrName::get("__lt__"), StrName::get("__le__"), StrName::get("__eq__"),
StrName::get("__ne__"), StrName::get("__gt__"), StrName::get("__ge__")
};

View File

@ -320,7 +320,7 @@ public:
CodeObject_ compile(Str source, Str filename, CompileMode mode);
PyObject* num_negated(PyObject* obj);
f64 num_to_float(PyObject* obj);
PyObject* asBool(PyObject* obj);
bool asBool(PyObject* obj);
i64 hash(PyObject* obj);
PyObject* asRepr(PyObject* obj);
PyObject* new_module(StrName name);
@ -357,30 +357,13 @@ inline void CodeObject::optimize(VM* vm){
perfect_locals_capacity = find_next_capacity(base_n);
perfect_hash_seed = find_perfect_hash_seed(perfect_locals_capacity, keys);
// for(int i=1; i<codes.size(); i++){
// if(codes[i].op == OP_UNARY_NEGATIVE && codes[i-1].op == OP_LOAD_CONST){
// codes[i].op = OP_NO_OP;
// int pos = codes[i-1].arg;
// consts[pos] = vm->num_negated(consts[pos]);
// }
// if(i>=2 && codes[i].op == OP_BUILD_INDEX){
// const Bytecode& a = codes[i-1];
// const Bytecode& x = codes[i-2];
// if(codes[i].arg == 1){
// if(a.op == OP_LOAD_NAME && x.op == OP_LOAD_NAME){
// codes[i].op = OP_FAST_INDEX;
// }else continue;
// }else{
// if(a.op == OP_LOAD_NAME_REF && x.op == OP_LOAD_NAME_REF){
// codes[i].op = OP_FAST_INDEX_REF;
// }else continue;
// }
// codes[i].arg = (a.arg << 16) | x.arg;
// codes[i-1].op = OP_NO_OP;
// codes[i-2].op = OP_NO_OP;
// }
// }
for(int i=1; i<codes.size(); i++){
if(codes[i].op == OP_UNARY_NEGATIVE && codes[i-1].op == OP_LOAD_CONST){
codes[i].op = OP_NO_OP;
int pos = codes[i-1].arg;
consts[pos] = vm->num_negated(consts[pos]);
}
}
// pre-compute sn in co_consts
for(int i=0; i<consts.size(); i++){
@ -525,17 +508,17 @@ inline f64 VM::num_to_float(PyObject* obj){
return 0;
}
inline PyObject* VM::asBool(PyObject* obj){
if(is_type(obj, tp_bool)) return obj;
if(obj == None) return False;
if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0);
if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0);
inline bool VM::asBool(PyObject* obj){
if(is_type(obj, tp_bool)) return obj == True;
if(obj == None) return false;
if(is_type(obj, tp_int)) return CAST(i64, obj) != 0;
if(is_type(obj, tp_float)) return CAST(f64, obj) != 0.0;
PyObject* len_f = getattr(obj, __len__, false, true);
if(len_f != nullptr){
PyObject* ret = call(len_f, no_arg());
return VAR(CAST(i64, ret) > 0);
return CAST(i64, ret) > 0;
}
return True;
return true;
}
inline i64 VM::hash(PyObject* obj){
@ -617,11 +600,6 @@ inline Str VM::disassemble(CodeObject_ co){
if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE || byte.op == OP_STORE_NAME){
argStr += " (" + co->names[byte.arg].first.str().escape(true) + ")";
}
if(byte.op == OP_FAST_INDEX || byte.op == OP_FAST_INDEX_REF){
auto& a = co->names[byte.arg & 0xFFFF];
auto& x = co->names[(byte.arg >> 16) & 0xFFFF];
argStr += " (" + a.first.str() + '[' + x.first.str() + "])";
}
ss << argStr;
// ss << pad(argStr, 20); // may overflow
// ss << co->blocks[byte.block].to_string();