From: Dag Sverre Seljebotn Date: Tue, 29 Jul 2008 08:09:00 +0000 (+0200) Subject: Buffer releasing: More efficient non-error return path X-Git-Tag: 0.9.8.1~49^2~58 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ce24bec1bb4886ed611909c20a9fac977de90010;p=cython.git Buffer releasing: More efficient non-error return path --- diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 62cbf9ac..5d08fcc7 100755 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -147,16 +147,11 @@ def put_acquire_arg_buffer(entry, code, pos): # entry.cname, # entry.buffer_aux.buffer_info_var.cname)) -def put_release_buffer(entry, code): - code.putln(dedent("""\ - if (%s != Py_None) { - PyObject *__pyx_type, *__pyx_value, *__pyx_tb; - PyErr_Fetch(&__pyx_type, &__pyx_value, &__pyx_tb); - PyObject_ReleaseBuffer(%s, &%s); - PyErr_Restore(__pyx_type, __pyx_value, __pyx_tb); - }""" % (entry.cname, - entry.cname, - entry.buffer_aux.buffer_info_var.cname))) +def get_release_buffer_code(entry): + return "if (%s != Py_None) PyObject_ReleaseBuffer(%s, &%s)" % ( + entry.cname, + entry.cname, + entry.buffer_aux.buffer_info_var.cname) def put_assign_to_buffer(lhs_cname, rhs_cname, retcode_cname, buffer_aux, buffer_type, is_initialized, pos, code): diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 2fc9770e..2d6e5777 100755 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -19,6 +19,7 @@ class CCodeWriter: # error_label string error catch point label # continue_label string loop continue point label # break_label string loop break point label + # return_from_error_cleanup_label string # label_counter integer counter for naming labels # in_try_finally boolean inside try of try...finally # filename_table {string : int} for finding filename table indexes diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 00ebbbf7..aaee6856 100755 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -829,9 +829,13 @@ class FuncDefNode(StatNode, BlockNode): def generate_function_definitions(self, env, code, transforms): import Buffer + + lenv = self.local_scope + # Generate C code for header and body of function code.init_labels() - lenv = self.local_scope + code.return_from_error_cleanup_label = code.new_label() + # ----- Top-level constants used by this function code.mark_pos(self.pos) self.generate_interned_num_decls(lenv, code) @@ -899,12 +903,23 @@ class FuncDefNode(StatNode, BlockNode): val = self.return_type.default_value if val: code.putln("%s = %s;" % (Naming.retval_cname, val)) - #code.putln("goto %s;" % code.return_label) # ----- Error cleanup if code.error_label in code.labels_used: code.put_goto(code.return_label) code.put_label(code.error_label) code.put_var_xdecrefs(lenv.temp_entries) + + # Clean up buffers -- this calls a Python function + # so need to save and restore error state + buffers_present = len(lenv.buffer_entries) > 0 + if buffers_present: + code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;") + code.putln("PyErr_Fetch(&__pyx_type, &__pyx_value, &__pyx_tb);") + for entry in lenv.buffer_entries: + code.putln("%s;" % Buffer.get_release_buffer_code(entry)) + #code.putln("%s = 0;" % entry.cname) + code.putln("PyErr_Restore(__pyx_type, __pyx_value, __pyx_tb);}") + err_val = self.error_value() exc_check = self.caller_will_check_exceptions() if err_val is not None or exc_check: @@ -922,14 +937,22 @@ class FuncDefNode(StatNode, BlockNode): "%s = %s;" % ( Naming.retval_cname, err_val)) - # ----- Return cleanup + if buffers_present: + # Else, non-error return will be an empty clause + code.put_goto(code.return_from_error_cleanup_label) + + # ----- Non-error return cleanup + # PS! If adding something here, modify the conditions for the + # goto statement in error cleanup above code.put_label(code.return_label) + for entry in lenv.buffer_entries: + code.putln("%s;" % Buffer.get_release_buffer_code(entry)) + # ----- Return cleanup for both error and no-error return + code.put_label(code.return_from_error_cleanup_label) if not Options.init_local_none: for entry in lenv.var_entries: if lenv.control_flow.get_state((entry.name, 'initalized')) is not True: entry.xdecref_cleanup = 1 - for entry in lenv.buffer_entries: - Buffer.put_release_buffer(entry, code) code.put_var_decrefs(lenv.var_entries, used_only = 1) # Decref any increfed args for entry in lenv.arg_entries: