Commit 315fd426 authored by da-woods's avatar da-woods Committed by GitHub

Make reference counting more type specific by moving it into PyrexTypes (GH-3377)

The idea being that struct-types like memoryviews
can generate their own reference counting code
using a common interface with Python objects.
parent ffbecc75
......@@ -2095,123 +2095,89 @@ class CCodeWriter(object):
from .PyrexTypes import py_object_type, typecast
return typecast(py_object_type, type, cname)
def put_gotref(self, cname):
self.putln("__Pyx_GOTREF(%s);" % cname)
def put_gotref(self, cname, type):
type.generate_gotref(self, cname)
def put_giveref(self, cname):
self.putln("__Pyx_GIVEREF(%s);" % cname)
def put_giveref(self, cname, type):
type.generate_giveref(self, cname)
def put_xgiveref(self, cname):
self.putln("__Pyx_XGIVEREF(%s);" % cname)
def put_xgiveref(self, cname, type):
type.generate_xgiveref(self, cname)
def put_xgotref(self, cname):
self.putln("__Pyx_XGOTREF(%s);" % cname)
def put_xgotref(self, cname, type):
type.generate_xgotref(self, cname)
def put_incref(self, cname, type, nanny=True):
if nanny:
self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
else:
self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
# Note: original put_Memslice_Incref/Decref also added in some utility code
# this is unnecessary since the relevant utility code is loaded anyway if a memoryview is used
# and so has been removed. However, it's potentially a feature that might be useful here
type.generate_incref(self, cname, nanny=nanny)
def put_decref(self, cname, type, nanny=True):
self._put_decref(cname, type, nanny, null_check=False, clear=False)
def put_xincref(self, cname, type, nanny=True):
type.generate_xincref(self, cname, nanny=nanny)
def put_var_gotref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
def put_decref(self, cname, type, nanny=True, have_gil=True):
type.generate_decref(self, cname, nanny=nanny, have_gil=have_gil)
def put_var_giveref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
def put_xdecref(self, cname, type, nanny=True, have_gil=True):
type.generate_xdecref(self, cname, nanny=nanny, have_gil=have_gil)
def put_var_xgotref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
def put_decref_clear(self, cname, type, clear_before_decref=False, nanny=True, have_gil=True):
type.generate_decref_clear(self, cname, clear_before_decref=clear_before_decref,
nanny=nanny, have_gil=have_gil)
def put_var_xgiveref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
def put_xdecref_clear(self, cname, type, clear_before_decref=False, nanny=True, have_gil=True):
type.generate_xdecref_clear(self, cname, clear_before_decref=clear_before_decref,
nanny=nanny, have_gil=have_gil)
def put_var_incref(self, entry, nanny=True):
if entry.type.is_pyobject:
if nanny:
self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
else:
self.putln("Py_INCREF(%s);" % self.entry_as_pyobject(entry))
def put_decref_set(self, cname, type, rhs_cname):
type.generate_decref_set(self, cname, rhs_cname)
def put_var_xincref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XINCREF(%s);" % self.entry_as_pyobject(entry))
def put_xdecref_set(self, cname, type, rhs_cname):
type.generate_xdecref_set(self, cname, rhs_cname)
def put_decref_clear(self, cname, type, nanny=True, clear_before_decref=False):
self._put_decref(cname, type, nanny, null_check=False,
clear=True, clear_before_decref=clear_before_decref)
def put_incref_memoryviewslice(self, slice_cname, type, have_gil):
# TODO ideally this would just be merged into "put_incref"
type.generate_incref_memoryviewslice(self, slice_cname, have_gil=have_gil)
def put_xdecref(self, cname, type, nanny=True, have_gil=True):
self._put_decref(cname, type, nanny, null_check=True,
have_gil=have_gil, clear=False)
def put_var_incref_memoryviewslice(self, entry, have_gil):
self.put_incref_memoryviewslice(entry.cname, entry.type, have_gil=have_gil)
def put_xdecref_clear(self, cname, type, nanny=True, clear_before_decref=False):
self._put_decref(cname, type, nanny, null_check=True,
clear=True, clear_before_decref=clear_before_decref)
def put_var_gotref(self, entry):
self.put_gotref(entry.cname, entry.type)
def _put_decref(self, cname, type, nanny=True, null_check=False,
have_gil=True, clear=False, clear_before_decref=False):
if type.is_memoryviewslice:
self.put_xdecref_memoryviewslice(cname, have_gil=have_gil)
return
def put_var_giveref(self, entry):
self.put_giveref(entry.cname, entry.type)
prefix = '__Pyx' if nanny else 'Py'
X = 'X' if null_check else ''
def put_var_xgotref(self, entry):
self.put_xgotref(entry.cname, entry.type)
if clear:
if clear_before_decref:
if not nanny:
X = '' # CPython doesn't have a Py_XCLEAR()
self.putln("%s_%sCLEAR(%s);" % (prefix, X, cname))
else:
self.putln("%s_%sDECREF(%s); %s = 0;" % (
prefix, X, self.as_pyobject(cname, type), cname))
else:
self.putln("%s_%sDECREF(%s);" % (
prefix, X, self.as_pyobject(cname, type)))
def put_var_xgiveref(self, entry):
self.put_xgiveref(entry.cname, entry.type)
def put_decref_set(self, cname, rhs_cname):
self.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname))
def put_var_incref(self, entry, **kwds):
self.put_incref(entry.cname, entry.type, **kwds)
def put_xdecref_set(self, cname, rhs_cname):
self.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname))
def put_var_xincref(self, entry, **kwds):
self.put_xincref(entry.cname, entry.type, **kwds)
def put_var_decref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
def put_var_decref(self, entry, **kwds):
self.put_decref(entry.cname, entry.type, **kwds)
def put_var_xdecref(self, entry, nanny=True):
if entry.type.is_pyobject:
if nanny:
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
else:
self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry))
def put_var_decref_clear(self, entry):
self._put_var_decref_clear(entry, null_check=False)
def put_var_xdecref_clear(self, entry):
self._put_var_decref_clear(entry, null_check=True)
def _put_var_decref_clear(self, entry, null_check):
if entry.type.is_pyobject:
if entry.in_closure:
# reset before DECREF to make sure closure state is
# consistent during call to DECREF()
self.putln("__Pyx_%sCLEAR(%s);" % (
null_check and 'X' or '',
entry.cname))
else:
self.putln("__Pyx_%sDECREF(%s); %s = 0;" % (
null_check and 'X' or '',
self.entry_as_pyobject(entry),
entry.cname))
def put_var_xdecref(self, entry, **kwds):
self.put_xdecref(entry.cname, entry.type, **kwds)
def put_var_decref_clear(self, entry, **kwds):
self.put_decref_clear(entry.cname, entry.type, clear_before_decref=entry.in_closure, **kwds)
def put_var_decref_set(self, entry, rhs_cname, **kwds):
self.put_decref_set(entry.cname, entry.type, rhs_cname, **kwds)
def put_var_xdecref_set(self, entry, rhs_cname, **kwds):
self.put_xdecref_set(entry.cname, entry.type, rhs_cname, **kwds)
def put_var_xdecref_clear(self, entry, **kwds):
self.put_xdecref_clear(entry.cname, entry.type, clear_before_decref=entry.in_closure, **kwds)
def put_var_decrefs(self, entries, used_only = 0):
for entry in entries:
......@@ -2229,19 +2195,6 @@ class CCodeWriter(object):
for entry in entries:
self.put_var_xdecref_clear(entry)
def put_incref_memoryviewslice(self, slice_cname, have_gil=False):
from . import MemoryView
self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False):
from . import MemoryView
self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
def put_xgiveref_memoryviewslice(self, slice_cname):
self.put_xgiveref("%s.memview" % slice_cname)
def put_init_to_py_none(self, cname, type, nanny=True):
from .PyrexTypes import py_object_type, typecast
py_none = typecast(type, py_object_type, "Py_None")
......
......@@ -746,19 +746,20 @@ class ExprNode(Node):
def make_owned_reference(self, code):
"""
If result is a pyobject, make sure we own a reference to it.
Make sure we own a reference to result.
If the result is in a temp, it is already a new reference.
"""
if self.type.is_pyobject and not self.result_in_temp():
if not self.result_in_temp():
code.put_incref(self.result(), self.ctype())
def make_owned_memoryviewslice(self, code):
"""
Make sure we own the reference to this memoryview slice.
"""
# TODO ideally this would be shared with "make_owned_reference"
if not self.result_in_temp():
code.put_incref_memoryviewslice(self.result(),
have_gil=self.in_nogil_context)
code.put_incref_memoryviewslice(self.result(), self.type,
have_gil=not self.in_nogil_context)
def generate_evaluation_code(self, code):
# Generate code to evaluate this node and
......@@ -791,13 +792,8 @@ class ExprNode(Node):
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
if self.result():
if self.type.is_pyobject:
code.put_decref_clear(self.result(), self.ctype())
elif self.type.is_memoryviewslice:
code.put_xdecref_memoryviewslice(
self.result(), have_gil=not self.in_nogil_context)
code.putln("%s.memview = NULL;" % self.result())
code.putln("%s.data = NULL;" % self.result())
code.put_decref_clear(self.result(), self.ctype(),
have_gil=not self.in_nogil_context)
else:
# Already done if self.is_temp
self.generate_subexpr_disposal_code(code)
......@@ -849,6 +845,32 @@ class ExprNode(Node):
def generate_function_definitions(self, env, code):
pass
# ----Generation of small bits of reference counting --
def generate_decref_set(self, code, rhs):
code.put_decref_set(self.result(), self.ctype(), rhs)
def generate_xdecref_set(self, code, rhs):
code.put_xdecref_set(self.result(), self.ctype(), rhs)
def generate_gotref(self, code, handle_null=False,
maybe_null_extra_check=True):
if not (handle_null and self.cf_is_null):
if (handle_null and self.cf_maybe_null
and maybe_null_extra_check):
self.generate_xgotref(code)
else:
code.put_gotref(self.result(), self.ctype())
def generate_xgotref(self, code):
code.put_xgotref(self.result(), self.ctype())
def generate_giveref(self, code):
code.put_giveref(self.result(), self.ctype())
def generate_xgiveref(self, code):
code.put_xgiveref(self.result(), self.ctype())
# ---------------- Annotation ---------------------
def annotate(self, code):
......@@ -1774,7 +1796,7 @@ class ImagNode(AtomicExprNode):
self.result(),
float(self.value),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class NewExprNode(AtomicExprNode):
......@@ -2215,7 +2237,7 @@ class NameNode(AtomicExprNode):
if not self.cf_is_null:
code.putln("}")
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
self.generate_gotref(code)
elif entry.is_builtin and not entry.scope.is_module_scope:
# known builtin
......@@ -2228,7 +2250,7 @@ class NameNode(AtomicExprNode):
self.result(),
interned_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
elif entry.is_pyglobal or (entry.is_builtin and entry.scope.is_module_scope):
# name in class body, global name or unknown builtin
......@@ -2252,7 +2274,7 @@ class NameNode(AtomicExprNode):
entry.scope.namespace_cname,
interned_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
elif entry.is_local or entry.in_closure or entry.from_closure or entry.type.is_memoryviewslice:
# Raise UnboundLocalError for objects and memoryviewslices
......@@ -2345,27 +2367,20 @@ class NameNode(AtomicExprNode):
rhs.make_owned_reference(code)
is_external_ref = entry.is_cglobal or self.entry.in_closure or self.entry.from_closure
if is_external_ref:
if not self.cf_is_null:
if self.cf_maybe_null:
code.put_xgotref(self.py_result())
else:
code.put_gotref(self.py_result())
self.generate_gotref(code, handle_null=True)
assigned = True
if entry.is_cglobal:
code.put_decref_set(
self.result(), rhs.result_as(self.ctype()))
self.generate_decref_set(code, rhs.result_as(self.ctype()))
else:
if not self.cf_is_null:
if self.cf_maybe_null:
code.put_xdecref_set(
self.result(), rhs.result_as(self.ctype()))
self.generate_xdecref_set(code, rhs.result_as(self.ctype()))
else:
code.put_decref_set(
self.result(), rhs.result_as(self.ctype()))
self.generate_decref_set(code, rhs.result_as(self.ctype()))
else:
assigned = False
if is_external_ref:
code.put_giveref(rhs.py_result())
rhs.generate_giveref(code)
if not self.type.is_memoryviewslice:
if not assigned:
if overloaded_assignment:
......@@ -2468,21 +2483,15 @@ class NameNode(AtomicExprNode):
if self.cf_maybe_null and not ignore_nonexisting:
code.put_error_if_unbound(self.pos, self.entry)
if self.entry.type.is_pyobject:
if self.entry.in_closure:
# generator
if ignore_nonexisting and self.cf_maybe_null:
code.put_xgotref(self.result())
else:
code.put_gotref(self.result())
if ignore_nonexisting and self.cf_maybe_null:
code.put_xdecref(self.result(), self.ctype())
else:
code.put_decref(self.result(), self.ctype())
code.putln('%s = NULL;' % self.result())
if self.entry.in_closure:
# generator
self.generate_gotref(code, handle_null=True, maybe_null_extra_check=ignore_nonexisting)
if ignore_nonexisting and self.cf_maybe_null:
code.put_xdecref_clear(self.result(), self.ctype(),
have_gil=not self.nogil)
else:
code.put_xdecref_memoryviewslice(self.entry.cname,
have_gil=not self.nogil)
code.put_decref_clear(self.result(), self.ctype(),
have_gil=not self.nogil)
else:
error(self.pos, "Deletion of C names not supported")
......@@ -2521,7 +2530,7 @@ class BackquoteNode(ExprNode):
self.result(),
self.arg.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class ImportNode(ExprNode):
......@@ -2602,7 +2611,7 @@ class ImportNode(ExprNode):
self.result(),
import_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class IteratorNode(ExprNode):
......@@ -2758,7 +2767,7 @@ class IteratorNode(ExprNode):
self.result(),
self.sequence.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
# PyObject_GetIter() fails if "tp_iternext" is not set, but the check below
# makes it visible to the C compiler that the pointer really isn't NULL, so that
......@@ -2805,7 +2814,7 @@ class IteratorNode(ExprNode):
self.counter_cname,
inc_dec,
code.error_goto_if_null(result_name, self.pos)))
code.put_gotref(result_name)
code.put_gotref(result_name, py_object_type)
code.putln("#endif")
def generate_iter_next_result_code(self, result_name, code):
......@@ -2856,7 +2865,7 @@ class IteratorNode(ExprNode):
code.putln("}")
code.putln("break;")
code.putln("}")
code.put_gotref(result_name)
code.put_gotref(result_name, py_object_type)
code.putln("}")
def free_temps(self, code):
......@@ -2948,7 +2957,7 @@ class AsyncIteratorNode(ExprNode):
self.result(),
self.sequence.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
class AsyncNextNode(AtomicExprNode):
......@@ -2978,7 +2987,7 @@ class AsyncNextNode(AtomicExprNode):
self.result(),
self.iterator.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
class WithExitCallNode(ExprNode):
......@@ -3021,7 +3030,7 @@ class WithExitCallNode(ExprNode):
self.args.free_temps(code)
code.putln(code.error_goto_if_null(result_var, self.pos))
code.put_gotref(result_var)
code.put_gotref(result_var, py_object_type)
if self.await_expr:
# FIXME: result_var temp currently leaks into the closure
......@@ -3175,7 +3184,7 @@ class JoinedStrNode(ExprNode):
list_var,
num_items,
code.error_goto_if_null(list_var, self.pos)))
code.put_gotref(list_var)
code.put_gotref(list_var, py_object_type)
code.putln("%s = 0;" % ulength_var)
code.putln("%s = 127;" % max_char_var) # at least ASCII character range
......@@ -3219,7 +3228,7 @@ class JoinedStrNode(ExprNode):
max_char_var, max_char_value, max_char_var, max_char_value, max_char_var))
code.putln("%s += %s;" % (ulength_var, ulength))
code.put_giveref(node.py_result())
node.generate_giveref(code)
code.putln('PyTuple_SET_ITEM(%s, %s, %s);' % (list_var, i, node.py_result()))
node.generate_post_assignment_code(code)
node.free_temps(code)
......@@ -3234,7 +3243,7 @@ class JoinedStrNode(ExprNode):
ulength_var,
max_char_var,
code.error_goto_if_null(self.py_result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
code.put_decref_clear(list_var, py_object_type)
code.funcstate.release_temp(list_var)
......@@ -3291,7 +3300,7 @@ class FormattedValueNode(ExprNode):
self.result(),
convert_func_call,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
return
value_result = self.value.py_result()
......@@ -3330,7 +3339,7 @@ class FormattedValueNode(ExprNode):
value_result,
format_spec,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
#-------------------------------------------------------------------
......@@ -4080,7 +4089,7 @@ class IndexNode(_IndexingBaseNode):
self.extra_index_params(code),
code.error_goto_if(error_check % self.result(), self.pos)))
if self.type.is_pyobject:
code.put_gotref(self.py_result())
self.generate_gotref(code)
def generate_setitem_code(self, value_code, code):
if self.index.type.is_int:
......@@ -4369,11 +4378,11 @@ class BufferIndexNode(_IndexingBaseNode):
manage_ref=False)
rhs_code = rhs.result()
code.putln("%s = %s;" % (ptr, ptrexpr))
code.put_gotref("*%s" % ptr)
code.put_gotref("*%s" % ptr, self.buffer_type.dtype)
code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % (
rhs_code, ptr))
code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
code.put_giveref("*%s" % ptr)
code.put_giveref("*%s" % ptr, self.buffer_type.dtype)
code.funcstate.release_temp(ptr)
else:
# Simple case
......@@ -4630,7 +4639,7 @@ class MemoryViewSliceNode(MemoryViewIndexNode):
assert not list(it)
buffer_entry.generate_buffer_slice_code(
code, self.original_indices, self.result(),
code, self.original_indices, self.result(), self.type,
have_gil=have_gil, have_slices=have_slices,
directives=code.globalstate.directives)
......@@ -5075,7 +5084,7 @@ class SliceIndexNode(ExprNode):
start_code,
stop_code,
code.error_goto_if_null(result, self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
exception_check=None, exception_value=None):
......@@ -5310,9 +5319,9 @@ class SliceNode(ExprNode):
self.stop.py_result(),
self.step.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
if self.is_literal:
code.put_giveref(self.py_result())
self.generate_giveref(code)
class SliceIntNode(SliceNode):
# start:stop:step in subscript list
......@@ -5902,7 +5911,7 @@ class SimpleCallNode(CallNode):
arg.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
for subexpr in subexprs:
if subexpr is not None:
......@@ -5921,7 +5930,7 @@ class SimpleCallNode(CallNode):
self.function.py_result(),
arg_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
elif func_type.is_cfunction:
if self.has_optional_args:
actual_nargs = len(self.args)
......@@ -5982,7 +5991,7 @@ class SimpleCallNode(CallNode):
goto_error = ""
code.putln("%s%s; %s" % (lhs, rhs, goto_error))
if self.type.is_pyobject and self.result():
code.put_gotref(self.py_result())
self.generate_gotref(code)
if self.has_optional_args:
code.funcstate.release_temp(self.opt_arg_struct)
......@@ -6082,7 +6091,7 @@ class PyMethodCallNode(SimpleCallNode):
code.put_incref(self_arg, py_object_type)
code.put_incref("function", py_object_type)
# free method object as early to possible to enable reuse from CPython's freelist
code.put_decref_set(function, "function")
code.put_decref_set(function, py_object_type, "function")
code.putln("%s = 1;" % arg_offset_cname)
code.putln("}")
code.putln("}")
......@@ -6109,7 +6118,7 @@ class PyMethodCallNode(SimpleCallNode):
arg.generate_disposal_code(code)
arg.free_temps(code)
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
self.generate_gotref(code)
if reuse_function_temp:
self.function.generate_disposal_code(code)
......@@ -6215,7 +6224,7 @@ class InlinedDefNodeCallNode(CallNode):
self.function.def_node.entry.pyfunc_cname,
arg_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class PythonCapiFunctionNode(ExprNode):
......@@ -6285,7 +6294,7 @@ class CachedBuiltinMethodCallNode(CallNode):
self.result(), call_code,
code.error_goto_if_null(self.result(), self.pos)
))
code.put_gotref(self.result())
self.generate_gotref(code)
class GeneralCallNode(CallNode):
......@@ -6503,7 +6512,7 @@ class GeneralCallNode(CallNode):
self.positional_args.py_result(),
kwargs,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class AsTupleNode(ExprNode):
......@@ -6545,7 +6554,7 @@ class AsTupleNode(ExprNode):
self.result(),
cfunc, self.arg.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class MergedDictNode(ExprNode):
......@@ -6647,7 +6656,7 @@ class MergedDictNode(ExprNode):
self.result(),
item.py_result(),
code.error_goto_if_null(self.result(), item.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
item.generate_disposal_code(code)
if item.type is not dict_type:
......@@ -6656,7 +6665,7 @@ class MergedDictNode(ExprNode):
self.result(),
item.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
item.generate_disposal_code(code)
code.putln('}')
item.free_temps(code)
......@@ -7175,7 +7184,7 @@ class AttributeNode(ExprNode):
self.obj.py_result(),
code.intern_identifier(self.attribute),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
elif self.type.is_memoryviewslice:
if self.is_memslice_transpose:
# transpose the slice
......@@ -7186,7 +7195,8 @@ class AttributeNode(ExprNode):
return
code.putln("%s = %s;" % (self.result(), self.obj.result()))
code.put_incref_memoryviewslice(self.result(), have_gil=True)
code.put_incref_memoryviewslice(self.result(), self.type,
have_gil=True)
T = "__pyx_memslice_transpose(&%s) == 0"
code.putln(code.error_goto_if(T % self.result(), self.pos))
......@@ -7209,10 +7219,7 @@ class AttributeNode(ExprNode):
def generate_disposal_code(self, code):
if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
# mirror condition for putting the memview incref here:
code.put_xdecref_memoryviewslice(
self.result(), have_gil=True)
code.putln("%s.memview = NULL;" % self.result())
code.putln("%s.data = NULL;" % self.result())
code.put_xdecref_clear(self.result(), self.type, have_gil=True)
else:
ExprNode.generate_disposal_code(self, code)
......@@ -7238,8 +7245,8 @@ class AttributeNode(ExprNode):
select_code = self.result()
if self.type.is_pyobject and self.use_managed_ref:
rhs.make_owned_reference(code)
code.put_giveref(rhs.py_result())
code.put_gotref(select_code)
rhs.generate_giveref(code)
code.put_gotref(select_code, self.type)
code.put_decref(select_code, self.ctype())
elif self.type.is_memoryviewslice:
from . import MemoryView
......@@ -7485,7 +7492,7 @@ class SequenceNode(ExprNode):
len(self.args),
', '.join(arg.py_result() for arg in self.args),
code.error_goto_if_null(target, self.pos)))
code.put_gotref(target)
code.put_gotref(target, py_object_type)
elif self.type.is_ctuple:
for i, arg in enumerate(self.args):
code.putln("%s.f%s = %s;" % (
......@@ -7502,7 +7509,7 @@ class SequenceNode(ExprNode):
code.putln("%s = %s(%s%s); %s" % (
target, create_func, arg_count, size_factor,
code.error_goto_if_null(target, self.pos)))
code.put_gotref(target)
code.put_gotref(target, py_object_type)
if c_mult:
# FIXME: can't use a temp variable here as the code may
......@@ -7526,7 +7533,7 @@ class SequenceNode(ExprNode):
arg = self.args[i]
if c_mult or not arg.result_in_temp():
code.put_incref(arg.result(), arg.ctype())
code.put_giveref(arg.py_result())
arg.generate_giveref(code)
code.putln("%s(%s, %s, %s);" % (
set_item_func,
target,
......@@ -7543,7 +7550,7 @@ class SequenceNode(ExprNode):
Naming.quick_temp_cname, target, mult_factor.py_result(),
code.error_goto_if_null(Naming.quick_temp_cname, self.pos)
))
code.put_gotref(Naming.quick_temp_cname)
code.put_gotref(Naming.quick_temp_cname, py_object_type)
code.put_decref(target, py_object_type)
code.putln('%s = %s;' % (target, Naming.quick_temp_cname))
code.putln('}')
......@@ -7661,7 +7668,7 @@ class SequenceNode(ExprNode):
code.putln("%s = PySequence_ITEM(sequence, %d); %s" % (
item.result(), i,
code.error_goto_if_null(item.result(), self.pos)))
code.put_gotref(item.result())
code.put_gotref(item.result(), item.type)
else:
code.putln("{")
code.putln("Py_ssize_t i;")
......@@ -7671,7 +7678,7 @@ class SequenceNode(ExprNode):
code.putln("for (i=0; i < %s; i++) {" % len(self.unpacked_items))
code.putln("PyObject* item = PySequence_ITEM(sequence, i); %s" % (
code.error_goto_if_null('item', self.pos)))
code.put_gotref('item')
code.put_gotref('item', py_object_type)
code.putln("*(temps[i]) = item;")
code.putln("}")
code.putln("}")
......@@ -7710,7 +7717,7 @@ class SequenceNode(ExprNode):
iterator_temp,
rhs.py_result(),
code.error_goto_if_null(iterator_temp, self.pos)))
code.put_gotref(iterator_temp)
code.put_gotref(iterator_temp, py_object_type)
rhs.generate_disposal_code(code)
iternext_func = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False)
......@@ -7723,7 +7730,7 @@ class SequenceNode(ExprNode):
code.putln("for (index=0; index < %s; index++) {" % len(unpacked_items))
code.put("PyObject* item = %s; if (unlikely(!item)) " % unpack_code)
code.put_goto(unpacking_error_label)
code.put_gotref("item")
code.put_gotref("item", py_object_type)
code.putln("*(temps[index]) = item;")
code.putln("}")
else:
......@@ -7735,7 +7742,7 @@ class SequenceNode(ExprNode):
unpack_code,
item.result()))
code.put_goto(unpacking_error_label)
code.put_gotref(item.py_result())
item.generate_gotref(code)
if terminate:
code.globalstate.use_utility_code(
......@@ -7792,7 +7799,7 @@ class SequenceNode(ExprNode):
target_list,
iterator_temp or rhs.py_result(),
code.error_goto_if_null(target_list, self.pos)))
code.put_gotref(target_list)
starred_target.generate_gotref(code)
if iterator_temp:
code.put_decref_clear(iterator_temp, py_object_type)
......@@ -7823,7 +7830,7 @@ class SequenceNode(ExprNode):
code.putln("%s = PySequence_ITEM(%s, %s-%d); " % (
item.py_result(), target_list, length_temp, i+1))
code.putln('#endif')
code.put_gotref(item.py_result())
item.generate_gotref(code)
coerced_arg.generate_evaluation_code(code)
code.putln('#if !CYTHON_COMPILING_IN_CPYTHON')
......@@ -7831,7 +7838,7 @@ class SequenceNode(ExprNode):
code.putln('%s = PySequence_GetSlice(%s, 0, %s-%d); %s' % (
sublist_temp, target_list, length_temp, len(unpacked_fixed_items_right),
code.error_goto_if_null(sublist_temp, self.pos)))
code.put_gotref(sublist_temp)
code.put_gotref(sublist_temp, py_object_type)
code.funcstate.release_temp(length_temp)
code.put_decref(target_list, py_object_type)
code.putln('%s = %s; %s = NULL;' % (target_list, sublist_temp, sublist_temp))
......@@ -7977,7 +7984,7 @@ class TupleNode(SequenceNode):
# constant is not yet initialised
const_code.mark_pos(self.pos)
self.generate_sequence_packing_code(const_code, tuple_target, plain=not self.is_literal)
const_code.put_giveref(tuple_target)
const_code.put_giveref(tuple_target, py_object_type)
if self.is_literal:
self.result_code = tuple_target
else:
......@@ -7985,7 +7992,7 @@ class TupleNode(SequenceNode):
self.result(), tuple_target, self.mult_factor.py_result(),
code.error_goto_if_null(self.result(), self.pos)
))
code.put_gotref(self.py_result())
self.generate_gotref(code)
else:
self.type.entry.used = True
self.generate_sequence_packing_code(code)
......@@ -8237,7 +8244,7 @@ class ScopedExprNode(ExprNode):
for entry in py_entries:
if entry.is_cglobal:
code.put_var_gotref(entry)
code.put_decref_set(entry.cname, "Py_None")
code.put_var_decref_set(entry, "Py_None")
else:
code.put_var_xdecref_clear(entry)
......@@ -8289,7 +8296,7 @@ class ComprehensionNode(ScopedExprNode):
self.result(), create_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
self.loop.generate_execution_code(code)
def annotate(self, code):
......@@ -8414,7 +8421,7 @@ class InlinedGeneratorExpressionNode(ExprNode):
code.putln("%s = __Pyx_Generator_Next(%s); %s" % (
self.result(), self.gen.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
class MergedSequenceNode(ExprNode):
......@@ -8525,7 +8532,7 @@ class MergedSequenceNode(ExprNode):
'PySet_New' if is_set else 'PySequence_List',
item.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
item.generate_disposal_code(code)
item.free_temps(code)
......@@ -8575,7 +8582,7 @@ class MergedSequenceNode(ExprNode):
self.result(),
Naming.quick_temp_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
code.putln("}")
for helper in sorted(helpers):
......@@ -8625,7 +8632,7 @@ class SetNode(ExprNode):
"%s = PySet_New(0); %s" % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
for arg in self.args:
code.put_error_if_neg(
self.pos,
......@@ -8747,7 +8754,7 @@ class DictNode(ExprNode):
self.result(),
len(self.key_value_pairs),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
keys_seen = set()
key_type = None
......@@ -8875,7 +8882,7 @@ class SortedDictKeysNode(ExprNode):
code.putln('%s = PyDict_Keys(%s); %s' % (
self.result(), dict_result,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
else:
# originally used PyMapping_Keys() here, but that may return a tuple
code.globalstate.use_utility_code(UtilityCode.load_cached(
......@@ -8884,11 +8891,11 @@ class SortedDictKeysNode(ExprNode):
code.putln('%s = __Pyx_PyObject_CallMethod0(%s, %s); %s' % (
self.result(), dict_result, keys_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
code.putln("if (unlikely(!PyList_Check(%s))) {" % self.result())
code.put_decref_set(self.result(), "PySequence_List(%s)" % self.result())
self.generate_decref_set(code, "PySequence_List(%s)" % self.result())
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
self.generate_gotref(code)
code.putln("}")
code.put_error_if_neg(
self.pos, 'PyList_Sort(%s)' % self.py_result())
......@@ -8956,7 +8963,7 @@ class ClassNode(ExprNode, ModuleNameMixin):
qualname,
py_mod_name,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class Py3ClassNode(ExprNode):
......@@ -9006,7 +9013,7 @@ class Py3ClassNode(ExprNode):
self.calculate_metaclass,
self.allow_py2_metaclass,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class PyClassMetaclassNode(ExprNode):
......@@ -9042,7 +9049,7 @@ class PyClassMetaclassNode(ExprNode):
"%s = %s; %s" % (
self.result(), call,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
......@@ -9084,7 +9091,7 @@ class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
py_mod_name,
doc_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class ClassCellInjectorNode(ExprNode):
......@@ -9103,7 +9110,7 @@ class ClassCellInjectorNode(ExprNode):
'%s = PyList_New(0); %s' % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
def generate_injection_code(self, code, classobj_cname):
assert self.is_active
......@@ -9331,7 +9338,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
py_mod_name,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
def generate_cyfunction_code(self, code):
if self.specialized_cpdefs:
......@@ -9372,7 +9379,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
code.putln('%s = PyDict_New(); %s' % (
dict_temp,
code.error_goto_if_null(dict_temp, self.pos)))
code.put_gotref(dict_temp)
code.put_gotref(dict_temp, py_object_type)
code.putln(
'%s = %s(&%s, %s, %s, %s, %s, %s, %s); %s' % (
self.result(),
......@@ -9402,7 +9409,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
code.error_goto_if_null(self.result(), self.pos)))
code.putln('#endif')
code.put_gotref(self.py_result())
self.generate_gotref(code)
if def_node.requires_classobj:
assert code.pyclass_stack, "pyclass_stack is empty"
......@@ -9412,7 +9419,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
'PyList_Append(%s, %s);' % (
class_node.class_cell.result(),
self.result()))
code.put_giveref(self.py_result())
self.generate_giveref(code)
if self.defaults:
code.putln(
......@@ -9672,7 +9679,7 @@ class GeneratorExpressionNode(LambdaNode):
self.def_node.entry.pyfunc_cname,
self.closure_result_code(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class YieldExprNode(ExprNode):
......@@ -9731,11 +9738,10 @@ class YieldExprNode(ExprNode):
for cname, type, manage_ref in code.funcstate.temps_in_use():
save_cname = code.funcstate.closure_temps.allocate_temp(type)
saved.append((cname, save_cname, type))
if type.is_pyobject:
code.put_xgiveref(cname)
code.put_xgiveref(cname, type)
code.putln('%s->%s = %s;' % (Naming.cur_scope_cname, save_cname, cname))
code.put_xgiveref(Naming.retval_cname)
code.put_xgiveref(Naming.retval_cname, py_object_type)
profile = code.globalstate.directives['profile']
linetrace = code.globalstate.directives['linetrace']
if profile or linetrace:
......@@ -9766,7 +9772,7 @@ class YieldExprNode(ExprNode):
code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
if type.is_pyobject:
code.putln('%s->%s = 0;' % (Naming.cur_scope_cname, save_cname))
code.put_xgotref(cname)
code.put_xgotref(cname, type)
self.generate_sent_value_handling_code(code, Naming.sent_value_cname)
if self.result_is_used:
self.allocate_temp_result(code)
......@@ -9794,7 +9800,7 @@ class _YieldDelegationExprNode(YieldExprNode):
self.arg.free_temps(code)
elif decref_source:
code.put_decref_clear(source_cname, py_object_type)
code.put_xgotref(Naming.retval_cname)
code.put_xgotref(Naming.retval_cname, py_object_type)
code.putln("if (likely(%s)) {" % Naming.retval_cname)
self.generate_yield_code(code)
......@@ -9810,7 +9816,7 @@ class _YieldDelegationExprNode(YieldExprNode):
# YieldExprNode has allocated the result temp for us
code.putln("%s = NULL;" % self.result())
code.put_error_if_neg(self.pos, "__Pyx_PyGen_FetchStopIterationValue(&%s)" % self.result())
code.put_gotref(self.result())
self.generate_gotref(code)
def handle_iteration_exception(self, code):
code.putln("PyObject* exc_type = __Pyx_PyErr_Occurred();")
......@@ -9902,7 +9908,7 @@ class GlobalsExprNode(AtomicExprNode):
code.putln('%s = __Pyx_Globals(); %s' % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
class LocalsDictItemNode(DictItemNode):
......@@ -10092,7 +10098,7 @@ class UnopNode(ExprNode):
function,
self.operand.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
def type_error(self):
if not self.operand.type.is_error:
......@@ -10675,8 +10681,8 @@ class CythonArrayNode(ExprNode):
shapes_temp,
format_temp)
code.putln(code.error_goto_if(err, self.pos))
code.put_gotref(format_temp)
code.put_gotref(shapes_temp)
code.put_gotref(format_temp, py_object_type)
code.put_gotref(shapes_temp, py_object_type)
tup = (self.result(), shapes_temp, itemsize, format_temp,
self.mode, self.operand.result())
......@@ -10684,7 +10690,7 @@ class CythonArrayNode(ExprNode):
'%s, %s, PyBytes_AS_STRING(%s), '
'(char *) "%s", (char *) %s);' % tup)
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.result())
self.generate_gotref(code)
def dispose(temp):
code.put_decref_clear(temp, py_object_type)
......@@ -11132,7 +11138,7 @@ class BinopNode(ExprNode):
self.operand2.py_result(),
extra_args,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
elif self.is_temp:
# C++ overloaded operators with exception values are currently all
# handled through temporaries.
......@@ -13209,7 +13215,7 @@ class CoerceToPyTypeNode(CoercionNode):
self.target_type),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.generate_gotref(code)
class CoerceIntToBytesNode(CoerceToPyTypeNode):
......@@ -13249,7 +13255,7 @@ class CoerceIntToBytesNode(CoerceToPyTypeNode):
code.error_goto_if_null(self.result(), self.pos)))
if temp is not None:
code.funcstate.release_temp(temp)
code.put_gotref(self.py_result())
self.generate_gotref(code)
class CoerceFromPyTypeNode(CoercionNode):
......@@ -13287,7 +13293,7 @@ class CoerceFromPyTypeNode(CoercionNode):
code.putln(self.type.from_py_call_code(
self.arg.py_result(), self.result(), self.pos, code, from_py_function=from_py_function))
if self.type.is_pyobject:
code.put_gotref(self.py_result())
self.generate_gotref(code)
def nogil_check(self, env):
error(self.pos, "Coercion from Python not allowed without the GIL")
......@@ -13408,11 +13414,11 @@ class CoerceToTempNode(CoercionNode):
code.putln("%s = %s;" % (
self.result(), self.arg.result_as(self.ctype())))
if self.use_managed_ref:
if self.type.is_pyobject:
if not self.type.is_memoryviewslice:
code.put_incref(self.result(), self.ctype())
elif self.type.is_memoryviewslice:
code.put_incref_memoryviewslice(self.result(),
not self.in_nogil_context)
else:
code.put_incref_memoryviewslice(self.result(), self.type,
have_gil=not self.in_nogil_context)
class ProxyNode(CoercionNode):
"""
......@@ -13578,7 +13584,7 @@ class DocstringRefNode(ExprNode):
self.result(), self.body.result(),
code.intern_identifier(StringEncoding.EncodedString("__doc__")),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
self.generate_gotref(code)
class AnnotationNode(ExprNode):
# Deals with the two possible uses of an annotation.
......
......@@ -881,7 +881,7 @@ class FusedCFuncDefNode(StatListNode):
"((__pyx_FusedFunctionObject *) %s)->__signatures__ = %s;" %
(self.resulting_fused_function.result(),
self.__signatures__.result()))
code.put_giveref(self.__signatures__.result())
self.__signatures__.generate_giveref(code)
self.fused_func_assignment.generate_execution_code(code)
......
......@@ -101,7 +101,8 @@ def put_acquire_memoryviewslice(lhs_cname, lhs_type, lhs_pos, rhs, code,
def put_assign_to_memviewslice(lhs_cname, rhs, rhs_cname, memviewslicetype, code,
have_gil=False, first_assignment=False):
if not first_assignment:
code.put_xdecref_memoryviewslice(lhs_cname, have_gil=have_gil)
code.put_xdecref(lhs_cname, memviewslicetype,
have_gil=have_gil)
if not rhs.result_in_temp():
rhs.make_owned_memoryviewslice(code)
......@@ -248,7 +249,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
return bufp
def generate_buffer_slice_code(self, code, indices, dst, have_gil,
def generate_buffer_slice_code(self, code, indices, dst, dst_type, have_gil,
have_slices, directives):
"""
Slice a memoryviewslice.
......@@ -265,7 +266,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
code.putln("%(dst)s.data = %(src)s.data;" % locals())
code.putln("%(dst)s.memview = %(src)s.memview;" % locals())
code.put_incref_memoryviewslice(dst)
code.put_incref_memoryviewslice(dst, dst_type, have_gil=have_gil)
all_dimensions_direct = all(access == 'direct' for access, packing in self.type.axes)
suboffset_dim_temp = []
......
......@@ -1582,13 +1582,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for entry in cpp_class_attrs:
code.putln("__Pyx_call_destructor(p->%s);" % entry.cname)
for entry in py_attrs:
for entry in (py_attrs + memoryview_slices):
code.put_xdecref_clear("p->%s" % entry.cname, entry.type, nanny=False,
clear_before_decref=True)
for entry in memoryview_slices:
code.put_xdecref_memoryviewslice("p->%s" % entry.cname,
have_gil=True)
clear_before_decref=True, have_gil=True)
if base_type:
if needs_gc:
......@@ -2945,7 +2941,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
EncodedString(decode_filename(
os.path.dirname(module_path)))).cname,
code.error_goto_if_null(temp, self.pos)))
code.put_gotref(temp)
code.put_gotref(temp, py_object_type)
code.putln(
'if (PyObject_SetAttrString(%s, "__path__", %s) < 0) %s;' % (
env.module_cname, temp, code.error_goto(self.pos)))
......@@ -3182,7 +3178,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
module_temp,
Naming.pymoduledef_cname,
code.error_goto_if_null(module_temp, self.pos)))
code.put_gotref(module_temp)
code.put_gotref(module_temp, py_object_type)
code.putln(code.error_goto_if_neg("PyState_AddModule(%s, &%s)" % (
module_temp, Naming.pymoduledef_cname), self.pos))
code.put_decref_clear(module_temp, type=py_object_type)
......@@ -3536,7 +3532,7 @@ class ModuleImportGenerator(object):
self.temps.append(temp)
code.putln('%s = PyImport_ImportModule(%s); if (unlikely(!%s)) %s' % (
temp, module_name_string, temp, error_code))
code.put_gotref(temp)
code.put_gotref(temp, py_object_type)
self.imported[module_name_string] = temp
return temp
......
......@@ -921,8 +921,7 @@ class CArgDeclNode(Node):
default.make_owned_reference(code)
result = default.result() if overloaded_assignment else default.result_as(self.type)
code.putln("%s = %s;" % (target, result))
if self.type.is_pyobject:
code.put_giveref(default.result())
code.put_giveref(default.result(), self.type)
default.generate_post_assignment_code(code)
default.free_temps(code)
......@@ -1540,7 +1539,7 @@ class CEnumDefNode(StatNode):
temp,
item.cname,
code.error_goto_if_null(temp, item.pos)))
code.put_gotref(temp)
code.put_gotref(temp, PyrexTypes.py_object_type)
code.putln('if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % (
Naming.moddict_cname,
item.name,
......@@ -1885,7 +1884,7 @@ class FuncDefNode(StatNode, BlockNode):
code.put_incref("Py_None", py_object_type)
code.putln(code.error_goto(self.pos))
code.putln("} else {")
code.put_gotref(Naming.cur_scope_cname)
code.put_gotref(Naming.cur_scope_cname, lenv.scope_class.type)
code.putln("}")
# Note that it is unsafe to decref the scope at this point.
if self.needs_outer_scope:
......@@ -1904,7 +1903,7 @@ class FuncDefNode(StatNode, BlockNode):
elif self.needs_closure:
# inner closures own a reference to their outer parent
code.put_incref(outer_scope_cname, cenv.scope_class.type)
code.put_giveref(outer_scope_cname)
code.put_giveref(outer_scope_cname, cenv.scope_class.type)
# ----- Trace function call
if profile or linetrace:
# this looks a bit late, but if we don't get here due to a
......@@ -1924,18 +1923,18 @@ class FuncDefNode(StatNode, BlockNode):
# incref it to properly keep track of refcounts.
is_cdef = isinstance(self, CFuncDefNode)
for entry in lenv.arg_entries:
if entry.type.is_pyobject:
if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure:
if not entry.type.is_memoryviewslice:
if (acquire_gil or entry.cf_is_reassigned) and not entry.in_closure:
code.put_var_incref(entry)
# Note: defaults are always incref-ed. For def functions, we
# we acquire arguments from object conversion, so we have
# new references. If we are a cdef function, we need to
# incref our arguments
elif is_cdef and entry.type.is_memoryviewslice and len(entry.cf_assignments) > 1:
code.put_incref_memoryviewslice(entry.cname, have_gil=code.funcstate.gil_owned)
elif is_cdef and entry.cf_is_reassigned:
code.put_var_incref_memoryviewslice(entry,
have_gil=code.funcstate.gil_owned)
for entry in lenv.var_entries:
if entry.is_arg and len(entry.cf_assignments) > 1 and not entry.in_closure:
if entry.is_arg and entry.cf_is_reassigned and not entry.in_closure:
if entry.xdecref_cleanup:
code.put_var_xincref(entry)
else:
......@@ -2077,26 +2076,27 @@ class FuncDefNode(StatNode, BlockNode):
if not entry.used or entry.in_closure:
continue
if entry.type.is_memoryviewslice:
code.put_xdecref_memoryviewslice(entry.cname, have_gil=not lenv.nogil)
elif entry.type.is_pyobject:
if not entry.is_arg or len(entry.cf_assignments) > 1:
if entry.xdecref_cleanup:
code.put_var_xdecref(entry)
else:
code.put_var_decref(entry)
if entry.type.is_pyobject:
if entry.is_arg and not entry.cf_is_reassigned:
continue
# FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code.put_var_xdecref(entry, have_gil=not lenv.nogil)
# Decref any increfed args
for entry in lenv.arg_entries:
if entry.type.is_pyobject:
if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure:
code.put_var_decref(entry)
elif (entry.type.is_memoryviewslice and
(not is_cdef or len(entry.cf_assignments) > 1)):
if entry.type.is_memoryviewslice:
# decref slices of def functions and acquired slices from cdef
# functions, but not borrowed slices from cdef functions.
code.put_xdecref_memoryviewslice(entry.cname,
have_gil=not lenv.nogil)
if is_cdef and not entry.cf_is_reassigned:
continue
else:
if entry.in_closure:
continue
if not acquire_gil and not entry.cf_is_reassigned:
continue
# FIXME use entry.xdecref_cleanup - del arg seems to be the problem
code.put_var_xdecref(entry, have_gil=not lenv.nogil)
if self.needs_closure:
code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
......@@ -2107,8 +2107,7 @@ class FuncDefNode(StatNode, BlockNode):
err_val = self.error_value()
if err_val is None and default_retval:
err_val = default_retval # FIXME: why is err_val not used?
if self.return_type.is_pyobject:
code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))
code.put_xgiveref(Naming.retval_cname, self.return_type)
if self.entry.is_special and self.entry.name == "__hash__":
# Returning -1 for __hash__ is supposed to signal an error
......@@ -2237,7 +2236,7 @@ class FuncDefNode(StatNode, BlockNode):
view = py_buffer.cname
if obj_type and obj_type.is_pyobject:
code.put_init_to_py_none("%s->obj" % view, obj_type)
code.put_giveref("%s->obj" % view) # Do not refnanny object within structs
code.put_giveref("%s->obj" % view, obj_type) # Do not refnanny object within structs
else:
code.putln("%s->obj = NULL;" % view)
......@@ -2246,7 +2245,7 @@ class FuncDefNode(StatNode, BlockNode):
view = py_buffer.cname
if obj_type and obj_type.is_pyobject:
code.putln("if (%s->obj != NULL) {" % view)
code.put_gotref("%s->obj" % view)
code.put_gotref("%s->obj" % view, obj_type)
code.put_decref_clear("%s->obj" % view, obj_type)
code.putln("}")
else:
......@@ -2257,7 +2256,7 @@ class FuncDefNode(StatNode, BlockNode):
view = py_buffer.cname
if obj_type and obj_type.is_pyobject:
code.putln("if (%s->obj == Py_None) {" % view)
code.put_gotref("%s->obj" % view)
code.put_gotref("%s->obj" % view, obj_type)
code.put_decref_clear("%s->obj" % view, obj_type)
code.putln("}")
......@@ -3414,7 +3413,10 @@ class DefNodeWrapper(FuncDefNode):
code.put_label(code.return_label)
for entry in lenv.var_entries:
if entry.is_arg and entry.type.is_pyobject:
code.put_var_decref(entry)
if entry.xdecref_cleanup:
code.put_var_xdecref(entry)
else:
code.put_var_decref(entry)
code.put_finish_refcount_context()
if not self.return_type.is_void:
......@@ -3623,7 +3625,7 @@ class DefNodeWrapper(FuncDefNode):
Naming.kwvalues_cname))
code.putln("if (unlikely(!%s)) return %s;" % (
self.starstar_arg.entry.cname, self.error_value()))
code.put_gotref(self.starstar_arg.entry.cname)
code.put_gotref(self.starstar_arg.entry.cname, py_object_type)
code.putln("} else {")
allow_null = all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references)
if allow_null:
......@@ -3632,7 +3634,7 @@ class DefNodeWrapper(FuncDefNode):
code.putln("%s = PyDict_New();" % (self.starstar_arg.entry.cname,))
code.putln("if (unlikely(!%s)) return %s;" % (
self.starstar_arg.entry.cname, self.error_value()))
code.put_gotref(self.starstar_arg.entry.cname)
code.put_var_gotref(self.starstar_arg.entry)
self.starstar_arg.entry.xdecref_cleanup = allow_null
code.putln("}")
......@@ -3645,14 +3647,14 @@ class DefNodeWrapper(FuncDefNode):
self.star_arg.entry.cname))
if self.starstar_arg and self.starstar_arg.entry.cf_used:
code.putln("{")
code.put_xdecref_clear(self.starstar_arg.entry.cname, py_object_type)
code.put_var_xdecref_clear(self.starstar_arg.entry)
code.putln("return %s;" % self.error_value())
code.putln("}")
else:
code.putln("return %s;" % self.error_value())
code.put_gotref(self.star_arg.entry.cname)
code.put_var_gotref(self.star_arg.entry)
code.put_incref(Naming.self_cname, py_object_type)
code.put_giveref(Naming.self_cname)
code.put_giveref(Naming.self_cname, py_object_type)
code.putln("PyTuple_SET_ITEM(%s, 0, %s);" % (
self.star_arg.entry.cname, Naming.self_cname))
temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
......@@ -3661,7 +3663,7 @@ class DefNodeWrapper(FuncDefNode):
code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % (
Naming.args_cname, temp))
code.put_incref("item", py_object_type)
code.put_giveref("item")
code.put_giveref("item", py_object_type)
code.putln("PyTuple_SET_ITEM(%s, %s+1, item);" % (
self.star_arg.entry.cname, temp))
code.putln("}")
......@@ -3889,8 +3891,7 @@ class DefNodeWrapper(FuncDefNode):
arg.entry.cname,
arg.calculate_default_value_code(code)))
if arg.type.is_memoryviewslice:
code.put_incref_memoryviewslice(arg.entry.cname,
have_gil=True)
code.put_var_incref_memoryviewslice(arg.entry, have_gil=True)
code.putln('}')
else:
error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
......@@ -3902,7 +3903,7 @@ class DefNodeWrapper(FuncDefNode):
self.starstar_arg.entry.cname,
self.starstar_arg.entry.cname,
self.error_value()))
code.put_gotref(self.starstar_arg.entry.cname)
code.put_var_gotref(self.starstar_arg.entry)
if self.star_arg:
self.star_arg.entry.xdecref_cleanup = 0
if max_positional_args == 0:
......@@ -3918,13 +3919,14 @@ class DefNodeWrapper(FuncDefNode):
code.putln('%s = __Pyx_ArgsSlice_%s(%s, %d, %s);' % (
self.star_arg.entry.cname, self.signature.fastvar,
Naming.args_cname, max_positional_args, Naming.nargs_cname))
code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
code.putln("if (unlikely(!%s)) {" %
self.star_arg.entry.type.nullcheck_string(self.star_arg.entry.cname))
if self.starstar_arg:
code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
code.put_var_decref_clear(self.starstar_arg.entry)
code.put_finish_refcount_context()
code.putln('return %s;' % self.error_value())
code.putln('}')
code.put_gotref(self.star_arg.entry.cname)
code.put_var_gotref(self.star_arg.entry)
def generate_argument_values_setup_code(self, args, code):
max_args = len(args)
......@@ -4278,7 +4280,7 @@ class GeneratorDefNode(DefNode):
code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
classobj_cname, Naming.self_cname))
code.put_incref(classobj_cname, py_object_type)
code.put_giveref(classobj_cname)
code.put_giveref(classobj_cname, py_object_type)
code.put_finish_refcount_context()
code.putln('return (PyObject *) gen;')
code.putln('}')
......@@ -4398,7 +4400,7 @@ class GeneratorBodyDefNode(DefNode):
code.putln("%s = %s; %s" % (
Naming.retval_cname, comp_init,
code.error_goto_if_null(Naming.retval_cname, self.pos)))
code.put_gotref(Naming.retval_cname)
code.put_gotref(Naming.retval_cname, py_object_type)
# ----- Function body
self.generate_function_body(env, code)
......@@ -4444,7 +4446,7 @@ class GeneratorBodyDefNode(DefNode):
# ----- Non-error return cleanup
code.put_label(code.return_label)
if self.is_inlined:
code.put_xgiveref(Naming.retval_cname)
code.put_xgiveref(Naming.retval_cname, py_object_type)
else:
code.put_xdecref_clear(Naming.retval_cname, py_object_type)
# For Py3.7, clearing is already done below.
......@@ -4560,7 +4562,7 @@ class OverrideCheckNode(StatNode):
err = code.error_goto_if_null(func_node_temp, self.pos)
code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % (
func_node_temp, self_arg, interned_attr_cname, err))
code.put_gotref(func_node_temp)
code.put_gotref(func_node_temp, py_object_type)
is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp
is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)(void*)%s)" % (
......@@ -5051,7 +5053,7 @@ class CClassDefNode(ClassDefNode):
code.putln("%s = PyType_Type.tp_new(&PyType_Type, %s, NULL);" % (
trial_type, self.type_init_args.result()))
code.putln(code.error_goto_if_null(trial_type, self.pos))
code.put_gotref(trial_type)
code.put_gotref(trial_type, py_object_type)
code.putln("if (((PyTypeObject*) %s)->tp_base != %s) {" % (
trial_type, first_base))
code.putln("PyErr_Format(PyExc_TypeError, \"best base '%s' must be equal to first base '%s'\",")
......@@ -5061,7 +5063,7 @@ class CClassDefNode(ClassDefNode):
code.putln("}")
code.funcstate.release_temp(trial_type)
code.put_incref(bases, PyrexTypes.py_object_type)
code.put_giveref(bases)
code.put_giveref(bases, py_object_type)
code.putln("%s.tp_bases = %s;" % (self.entry.type.typeobj_cname, bases))
code.put_decref_clear(trial_type, PyrexTypes.py_object_type)
self.type_init_args.generate_disposal_code(code)
......@@ -5091,7 +5093,7 @@ class CClassDefNode(ClassDefNode):
tuple_temp,
base_type.typeptr_cname,
code.error_goto_if_null(tuple_temp, entry.pos)))
code.put_gotref(tuple_temp)
code.put_gotref(tuple_temp, py_object_type)
code.putln(
"%s = PyType_FromSpecWithBases(&%s_spec, %s); %s" % (
typeobj_cname,
......@@ -6045,7 +6047,7 @@ class ExecStatNode(StatNode):
arg.free_temps(code)
code.putln(
code.error_goto_if_null(temp_result, self.pos))
code.put_gotref(temp_result)
code.put_gotref(temp_result, py_object_type)
code.put_decref_clear(temp_result, py_object_type)
code.funcstate.release_temp(temp_result)
......@@ -6398,10 +6400,10 @@ class ReraiseStatNode(StatNode):
vars = code.funcstate.exc_vars
if vars:
code.globalstate.use_utility_code(restore_exception_utility_code)
code.put_giveref(vars[0])
code.put_giveref(vars[1])
code.put_giveref(vars[0], py_object_type)
code.put_giveref(vars[1], py_object_type)
# fresh exceptions may not have a traceback yet (-> finally!)
code.put_xgiveref(vars[2])
code.put_xgiveref(vars[2], py_object_type)
code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % tuple(vars))
for varname in vars:
code.put("%s = 0; " % varname)
......@@ -6810,7 +6812,7 @@ class DictIterationNextNode(Node):
# evaluate all coercions before the assignments
for var, result, target in assignments:
code.put_gotref(var.result())
var.generate_gotref(code)
for var, result, target in assignments:
result.generate_evaluation_code(code)
for var, result, target in assignments:
......@@ -6872,7 +6874,7 @@ class SetIterationNextNode(Node):
code.funcstate.release_temp(result_temp)
# evaluate all coercions before the assignments
code.put_gotref(value_ref.result())
value_ref.generate_gotref(code)
self.coerced_value_var.generate_evaluation_code(code)
self.value_target.generate_assignment_code(self.coerced_value_var, code)
value_ref.release(code)
......@@ -7185,7 +7187,7 @@ class ForFromStatNode(LoopNode, StatNode):
target_node.result(),
interned_cname,
code.error_goto_if_null(target_node.result(), self.target.pos)))
code.put_gotref(target_node.result())
target_node.generate_gotref(code)
else:
target_node = self.target
from_py_node = ExprNodes.CoerceFromPyTypeNode(
......@@ -7321,7 +7323,7 @@ class WithStatNode(StatNode):
code.intern_identifier(EncodedString('__aexit__' if self.is_async else '__exit__')),
code.error_goto_if_null(self.exit_var, self.pos),
))
code.put_gotref(self.exit_var)
code.put_gotref(self.exit_var, py_object_type)
# need to free exit_var in the face of exceptions during setup
old_error_label = code.new_error_label()
......@@ -7465,11 +7467,11 @@ class TryExceptStatNode(StatNode):
save_exc.putln("__Pyx_ExceptionSave(%s);" % (
', '.join(['&%s' % var for var in exc_save_vars])))
for var in exc_save_vars:
save_exc.put_xgotref(var)
save_exc.put_xgotref(var, py_object_type)
def restore_saved_exception():
for name in exc_save_vars:
code.put_xgiveref(name)
code.put_xgiveref(name, py_object_type)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(exc_save_vars))
else:
......@@ -7671,7 +7673,7 @@ class ExceptClauseNode(Node):
code.putln("if (__Pyx_GetException(%s) < 0) %s" % (
exc_args, code.error_goto(self.pos)))
for var in exc_vars:
code.put_gotref(var)
code.put_gotref(var, py_object_type)
if self.target:
self.exc_value.set_var(exc_vars[1])
self.exc_value.generate_evaluation_code(code)
......@@ -7950,7 +7952,7 @@ class TryFinallyStatNode(StatNode):
" unlikely(__Pyx_GetException(&%s, &%s, &%s) < 0)) "
"__Pyx_ErrFetch(&%s, &%s, &%s);" % (exc_vars[:3] * 2))
for var in exc_vars:
code.put_xgotref(var)
code.put_xgotref(var, py_object_type)
if exc_lineno_cnames:
code.putln("%s = %s; %s = %s; %s = %s;" % (
exc_lineno_cnames[0], Naming.lineno_cname,
......@@ -7971,11 +7973,11 @@ class TryFinallyStatNode(StatNode):
# unused utility functions and/or temps
code.putln("if (PY_MAJOR_VERSION >= 3) {")
for var in exc_vars[3:]:
code.put_xgiveref(var)
code.put_xgiveref(var, py_object_type)
code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
code.putln("}")
for var in exc_vars[:3]:
code.put_xgiveref(var)
code.put_xgiveref(var, py_object_type)
code.putln("__Pyx_ErrRestore(%s, %s, %s);" % exc_vars[:3])
if self.is_try_finally_in_nogil:
......@@ -7997,7 +7999,7 @@ class TryFinallyStatNode(StatNode):
# unused utility functions and/or temps
code.putln("if (PY_MAJOR_VERSION >= 3) {")
for var in exc_vars[3:]:
code.put_xgiveref(var)
code.put_xgiveref(var, py_object_type)
code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
code.putln("}")
for var in exc_vars[:3]:
......@@ -8357,7 +8359,7 @@ class FromImportStatNode(StatNode):
self.module.py_result(),
code.intern_identifier(name),
code.error_goto_if_null(item_temp, self.pos)))
code.put_gotref(item_temp)
code.put_gotref(item_temp, py_object_type)
if coerced_item is None:
target.generate_assignment_code(self.item, code)
else:
......@@ -8734,11 +8736,7 @@ class ParallelStatNode(StatNode, ParallelNode):
if self.is_parallel and not self.is_nested_prange:
code.putln("/* Clean up any temporaries */")
for temp, type in sorted(self.temps):
if type.is_memoryviewslice:
code.put_xdecref_memoryviewslice(temp, have_gil=False)
elif type.is_pyobject:
code.put_xdecref(temp, type)
code.putln("%s = NULL;" % temp)
code.put_xdecref_clear(temp, type, have_gil=False)
def setup_parallel_control_flow_block(self, code):
"""
......@@ -8969,7 +8967,7 @@ class ParallelStatNode(StatNode, ParallelNode):
pos_info = chain(*zip(self.parallel_pos_info, self.pos_info))
code.funcstate.uses_error_indicator = True
code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
code.put_gotref(Naming.parallel_exc_type)
code.put_gotref(Naming.parallel_exc_type, py_object_type)
code.putln(
"}")
......@@ -8982,7 +8980,7 @@ class ParallelStatNode(StatNode, ParallelNode):
code.begin_block()
code.put_ensure_gil(declare_gilstate=True)
code.put_giveref(Naming.parallel_exc_type)
code.put_giveref(Naming.parallel_exc_type, py_object_type)
code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % self.parallel_exc)
pos_info = chain(*zip(self.pos_info, self.parallel_pos_info))
code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
......
......@@ -193,6 +193,8 @@ class PyrexType(BaseType):
# is_pythran_expr boolean Is Pythran expr
# is_numpy_buffer boolean Is Numpy array buffer
# has_attributes boolean Has C dot-selectable attributes
# needs_refcounting boolean Needs code to be generated similar to incref/gotref/decref.
# Largely used internally.
# default_value string Initial value that can be assigned before first user assignment.
# declaration_value string The value statically assigned on declaration (if any).
# entry Entry The Entry for this type
......@@ -257,6 +259,7 @@ class PyrexType(BaseType):
is_pythran_expr = 0
is_numpy_buffer = 0
has_attributes = 0
needs_refcounting = 0
default_value = ""
declaration_value = ""
......@@ -334,6 +337,31 @@ class PyrexType(BaseType):
convert_call,
code.error_goto_if(error_condition or self.error_condition(result_code), error_pos))
def _generate_dummy_refcounting(self, code, *ignored_args, **ignored_kwds):
if self.needs_refcounting:
raise NotImplementedError("Ref-counting operation not yet implemented for type %s" %
self)
def _generate_dummy_refcounting_assignment(self, code, cname, rhs_cname, *ignored_args, **ignored_kwds):
if self.needs_refcounting:
raise NotImplementedError("Ref-counting operation not yet implemented for type %s" %
self)
code.putln("%s = %s" % (cname, rhs_cname))
generate_incref = generate_xincref = generate_decref = generate_xdecref \
= generate_decref_clear = generate_xdecref_clear \
= generate_gotref = generate_xgotref = generate_giveref = generate_xgiveref \
= _generate_dummy_refcounting
generate_decref_set = generate_xdecref_set = _generate_dummy_refcounting_assignment
def nullcheck_string(self, code, cname):
if self.needs_refcounting:
raise NotImplementedError("Ref-counting operation not yet implemented for type %s" %
self)
code.putln("1")
def public_decl(base_code, dll_linkage):
if dll_linkage:
......@@ -566,6 +594,10 @@ class MemoryViewSliceType(PyrexType):
is_memoryviewslice = 1
has_attributes = 1
needs_refcounting = 1 # Ideally this would be true and reference counting for
# memoryview and pyobject code could be generated in the same way.
# However, memoryviews are sufficiently specialized that this doesn't
# seem practical. Implement a limited version of it for now
scope = None
# These are special cased in Defnode
......@@ -1039,6 +1071,36 @@ class MemoryViewSliceType(PyrexType):
def cast_code(self, expr_code):
return expr_code
# When memoryviews are increfed currently seems heavily special-cased.
# Therefore, use our own function for now
def generate_incref(self, code, name, **kwds):
pass
def generate_incref_memoryviewslice(self, code, slice_cname, have_gil):
# TODO ideally would be done separately
code.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
# decref however did look to always apply for memoryview slices
# with "have_gil" set to True by default
def generate_xdecref(self, code, cname, nanny, have_gil):
code.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (cname, int(have_gil)))
def generate_decref(self, code, cname, nanny, have_gil):
# Fall back to xdecref since we don't care to have a separate decref version for this.
self.generate_xdecref(code, cname, nanny, have_gil)
def generate_xdecref_clear(self, code, cname, clear_before_decref, **kwds):
self.generate_xdecref(code, cname, **kwds)
code.putln("%s.memview = NULL; %s.data = NULL;" % (cname, cname))
def generate_decref_clear(self, code, cname, **kwds):
# memoryviews don't currently distinguish between xdecref and decref
self.generate_xdecref_clear(code, cname, **kwds)
# memoryviews don't participate in giveref/gotref
generate_gotref = generate_xgotref = generate_xgiveref = generate_giveref = lambda *args: None
class BufferType(BaseType):
#
......@@ -1137,6 +1199,7 @@ class PyObjectType(PyrexType):
is_subclassed = False
is_gc_simple = False
builtin_trashcan = False # builtin type using trashcan
needs_refcounting = True
def __str__(self):
return "Python object"
......@@ -1189,6 +1252,76 @@ class PyObjectType(PyrexType):
def check_for_null_code(self, cname):
return cname
def generate_incref(self, code, cname, nanny):
if nanny:
code.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname))
else:
code.putln("Py_INCREF(%s);" % self.as_pyobject(cname))
def generate_xincref(self, code, cname, nanny):
if nanny:
code.putln("__Pyx_XINCREF(%s);" % self.as_pyobject(cname))
else:
code.putln("Py_XINCREF(%s);" % self.as_pyobject(cname))
def generate_decref(self, code, cname, nanny, have_gil):
# have_gil is for the benefit of memoryviewslice - it's ignored here
assert have_gil
self._generate_decref(code, cname, nanny, null_check=False, clear=False)
def generate_xdecref(self, code, cname, nanny, have_gil):
# in this (and other) PyObjectType functions, have_gil is being
# passed to provide a common interface with MemoryviewSlice.
# It's ignored here
self._generate_decref(code, cname, nanny, null_check=True,
clear=False)
def generate_decref_clear(self, code, cname, clear_before_decref, nanny, have_gil):
self._generate_decref(code, cname, nanny, null_check=False,
clear=True, clear_before_decref=clear_before_decref)
def generate_xdecref_clear(self, code, cname, clear_before_decref=False, nanny=True, have_gil=None):
self._generate_decref(code, cname, nanny, null_check=True,
clear=True, clear_before_decref=clear_before_decref)
def generate_gotref(self, code, cname):
code.putln("__Pyx_GOTREF(%s);" % self.as_pyobject(cname))
def generate_xgotref(self, code, cname):
code.putln("__Pyx_XGOTREF(%s);" % self.as_pyobject(cname))
def generate_giveref(self, code, cname):
code.putln("__Pyx_GIVEREF(%s);" % self.as_pyobject(cname))
def generate_xgiveref(self, code, cname):
code.putln("__Pyx_XGIVEREF(%s);" % self.as_pyobject(cname))
def generate_decref_set(self, code, cname, rhs_cname):
code.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname))
def generate_xdecref_set(self, code, cname, rhs_cname):
code.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname))
def _generate_decref(self, code, cname, nanny, null_check=False,
clear=False, clear_before_decref=False):
prefix = '__Pyx' if nanny else 'Py'
X = 'X' if null_check else ''
if clear:
if clear_before_decref:
if not nanny:
X = '' # CPython doesn't have a Py_XCLEAR()
code.putln("%s_%sCLEAR(%s);" % (prefix, X, cname))
else:
code.putln("%s_%sDECREF(%s); %s = 0;" % (
prefix, X, self.as_pyobject(cname), cname))
else:
code.putln("%s_%sDECREF(%s);" % (
prefix, X, self.as_pyobject(cname)))
def nullcheck_string(self, cname):
return cname
builtin_types_that_cannot_create_refcycles = set([
'object', 'bool', 'int', 'long', 'float', 'complex',
......
......@@ -262,6 +262,10 @@ class Entry(object):
else:
return NotImplemented
@property
def cf_is_reassigned(self):
return len(self.cf_assignments) > 1
class InnerEntry(Entry):
"""
......
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