# 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
# 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)):
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
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()
"""
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
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
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))
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
# 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