From 751d5612fe1c34ec3df1ba298e2b2928616d6064 Mon Sep 17 00:00:00 2001 From: Dag Sverre Seljebotn Date: Thu, 27 Nov 2008 13:11:43 +0100 Subject: [PATCH] Cleanup, make manage_ref mandatory for allocate_temp. This caught a bug too. --- Cython/Compiler/Buffer.py | 4 ++-- Cython/Compiler/Code.py | 22 +++++++++++++++++----- Cython/Compiler/ExprNodes.py | 8 ++++---- Cython/Compiler/Nodes.py | 5 ++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 7ce70468..0a5f78bf 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -291,7 +291,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, # Release any existing buffer code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct) # Acquire - retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type) + retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname)) code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname))) # If acquisition failed, attempt to reacquire the old buffer @@ -353,7 +353,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, options, pos, cod # We allocate a temporary which is initialized to -1, meaning OK (!). # If an error occurs, the temp is set to the dimension index the # error is occuring at. - tmp_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type) + tmp_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) code.putln("%s = -1;" % tmp_cname) for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, bufaux.shapevars)): diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 1bafa015..10558f16 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -104,7 +104,7 @@ class FunctionState(object): def label_used(self, lbl): return lbl in self.labels_used - def allocate_temp(self, type, manage_ref=True): + def allocate_temp(self, type, manage_ref): """ Allocates a temporary (which may create a new one or get a previously allocated and released one of the same type). Type is simply registered @@ -115,11 +115,16 @@ class FunctionState(object): handling clauses. Otherwise the caller has to deal with any reference counting of the variable. + If not type.is_pyobject, then manage_ref will be ignored, but it + still has to be passed. It is recommended to pass False by convention + if it is known that type will never be a Python object. + A C string referring to the variable is returned. """ - if not type.is_pyobject and manage_ref is not True: - # Make manage_ref canonical for temps_free lookup purposes - raise ValueError("manage_ref only applicable when type.is_pyobject") + if not type.is_pyobject: + # Make manage_ref canonical, so that manage_ref will always mean + # a decref is needed. + manage_ref = False freelist = self.temps_free.get((type, manage_ref)) if freelist is not None and len(freelist) > 0: result = freelist.pop() @@ -163,7 +168,14 @@ class FunctionState(object): """ return [(name, type) for name, type, manage_ref in self.temps_in_use() - if (type.is_pyobject and manage_ref)] + if manage_ref] + + def all_managed_temps(self): + """Return a list of (cname, type) tuples of refcount-managed Python objects. + """ + return [(cname, type) + for cname, type, manage_ref in self.temps_allocated + if manage_ref] class GlobalState(object): # filename_table {string : int} for finding filename table indexes diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 87ea05c9..d7190b90 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -613,7 +613,7 @@ class NewTempExprNode(ExprNode): if self.backwards_compatible_result: self.temp_code = self.backwards_compatible_result else: - self.temp_code = code.funcstate.allocate_temp(type) + self.temp_code = code.funcstate.allocate_temp(type, manage_ref=True) else: self.temp_code = None @@ -1718,9 +1718,9 @@ class IndexNode(ExprNode): if self.buffer_type.dtype.is_pyobject: # Must manage refcounts. Decref what is already there # and incref what we put in. - ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type) + ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type, manage_ref=False) if rhs.is_temp: - rhs_code = code.funcstate.allocate_temp(rhs.type) + rhs_code = code.funcstate.allocate_temp(rhs.type, manage_ref=False) else: rhs_code = rhs.result() code.putln("%s = %s;" % (ptr, ptrexpr)) @@ -1772,7 +1772,7 @@ class IndexNode(ExprNode): def buffer_lookup_code(self, code): # Assign indices to temps - index_temps = [code.funcstate.allocate_temp(i.type) for i in self.indices] + index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False) for i in self.indices] for temp, index in zip(index_temps, self.indices): code.putln("%s = %s;" % (temp, index.result())) # Generate buffer access code using these temps diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index e7b168be..5cf0e39d 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1063,9 +1063,8 @@ class FuncDefNode(StatNode, BlockNode): # cleanup temps the old way code.put_var_xdecrefs(lenv.temp_entries) # cleanup temps the new way - for cname, type, manage_ref in code.funcstate.temps_allocated: - if type.is_pyobject and manage_ref: - code.put_xdecref(cname, type) + for cname, type in code.funcstate.all_managed_temps(): + code.put_xdecref(cname, type) # Clean up buffers -- this calls a Python function # so need to save and restore error state -- 2.26.2