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): ...@@ -2058,7 +2058,7 @@ class CCodeWriter(object):
entry.cname, dll_linkage=dll_linkage)) entry.cname, dll_linkage=dll_linkage))
if entry.init is not None: if entry.init is not None:
self.put_safe(" = %s" % entry.type.literal_code(entry.init)) 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.put(" = NULL")
self.putln(";") self.putln(";")
...@@ -2069,8 +2069,8 @@ class CCodeWriter(object): ...@@ -2069,8 +2069,8 @@ class CCodeWriter(object):
self.putln("%s = NULL;" % decl) self.putln("%s = NULL;" % decl)
elif type.is_memoryviewslice: elif type.is_memoryviewslice:
self.putln("%s = %s;" % (decl, type.literal_code(type.default_value))) self.putln("%s = %s;" % (decl, type.literal_code(type.default_value)))
elif type.is_struct and type.is_extension_type and type.nogil: elif type.is_cyp_class:
self.putln("%s;" % decl) self.putln("%s = NULL;" % decl)
else: else:
self.putln("%s%s;" % (static and "static " or "", decl)) self.putln("%s%s;" % (static and "static " or "", decl))
...@@ -2103,6 +2103,29 @@ class CCodeWriter(object): ...@@ -2103,6 +2103,29 @@ 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):
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 # Python objects and reference counting
def entry_as_pyobject(self, entry): def entry_as_pyobject(self, entry):
......
...@@ -784,7 +784,10 @@ class ExprNode(Node): ...@@ -784,7 +784,10 @@ 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():
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): def make_owned_memoryviewslice(self, code):
""" """
...@@ -826,7 +829,10 @@ class ExprNode(Node): ...@@ -826,7 +829,10 @@ 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():
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) 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(
...@@ -849,6 +855,8 @@ class ExprNode(Node): ...@@ -849,6 +855,8 @@ class ExprNode(Node):
self.free_subexpr_temps(code) self.free_subexpr_temps(code)
elif self.type.is_pyobject: elif self.type.is_pyobject:
code.putln("%s = 0;" % self.result()) code.putln("%s = 0;" % self.result())
elif self.type.is_cyp_class:
code.putln("%s = 0;" % self.result())
elif self.type.is_memoryviewslice: elif self.type.is_memoryviewslice:
code.putln("%s.memview = NULL;" % self.result()) code.putln("%s.memview = NULL;" % self.result())
code.putln("%s.data = NULL;" % self.result()) code.putln("%s.data = NULL;" % self.result())
...@@ -1843,7 +1851,10 @@ class ImagNode(AtomicExprNode): ...@@ -1843,7 +1851,10 @@ 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)))
self.generate_gotref(code) if self.type.is_cyp_class:
code.put_cygotref(self.result())
else:
self.generate_gotref(code)
class NewExprNode(AtomicExprNode): class NewExprNode(AtomicExprNode):
...@@ -2324,8 +2335,9 @@ class NameNode(AtomicExprNode): ...@@ -2324,8 +2335,9 @@ class NameNode(AtomicExprNode):
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
self.generate_gotref(code) self.generate_gotref(code)
elif entry.is_local and isinstance(entry.type, PyrexTypes.CythonExtensionType): elif entry.is_local and entry.type.is_cyp_class:
pass code.put_cygotref(self.result())
#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:
# Raise UnboundLocalError for objects and memoryviewslices # Raise UnboundLocalError for objects and memoryviewslices
...@@ -2423,6 +2435,10 @@ class NameNode(AtomicExprNode): ...@@ -2423,6 +2435,10 @@ class NameNode(AtomicExprNode):
assigned = False assigned = False
if is_external_ref: if is_external_ref:
rhs.generate_giveref(code) 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 self.type.is_memoryviewslice:
if not assigned: if not assigned:
if overloaded_assignment: if overloaded_assignment:
...@@ -2534,6 +2550,22 @@ class NameNode(AtomicExprNode): ...@@ -2534,6 +2550,22 @@ 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")
...@@ -4186,6 +4218,8 @@ class IndexNode(_IndexingBaseNode): ...@@ -4186,6 +4218,8 @@ class IndexNode(_IndexingBaseNode):
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:
self.generate_gotref(code) self.generate_gotref(code)
elif self.type.is_cyp_class:
code.put_cygotref(self.result())
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:
...@@ -5606,18 +5640,6 @@ class CallNode(ExprNode): ...@@ -5606,18 +5640,6 @@ class CallNode(ExprNode):
self.analyse_c_function_call(env) self.analyse_c_function_call(env)
self.type = type self.type = type
return True 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): def is_lvalue(self):
return self.type.is_reference return self.type.is_reference
...@@ -6125,6 +6147,8 @@ class SimpleCallNode(CallNode): ...@@ -6125,6 +6147,8 @@ class SimpleCallNode(CallNode):
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():
self.generate_gotref(code) self.generate_gotref(code)
elif self.type.is_cyp_class and self.result():
code.put_cygotref(self.result())
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)
...@@ -7128,6 +7152,8 @@ class AttributeNode(ExprNode): ...@@ -7128,6 +7152,8 @@ class AttributeNode(ExprNode):
self.op = "->" self.op = "->"
elif obj_type.is_reference and obj_type.is_fake_reference: elif obj_type.is_reference and obj_type.is_fake_reference:
self.op = "->" self.op = "->"
elif obj_type.is_cyp_class:
self.op = "->"
else: else:
self.op = "." self.op = "."
if obj_type.has_attributes: if obj_type.has_attributes:
...@@ -7278,12 +7304,9 @@ class AttributeNode(ExprNode): ...@@ -7278,12 +7304,9 @@ class AttributeNode(ExprNode):
# (AnalyseExpressionsTransform) # (AnalyseExpressionsTransform)
self.member = self.entry.cname self.member = self.entry.cname
if obj.type.nogil: return "((struct %s *)%s%s%s)->%s" % (
return "%s" % self.entry.func_cname obj.type.vtabstruct_cname, obj_code, self.op,
else: 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: elif self.result_is_used:
return self.member return self.member
# Generating no code at all for unused access to optimised builtin # Generating no code at all for unused access to optimised builtin
...@@ -7386,6 +7409,11 @@ class AttributeNode(ExprNode): ...@@ -7386,6 +7409,11 @@ class AttributeNode(ExprNode):
from . import MemoryView from . import MemoryView
MemoryView.put_assign_to_memviewslice( MemoryView.put_assign_to_memviewslice(
select_code, rhs, rhs.result(), self.type, code) 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: if not self.type.is_memoryviewslice:
code.putln( code.putln(
...@@ -8882,8 +8910,6 @@ class DictNode(ExprNode): ...@@ -8882,8 +8910,6 @@ class DictNode(ExprNode):
# pairs are evaluated and used one at a time. # pairs are evaluated and used one at a time.
code.mark_pos(self.pos) code.mark_pos(self.pos)
self.allocate_temp_result(code) 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 is_dict = self.type.is_pyobject
if is_dict: if is_dict:
...@@ -8941,11 +8967,6 @@ class DictNode(ExprNode): ...@@ -8941,11 +8967,6 @@ class DictNode(ExprNode):
code.putln('}') code.putln('}')
if self.exclude_null_values: if self.exclude_null_values:
code.putln('}') code.putln('}')
elif self.type.nogil:
code.putln("%s->%s = %s;" % (
self.result(),
item.key.value,
item.value.result()))
else: else:
code.putln("%s.%s = %s;" % ( code.putln("%s.%s = %s;" % (
self.result(), self.result(),
...@@ -13579,7 +13600,10 @@ class CoerceToTempNode(CoercionNode): ...@@ -13579,7 +13600,10 @@ 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:
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: 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)
......
...@@ -6,7 +6,7 @@ from __future__ import absolute_import ...@@ -6,7 +6,7 @@ from __future__ import absolute_import
import cython import cython
cython.declare(Naming=object, Options=object, PyrexTypes=object, TypeSlots=object, 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) EncodedString=object, re=object)
from collections import defaultdict from collections import defaultdict
...@@ -28,7 +28,7 @@ from . import PyrexTypes ...@@ -28,7 +28,7 @@ from . import PyrexTypes
from . import Pythran from . import Pythran
from .Errors import error, warning 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 ..Utils import open_new_file, replace_suffix, decode_filename, build_hex_version
from .Code import UtilityCode, IncludeCode, TempitaUtilityCode from .Code import UtilityCode, IncludeCode, TempitaUtilityCode
from .StringEncoding import EncodedString, encoded_string_or_bytes_literal from .StringEncoding import EncodedString, encoded_string_or_bytes_literal
...@@ -981,17 +981,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -981,17 +981,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# Just let everything be public. # Just let everything be public.
code.put("struct %s" % type.cname) code.put("struct %s" % type.cname)
if type.base_classes: if type.base_classes:
base_class_decl = ", public ".join( base_class_list = [base_class.empty_declaration_code() for base_class in type.base_classes]
[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.put(" : public %s" % base_class_decl)
code.putln(" {") code.putln(" {")
self.generate_type_header_code(scope.type_entries, code) 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() py_attrs = [e for e in scope.entries.values()
if e.type.is_pyobject and not e.is_inherited] if e.type.is_pyobject and not e.is_inherited]
has_virtual_methods = False has_virtual_methods = False
constructor = None constructor = None
destructor = None destructor = None
for attr in scope.var_entries: for attr in scope.var_entries:
cname = attr.cname
if attr.type.is_cfunction and attr.type.is_static_method: if attr.type.is_cfunction and attr.type.is_static_method:
code.put("static ") code.put("static ")
elif attr.name == "<init>": elif attr.name == "<init>":
...@@ -1002,7 +1006,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1002,7 +1006,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
elif attr.type.is_cfunction: elif attr.type.is_cfunction:
code.put("virtual ") code.put("virtual ")
has_virtual_methods = True 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 is_implementing = 'init_module' in code.globalstate.parts
def generate_cpp_constructor_code(arg_decls, arg_names, is_implementing, py_attrs, constructor): def generate_cpp_constructor_code(arg_decls, arg_names, is_implementing, py_attrs, constructor):
...@@ -1085,6 +1091,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1085,6 +1091,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("%s& operator=(const %s& __Pyx_other);" % (type.cname, type.cname)) code.putln("%s& operator=(const %s& __Pyx_other);" % (type.cname, type.cname))
code.putln("};") 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): def generate_enum_definition(self, entry, code):
code.mark_pos(entry.pos) code.mark_pos(entry.pos)
type = entry.type type = entry.type
...@@ -1202,7 +1212,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1202,7 +1212,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.sue_header_footer(type, "struct", type.objstruct_cname) self.sue_header_footer(type, "struct", type.objstruct_cname)
code.putln(header) code.putln(header)
base_type = type.base_type base_type = type.base_type
nogil = type.nogil
if base_type: if base_type:
basestruct_cname = base_type.objstruct_cname basestruct_cname = base_type.objstruct_cname
if basestruct_cname == "PyTypeObject": if basestruct_cname == "PyTypeObject":
...@@ -1213,16 +1222,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1213,16 +1222,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
("struct ", "")[base_type.typedef_flag], ("struct ", "")[base_type.typedef_flag],
basestruct_cname, basestruct_cname,
Naming.obj_base_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: else:
code.putln( code.putln(
"PyObject_HEAD") "PyObject_HEAD")
......
This diff is collapsed.
...@@ -2247,7 +2247,7 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -2247,7 +2247,7 @@ def p_statement(s, ctx, first_statement = 0):
elif s.sy == 'IF': elif s.sy == 'IF':
return p_IF_statement(s, ctx) return p_IF_statement(s, ctx)
elif s.sy == '@': 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.error('decorator not allowed here')
s.level = ctx.level s.level = ctx.level
decorators = p_decorators(s) decorators = p_decorators(s)
...@@ -2261,21 +2261,20 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -2261,21 +2261,20 @@ def p_statement(s, ctx, first_statement = 0):
return p_pass_statement(s, with_newline=1) return p_pass_statement(s, with_newline=1)
overridable = 0 overridable = 0
nogil_flag = ctx.nogil
if s.sy == 'cdef': if s.sy == 'cdef':
cdef_flag = 1 cdef_flag = 1
s.next() s.next()
elif s.sy == 'cpdef': elif s.sy == 'cpdef':
if ctx.level == 'c_class_nogil':
s.error('cpdef statement not allowed in nogil extension type')
s.level = ctx.level s.level = ctx.level
cdef_flag = 1 cdef_flag = 1
overridable = 1 overridable = 1
s.next() s.next()
if cdef_flag: 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.error('cdef statement not allowed here')
s.level = ctx.level 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: if decorators is not None:
tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode) tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)
if ctx.allow_struct_enum_decorator: if ctx.allow_struct_enum_decorator:
...@@ -2292,8 +2291,6 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -2292,8 +2291,6 @@ def p_statement(s, ctx, first_statement = 0):
# as part of a cdef class # as part of a cdef class
if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'): if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
s.error('def statement not allowed here') 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 s.level = ctx.level
return p_def_statement(s, decorators) return p_def_statement(s, decorators)
elif s.sy == 'class': elif s.sy == 'class':
...@@ -2304,7 +2301,7 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -2304,7 +2301,7 @@ def p_statement(s, ctx, first_statement = 0):
if ctx.level not in ('module', 'module_pxd'): if ctx.level not in ('module', 'module_pxd'):
s.error("include statement not allowed here") s.error("include statement not allowed here")
return p_include_statement(s, ctx) 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) return p_property_decl(s)
elif s.sy == 'pass' and ctx.level != 'property': elif s.sy == 'pass' and ctx.level != 'property':
return p_pass_statement(s, with_newline=True) return p_pass_statement(s, with_newline=True)
...@@ -3080,9 +3077,11 @@ def p_cdef_statement(s, ctx): ...@@ -3080,9 +3077,11 @@ def p_cdef_statement(s, ctx):
return p_cdef_extern_block(s, pos, ctx) return p_cdef_extern_block(s, pos, ctx)
elif p_nogil(s): elif p_nogil(s):
ctx.nogil = 1 ctx.nogil = 1
if ctx.overridable: # if ctx.overridable:
error(pos, "cdef blocks cannot be declared cpdef") # error(pos, "cdef blocks cannot be declared cpdef")
return p_cdef_block(s, ctx) return p_cdef_block(s, ctx)
elif ctx.overridable and ctx.nogil:
error(pos, "nogil blocks cannot be declared cpdef")
elif s.sy == ':': elif s.sy == ':':
if ctx.overridable: if ctx.overridable:
error(pos, "cdef blocks cannot be declared cpdef") error(pos, "cdef blocks cannot be declared cpdef")
...@@ -3093,7 +3092,7 @@ def p_cdef_statement(s, ctx): ...@@ -3093,7 +3092,7 @@ def p_cdef_statement(s, ctx):
if ctx.overridable: if ctx.overridable:
error(pos, "Extension types cannot be declared cpdef") error(pos, "Extension types cannot be declared cpdef")
return p_c_class_definition(s, pos, ctx) 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) return p_cpp_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in struct_enum_union: elif s.sy == 'IDENT' and s.systring in struct_enum_union:
if ctx.level not in ('module', 'module_pxd'): if ctx.level not in ('module', 'module_pxd'):
...@@ -3323,7 +3322,7 @@ def p_c_modifiers(s): ...@@ -3323,7 +3322,7 @@ def p_c_modifiers(s):
return [] return []
def p_c_func_or_var_declaration(s, pos, ctx): 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) modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates) base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates)
declarator = p_c_declarator(s, ctx(modifiers=modifiers), cmethod_flag = cmethod_flag, 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): ...@@ -3342,13 +3341,8 @@ def p_c_func_or_var_declaration(s, pos, ctx):
fatal=False) fatal=False)
s.next() s.next()
p_test(s) # Keep going, but ignore result. 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 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") s.error("C function definition not allowed here")
doc, suite = p_suite_with_docstring(s, Ctx(level='function')) doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
result = Nodes.CFuncDefNode(pos, result = Nodes.CFuncDefNode(pos,
...@@ -3376,7 +3370,7 @@ def p_c_func_or_var_declaration(s, pos, ctx): ...@@ -3376,7 +3370,7 @@ def p_c_func_or_var_declaration(s, pos, ctx):
declarators.append(declarator) declarators.append(declarator)
doc_line = s.start_line + 1 doc_line = s.start_line + 1
s.expect_newline("Syntax error in C variable declaration", ignore_semicolon=True) 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) doc = p_doc_string(s)
else: else:
doc = None doc = None
...@@ -3577,12 +3571,9 @@ def p_c_class_definition(s, pos, ctx): ...@@ -3577,12 +3571,9 @@ def p_c_class_definition(s, pos, ctx):
if ctx.visibility not in ('public', 'extern') and not ctx.api: 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") 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) objstruct_name, typeobj_name, check_size = p_c_class_options(s)
nogil = p_nogil(s)
if s.sy == ':': if s.sy == ':':
if ctx.level == 'module_pxd': if ctx.level == 'module_pxd':
body_level = 'c_class_pxd' body_level = 'c_class_pxd'
elif nogil:
body_level = 'c_class_nogil'
else: else:
body_level = 'c_class' body_level = 'c_class'
doc, body = p_suite_with_docstring(s, Ctx(level=body_level)) doc, body = p_suite_with_docstring(s, Ctx(level=body_level))
...@@ -3621,8 +3612,7 @@ def p_c_class_definition(s, pos, ctx): ...@@ -3621,8 +3612,7 @@ def p_c_class_definition(s, pos, ctx):
check_size = check_size, check_size = check_size,
in_pxd = ctx.level == 'module_pxd', in_pxd = ctx.level == 'module_pxd',
doc = doc, doc = doc,
body = body, body = body)
nogil = nogil or ctx.nogil)
def p_c_class_options(s): def p_c_class_options(s):
...@@ -3803,7 +3793,8 @@ def p_template_definition(s): ...@@ -3803,7 +3793,8 @@ def p_template_definition(s):
return name, required return name, required
def p_cpp_class_definition(s, pos, ctx): def p_cpp_class_definition(s, pos, ctx):
# s.sy == 'cppclass' # s.sy in ('cppclass', 'cypclass')
cypclass = s.systring == 'cypclass'
s.next() s.next()
class_name = p_ident(s) class_name = p_ident(s)
cname = p_opt_cname(s) cname = p_opt_cname(s)
...@@ -3833,7 +3824,7 @@ def p_cpp_class_definition(s, pos, ctx): ...@@ -3833,7 +3824,7 @@ def p_cpp_class_definition(s, pos, ctx):
base_classes = [] base_classes = []
if s.sy == '[': if s.sy == '[':
error(s.position(), "Name options not allowed for C++ class") error(s.position(), "Name options not allowed for C++ class")
nogil = p_nogil(s) nogil = p_nogil(s) or cypclass
if s.sy == ':': if s.sy == ':':
s.next() s.next()
s.expect('NEWLINE') s.expect('NEWLINE')
...@@ -3862,7 +3853,7 @@ def p_cpp_class_definition(s, pos, ctx): ...@@ -3862,7 +3853,7 @@ def p_cpp_class_definition(s, pos, ctx):
visibility = ctx.visibility, visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd', in_pxd = ctx.level == 'module_pxd',
attributes = attributes, attributes = attributes,
templates = templates) templates = templates, cypclass=cypclass)
def p_cpp_class_attribute(s, ctx): def p_cpp_class_attribute(s, ctx):
decorators = None decorators = None
......
This diff is collapsed.
...@@ -17,7 +17,7 @@ from .Errors import warning, error, InternalError ...@@ -17,7 +17,7 @@ from .Errors import warning, error, InternalError
from .StringEncoding import EncodedString from .StringEncoding import EncodedString
from . import Options, Naming from . import Options, Naming
from . import PyrexTypes 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 ( from .TypeSlots import (
pyfunction_signature, pymethod_signature, richcmp_special_methods, pyfunction_signature, pymethod_signature, richcmp_special_methods,
get_special_method_signature, get_property_accessor_signature) get_special_method_signature, get_property_accessor_signature)
...@@ -628,7 +628,7 @@ class Scope(object): ...@@ -628,7 +628,7 @@ class Scope(object):
def declare_cpp_class(self, name, scope, def declare_cpp_class(self, name, scope,
pos, cname = None, base_classes = (), pos, cname = None, base_classes = (),
visibility = 'extern', templates = None): visibility = 'extern', templates = None, cypclass=0):
if cname is None: if cname is None:
if self.in_cinclude or (visibility != 'private'): if self.in_cinclude or (visibility != 'private'):
cname = name cname = name
...@@ -637,8 +637,12 @@ class Scope(object): ...@@ -637,8 +637,12 @@ class Scope(object):
base_classes = list(base_classes) base_classes = list(base_classes)
entry = self.lookup_here(name) entry = self.lookup_here(name)
if not entry: if not entry:
type = PyrexTypes.CppClassType( if cypclass:
name, scope, cname, base_classes, templates = templates) 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, entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None) visibility = visibility, defining = scope is not None)
self.sue_entries.append(entry) self.sue_entries.append(entry)
...@@ -666,7 +670,7 @@ class Scope(object): ...@@ -666,7 +670,7 @@ class Scope(object):
def declare_inherited_attributes(entry, base_classes): def declare_inherited_attributes(entry, base_classes):
for base_class in 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 continue
if base_class.scope is None: if base_class.scope is None:
error(pos, "Cannot inherit from incomplete type") error(pos, "Cannot inherit from incomplete type")
...@@ -1580,7 +1584,7 @@ class ModuleScope(Scope): ...@@ -1580,7 +1584,7 @@ class ModuleScope(Scope):
def declare_c_class(self, name, pos, defining=0, implementing=0, def declare_c_class(self, name, pos, defining=0, implementing=0,
module_name=None, base_type=None, objstruct_cname=None, module_name=None, base_type=None, objstruct_cname=None,
typeobj_cname=None, typeptr_cname=None, visibility='private', 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): buffer_defaults=None, shadow=0):
# If this is a non-extern typedef class, expose the typedef, but use # If this is a non-extern typedef class, expose the typedef, but use
# the non-typedef struct internally to avoid needing forward # the non-typedef struct internally to avoid needing forward
...@@ -1613,15 +1617,8 @@ class ModuleScope(Scope): ...@@ -1613,15 +1617,8 @@ class ModuleScope(Scope):
# Make a new entry if needed # Make a new entry if needed
# #
if not entry or shadow: if not entry or shadow:
if nogil: type = PyrexTypes.PyExtensionType(
pass name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
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.pos = pos type.pos = pos
type.buffer_defaults = buffer_defaults type.buffer_defaults = buffer_defaults
if objtypedef_cname is not None: if objtypedef_cname is not None:
...@@ -2341,8 +2338,7 @@ class CClassScope(ClassScope): ...@@ -2341,8 +2338,7 @@ class CClassScope(ClassScope):
defining=0, modifiers=(), utility_code=None, overridable=False): defining=0, modifiers=(), utility_code=None, overridable=False):
name = self.mangle_class_private_name(name) name = self.mangle_class_private_name(name)
if get_special_method_signature(name) and not self.parent_type.is_builtin_type: 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 args = type.args
if not type.is_static_method: if not type.is_static_method:
if not args: if not args:
...@@ -2578,6 +2574,8 @@ class CppClassScope(Scope): ...@@ -2578,6 +2574,8 @@ class CppClassScope(Scope):
type.return_type = PyrexTypes.c_void_type type.return_type = PyrexTypes.c_void_type
if name in ('<init>', '<del>') and type.nogil: if name in ('<init>', '<del>') and type.nogil:
for base in self.type.base_classes: for base in self.type.base_classes:
if base is cy_object_type:
continue
base_entry = base.scope.lookup(name) base_entry = base.scope.lookup(name)
if base_entry and not base_entry.type.nogil: 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") 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): ...@@ -198,10 +198,13 @@ class ResultRefNode(AtomicExprNode):
pass pass
def generate_assignment_code(self, rhs, code, overloaded_assignment=False): 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) rhs.make_owned_reference(code)
if not self.lhs_of_first_assignment: 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;' % ( 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()),
...@@ -248,6 +251,9 @@ class LetNodeMixin: ...@@ -248,6 +251,9 @@ class LetNodeMixin:
else: else:
if self.temp_type.is_pyobject: if self.temp_type.is_pyobject:
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:
pass
#code.put_decref_clear(self.temp, self.temp_type)
code.funcstate.release_temp(self.temp) 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: ...@@ -1878,51 +1878,6 @@ try_unpack:
return 0; 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);
}
}
static inline void _Cy_INCREF(struct CyObject *op) {
atomic_fetch_add(&(op->ob_refcnt), 1);
}
#define Cy_INCREF(op) _Cy_INCREF(_CyObject_CAST(op))
#define Cy_DECREF(op) _Cy_DECREF(_CyObject_CAST(op))
*/
/////////////// UnpackUnboundCMethod.proto /////////////// /////////////// UnpackUnboundCMethod.proto ///////////////
......
...@@ -32,7 +32,7 @@ from libc.stdio cimport printf ...@@ -32,7 +32,7 @@ from libc.stdio cimport printf
# cdef class SomeMemory: # cdef class SomeMemory:
cdef class SomeMemory nogil: ccdef class SomeMemory:
""" """
This is a cdef class which is also called This is a cdef class which is also called
a extensino type. It is a kind of C struct a extensino type. It is a kind of C struct
...@@ -41,7 +41,7 @@ cdef class SomeMemory nogil: ...@@ -41,7 +41,7 @@ cdef class SomeMemory nogil:
We would like to be able to define "nogil" We would like to be able to define "nogil"
extension types: extension types:
cdef class SomeMemory nogil: ccdef class SomeMemory:
where all methods are "nogil" and memory where all methods are "nogil" and memory
allocation does not depend on python runtime allocation does not depend on python runtime
...@@ -54,10 +54,10 @@ cdef class SomeMemory nogil: ...@@ -54,10 +54,10 @@ cdef class SomeMemory nogil:
# self.b = b # self.b = b
pass pass
cdef void cdealloc(self) nogil: cdef void cdealloc(self):
pass pass
cdef void foo1(self) nogil: cdef void foo1(self):
""" """
It is possible to define native C/Cython methods It is possible to define native C/Cython methods
that release the GIL (cool...) that release the GIL (cool...)
......
...@@ -31,7 +31,7 @@ from libc.stdio cimport printf ...@@ -31,7 +31,7 @@ from libc.stdio cimport printf
# cdef class SomeMemory: # cdef class SomeMemory:
cdef class SomeMemory nogil: ccdef class SomeMemory:
""" """
This is a cdef class which is also called This is a cdef class which is also called
a extensino type. It is a kind of C struct a extensino type. It is a kind of C struct
......
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