فهرست منبع

remove `CodeObject_`

blueloveTH 1 سال پیش
والد
کامیت
28c3b35d39

+ 2 - 2
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();
 };
 

+ 2 - 2
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<Expr*> _s_expr;
     int level;
     vector<StrName> 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);
     }
 

+ 3 - 3
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; }
 

+ 3 - 3
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();

+ 4 - 3
include/pocketpy/objects/codeobject.hpp

@@ -14,7 +14,6 @@ typedef PyVar (*NativeFuncC)(VM*, ArgsView);
 
 struct CodeObject;
 struct FuncDecl;
-using CodeObject_ = std::shared_ptr<CodeObject>;
 using FuncDecl_ = std::shared_ptr<FuncDecl>;
 
 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<int, 8> 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);
     }

+ 7 - 6
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 <cstdarg>
 
@@ -19,16 +20,16 @@ NameScope Compiler::name_scope() const noexcept{
     return s;
 }
 
-CodeObject_ Compiler::push_global_context() noexcept{
-    CodeObject_ co = std::make_shared<CodeObject>(lexer.src, static_cast<const Str&>(lexer.src->filename));
+CodeObject* Compiler::push_global_context() noexcept{
+    CodeObject* co = new CodeObject(lexer.src, static_cast<const Str&>(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<FuncDecl>();
-    decl->code = std::make_shared<CodeObject>(lexer.src, name);
+    CodeObject* co = new CodeObject(lexer.src, name);
+    FuncDecl_ decl = std::make_shared<FuncDecl>(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

+ 3 - 2
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>", EVAL_MODE, true);
-                        _0 = vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
+                        CodeObject* code = vm->compile(string, "<eval>", EVAL_MODE, true);
+                        _0 = vm->_exec(code, frame->_module, frame->_callable, frame->_locals);
+                        delete code;    // leak on error
                         PUSH(_0);
                     }
                         DISPATCH()

+ 27 - 21
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<Function>(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>", EXEC_MODE, true);
+    CodeObject* code = vm->compile(source, "<exec>", 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>", EVAL_MODE, true);
+    CodeObject* code = vm->compile(source, "<eval>", 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, "<bind>", EXEC_MODE);
-    assert(co->func_decls.size() == 1);
-    
-    FuncDecl_ decl = co->func_decls[0];
+    CodeObject* code = compile(source, "<bind>", 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<NativeFunc>(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, "<stdin>", EVAL_MODE, true);
-                PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
+                CodeObject* code = compile(arg, "<stdin>", 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, "<stdin>", EXEC_MODE, true);
-                vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
+                CodeObject* code = compile(arg, "<stdin>", EXEC_MODE, true);
+                vm->_exec(code, frame_0->_module, frame_0->_callable, frame_0->_locals);
+                delete code;
             }
             continue;
         }

+ 10 - 4
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>", JSON_MODE);
-        return vm->_exec(code, vm->callstack.top()._module);
+        CodeObject* code = vm->compile(sv, "<json>", 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, "<dis>", 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

+ 8 - 5
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", "<dynamic>", EXEC_MODE);
-        __dynamic_func_decl = dynamic_co->func_decls[0];
+        CodeObject* code = compile("def _(): pass", "<dynamic>", EXEC_MODE);
+        __dynamic_func_decl = code->func_decls[0];
+        delete code;    // may leak on error
         // initialize builtins
-        CodeObject_ code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE);
+        code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE);
         this->_exec(code, this->builtins);
+        delete code;    // may leak on error
         code = compile(kPythonLibs__set, "<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;

+ 6 - 3
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>", EVAL_MODE);
+        CodeObject* co = vm->compile(source, "<eval>", 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;
 }