From 6ccbc0d091a017f2e45cba7b2e6b246bced03cdf Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Tue, 16 Nov 2010 16:23:47 +0100 Subject: [PATCH] cache constant tuples (including constant call arg tuples) --- Cython/Compiler/Code.py | 51 ++++++++++++++++++++++++++++------- Cython/Compiler/ExprNodes.py | 20 +++++++++++++- Cython/Compiler/ModuleNode.py | 6 +++-- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index a3225f0e..fae56888 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -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): diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 3fae480a..4eb84f91 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -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 diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 6cf3b176..8d8344c1 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -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) -- 2.26.2