cache constant tuples (including constant call arg tuples)
authorStefan Behnel <scoder@users.berlios.de>
Tue, 16 Nov 2010 15:23:47 +0000 (16:23 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Tue, 16 Nov 2010 15:23:47 +0000 (16:23 +0100)
Cython/Compiler/Code.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py

index a3225f0e25889e9ed915af88e0d08e7fa3c364f6..fae568881b3f22c4293ec1b49c2ec604c43068b5 100644 (file)
@@ -421,6 +421,7 @@ class GlobalState(object):
         'all_the_rest',
         'pystring_table',
         'cached_builtins',
+        'cached_constants',
         'init_globals',
         'init_module',
         'cleanup_globals',
@@ -462,7 +463,12 @@ class GlobalState(object):
             w.enter_cfunc_scope()
             w.putln("static int __Pyx_InitCachedBuiltins(void) {")
 
-        
+        w = self.parts['cached_constants']
+        w.enter_cfunc_scope()
+        w.putln("")
+        w.putln("static int __Pyx_InitCachedConstants(void) {")
+        w.put_setup_refcount_context("__Pyx_InitCachedConstants")
+
         w = self.parts['init_globals']
         w.enter_cfunc_scope()
         w.putln("")
@@ -509,15 +515,27 @@ class GlobalState(object):
         if Options.cache_builtins:
             w = self.parts['cached_builtins']
             w.putln("return 0;")
-            w.put_label(w.error_label)
-            w.putln("return -1;")
+            if w.label_used(w.error_label):
+                w.put_label(w.error_label)
+                w.putln("return -1;")
             w.putln("}")
             w.exit_cfunc_scope()
 
+        w = self.parts['cached_constants']
+        w.put_finish_refcount_context()
+        w.putln("return 0;")
+        if w.label_used(w.error_label):
+            w.put_label(w.error_label)
+            w.put_finish_refcount_context()
+            w.putln("return -1;")
+        w.putln("}")
+        w.exit_cfunc_scope()
+
         w = self.parts['init_globals']
         w.putln("return 0;")
-        w.put_label(w.error_label)
-        w.putln("return -1;")
+        if w.label_used(w.error_label):
+            w.put_label(w.error_label)
+            w.putln("return -1;")
         w.putln("}")
         w.exit_cfunc_scope()
 
@@ -536,6 +554,12 @@ class GlobalState(object):
 
     # constant handling at code generation time
 
+    def get_cached_constants_writer(self):
+        return self.parts['cached_constants']
+
+    def get_globals_cleanup_writer(self):
+        return self.parts['cleanup_globals']
+
     def get_int_const(self, str_value, longness=False):
         longness = bool(longness)
         try:
@@ -544,9 +568,9 @@ class GlobalState(object):
             c = self.new_int_const(str_value, longness)
         return c
 
-    def get_py_const(self, type):
+    def get_py_const(self, type, prefix=''):
         # create a new Python object constant
-        return self.new_py_const(type)
+        return self.new_py_const(type, prefix)
 
     def get_string_const(self, text):
         # return a C string constant, creating a new one if necessary
@@ -581,8 +605,8 @@ class GlobalState(object):
         self.int_const_index[(value, longness)] = c
         return c
 
-    def new_py_const(self, type):
-        cname = self.new_const_cname()
+    def new_py_const(self, type, prefix=''):
+        cname = self.new_const_cname(prefix)
         c = PyObjectConst(cname, type)
         self.py_constants.append(c)
         return c
@@ -938,6 +962,9 @@ class CCodeWriter(object):
     def get_py_num(self, str_value, longness):
         return self.globalstate.get_int_const(str_value, longness).cname
 
+    def get_py_const(self, type, prefix=''):
+        return self.globalstate.get_py_const(type, prefix).cname
+
     def get_string_const(self, text):
         return self.globalstate.get_string_const(text).cname
 
@@ -953,6 +980,12 @@ class CCodeWriter(object):
     def intern_identifier(self, text):
         return self.get_py_string_const(text, identifier=True)
 
+    def get_cached_constants_writer(self):
+        return self.globalstate.get_cached_constants_writer()
+
+    def get_globals_cleanup_writer(self):
+        return self.globalstate.get_globals_cleanup_writer()
+
     # code generation
 
     def putln(self, code = "", safe=False):
index 3fae480af1d154295fc91f3f1a1c09a39cf1915c..4eb84f91b726b8a022c3e8714dd0a116195b1e90 100755 (executable)
@@ -3932,10 +3932,16 @@ class TupleNode(SequenceNode):
             self.is_literal = 1
         else:
             SequenceNode.analyse_types(self, env, skip_children)
+            for child in self.args:
+                if not child.is_literal:
+                    break
+            else:
+                self.is_temp = 0
+                self.is_literal = 1
 
     def calculate_result_code(self):
         if len(self.args) > 0:
-            error(self.pos, "Positive length tuples must be constructed.")
+            return self.result_code
         else:
             return Naming.empty_tuple
 
@@ -3954,6 +3960,16 @@ class TupleNode(SequenceNode):
         if len(self.args) == 0:
             # result_code is Naming.empty_tuple
             return
+        if self.is_literal:
+            # non-empty cached tuple => result is global constant,
+            # creation code goes into separate code writer
+            self.result_code = code.get_py_const(py_object_type, 'tuple_')
+            if Options.generate_cleanup_code >= 2:
+                cleanup_writer = code.get_globals_cleanup_writer()
+                cleanup_writer.put_xdecref_clear(self.result(), py_object_type, nanny=False)
+            code = code.get_cached_constants_writer()
+            code.mark_pos(self.pos)
+
         code.putln(
             "%s = PyTuple_New(%s); %s" % (
                 self.result(),
@@ -3970,6 +3986,8 @@ class TupleNode(SequenceNode):
                     i,
                     arg.py_result()))
             code.put_giveref(arg.py_result())
+        if self.is_literal:
+            code.put_giveref(self.py_result())
     
     def generate_subexpr_disposal_code(self, code):
         # We call generate_post_assignment_code here instead
index 6cf3b176ac4086e89696b6dbf8204ba9b9b3d4dc..8d8344c147b765e50122d35c42f9a1f3eb977f85 100644 (file)
@@ -1746,8 +1746,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
         if Options.cache_builtins:
             code.putln("/*--- Builtin init code ---*/")
-            code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()",
-                                              self.pos))
+            code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()", self.pos))
+
+        code.putln("/*--- Constants init code ---*/")
+        code.putln(code.error_goto_if_neg("__Pyx_InitCachedConstants()", self.pos))
 
         code.putln("/*--- Global init code ---*/")
         self.generate_global_init_code(env, code)