Commit c8ecf45e authored by gsamain's avatar gsamain Committed by Xavier Thompson

Gwenael: Remove nogil extension and introduce refcounted cypclass

parent c63eede4
......@@ -2058,7 +2058,7 @@ class CCodeWriter(object):
entry.cname, dll_linkage=dll_linkage))
if entry.init is not None:
self.put_safe(" = %s" % entry.type.literal_code(entry.init))
elif entry.type.is_pyobject:
elif entry.type.is_pyobject or entry.type.is_cyp_class:
self.put(" = NULL")
self.putln(";")
......@@ -2069,8 +2069,8 @@ class CCodeWriter(object):
self.putln("%s = NULL;" % decl)
elif type.is_memoryviewslice:
self.putln("%s = %s;" % (decl, type.literal_code(type.default_value)))
elif type.is_struct and type.is_extension_type and type.nogil:
self.putln("%s;" % decl)
elif type.is_cyp_class:
self.putln("%s = NULL;" % decl)
else:
self.putln("%s%s;" % (static and "static " or "", decl))
......@@ -2103,6 +2103,29 @@ class CCodeWriter(object):
return ''
return '%s ' % ' '.join([mapper(m,m) for m in modifiers])
# CyObjects reference counting
def put_cygotref(self, cname):
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):
......
......@@ -784,7 +784,10 @@ class ExprNode(Node):
If the result is in a temp, it is already a new reference.
"""
if not self.result_in_temp():
code.put_incref(self.result(), self.ctype())
if self.type.is_cyp_class and "NULL" not in self.result():
code.put_cyincref(self.result())
else:
code.put_incref(self.result(), self.ctype())
def make_owned_memoryviewslice(self, code):
"""
......@@ -826,7 +829,10 @@ class ExprNode(Node):
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
if self.result():
code.put_decref_clear(self.result(), self.ctype(),
if self.type.is_cyp_class:
code.put_cyxdecref(self.result())
else:
code.put_decref_clear(self.result(), self.ctype(),
have_gil=not self.in_nogil_context)
if self.has_temp_moved:
code.globalstate.use_utility_code(
......@@ -849,6 +855,8 @@ class ExprNode(Node):
self.free_subexpr_temps(code)
elif self.type.is_pyobject:
code.putln("%s = 0;" % self.result())
elif self.type.is_cyp_class:
code.putln("%s = 0;" % self.result())
elif self.type.is_memoryviewslice:
code.putln("%s.memview = NULL;" % self.result())
code.putln("%s.data = NULL;" % self.result())
......@@ -1843,7 +1851,10 @@ class ImagNode(AtomicExprNode):
self.result(),
float(self.value),
code.error_goto_if_null(self.result(), self.pos)))
self.generate_gotref(code)
if self.type.is_cyp_class:
code.put_cygotref(self.result())
else:
self.generate_gotref(code)
class NewExprNode(AtomicExprNode):
......@@ -2324,8 +2335,9 @@ class NameNode(AtomicExprNode):
code.error_goto_if_null(self.result(), self.pos)))
self.generate_gotref(code)
elif entry.is_local and isinstance(entry.type, PyrexTypes.CythonExtensionType):
pass
elif entry.is_local and entry.type.is_cyp_class:
code.put_cygotref(self.result())
#pass
# code.putln(entry.cname)
elif entry.is_local or entry.in_closure or entry.from_closure or entry.type.is_memoryviewslice:
# Raise UnboundLocalError for objects and memoryviewslices
......@@ -2423,6 +2435,10 @@ class NameNode(AtomicExprNode):
assigned = False
if is_external_ref:
rhs.generate_giveref(code)
elif self.type.is_cyp_class:
code.put_cyxdecref(self.result())
if isinstance(rhs, NameNode):
rhs.make_owned_reference(code)
if not self.type.is_memoryviewslice:
if not assigned:
if overloaded_assignment:
......@@ -2534,6 +2550,22 @@ class NameNode(AtomicExprNode):
else:
code.put_decref_clear(self.result(), self.ctype(),
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:
error(self.pos, "Deletion of C names not supported")
......@@ -4186,6 +4218,8 @@ class IndexNode(_IndexingBaseNode):
code.error_goto_if(error_check % self.result(), self.pos)))
if self.type.is_pyobject:
self.generate_gotref(code)
elif self.type.is_cyp_class:
code.put_cygotref(self.result())
def generate_setitem_code(self, value_code, code):
if self.index.type.is_int:
......@@ -5606,18 +5640,6 @@ class CallNode(ExprNode):
self.analyse_c_function_call(env)
self.type = type
return True
elif type and type.is_struct and type.nogil:
args, kwds = self.explicit_args_kwds()
items = []
for arg, member in zip(args, type.scope.var_entries):
items.append(DictItemNode(pos=arg.pos, key=StringNode(pos=arg.pos, value=member.name), value=arg))
if kwds:
items += kwds.key_value_pairs
self.key_value_pairs = items
self.__class__ = DictNode
self.analyse_types(env) # FIXME
self.coerce_to(type, env)
return True
def is_lvalue(self):
return self.type.is_reference
......@@ -6125,6 +6147,8 @@ class SimpleCallNode(CallNode):
code.putln("%s%s; %s" % (lhs, rhs, goto_error))
if self.type.is_pyobject and self.result():
self.generate_gotref(code)
elif self.type.is_cyp_class and self.result():
code.put_cygotref(self.result())
if self.has_optional_args:
code.funcstate.release_temp(self.opt_arg_struct)
......@@ -7128,6 +7152,8 @@ class AttributeNode(ExprNode):
self.op = "->"
elif obj_type.is_reference and obj_type.is_fake_reference:
self.op = "->"
elif obj_type.is_cyp_class:
self.op = "->"
else:
self.op = "."
if obj_type.has_attributes:
......@@ -7278,12 +7304,9 @@ class AttributeNode(ExprNode):
# (AnalyseExpressionsTransform)
self.member = self.entry.cname
if obj.type.nogil:
return "%s" % self.entry.func_cname
else:
return "((struct %s *)%s%s%s)->%s" % (
obj.type.vtabstruct_cname, obj_code, self.op,
obj.type.vtabslot_cname, self.member)
return "((struct %s *)%s%s%s)->%s" % (
obj.type.vtabstruct_cname, obj_code, self.op,
obj.type.vtabslot_cname, self.member)
elif self.result_is_used:
return self.member
# Generating no code at all for unused access to optimised builtin
......@@ -7386,6 +7409,11 @@ class AttributeNode(ExprNode):
from . import MemoryView
MemoryView.put_assign_to_memviewslice(
select_code, rhs, rhs.result(), self.type, code)
elif self.type.is_cyp_class:
rhs.make_owned_reference(code)
code.put_cygiveref(rhs.result())
code.put_cygotref(select_code)
code.put_cyxdecref(select_code)
if not self.type.is_memoryviewslice:
code.putln(
......@@ -8882,8 +8910,6 @@ class DictNode(ExprNode):
# pairs are evaluated and used one at a time.
code.mark_pos(self.pos)
self.allocate_temp_result(code)
if hasattr(self.type, 'nogil') and self.type.nogil:
code.putln("%s = (struct %s *)malloc(sizeof(struct %s));" % (self.result(), self.type.objstruct_cname, self.type.objstruct_cname))
is_dict = self.type.is_pyobject
if is_dict:
......@@ -8941,11 +8967,6 @@ class DictNode(ExprNode):
code.putln('}')
if self.exclude_null_values:
code.putln('}')
elif self.type.nogil:
code.putln("%s->%s = %s;" % (
self.result(),
item.key.value,
item.value.result()))
else:
code.putln("%s.%s = %s;" % (
self.result(),
......@@ -13579,7 +13600,10 @@ class CoerceToTempNode(CoercionNode):
self.result(), self.arg.result_as(self.ctype())))
if self.use_managed_ref:
if not self.type.is_memoryviewslice:
code.put_incref(self.result(), self.ctype())
if self.type.is_cyp_class:
code.put_cyincref(self.result())
else:
code.put_incref(self.result(), self.ctype())
else:
code.put_incref_memoryviewslice(self.result(), self.type,
have_gil=not self.in_nogil_context)
......
......@@ -6,7 +6,7 @@ from __future__ import absolute_import
import cython
cython.declare(Naming=object, Options=object, PyrexTypes=object, TypeSlots=object,
error=object, warning=object, py_object_type=object, UtilityCode=object,
error=object, warning=object, py_object_type=object, cy_object_type=object, UtilityCode=object,
EncodedString=object, re=object)
from collections import defaultdict
......@@ -28,7 +28,7 @@ from . import PyrexTypes
from . import Pythran
from .Errors import error, warning
from .PyrexTypes import py_object_type
from .PyrexTypes import py_object_type, cy_object_type
from ..Utils import open_new_file, replace_suffix, decode_filename, build_hex_version
from .Code import UtilityCode, IncludeCode, TempitaUtilityCode
from .StringEncoding import EncodedString, encoded_string_or_bytes_literal
......@@ -981,17 +981,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# Just let everything be public.
code.put("struct %s" % type.cname)
if type.base_classes:
base_class_decl = ", public ".join(
[base_class.empty_declaration_code() for base_class in type.base_classes])
base_class_list = [base_class.empty_declaration_code() for base_class in type.base_classes]
if type.is_cyp_class and type.base_classes[-1] is cy_object_type:
base_class_list[-1] = "virtual " + base_class_list[-1]
base_class_decl = ", public ".join(base_class_list)
code.put(" : public %s" % base_class_decl)
code.putln(" {")
self.generate_type_header_code(scope.type_entries, code)
self.generate_cyp_class_wrapper_definitions(scope.sue_entries, code)
py_attrs = [e for e in scope.entries.values()
if e.type.is_pyobject and not e.is_inherited]
has_virtual_methods = False
constructor = None
destructor = None
for attr in scope.var_entries:
cname = attr.cname
if attr.type.is_cfunction and attr.type.is_static_method:
code.put("static ")
elif attr.name == "<init>":
......@@ -1002,7 +1006,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
elif attr.type.is_cfunction:
code.put("virtual ")
has_virtual_methods = True
code.putln("%s;" % attr.type.declaration_code(attr.cname))
elif attr.type.is_cyp_class:
cname = "%s = NULL" % cname
code.putln("%s;" % attr.type.declaration_code(cname))
is_implementing = 'init_module' in code.globalstate.parts
def generate_cpp_constructor_code(arg_decls, arg_names, is_implementing, py_attrs, constructor):
......@@ -1085,6 +1091,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("%s& operator=(const %s& __Pyx_other);" % (type.cname, type.cname))
code.putln("};")
if type.is_cyp_class:
code.globalstate.use_utility_code(
UtilityCode.load("CyObjects", "CyObjects.cpp", proto_block="utility_code_proto_before_types"))
def generate_enum_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type
......@@ -1202,7 +1212,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.sue_header_footer(type, "struct", type.objstruct_cname)
code.putln(header)
base_type = type.base_type
nogil = type.nogil
if base_type:
basestruct_cname = base_type.objstruct_cname
if basestruct_cname == "PyTypeObject":
......@@ -1213,16 +1222,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
("struct ", "")[base_type.typedef_flag],
basestruct_cname,
Naming.obj_base_cname))
elif nogil:
# Extension type with nogil keyword indicate it is a CPython-free struct
code.globalstate.use_utility_code(
UtilityCode.load_cached("CythonReferenceCounting", "ObjectHandling.c"))
code.putln(
"// nogil"
)
code.putln(
"int ob_refcnt;" # "CyObject_HEAD;" Sometimes the CythonReferenceCounting was put after the nogil extension declaration, WTF!!!
)
else:
code.putln(
"PyObject_HEAD")
......
This diff is collapsed.
......@@ -2247,7 +2247,7 @@ def p_statement(s, ctx, first_statement = 0):
elif s.sy == 'IF':
return p_IF_statement(s, ctx)
elif s.sy == '@':
if ctx.level not in ('module', 'class', 'c_class', 'class_nogil', 'function', 'property', 'module_pxd', 'c_class_pxd', 'other'):
if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd', 'other'):
s.error('decorator not allowed here')
s.level = ctx.level
decorators = p_decorators(s)
......@@ -2261,21 +2261,20 @@ def p_statement(s, ctx, first_statement = 0):
return p_pass_statement(s, with_newline=1)
overridable = 0
nogil_flag = ctx.nogil
if s.sy == 'cdef':
cdef_flag = 1
s.next()
elif s.sy == 'cpdef':
if ctx.level == 'c_class_nogil':
s.error('cpdef statement not allowed in nogil extension type')
s.level = ctx.level
cdef_flag = 1
overridable = 1
s.next()
if cdef_flag:
if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_nogil', 'c_class_pxd'):
if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
s.error('cdef statement not allowed here')
s.level = ctx.level
node = p_cdef_statement(s, ctx(overridable=overridable))
node = p_cdef_statement(s, ctx(overridable=overridable, nogil=nogil_flag))
if decorators is not None:
tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)
if ctx.allow_struct_enum_decorator:
......@@ -2292,8 +2291,6 @@ def p_statement(s, ctx, first_statement = 0):
# as part of a cdef class
if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
s.error('def statement not allowed here')
if ctx.level == 'c_class_nogil':
s.error('def statement not allowed in nogil extension type, only cdef with nogil is allowed')
s.level = ctx.level
return p_def_statement(s, decorators)
elif s.sy == 'class':
......@@ -2304,7 +2301,7 @@ def p_statement(s, ctx, first_statement = 0):
if ctx.level not in ('module', 'module_pxd'):
s.error("include statement not allowed here")
return p_include_statement(s, ctx)
elif ctx.level in ('c_class', 'c_class_nogil') and s.sy == 'IDENT' and s.systring == 'property':
elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
return p_property_decl(s)
elif s.sy == 'pass' and ctx.level != 'property':
return p_pass_statement(s, with_newline=True)
......@@ -3080,9 +3077,11 @@ def p_cdef_statement(s, ctx):
return p_cdef_extern_block(s, pos, ctx)
elif p_nogil(s):
ctx.nogil = 1
if ctx.overridable:
error(pos, "cdef blocks cannot be declared cpdef")
# if ctx.overridable:
# error(pos, "cdef blocks cannot be declared cpdef")
return p_cdef_block(s, ctx)
elif ctx.overridable and ctx.nogil:
error(pos, "nogil blocks cannot be declared cpdef")
elif s.sy == ':':
if ctx.overridable:
error(pos, "cdef blocks cannot be declared cpdef")
......@@ -3093,7 +3092,7 @@ def p_cdef_statement(s, ctx):
if ctx.overridable:
error(pos, "Extension types cannot be declared cpdef")
return p_c_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring == 'cppclass':
elif s.sy == 'IDENT' and s.systring in ('cppclass', 'cypclass'):
return p_cpp_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in struct_enum_union:
if ctx.level not in ('module', 'module_pxd'):
......@@ -3323,7 +3322,7 @@ def p_c_modifiers(s):
return []
def p_c_func_or_var_declaration(s, pos, ctx):
cmethod_flag = ctx.level in ('c_class', 'c_class_pxd', 'c_class_nogil')
cmethod_flag = ctx.level in ('c_class', 'c_class_pxd')
modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates)
declarator = p_c_declarator(s, ctx(modifiers=modifiers), cmethod_flag = cmethod_flag,
......@@ -3342,13 +3341,8 @@ def p_c_func_or_var_declaration(s, pos, ctx):
fatal=False)
s.next()
p_test(s) # Keep going, but ignore result.
if s.sy == 'nogil':
nogil = p_nogil(s)
s.next()
if ctx.level == 'c_class_nogil' and not nogil:
s.error("Only C function with nogil allowed in nogil extension")
if s.sy == ':':
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class', 'c_class_nogil') and not ctx.templates:
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
s.error("C function definition not allowed here")
doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
result = Nodes.CFuncDefNode(pos,
......@@ -3376,7 +3370,7 @@ def p_c_func_or_var_declaration(s, pos, ctx):
declarators.append(declarator)
doc_line = s.start_line + 1
s.expect_newline("Syntax error in C variable declaration", ignore_semicolon=True)
if ctx.level in ('c_class', 'c_class_pxd', 'c_class_nogil') and s.start_line == doc_line:
if ctx.level in ('c_class', 'c_class_pxd') and s.start_line == doc_line:
doc = p_doc_string(s)
else:
doc = None
......@@ -3577,12 +3571,9 @@ def p_c_class_definition(s, pos, ctx):
if ctx.visibility not in ('public', 'extern') and not ctx.api:
error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
objstruct_name, typeobj_name, check_size = p_c_class_options(s)
nogil = p_nogil(s)
if s.sy == ':':
if ctx.level == 'module_pxd':
body_level = 'c_class_pxd'
elif nogil:
body_level = 'c_class_nogil'
else:
body_level = 'c_class'
doc, body = p_suite_with_docstring(s, Ctx(level=body_level))
......@@ -3621,8 +3612,7 @@ def p_c_class_definition(s, pos, ctx):
check_size = check_size,
in_pxd = ctx.level == 'module_pxd',
doc = doc,
body = body,
nogil = nogil or ctx.nogil)
body = body)
def p_c_class_options(s):
......@@ -3803,7 +3793,8 @@ def p_template_definition(s):
return name, required
def p_cpp_class_definition(s, pos, ctx):
# s.sy == 'cppclass'
# s.sy in ('cppclass', 'cypclass')
cypclass = s.systring == 'cypclass'
s.next()
class_name = p_ident(s)
cname = p_opt_cname(s)
......@@ -3833,7 +3824,7 @@ def p_cpp_class_definition(s, pos, ctx):
base_classes = []
if s.sy == '[':
error(s.position(), "Name options not allowed for C++ class")
nogil = p_nogil(s)
nogil = p_nogil(s) or cypclass
if s.sy == ':':
s.next()
s.expect('NEWLINE')
......@@ -3862,7 +3853,7 @@ def p_cpp_class_definition(s, pos, ctx):
visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd',
attributes = attributes,
templates = templates)
templates = templates, cypclass=cypclass)
def p_cpp_class_attribute(s, ctx):
decorators = None
......
This diff is collapsed.
......@@ -17,7 +17,7 @@ from .Errors import warning, error, InternalError
from .StringEncoding import EncodedString
from . import Options, Naming
from . import PyrexTypes
from .PyrexTypes import py_object_type, unspecified_type
from .PyrexTypes import py_object_type, cy_object_type, unspecified_type
from .TypeSlots import (
pyfunction_signature, pymethod_signature, richcmp_special_methods,
get_special_method_signature, get_property_accessor_signature)
......@@ -628,7 +628,7 @@ class Scope(object):
def declare_cpp_class(self, name, scope,
pos, cname = None, base_classes = (),
visibility = 'extern', templates = None):
visibility = 'extern', templates = None, cypclass=0):
if cname is None:
if self.in_cinclude or (visibility != 'private'):
cname = name
......@@ -637,8 +637,12 @@ class Scope(object):
base_classes = list(base_classes)
entry = self.lookup_here(name)
if not entry:
type = PyrexTypes.CppClassType(
name, scope, cname, base_classes, templates = templates)
if cypclass:
type = PyrexTypes.CypClassType(
name, scope, cname, base_classes, templates = templates)
else:
type = PyrexTypes.CppClassType(
name, scope, cname, base_classes, templates = templates)
entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None)
self.sue_entries.append(entry)
......@@ -666,7 +670,7 @@ class Scope(object):
def declare_inherited_attributes(entry, base_classes):
for base_class in base_classes:
if base_class is PyrexTypes.error_type:
if base_class is PyrexTypes.error_type or base_class is PyrexTypes.cy_object_type:
continue
if base_class.scope is None:
error(pos, "Cannot inherit from incomplete type")
......@@ -1580,7 +1584,7 @@ class ModuleScope(Scope):
def declare_c_class(self, name, pos, defining=0, implementing=0,
module_name=None, base_type=None, objstruct_cname=None,
typeobj_cname=None, typeptr_cname=None, visibility='private',
typedef_flag=0, api=0, nogil=0, check_size=None,
typedef_flag=0, api=0, check_size=None,
buffer_defaults=None, shadow=0):
# If this is a non-extern typedef class, expose the typedef, but use
# the non-typedef struct internally to avoid needing forward
......@@ -1613,15 +1617,8 @@ class ModuleScope(Scope):
# Make a new entry if needed
#
if not entry or shadow:
if nogil:
pass
if nogil:
type = PyrexTypes.CythonExtensionType(
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
else:
type = PyrexTypes.PyExtensionType(
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
type.nogil = nogil
type = PyrexTypes.PyExtensionType(
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
type.pos = pos
type.buffer_defaults = buffer_defaults
if objtypedef_cname is not None:
......@@ -2341,8 +2338,7 @@ class CClassScope(ClassScope):
defining=0, modifiers=(), utility_code=None, overridable=False):
name = self.mangle_class_private_name(name)
if get_special_method_signature(name) and not self.parent_type.is_builtin_type:
if not(hasattr(self.parent_type, "nogil") and self.parent_type.nogil and self.parent_type.is_struct_or_union):
error(pos, "Special methods must be declared with 'def', not 'cdef'")
error(pos, "Special methods must be declared with 'def', not 'cdef'")
args = type.args
if not type.is_static_method:
if not args:
......@@ -2578,6 +2574,8 @@ class CppClassScope(Scope):
type.return_type = PyrexTypes.c_void_type
if name in ('<init>', '<del>') and type.nogil:
for base in self.type.base_classes:
if base is cy_object_type:
continue
base_entry = base.scope.lookup(name)
if base_entry and not base_entry.type.nogil:
error(pos, "Constructor cannot be called without GIL unless all base constructors can also be called without GIL")
......
......@@ -198,10 +198,13 @@ class ResultRefNode(AtomicExprNode):
pass
def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
if self.type.is_pyobject:
if self.type.is_pyobject or self.type.is_cyp_class:
rhs.make_owned_reference(code)
if not self.lhs_of_first_assignment:
code.put_decref(self.result(), self.ctype())
if self.type.is_pyobject:
code.put_decref(self.result(), self.ctype())
elif self.type.is_cyp_class:
code.put_cydecref(self.result())
code.putln('%s = %s;' % (
self.result(),
rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
......@@ -248,6 +251,9 @@ class LetNodeMixin:
else:
if self.temp_type.is_pyobject:
code.put_decref_clear(self.temp, self.temp_type)
elif self.temp_type.is_cyp_class:
pass
#code.put_decref_clear(self.temp, self.temp_type)
code.funcstate.release_temp(self.temp)
......
/////////////// CyObjects.proto ///////////////
#if !defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
/* Test for GCC > 4.9.0 */
#if GCC_VERSION < 40900
#error atomic.h works only with GCC newer than version 4.9
#endif /* GNUC >= 4.9 */
#endif /* Has GCC */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#include <atomic>
using namespace std;
#define CyObject_ATOMIC_REFCOUNT_TYPE atomic_int
class CyObject {
private:
CyObject_ATOMIC_REFCOUNT_TYPE ob_refcnt;
public:
CyObject(): ob_refcnt(1) {}
virtual ~CyObject() {}
void CyObject_INCREF();
int CyObject_DECREF();
};
static inline int _Cy_DECREF(CyObject *op) {
return op->CyObject_DECREF();
}
static inline void _Cy_INCREF(CyObject *op) {
op->CyObject_INCREF();
}
/* Cast argument to CyObject* type. */
#define _CyObject_CAST(op) op
#define Cy_INCREF(op) do {if (op != NULL) {_Cy_INCREF(_CyObject_CAST(op));}} while(0)
#define Cy_DECREF(op) do {if (_Cy_DECREF(_CyObject_CAST(op))) {op = NULL;}} while(0)
#define Cy_XDECREF(op) do {if (op != NULL) {Cy_DECREF(op);}} while(0)
#define Cy_GOTREF(op)
#define Cy_XGOTREF(op)
#define Cy_GIVEREF(op)
#define Cy_XGIVEREF(op)
#endif
#endif
/////////////// CyObjects ///////////////
#ifdef __cplusplus
#include <cstdlib>
#include <cstddef>
// atomic is already included in ModuleSetupCode
// #include <atomic>
#else
#error C++ needed for cython+ nogil classes
#endif /* __cplusplus */
void CyObject::CyObject_INCREF()
{
atomic_fetch_add(&(this->ob_refcnt), 1);
}
int CyObject::CyObject_DECREF()
{
if (atomic_fetch_sub(&(this->ob_refcnt), 1) == 1) {
delete this;
return 1;
}
return 0;
}
......@@ -1878,51 +1878,6 @@ try_unpack:
return 0;
}
/////////////// CythonReferenceCounting.proto ///////////////
#include <stdlib.h>
#include <stddef.h>
#if !defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
/* Test for GCC > 4.9.0 */
#if GCC_VERSION < 40900
#error atomic.h works only with GCC newer than version 4.9
#endif /* GNUC >= 4.9 */
#endif /* Has GCC */
// #include <stdatomic.h>
/* CyObject_HEAD defines the initial segment of every CyObject. */
#define CyObject_HEAD \
int ob_refcnt; \
void (*cdealloc)();
struct CyObject {
CyObject_HEAD
};
/* Cast argument to PyObject* type. */
#define _CyObject_CAST(op) ((struct CyObject*)(op))
// XXX: Without scope analysis this is useless...
/*
static inline void _Cy_DECREF(struct CyObject *op) {
if (atomic_fetch_sub(&(op->ob_refcnt), 1) == 1) {
op->cdealloc(op);
}