Commit 307653ff authored by Xavier Thompson's avatar Xavier Thompson

Refactor cypclass reference counting code generation

parent d4a204b6
...@@ -2103,30 +2103,8 @@ class CCodeWriter(object): ...@@ -2103,30 +2103,8 @@ class CCodeWriter(object):
return '' return ''
return '%s ' % ' '.join([mapper(m,m) for m in modifiers]) return '%s ' % ' '.join([mapper(m,m) for m in modifiers])
# CyObjects reference counting
def put_cygotref(self, cname): # Reference counting
self.putln("Cy_GOTREF(%s);" % cname)
def put_cygiveref(self, cname):
self.putln("Cy_GIVEREF(%s);" % cname)
def put_cyxgiveref(self, cname):
self.putln("Cy_XGIVEREF(%s);" % cname)
def put_cyxgotref(self, cname):
self.putln("Cy_XGOTREF(%s);" % cname)
def put_cyincref(self, cname):
self.putln("Cy_INCREF(%s);" % cname)
def put_cydecref(self, cname):
self.putln("Cy_DECREF(%s);" % cname)
def put_cyxdecref(self, cname):
self.putln("Cy_XDECREF(%s);" % cname)
# Python objects and reference counting
def entry_as_pyobject(self, entry): def entry_as_pyobject(self, entry):
type = entry.type type = entry.type
......
...@@ -782,8 +782,9 @@ class ExprNode(Node): ...@@ -782,8 +782,9 @@ class ExprNode(Node):
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 not self.result_in_temp(): if not self.result_in_temp():
if self.type.is_cyp_class and "NULL" not in self.result(): # FIXME: is this verification really necessary ?
code.put_cyincref(self.result()) if self.type.is_cyp_class and "NULL" in self.result():
pass
else: else:
code.put_incref(self.result(), self.ctype()) code.put_incref(self.result(), self.ctype())
...@@ -827,10 +828,7 @@ class ExprNode(Node): ...@@ -827,10 +828,7 @@ 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_cyp_class: code.put_decref_clear(self.result(), self.ctype(),
code.put_cyxdecref(self.result())
else:
code.put_decref_clear(self.result(), self.ctype(),
have_gil=not self.in_nogil_context) have_gil=not self.in_nogil_context)
if self.has_temp_moved: if self.has_temp_moved:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
...@@ -1851,11 +1849,9 @@ class ImagNode(AtomicExprNode): ...@@ -1851,11 +1849,9 @@ 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)))
if self.type.is_cyp_class: self.generate_gotref(code)
code.put_cygotref(self.result()) elif self.type.is_cyp_class:
else: self.generate_gotref(code)
self.generate_gotref(code)
class NewExprNode(AtomicExprNode): class NewExprNode(AtomicExprNode):
...@@ -2336,7 +2332,7 @@ class NameNode(AtomicExprNode): ...@@ -2336,7 +2332,7 @@ class NameNode(AtomicExprNode):
self.generate_gotref(code) self.generate_gotref(code)
elif entry.type.is_cyp_class: elif entry.type.is_cyp_class:
code.put_cygotref(self.result()) self.generate_gotref(code)
#pass #pass
# code.putln(entry.cname) # code.putln(entry.cname)
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:
...@@ -2438,7 +2434,7 @@ class NameNode(AtomicExprNode): ...@@ -2438,7 +2434,7 @@ class NameNode(AtomicExprNode):
elif self.type.is_cyp_class: elif self.type.is_cyp_class:
if self.use_managed_ref: if self.use_managed_ref:
rhs.make_owned_reference(code) rhs.make_owned_reference(code)
code.put_cyxdecref(self.result()) code.put_xdecref(self.result(), self.type)
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
if not assigned: if not assigned:
if overloaded_assignment: if overloaded_assignment:
...@@ -2536,7 +2532,7 @@ class NameNode(AtomicExprNode): ...@@ -2536,7 +2532,7 @@ class NameNode(AtomicExprNode):
'}' % (del_code, code.error_goto(self.pos))) '}' % (del_code, code.error_goto(self.pos)))
else: else:
code.put_error_if_neg(self.pos, del_code) code.put_error_if_neg(self.pos, del_code)
elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice: elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice or self.entry.type.is_cyp_class:
if not self.cf_is_null: if not self.cf_is_null:
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)
...@@ -2550,22 +2546,6 @@ class NameNode(AtomicExprNode): ...@@ -2550,22 +2546,6 @@ class NameNode(AtomicExprNode):
else: else:
code.put_decref_clear(self.result(), self.ctype(), code.put_decref_clear(self.result(), self.ctype(),
have_gil=not self.nogil) have_gil=not self.nogil)
elif self.entry.type.is_cyp_class:
if not self.cf_is_null:
if self.cf_maybe_null and not ignore_nonexisting:
code.put_error_if_unbound(self.pos, self.entry)
if self.entry.in_closure:
# generator
if ignore_nonexisting and self.cf_maybe_null:
code.put_cyxgotref(self.result())
else:
code.put_cygotref(self.result())
if ignore_nonexisting and self.cf_maybe_null:
code.put_cyxdecref(self.result())
else:
code.put_cydecref(self.result())
code.putln('%s = NULL;' % self.result())
else: else:
error(self.pos, "Deletion of C names not supported") error(self.pos, "Deletion of C names not supported")
...@@ -3034,7 +3014,7 @@ class NextNode(AtomicExprNode): ...@@ -3034,7 +3014,7 @@ class NextNode(AtomicExprNode):
def generate_result_code(self, code): def generate_result_code(self, code):
self.iterator.generate_iter_next_result_code(self.result(), code) self.iterator.generate_iter_next_result_code(self.result(), code)
if self.type.is_cyp_class: if self.type.is_cyp_class:
code.put_cyincref(self.result()) code.put_incref(self.result(), self.type)
class AsyncIteratorNode(ExprNode): class AsyncIteratorNode(ExprNode):
...@@ -4295,7 +4275,7 @@ class IndexNode(_IndexingBaseNode): ...@@ -4295,7 +4275,7 @@ class IndexNode(_IndexingBaseNode):
if self.type.is_pyobject: if self.type.is_pyobject:
self.generate_gotref(code) self.generate_gotref(code)
elif self.type.is_cyp_class: elif self.type.is_cyp_class:
code.put_cygotref(self.result()) code.put_gotref(self.result(), self.type)
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:
...@@ -6339,7 +6319,7 @@ class SimpleCallNode(CallNode): ...@@ -6339,7 +6319,7 @@ class SimpleCallNode(CallNode):
if self.type.is_pyobject and self.result(): if self.type.is_pyobject and self.result():
self.generate_gotref(code) self.generate_gotref(code)
elif self.type.is_cyp_class and self.result(): elif self.type.is_cyp_class and self.result():
code.put_cygotref(self.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)
...@@ -7624,9 +7604,9 @@ class AttributeNode(ExprNode): ...@@ -7624,9 +7604,9 @@ class AttributeNode(ExprNode):
select_code, rhs, rhs.result(), self.type, code) select_code, rhs, rhs.result(), self.type, code)
elif self.type.is_cyp_class: elif self.type.is_cyp_class:
rhs.make_owned_reference(code) rhs.make_owned_reference(code)
code.put_cygiveref(rhs.result()) rhs.generate_giveref(code)
code.put_cygotref(select_code) code.put_gotref(select_code, self.type)
code.put_cyxdecref(select_code) code.put_xdecref(select_code, self.type)
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
code.putln( code.putln(
...@@ -10908,7 +10888,7 @@ class TypecastNode(ExprNode): ...@@ -10908,7 +10888,7 @@ class TypecastNode(ExprNode):
self.result(), self.result(),
self.type.declaration_code(''), self.type.declaration_code(''),
operand_result)) operand_result))
code.put_cyincref(self.result()) code.put_incref(self.result(), self.type)
ERR_START = "Start may not be given" ERR_START = "Start may not be given"
...@@ -14014,10 +13994,7 @@ class CoerceToTempNode(CoercionNode): ...@@ -14014,10 +13994,7 @@ class CoerceToTempNode(CoercionNode):
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 not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
if self.type.is_cyp_class: code.put_incref(self.result(), self.ctype())
code.put_cyincref(self.result())
else:
code.put_incref(self.result(), self.ctype())
else: else:
code.put_incref_memoryviewslice(self.result(), self.type, code.put_incref_memoryviewslice(self.result(), self.type,
have_gil=not self.in_nogil_context) have_gil=not self.in_nogil_context)
......
...@@ -965,10 +965,7 @@ class CArgDeclNode(Node): ...@@ -965,10 +965,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_cyp_class: code.put_giveref(default.result(), self.type)
code.put_cygiveref(default.result())
else:
code.put_giveref(default.result(), self.type)
default.generate_post_assignment_code(code) default.generate_post_assignment_code(code)
default.free_temps(code) default.free_temps(code)
...@@ -2127,7 +2124,10 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2127,7 +2124,10 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
if not entry.type.is_memoryviewslice: if not entry.type.is_memoryviewslice:
if (acquire_gil or entry.cf_is_reassigned) and not entry.in_closure: if (acquire_gil or entry.cf_is_reassigned) and not entry.in_closure:
code.put_var_incref(entry) if entry.type.is_cyp_class and entry.is_self_arg:
pass
else:
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
...@@ -2135,9 +2135,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2135,9 +2135,6 @@ class FuncDefNode(StatNode, BlockNode):
elif is_cdef and entry.cf_is_reassigned: elif is_cdef and entry.cf_is_reassigned:
code.put_var_incref_memoryviewslice(entry, code.put_var_incref_memoryviewslice(entry,
have_gil=code.funcstate.gil_owned) have_gil=code.funcstate.gil_owned)
# We have to Cy_INCREF the nogil classes (ccdef'ed ones)
elif entry.type.is_cyp_class and len(entry.cf_assignments) > 1 and not entry.is_self_arg:
code.put_cyincref(entry.cname)
for entry in lenv.var_entries: for entry in lenv.var_entries:
if entry.is_arg and entry.cf_is_reassigned 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:
...@@ -2325,11 +2322,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2325,11 +2322,8 @@ class FuncDefNode(StatNode, BlockNode):
continue continue
if entry.type.needs_refcounting: if entry.type.needs_refcounting:
assure_gil('success') assure_gil('success')
if entry.type.is_cyp_class: # FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code.put_cyxdecref(entry.cname) code.put_var_xdecref(entry, have_gil=gil_owned['success'])
else:
# FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code.put_var_xdecref(entry, have_gil=gil_owned['success'])
# Decref any increfed args # Decref any increfed args
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
...@@ -2345,10 +2339,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2345,10 +2339,8 @@ class FuncDefNode(StatNode, BlockNode):
continue continue
if entry.type.needs_refcounting: if entry.type.needs_refcounting:
assure_gil('success') assure_gil('success')
if entry.type.is_cyp_class and not entry.is_self_arg: if entry.type.is_cyp_class and entry.is_self_arg:
# We must check for NULL because it is possible to have pass
# NULL as a valid cypclass (with a typecast)
code.put_cyxdecref(entry.cname)
else: else:
# FIXME use entry.xdecref_cleanup - del arg seems to be the problem # FIXME use entry.xdecref_cleanup - del arg seems to be the problem
code.put_var_xdecref(entry, have_gil=gil_owned['success']) code.put_var_xdecref(entry, have_gil=gil_owned['success'])
...@@ -2358,15 +2350,13 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2358,15 +2350,13 @@ class FuncDefNode(StatNode, BlockNode):
# ----- Return # ----- Return
# This code is duplicated in ModuleNode.generate_module_init_func # This code is duplicated in ModuleNode.generate_module_init_func
if not lenv.nogil: # We can always return a CythonExtensionType as it is nogil-compliant
if not lenv.nogil or self.return_type.is_cyp_class:
default_retval = return_type.default_value default_retval = return_type.default_value
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?
code.put_xgiveref(Naming.retval_cname, return_type) code.put_xgiveref(Naming.retval_cname, return_type)
# We can always return a CythonExtensionType as it is nogil-compliant
if self.return_type.is_cyp_class:
code.put_cyxgiveref(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
...@@ -3712,20 +3702,22 @@ class DefNodeWrapper(FuncDefNode): ...@@ -3712,20 +3702,22 @@ class DefNodeWrapper(FuncDefNode):
# ----- Non-error return cleanup # ----- Non-error return cleanup
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:
# The conversion from PyObject to CyObject always creates a new CyObject reference.
# This decrements all arguments-as-variables converted straight from an actual argument.
# This includes CyObjects converted directly from a corresponding PyObject argument.
if entry.xdecref_cleanup: if entry.xdecref_cleanup:
code.put_var_xdecref(entry) code.put_var_xdecref(entry)
else: else:
code.put_var_decref(entry) code.put_var_decref(entry)
elif entry.is_arg and entry.type.is_cyp_class:
# The conversion from PyObject to CyObject creates a new CyObject reference.
code.put_cyxdecref(entry.cname)
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
if entry.type.is_cyp_class: if entry.type.is_cyp_class:
# The conversion from PyObject to CyObject creates a new CyObject reference. # The conversion from PyObject to CyObject always creates a new CyObject reference.
# Such a conversion occurs even when the argument is not explicitly marked # This decrements CyObjects converted from generic PyObject args passed via tuple and kw dict.
# as needing a conversion and declared as a variable in var_entries. if entry.xdecref_cleanup:
code.put_cyxdecref(entry.cname) code.put_var_xdecref(entry)
else:
code.put_var_decref(entry)
code.put_finish_refcount_context() code.put_finish_refcount_context()
if not self.return_type.is_void: if not self.return_type.is_void:
...@@ -6626,7 +6618,7 @@ class ReturnStatNode(StatNode): ...@@ -6626,7 +6618,7 @@ class ReturnStatNode(StatNode):
value = None value = None
if self.return_type.is_cyp_class: if self.return_type.is_cyp_class:
code.put_cyxdecref(Naming.retval_cname) code.put_xdecref(Naming.retval_cname, self.return_type)
if value: if value:
value.generate_evaluation_code(code) value.generate_evaluation_code(code)
......
...@@ -4387,6 +4387,43 @@ class CypClassType(CppClassType): ...@@ -4387,6 +4387,43 @@ class CypClassType(CppClassType):
init_entry.is_cfunction = 1 init_entry.is_cfunction = 1
return init_entry return init_entry
def generate_incref(self, code, cname, **kwds):
code.putln("Cy_INCREF(%s);" % cname)
generate_xincref = generate_incref
def generate_decref(self, code, cname, **kwds):
code.putln("Cy_DECREF(%s);" % cname)
def generate_decref_clear(self, code, cname, **kwds):
code.putln("Cy_DECREF(%s);" % cname)
code.putln("%s = NULL;" % cname)
def generate_xdecref(self, code, cname, **kwds):
code.putln("Cy_XDECREF(%s);" % cname)
def generate_xdecref_clear(self, code, cname, **kwds):
code.putln("Cy_XDECREF(%s);" % cname)
code.putln("%s = NULL;" % cname)
def generate_gotref(self, code, cname):
code.putln("Cy_GOTREF(%s);" % cname)
def generate_xgotref(self, code, cname):
code.putln("Cy_XGOTREF(%s);" % cname)
def generate_giveref(self, code, cname):
code.putln("Cy_GIVEREF(%s);" % cname)
def generate_xgiveref(self, code, cname):
code.putln("Cy_XGIVEREF(%s);" % cname)
def generate_decref_set(self, code, cname, rhs_cname):
raise NotImplementedError("Cy_DECREF_SET is not defined for decrementing a group of cyobjects")
def generate_xdecref_set(self, code, cname, rhs_cname):
raise NotImplementedError("Cy_XDECREF_SET is not defined for decrementing a group of cyobjects")
class TemplatePlaceholderType(CType): class TemplatePlaceholderType(CType):
......
...@@ -201,10 +201,8 @@ class ResultRefNode(AtomicExprNode): ...@@ -201,10 +201,8 @@ class ResultRefNode(AtomicExprNode):
if self.type.is_pyobject or self.type.is_cyp_class: if self.type.is_pyobject or self.type.is_cyp_class:
rhs.make_owned_reference(code) rhs.make_owned_reference(code)
if not self.lhs_of_first_assignment: if not self.lhs_of_first_assignment:
if self.type.is_pyobject: if self.type.is_pyobject or self.type.is_cyp_class:
code.put_decref(self.result(), self.ctype()) code.put_decref(self.result(), self.ctype())
elif self.type.is_cyp_class:
code.put_cydecref(self.result())
code.putln('%s = %s;' % ( code.putln('%s = %s;' % (
self.result(), self.result(),
rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()), rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
...@@ -249,10 +247,8 @@ class LetNodeMixin: ...@@ -249,10 +247,8 @@ class LetNodeMixin:
self.temp_expression.generate_disposal_code(code) self.temp_expression.generate_disposal_code(code)
self.temp_expression.free_temps(code) self.temp_expression.free_temps(code)
else: else:
if self.temp_type.is_pyobject: if self.temp_type.is_pyobject or self.temp_type.is_cyp_class:
code.put_decref_clear(self.temp, self.temp_type) code.put_decref_clear(self.temp, self.temp_type)
elif self.temp_type.is_cyp_class:
code.put_cyxdecref(self.temp)
code.funcstate.release_temp(self.temp) code.funcstate.release_temp(self.temp)
......
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