From: Robert Bradshaw Date: Wed, 24 Oct 2007 11:50:55 +0000 (-0700) Subject: Generate module cleanup code X-Git-Tag: 0.9.6.14~29^2~111 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=fce655c1fa69775af9e5384cd9993b7ce66c9582;p=cython.git Generate module cleanup code Decref cdef globals, interned values, and imported types --- diff --git a/Cython/Compiler/CmdLine.py b/Cython/Compiler/CmdLine.py index aefa24fb..0cf66f2d 100644 --- a/Cython/Compiler/CmdLine.py +++ b/Cython/Compiler/CmdLine.py @@ -80,6 +80,8 @@ def parse_command_line(args): Options.pre_import = pop_arg() elif option == "--incref-local-binop": Options.incref_local_binop = 1 + elif option == "--cleanup": + Options.generate_cleanup_code = int(pop_arg()) else: bad_usage() else: diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index f27e37ba..f541f1f1 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -217,6 +217,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_method_table(env, code) self.generate_filename_init_prototype(code) self.generate_module_init_func(modules[:-1], env, code) + self.generate_module_cleanup_func(env, code) self.generate_filename_table(code) self.generate_utility_functions(env, code) @@ -1262,13 +1263,47 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("/*--- Execution code ---*/") self.body.generate_execution_code(code) + + if Options.generate_cleanup_code: + code.putln("if (__Pyx_RegisterCleanup()) %s;" % code.error_goto(self.pos)) + code.putln("return;") code.put_label(code.error_label) code.put_var_xdecrefs(env.temp_entries) code.putln('__Pyx_AddTraceback("%s");' % (env.qualified_name)) env.use_utility_code(Nodes.traceback_utility_code) code.putln('}') - + + def generate_module_cleanup_func(self, env, code): + if not Options.generate_cleanup_code: + return + env.use_utility_code(import_module_utility_code) + env.use_utility_code(register_cleanup_utility_code) + code.putln() + code.putln('static PyObject* cleanup(PyObject *self, PyObject *unused) {') + if Options.generate_cleanup_code >= 2: + code.putln("/*--- Global cleanup code ---*/") + for entry in reversed(env.var_entries): + if entry.visibility != 'extern': + if entry.type.is_pyobject: + code.put_var_decref_clear(entry) + if Options.generate_cleanup_code >= 3: + code.putln("/*--- Type import cleanup code ---*/") + for type, _ in env.types_imported.items(): + code.put_decref("((PyObject*)%s)" % type.typeptr_cname, PyrexTypes.py_object_type) + if Options.cache_builtins: + code.putln("/*--- Builtin cleanup code ---*/") + for entry in env.builtin_scope().cached_entries: + code.put_var_decref_clear(entry) + code.putln("/*--- Intern cleanup code ---*/") + for entry in env.pynum_entries: + code.put_var_decref_clear(entry) + if env.intern_map: + for name, cname in env.intern_map.items(): + code.put_decref_clear(cname, PyrexTypes.py_object_type) + code.putln("Py_INCREF(Py_None); return Py_None;") + code.putln('}') + def generate_filename_init_call(self, code): code.putln("%s();" % Naming.fileinit_cname) @@ -1689,3 +1724,48 @@ bad: } #endif """ % dict(API = Naming.api_name)] + +register_cleanup_utility_code = [ +""" +static int __Pyx_RegisterCleanup(); /*proto*/ +static PyObject* cleanup(PyObject *self, PyObject *unused); /*proto*/ +static PyMethodDef cleanup_def = {"__cleanup", (PyCFunction)&cleanup, METH_NOARGS, 0}; +""",""" +static int __Pyx_RegisterCleanup() { + /* Don't use Py_AtExit because that has a 32-call limit + * and is called after python finalization. + */ + + PyObject *cleanup_func = 0; + PyObject *atexit = 0; + PyObject *reg = 0; + PyObject *args = 0; + PyObject *res = 0; + int ret = -1; + + cleanup_func = PyCFunction_New(&cleanup_def, 0); + args = PyTuple_New(1); + if (!cleanup_func || !args) + goto bad; + PyTuple_SET_ITEM(args, 0, cleanup_func); + cleanup_func = 0; + + atexit = __Pyx_ImportModule("atexit"); + if (!atexit) + goto bad; + reg = PyObject_GetAttrString(atexit, "register"); + if (!reg) + goto bad; + res = PyObject_CallObject(reg, args); + if (!res) + goto bad; + ret = 0; +bad: + Py_XDECREF(cleanup_func); + Py_XDECREF(atexit); + Py_XDECREF(reg); + Py_XDECREF(args); + Py_XDECREF(res); + return ret; +} +"""] diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 3b426f24..8c190978 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -16,3 +16,6 @@ pre_import = None # safe detection of inplace operators. incref_local_binop = 0 +# Decref global variables in this module on exit for garbage collection. +# 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects +generate_cleanup_code = 1 diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 7c18055f..3ad1b484 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -449,7 +449,7 @@ class Scope: # Add an entry for an int constant. cname = "%s%s" % (Naming.interned_num_prefix, value) cname = cname.replace('-', 'neg_').replace('.','_') - entry = Entry("", cname, c_long_type, init = value) + entry = Entry("", cname, py_object_type, init = value) entry.used = 1 entry.is_interned = 1 self.const_entries.append(entry)