From 28c3b35d399fba067c7d2a2cc3d0e51b2e61d092 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 22 Jun 2024 15:46:48 +0800 Subject: [PATCH] remove `CodeObject_` --- include/pocketpy/compiler/compiler.hpp | 4 +-- include/pocketpy/compiler/expr.hpp | 4 +-- include/pocketpy/interpreter/frame.hpp | 6 ++-- include/pocketpy/interpreter/vm.hpp | 6 ++-- include/pocketpy/objects/codeobject.hpp | 7 ++-- src/compiler/compiler.cpp | 13 +++---- src/interpreter/ceval.cpp | 5 +-- src/interpreter/vm.cpp | 48 ++++++++++++++----------- src/modules/modules.cpp | 14 +++++--- src/pocketpy.cpp | 13 ++++--- src/pocketpy_c.cpp | 9 +++-- 11 files changed, 75 insertions(+), 54 deletions(-) diff --git a/include/pocketpy/compiler/compiler.hpp b/include/pocketpy/compiler/compiler.hpp index bdb06812..c4e7fe01 100644 --- a/include/pocketpy/compiler/compiler.hpp +++ b/include/pocketpy/compiler/compiler.hpp @@ -54,7 +54,7 @@ struct Compiler { CompileMode mode() const noexcept{ return lexer.src->mode; } NameScope name_scope() const noexcept; - CodeObject_ push_global_context() noexcept; + CodeObject* push_global_context() noexcept; FuncDecl_ push_f_context(Str name) noexcept; static void init_pratt_rules() noexcept; @@ -134,7 +134,7 @@ struct Compiler { public: Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false) noexcept; - [[nodiscard]] Error* compile(CodeObject_* out) noexcept; + [[nodiscard]] Error* compile(CodeObject** out) noexcept; ~Compiler(); }; diff --git a/include/pocketpy/compiler/expr.hpp b/include/pocketpy/compiler/expr.hpp index 90fbe46c..b3d3cd1c 100644 --- a/include/pocketpy/compiler/expr.hpp +++ b/include/pocketpy/compiler/expr.hpp @@ -48,12 +48,12 @@ inline void delete_expr(Expr* p) noexcept{ struct CodeEmitContext{ VM* vm; FuncDecl_ func; // optional - CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_ + CodeObject* co; // 1 CodeEmitContext <=> 1 CodeObject* vector _s_expr; int level; vector global_names; - CodeEmitContext(VM* vm, CodeObject_ co, int level) : vm(vm), co(co), level(level) { + CodeEmitContext(VM* vm, CodeObject* co, int level) : vm(vm), co(co), level(level) { c11_smallmap_s2n__ctor(&_co_consts_string_dedup_map); } diff --git a/include/pocketpy/interpreter/frame.hpp b/include/pocketpy/interpreter/frame.hpp index 0fa99c4f..568d0343 100644 --- a/include/pocketpy/interpreter/frame.hpp +++ b/include/pocketpy/interpreter/frame.hpp @@ -130,9 +130,9 @@ struct Frame { _uw_list(nullptr) {} // global scope - Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) : - _ip(co->codes.data() - 1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), - _locals(co.get(), p0), _uw_list(nullptr) {} + Frame(PyVar* p0, const CodeObject* co, PyObject* _module) : + _ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(nullptr), + _locals(co, p0), _uw_list(nullptr) {} PyVar* actual_sp_base() const { return _locals.a; } diff --git a/include/pocketpy/interpreter/vm.hpp b/include/pocketpy/interpreter/vm.hpp index 78840f72..56f8dee2 100644 --- a/include/pocketpy/interpreter/vm.hpp +++ b/include/pocketpy/interpreter/vm.hpp @@ -265,7 +265,7 @@ public: ArgsView cast_array_view(PyVar obj); void set_main_argv(int argc, char** argv); i64 normalized_index(i64 index, int size); - Str disassemble(CodeObject_ co); + Str disassemble(CodeObject* co); void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step); void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj.get()); } void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); } @@ -280,7 +280,7 @@ public: #endif #if PK_REGION("Source Execution Methods") - CodeObject_ compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false); + CodeObject* compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false); Str precompile(std::string_view source, const Str& filename, CompileMode mode); PyVar exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr); PyVar exec(std::string_view source); @@ -494,7 +494,7 @@ public: #if PK_DEBUG_CEVAL_STEP void __log_s_data(const char* title = nullptr); #endif - PyVar __py_exec_internal(const CodeObject_& code, PyVar globals, PyVar locals); + PyVar __py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals); void __breakpoint(); PyVar __format_object(PyVar, Str); PyVar __run_top_frame(); diff --git a/include/pocketpy/objects/codeobject.hpp b/include/pocketpy/objects/codeobject.hpp index 7c0c2b6f..a2a7fdd8 100644 --- a/include/pocketpy/objects/codeobject.hpp +++ b/include/pocketpy/objects/codeobject.hpp @@ -14,7 +14,6 @@ typedef PyVar (*NativeFuncC)(VM*, ArgsView); struct CodeObject; struct FuncDecl; -using CodeObject_ = std::shared_ptr; using FuncDecl_ = std::shared_ptr; struct CodeObject { @@ -69,7 +68,7 @@ struct FuncDecl { PyVar value; // default value }; - CodeObject_ code; // code object of this function + CodeObject* code; // strong ref small_vector_2 args; // indices in co->varnames c11_vector/*T=KwArg*/ kwargs; // indices in co->varnames @@ -90,12 +89,14 @@ struct FuncDecl { void _gc_mark(VM*) const; - FuncDecl(){ + FuncDecl(CodeObject* code){ + this->code = code; c11_vector__ctor(&kwargs, sizeof(KwArg)); c11_smallmap_n2i__ctor(&kw_to_index); } ~FuncDecl(){ + delete code; c11_vector__dtor(&kwargs); c11_smallmap_n2i__dtor(&kw_to_index); } diff --git a/src/compiler/compiler.cpp b/src/compiler/compiler.cpp index 0b1720f3..71dbe579 100644 --- a/src/compiler/compiler.cpp +++ b/src/compiler/compiler.cpp @@ -1,6 +1,7 @@ #include "pocketpy/compiler/compiler.hpp" #include "pocketpy/common/config.h" #include "pocketpy/interpreter/vm.hpp" +#include "pocketpy/objects/codeobject.hpp" #include @@ -19,16 +20,16 @@ NameScope Compiler::name_scope() const noexcept{ return s; } -CodeObject_ Compiler::push_global_context() noexcept{ - CodeObject_ co = std::make_shared(lexer.src, static_cast(lexer.src->filename)); +CodeObject* Compiler::push_global_context() noexcept{ + CodeObject* co = new CodeObject(lexer.src, static_cast(lexer.src->filename)); co->start_line = __i == 0 ? 1 : prev().line; contexts.push_back(CodeEmitContext(vm, co, contexts.size())); return co; } FuncDecl_ Compiler::push_f_context(Str name) noexcept{ - FuncDecl_ decl = std::make_shared(); - decl->code = std::make_shared(lexer.src, name); + CodeObject* co = new CodeObject(lexer.src, name); + FuncDecl_ decl = std::make_shared(co); decl->code->start_line = __i == 0 ? 1 : prev().line; decl->nested = name_scope() == NAME_LOCAL; contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size())); @@ -1290,7 +1291,7 @@ Compiler::Compiler(VM* vm, std::string_view source, const Str& filename, Compile init_pratt_rules(); } -Error* Compiler::compile(CodeObject_* out) noexcept{ +Error* Compiler::compile(CodeObject** out) noexcept{ assert(__i == 0); // make sure it is the first time to compile Error* err; @@ -1303,7 +1304,7 @@ Error* Compiler::compile(CodeObject_* out) noexcept{ // } // } - CodeObject_ code = push_global_context(); + CodeObject* code = push_global_context(); assert(curr().type == TK_SOF); advance(); // skip @sof, so prev() is always valid diff --git a/src/interpreter/ceval.cpp b/src/interpreter/ceval.cpp index 918005cb..475d5600 100644 --- a/src/interpreter/ceval.cpp +++ b/src/interpreter/ceval.cpp @@ -795,8 +795,9 @@ PyVar VM::__run_top_frame() { PyVar _0 = frame->co->consts[byte.arg]; std::string_view string = CAST(Str&, _0).sv(); // TODO: optimize this - CodeObject_ code = vm->compile(string, "", EVAL_MODE, true); - _0 = vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals); + CodeObject* code = vm->compile(string, "", EVAL_MODE, true); + _0 = vm->_exec(code, frame->_module, frame->_callable, frame->_locals); + delete code; // leak on error PUSH(_0); } DISPATCH() diff --git a/src/interpreter/vm.cpp b/src/interpreter/vm.cpp index 29fb6d2f..54daedf8 100644 --- a/src/interpreter/vm.cpp +++ b/src/interpreter/vm.cpp @@ -201,13 +201,16 @@ bool VM::issubclass(Type cls, Type base) { PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) { if(_module == nullptr) _module = _main; + CodeObject* code = NULL; try { #if PK_DEBUG_PRECOMPILED_EXEC == 1 Str precompiled = vm->precompile(source, filename, mode); source = precompiled.sv(); #endif - CodeObject_ code = compile(source, filename, mode); - return _exec(code, _module); + code = compile(source, filename, mode); + PyVar retval = _exec(code, _module); + delete code; // leak if exception occurs + return retval; } catch(TopLevelException e) { stderr_write(e.summary() + "\n"); } catch(const std::exception& e) { @@ -218,6 +221,7 @@ PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject Str msg = "An unknown exception occurred! It could be a bug. Please report it to @blueloveTH on GitHub.\n"; stderr_write(msg); } + delete code; callstack.clear(); s_data.clear(); return nullptr; @@ -410,12 +414,12 @@ PyObject* VM::py_import(Str path, bool throw_err) { // _lazy_modules.erase(it); // no need to erase } auto _ = __import_context.scope(path, is_init); - CodeObject_ code = compile(source, filename, EXEC_MODE); - Str name_cpnt = path_cpnts.back(); path_cpnts.pop_back(); PyObject* new_mod = new_module(name_cpnt, f_join(path_cpnts)); + CodeObject* code = compile(source, filename, EXEC_MODE); _exec(code, new_mod); + delete code; // leak if exception occurs return new_mod; } @@ -556,13 +560,13 @@ i64 VM::py_hash(PyVar obj) { } } -PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar locals) { +PyVar VM::__py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals) { Frame* frame = nullptr; if(!callstack.empty()) frame = &callstack.top(); // fast path if(frame && is_none(globals) && is_none(locals)) { - return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals); + return vm->_exec(code, frame->_module, frame->_callable, frame->_locals); } auto _lock = gc_scope_lock(); // for safety @@ -602,7 +606,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local }); PyObject* _callable = new_object(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get(); - retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp); + retval = vm->_exec(code, globals_obj, _callable, vm->s_data._sp); } if(globals_dict) { @@ -622,12 +626,12 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local } void VM::py_exec(std::string_view source, PyVar globals, PyVar locals) { - CodeObject_ code = vm->compile(source, "", EXEC_MODE, true); + CodeObject* code = vm->compile(source, "", EXEC_MODE, true); __py_exec_internal(code, globals, locals); } PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) { - CodeObject_ code = vm->compile(source, "", EVAL_MODE, true); + CodeObject* code = vm->compile(source, "", EVAL_MODE, true); return __py_exec_internal(code, globals, locals); } @@ -775,7 +779,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject return ss.str().str(); } -Str VM::disassemble(CodeObject_ co) { +Str VM::disassemble(CodeObject* co) { auto pad = [](const Str& s, const int n) { if(s.length() >= n) return s.slice(0, n); return s + std::string(n - s.length(), ' '); @@ -810,7 +814,7 @@ Str VM::disassemble(CodeObject_ co) { std::string bc_name(OP_NAMES[byte.op]); if(co->lines[i].is_virtual) bc_name += '*'; ss << " " << pad(bc_name, 25) << " "; - std::string argStr = _opcode_argstr(this, i, byte, co.get()); + std::string argStr = _opcode_argstr(this, i, byte, co); ss << argStr; if(i != co->codes.size() - 1) ss << '\n'; } @@ -983,7 +987,7 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict) { } void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const FuncDecl_& decl) { - const CodeObject* co = decl->code.get(); + const CodeObject* co = decl->code; int decl_argc = decl->args.size(); if(args.size() < decl_argc) { @@ -1070,7 +1074,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { if(s_data.is_overflow()) StackOverflowError(); const Function& fn = PK_OBJ_GET(Function, callable); - const CodeObject* co = fn.decl->code.get(); + const CodeObject* co = fn.decl->code; switch(fn.decl->type) { case FuncType_NORMAL: @@ -1380,10 +1384,10 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native int length = snprintf(buffer, sizeof(buffer), "def %s : pass", sig); std::string_view source(buffer, length); // fn(a, b, *c, d=1) -> None - CodeObject_ co = compile(source, "", EXEC_MODE); - assert(co->func_decls.size() == 1); - - FuncDecl_ decl = co->func_decls[0]; + CodeObject* code = compile(source, "", EXEC_MODE); + assert(code->func_decls.size() == 1); + FuncDecl_ decl = code->func_decls[0]; + delete code; // may leak if exception occurs decl->docstring = docstring; PyObject* f_obj = new_object(tp_native_func, fn, decl, std::move(userdata)).get(); @@ -1796,13 +1800,15 @@ void VM::__breakpoint() { std::string arg = line.substr(space + 1); if(arg.empty()) continue; // ignore empty command if(cmd == "p" || cmd == "print") { - CodeObject_ code = compile(arg, "", EVAL_MODE, true); - PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals); + CodeObject* code = compile(arg, "", EVAL_MODE, true); + PyVar retval = vm->_exec(code, frame_0->_module, frame_0->_callable, frame_0->_locals); + delete code; stdout_write(vm->py_repr(retval)); stdout_write("\n"); } else if(cmd == "!") { - CodeObject_ code = compile(arg, "", EXEC_MODE, true); - vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals); + CodeObject* code = compile(arg, "", EXEC_MODE, true); + vm->_exec(code, frame_0->_module, frame_0->_callable, frame_0->_locals); + delete code; } continue; } diff --git a/src/modules/modules.cpp b/src/modules/modules.cpp index 1fc3b04f..50c5cada 100644 --- a/src/modules/modules.cpp +++ b/src/modules/modules.cpp @@ -106,8 +106,10 @@ void add_module_json(VM* vm) { } else { sv = CAST(Str&, args[0]).sv(); } - CodeObject_ code = vm->compile(sv, "", JSON_MODE); - return vm->_exec(code, vm->callstack.top()._module); + CodeObject* code = vm->compile(sv, "", JSON_MODE); + PyVar retval = vm->_exec(code, vm->callstack.top()._module); + delete code; // leak on error + return retval; }); vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) { @@ -224,16 +226,19 @@ void add_module_dis(VM* vm) { PyObject* mod = vm->new_module("dis"); vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) { - CodeObject_ code; + CodeObject* code; + bool need_delete = false; PyVar obj = args[0]; if(is_type(obj, vm->tp_str)) { const Str& source = CAST(Str, obj); code = vm->compile(source, "", EXEC_MODE); + need_delete = true; } PyVar f = obj; if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func; code = CAST(Function&, f).decl->code; vm->stdout_write(vm->disassemble(code)); + if(need_delete) delete code; return vm->None; }); } @@ -245,8 +250,9 @@ void add_module_gc(VM* vm) { void add_module_enum(VM* vm) { PyObject* mod = vm->new_module("enum"); - CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE); + CodeObject* code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE); vm->_exec(code, mod); + delete code; // leak on error PyVar Enum = mod->attr("Enum"); vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) { new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 31dabfac..56fea6f8 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -1691,13 +1691,16 @@ void VM::__post_init_builtin_types() { try { // initialize dummy func_decl for exec/eval - CodeObject_ dynamic_co = compile("def _(): pass", "", EXEC_MODE); - __dynamic_func_decl = dynamic_co->func_decls[0]; + CodeObject* code = compile("def _(): pass", "", EXEC_MODE); + __dynamic_func_decl = code->func_decls[0]; + delete code; // may leak on error // initialize builtins - CodeObject_ code = compile(kPythonLibs_builtins, "", EXEC_MODE); + code = compile(kPythonLibs_builtins, "", EXEC_MODE); this->_exec(code, this->builtins); + delete code; // may leak on error code = compile(kPythonLibs__set, "", EXEC_MODE); this->_exec(code, this->builtins); + delete code; // may leak on error } catch(TopLevelException e) { std::cerr << e.summary() << std::endl; std::cerr << "failed to load builtins module!!" << std::endl; @@ -1723,9 +1726,9 @@ void VM::__post_init_builtin_types() { #endif } -CodeObject_ VM::compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) { +CodeObject* VM::compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) { Compiler compiler(this, source, filename, mode, unknown_global_scope); - CodeObject_ code; + CodeObject* code; Error* err = compiler.compile(&code); if(err) __compile_error(err); return code; diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index b6be1275..5a487cec 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -60,8 +60,9 @@ bool pkpy_exec(pkpy_vm* vm_handle, const char* source) { PK_ASSERT_NO_ERROR() PyVar res; PK_PROTECTED( - CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE); + CodeObject* code = vm->compile(source, "main.py", EXEC_MODE); res = vm->_exec(code, vm->_main); + delete code; // TODO: _exec may raise, so code may leak ) return res != nullptr; } @@ -76,8 +77,9 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i }else{ mod = vm->_modules[module].get(); // may raise } - CodeObject_ code = vm->compile(source, filename, (CompileMode)mode); + CodeObject* code = vm->compile(source, filename, (CompileMode)mode); res = vm->_exec(code, mod); + delete code; // TODO: _exec may raise, so code may leak ) return res != nullptr; } @@ -417,9 +419,10 @@ bool pkpy_eval(pkpy_vm* vm_handle, const char* source) { VM* vm = (VM*)vm_handle; PK_ASSERT_NO_ERROR() PK_PROTECTED( - CodeObject_ co = vm->compile(source, "", EVAL_MODE); + CodeObject* co = vm->compile(source, "", EVAL_MODE); PyVar ret = vm->_exec(co, vm->_main); vm->s_data.push(ret); + delete co; // TODO: _exec may raise, so code may leak ) return true; }