Generate module cleanup code
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 24 Oct 2007 11:50:55 +0000 (04:50 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 24 Oct 2007 11:50:55 +0000 (04:50 -0700)
Decref cdef globals, interned values, and imported types

Cython/Compiler/CmdLine.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Options.py
Cython/Compiler/Symtab.py

index aefa24fb5db57792018bbf451660c7eb66c78b3f..0cf66f2d10357661fd25e18a2f0c876c57309ef5 100644 (file)
@@ -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:
index f27e37bae460b8672407f8d8293ce5669ba4b881..f541f1f1eefb5b507fe19a5cd0dee0291c081828 100644 (file)
@@ -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;
+}
+"""]
index 3b426f24ee1fb2755899cc30f593b7f8f4e4f06d..8c190978087a0e2556e1ccab9ced39190d91ae64 100644 (file)
@@ -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
index 7c18055fdf6fe89c20476fd7bfbcbec8a6c5e1ed..3ad1b4844a4ee36842f2dc23b1886e17309c012b 100644 (file)
@@ -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)