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