From d1f5d31849335dbff4d2af1b31a25f3c00391abb Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 2 Apr 2023 16:38:51 +0800 Subject: [PATCH] up --- src/ceval.h | 220 +++++++++++++++++++++++++++----------------------- src/expr.h | 11 ++- src/opcodes.h | 76 ++++++++--------- src/str.h | 2 +- src/vm.h | 52 ++++-------- 5 files changed, 181 insertions(+), 180 deletions(-) diff --git a/src/ceval.h b/src/ceval.h index 21041305..139c31ae 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -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; diff --git a/src/expr.h b/src/expr.h index 8f35faba..fdf8c555 100644 --- a/src/expr.h +++ b/src/expr.h @@ -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){ diff --git a/src/opcodes.h b/src/opcodes.h index b0ebd237..98c0e425 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -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 \ No newline at end of file diff --git a/src/str.h b/src/str.h index 37102a5f..9cb4a001 100644 --- a/src/str.h +++ b/src/str.h @@ -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__") }; diff --git a/src/vm.h b/src/vm.h index 383a00cf..cf868ba3 100644 --- a/src/vm.h +++ b/src/vm.h @@ -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; inum_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; inum_negated(consts[pos]); + } + } // pre-compute sn in co_consts for(int i=0; i 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();