Commit eb1aba11 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents dc38b785 5748aa14
...@@ -291,7 +291,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, ...@@ -291,7 +291,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
# Release any existing buffer # Release any existing buffer
code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct) code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct)
# Acquire # 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("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname))) code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname)))
# If acquisition failed, attempt to reacquire the old buffer # 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 ...@@ -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 (!). # We allocate a temporary which is initialized to -1, meaning OK (!).
# If an error occurs, the temp is set to the dimension index the # If an error occurs, the temp is set to the dimension index the
# error is occuring at. # 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) code.putln("%s = -1;" % tmp_cname)
for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames,
bufaux.shapevars)): bufaux.shapevars)):
......
...@@ -104,7 +104,7 @@ class FunctionState(object): ...@@ -104,7 +104,7 @@ class FunctionState(object):
def label_used(self, lbl): def label_used(self, lbl):
return lbl in self.labels_used 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 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 allocated and released one of the same type). Type is simply registered
...@@ -115,11 +115,16 @@ class FunctionState(object): ...@@ -115,11 +115,16 @@ class FunctionState(object):
handling clauses. Otherwise the caller has to deal with any reference handling clauses. Otherwise the caller has to deal with any reference
counting of the variable. 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. A C string referring to the variable is returned.
""" """
if not type.is_pyobject and manage_ref is not True: if not type.is_pyobject:
# Make manage_ref canonical for temps_free lookup purposes # Make manage_ref canonical, so that manage_ref will always mean
raise ValueError("manage_ref only applicable when type.is_pyobject") # a decref is needed.
manage_ref = False
freelist = self.temps_free.get((type, manage_ref)) freelist = self.temps_free.get((type, manage_ref))
if freelist is not None and len(freelist) > 0: if freelist is not None and len(freelist) > 0:
result = freelist.pop() result = freelist.pop()
...@@ -163,7 +168,14 @@ class FunctionState(object): ...@@ -163,7 +168,14 @@ class FunctionState(object):
""" """
return [(name, type) return [(name, type)
for name, type, manage_ref in self.temps_in_use() 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): class GlobalState(object):
# filename_table {string : int} for finding filename table indexes # filename_table {string : int} for finding filename table indexes
......
...@@ -613,7 +613,7 @@ class NewTempExprNode(ExprNode): ...@@ -613,7 +613,7 @@ class NewTempExprNode(ExprNode):
if self.backwards_compatible_result: if self.backwards_compatible_result:
self.temp_code = self.backwards_compatible_result self.temp_code = self.backwards_compatible_result
else: else:
self.temp_code = code.funcstate.allocate_temp(type) self.temp_code = code.funcstate.allocate_temp(type, manage_ref=True)
else: else:
self.temp_code = None self.temp_code = None
...@@ -1718,18 +1718,13 @@ class IndexNode(ExprNode): ...@@ -1718,18 +1718,13 @@ class IndexNode(ExprNode):
if self.buffer_type.dtype.is_pyobject: if self.buffer_type.dtype.is_pyobject:
# Must manage refcounts. Decref what is already there # Must manage refcounts. Decref what is already there
# and incref what we put in. # 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 = rhs.result()
rhs_code = code.funcstate.allocate_temp(rhs.type)
else:
rhs_code = rhs.result()
code.putln("%s = %s;" % (ptr, ptrexpr)) code.putln("%s = %s;" % (ptr, ptrexpr))
code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % ( code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % (
ptr, rhs_code ptr, rhs_code
)) ))
code.putln("*%s %s= %s;" % (ptr, op, rhs_code)) code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
if rhs.is_temp:
code.funcstate.release_temp(rhs_code)
code.funcstate.release_temp(ptr) code.funcstate.release_temp(ptr)
else: else:
# Simple case # Simple case
...@@ -1772,7 +1767,7 @@ class IndexNode(ExprNode): ...@@ -1772,7 +1767,7 @@ class IndexNode(ExprNode):
def buffer_lookup_code(self, code): def buffer_lookup_code(self, code):
# Assign indices to temps # 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): for temp, index in zip(index_temps, self.indices):
code.putln("%s = %s;" % (temp, index.result())) code.putln("%s = %s;" % (temp, index.result()))
# Generate buffer access code using these temps # Generate buffer access code using these temps
......
...@@ -1063,9 +1063,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1063,9 +1063,8 @@ class FuncDefNode(StatNode, BlockNode):
# cleanup temps the old way # cleanup temps the old way
code.put_var_xdecrefs(lenv.temp_entries) code.put_var_xdecrefs(lenv.temp_entries)
# cleanup temps the new way # cleanup temps the new way
for cname, type, manage_ref in code.funcstate.temps_allocated: for cname, type in code.funcstate.all_managed_temps():
if type.is_pyobject and manage_ref: code.put_xdecref(cname, type)
code.put_xdecref(cname, type)
# Clean up buffers -- this calls a Python function # Clean up buffers -- this calls a Python function
# so need to save and restore error state # so need to save and restore error state
......
...@@ -972,6 +972,33 @@ def assign_to_object(object[object] buf, int idx, obj): ...@@ -972,6 +972,33 @@ def assign_to_object(object[object] buf, int idx, obj):
""" """
buf[idx] = obj buf[idx] = obj
@testcase
def assign_temporary_to_object(object[object] buf):
"""
See comments on printbuf_object above.
>>> a, b = [1, 2, 3], {4:23}
>>> get_refcount(a)
2
>>> addref(a)
>>> A = ObjectMockBuffer(None, [b, a])
>>> get_refcount(a)
3
>>> assign_temporary_to_object(A)
>>> get_refcount(a)
2
>>> printbuf_object(A, (2,))
{4: 23} 2
{1: 8} 2
To avoid leaking a reference in our testcase we need to
replace the temporary with something we can manually decref :-)
>>> assign_to_object(A, 1, a)
>>> decref(a)
"""
buf[1] = {3-2: 2+(2*4)-2}
# #
# cast option # cast option
# #
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment