From 5c8fd54fd60cb6c3c5fef929b6337b7371ca585e Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Apr 2023 18:23:57 +0800 Subject: [PATCH] ... --- src/frame.h | 10 +++++--- src/obj.h | 1 + src/vm.h | 73 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/src/frame.h b/src/frame.h index 382cd4dd..150e75c4 100644 --- a/src/frame.h +++ b/src/frame.h @@ -102,6 +102,7 @@ struct Frame { int _ip = -1; int _next_ip = 0; ValueStack* _s; + // This is for unwinding only, use `actual_sp_base()` for value stack access PyObject** _sp_base; const CodeObject* co; @@ -137,8 +138,9 @@ struct Frame { return co->src->snapshot(line); } - int stack_size() const { return _s->_sp - _sp_base; } - ArgsView stack_view() const { return ArgsView(_sp_base, _s->_sp); } + PyObject** actual_sp_base() const { return _locals.a; } + int stack_size() const { return _s->_sp - actual_sp_base(); } + ArgsView stack_view() const { return ArgsView(actual_sp_base(), _s->_sp); } void jump_abs(int i){ _next_ip = i; } // void jump_rel(int i){ _next_ip += i; } @@ -155,8 +157,8 @@ struct Frame { // get the stack size of the try block (depth of for loops) int _stack_size = co->blocks[block].for_loop_depth; if(stack_size() < _stack_size) throw std::runtime_error("invalid stack size"); - _s->reset(_sp_base + _stack_size); // rollback the stack - _s->push(obj); // push exception object + _s->reset(actual_sp_base() + _stack_size); // rollback the stack + _s->push(obj); // push exception object _next_ip = co->blocks[block].end; return true; } diff --git a/src/obj.h b/src/obj.h index 49f2b94a..4071d655 100644 --- a/src/obj.h +++ b/src/obj.h @@ -34,6 +34,7 @@ struct FuncDecl { pod_vector kwargs; // indices in co->varnames bool nested = false; // whether this function is nested void _gc_mark() const; + bool is_simple() const { return kwargs.empty() && starred_arg == -1; } }; using FuncDecl_ = shared_ptr; diff --git a/src/vm.h b/src/vm.h index df6a6cdb..12f1b92e 100644 --- a/src/vm.h +++ b/src/vm.h @@ -593,6 +593,33 @@ inline PyObject* VM::new_module(StrName name) { return obj; } +inline std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){ + std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); + switch(byte.op){ + case OP_LOAD_CONST: + if(vm != nullptr){ + argStr += fmt(" (", CAST(Str, vm->asRepr(co->consts[byte.arg])), ")"); + } + break; + case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL: + case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR: + case OP_IMPORT_NAME: case OP_BEGIN_CLASS: + case OP_DELETE_GLOBAL: + argStr += fmt(" (", StrName(byte.arg).sv(), ")"); + break; + case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: + argStr += fmt(" (", co->varnames[byte.arg].sv(), ")"); + break; + case OP_BINARY_OP: + argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")"); + break; + case OP_LOAD_FUNCTION: + argStr += fmt(" (", co->func_decls[byte.arg]->code->name, ")"); + break; + } + return argStr; +} + inline Str VM::disassemble(CodeObject_ co){ auto pad = [](const Str& s, const int n){ if(s.length() >= n) return s.substr(0, n); @@ -625,27 +652,7 @@ inline Str VM::disassemble(CodeObject_ co){ ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); ss << " " << pad(OP_NAMES[byte.op], 20) << " "; // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5); - std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); - switch(byte.op){ - case OP_LOAD_CONST: - argStr += fmt(" (", CAST(Str, asRepr(co->consts[byte.arg])), ")"); - break; - case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL: - case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR: - case OP_IMPORT_NAME: case OP_BEGIN_CLASS: - case OP_DELETE_GLOBAL: - argStr += fmt(" (", StrName(byte.arg).sv(), ")"); - break; - case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: - argStr += fmt(" (", co->varnames[byte.arg].sv(), ")"); - break; - case OP_BINARY_OP: - argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")"); - break; - case OP_LOAD_FUNCTION: - argStr += fmt(" (", co->func_decls[byte.arg]->code->name, ")"); - break; - } + std::string argStr = _opcode_argstr(this, byte, co.get()); ss << pad(argStr, 40); // may overflow ss << co->blocks[byte.block].type; if(i != co->codes.size() - 1) ss << '\n'; @@ -706,7 +713,7 @@ inline void VM::_log_s_data(const char* title) { } output.push_back(']'); Bytecode byte = frame->co->codes[frame->_ip]; - std::cout << output << " " << OP_NAMES[byte.op] << std::endl; + std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl; } inline void VM::init_builtin_types(){ @@ -868,11 +875,8 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args, const Function& fn = CAST(Function&, callable); const CodeObject* co = fn.decl->code.get(); + PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module; - static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES]; - for(int i=0; ivarnames.size(); i++) buffer[i] = nullptr; - - int i = 0; if(args.size() < fn.decl->args.size()){ vm->TypeError(fmt( "expected ", @@ -883,6 +887,22 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args, )); } + // if this function is simple, a.k.a, no kwargs or *args + // we can avoid using buffer copy + if(fn.decl->is_simple() && !co->is_generator){ +#if DEBUG_EXTRA_CHECK + for(PyObject** p=p0; pvarnames.size() - fn.decl->args.size(); + for(int j=0; jvarnames.size()); + // prepare args for(int index: fn.decl->args) buffer[index] = args[i++]; // prepare kwdefaults @@ -911,7 +931,6 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args, if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()")); buffer[index] = kwargs[i+1]; } - PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module; s_data.reset(p0); if(co->is_generator){