Commit b3f90047 authored by Boxiang Sun's avatar Boxiang Sun Committed by gsamain

Initial support for nogil extension C code generation

...@@ -674,6 +674,8 @@ class ExprNode(Node): ...@@ -674,6 +674,8 @@ class ExprNode(Node):
self.gil_error() self.gil_error()
def gil_assignment_check(self, env): def gil_assignment_check(self, env):
if self.type == PyrexTypes.PyExtensionType and env.nogil and self.type.nogil:
error("No gil type in no gil function")
if env.nogil and self.type.is_pyobject: if env.nogil and self.type.is_pyobject:
error(self.pos, "Assignment of Python object not allowed without gil") error(self.pos, "Assignment of Python object not allowed without gil")
...@@ -1665,6 +1667,9 @@ class StringNode(PyConstNode): ...@@ -1665,6 +1667,9 @@ class StringNode(PyConstNode):
is_identifier = None is_identifier = None
unicode_value = None unicode_value = None
# XXX: Let the StringNode can be used in nogil extension initializing
nogil_check = None
def calculate_constant_result(self): def calculate_constant_result(self):
if self.unicode_value is not None: if self.unicode_value is not None:
# only the Unicode value is portable across Py2/3 # only the Unicode value is portable across Py2/3
...@@ -2258,6 +2263,9 @@ class NameNode(AtomicExprNode): ...@@ -2258,6 +2263,9 @@ class NameNode(AtomicExprNode):
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
elif entry.is_local and isinstance(entry.type, PyrexTypes.CythonExtensionType):
pass
# 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
raise_unbound = ( raise_unbound = (
...@@ -5482,6 +5490,18 @@ class CallNode(ExprNode): ...@@ -5482,6 +5490,18 @@ 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
...@@ -7118,6 +7138,9 @@ class AttributeNode(ExprNode): ...@@ -7118,6 +7138,9 @@ class AttributeNode(ExprNode):
# (AnalyseExpressionsTransform) # (AnalyseExpressionsTransform)
self.member = self.entry.cname self.member = self.entry.cname
if obj.type.nogil:
return "%s" % self.entry.func_cname
else:
return "((struct %s *)%s%s%s)->%s" % ( return "((struct %s *)%s%s%s)->%s" % (
obj.type.vtabstruct_cname, obj_code, self.op, obj.type.vtabstruct_cname, obj_code, self.op,
obj.type.vtabslot_cname, self.member) obj.type.vtabslot_cname, self.member)
...@@ -8773,6 +8796,11 @@ class DictNode(ExprNode): ...@@ -8773,6 +8796,11 @@ 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(),
......
...@@ -1124,6 +1124,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1124,6 +1124,7 @@ 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":
...@@ -1134,6 +1135,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1134,6 +1135,14 @@ 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.putln(
"// nogil"
)
code.putln(
"size_t ob_refcnt;"
)
else: else:
code.putln( code.putln(
"PyObject_HEAD") "PyObject_HEAD")
......
...@@ -3323,6 +3323,8 @@ class DefNodeWrapper(FuncDefNode): ...@@ -3323,6 +3323,8 @@ class DefNodeWrapper(FuncDefNode):
# different code types. # different code types.
for arg in self.args: for arg in self.args:
if not arg.type.is_pyobject: if not arg.type.is_pyobject:
if arg.type is PyrexTypes.PyExtensionType and arg.type.nogil:
continue # XXX maybe here is not the correct place to put it...
if not arg.type.create_from_py_utility_code(env): if not arg.type.create_from_py_utility_code(env):
pass # will fail later pass # will fail later
elif arg.hdr_type and not arg.hdr_type.is_pyobject: elif arg.hdr_type and not arg.hdr_type.is_pyobject:
...@@ -4780,6 +4782,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4780,6 +4782,7 @@ class CClassDefNode(ClassDefNode):
# doc string or None # doc string or None
# body StatNode or None # body StatNode or None
# entry Symtab.Entry # entry Symtab.Entry
# nogil boolean
# base_type PyExtensionType or None # base_type PyExtensionType or None
# buffer_defaults_node DictNode or None Declares defaults for a buffer # buffer_defaults_node DictNode or None Declares defaults for a buffer
# buffer_defaults_pos # buffer_defaults_pos
...@@ -4789,6 +4792,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4789,6 +4792,7 @@ class CClassDefNode(ClassDefNode):
buffer_defaults_pos = None buffer_defaults_pos = None
typedef_flag = False typedef_flag = False
api = False api = False
nogil = False
objstruct_name = None objstruct_name = None
typeobj_name = None typeobj_name = None
check_size = None check_size = None
...@@ -4829,6 +4833,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4829,6 +4833,7 @@ class CClassDefNode(ClassDefNode):
typedef_flag=self.typedef_flag, typedef_flag=self.typedef_flag,
check_size = self.check_size, check_size = self.check_size,
api=self.api, api=self.api,
nogil=self.nogil,
buffer_defaults=self.buffer_defaults(env), buffer_defaults=self.buffer_defaults(env),
shadow=self.shadow) shadow=self.shadow)
...@@ -4917,6 +4922,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4917,6 +4922,7 @@ class CClassDefNode(ClassDefNode):
visibility=self.visibility, visibility=self.visibility,
typedef_flag=self.typedef_flag, typedef_flag=self.typedef_flag,
api=self.api, api=self.api,
nogil=self.nogil,
buffer_defaults=self.buffer_defaults(env), buffer_defaults=self.buffer_defaults(env),
shadow=self.shadow) shadow=self.shadow)
......
...@@ -1630,6 +1630,7 @@ if VALUE is not None: ...@@ -1630,6 +1630,7 @@ if VALUE is not None:
if stats: if stats:
node.body.stats += stats node.body.stats += stats
if (node.visibility != 'extern' if (node.visibility != 'extern'
and not node.nogil
and not node.scope.lookup('__reduce__') and not node.scope.lookup('__reduce__')
and not node.scope.lookup('__reduce_ex__')): and not node.scope.lookup('__reduce_ex__')):
self._inject_pickle_methods(node) self._inject_pickle_methods(node)
......
...@@ -1498,7 +1498,7 @@ class ModuleScope(Scope): ...@@ -1498,7 +1498,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, check_size=None, typedef_flag=0, api=0, nogil=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
...@@ -1531,8 +1531,15 @@ class ModuleScope(Scope): ...@@ -1531,8 +1531,15 @@ 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:
pass
if nogil:
type = PyrexTypes.CythonExtensionType(
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
else:
type = PyrexTypes.PyExtensionType( type = PyrexTypes.PyExtensionType(
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size) 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:
......
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