Commit 5a11a252 authored by Boxiang Sun's avatar Boxiang Sun

Initial support for nogil extension C code generation

parent f4290b82
...@@ -671,6 +671,8 @@ class ExprNode(Node): ...@@ -671,6 +671,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")
...@@ -1656,6 +1658,9 @@ class StringNode(PyConstNode): ...@@ -1656,6 +1658,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
...@@ -2249,6 +2254,9 @@ class NameNode(AtomicExprNode): ...@@ -2249,6 +2254,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 = (
...@@ -5442,6 +5450,18 @@ class CallNode(ExprNode): ...@@ -5442,6 +5450,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
...@@ -7157,9 +7177,12 @@ class AttributeNode(ExprNode): ...@@ -7157,9 +7177,12 @@ class AttributeNode(ExprNode):
# (AnalyseExpressionsTransform) # (AnalyseExpressionsTransform)
self.member = self.entry.cname self.member = self.entry.cname
return "((struct %s *)%s%s%s)->%s" % ( if obj.type.nogil:
obj.type.vtabstruct_cname, obj_code, self.op, return "%s" % self.entry.func_cname
obj.type.vtabslot_cname, self.member) else:
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
...@@ -8810,6 +8833,11 @@ class DictNode(ExprNode): ...@@ -8810,6 +8833,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(),
......
...@@ -1104,6 +1104,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1104,6 +1104,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":
...@@ -1114,6 +1115,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1114,6 +1115,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")
......
...@@ -3273,6 +3273,8 @@ class DefNodeWrapper(FuncDefNode): ...@@ -3273,6 +3273,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:
...@@ -4636,6 +4638,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4636,6 +4638,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
...@@ -4645,6 +4648,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4645,6 +4648,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
...@@ -4685,6 +4689,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4685,6 +4689,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)
...@@ -4773,6 +4778,7 @@ class CClassDefNode(ClassDefNode): ...@@ -4773,6 +4778,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)
......
...@@ -1482,7 +1482,7 @@ class ModuleScope(Scope): ...@@ -1482,7 +1482,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
...@@ -1515,8 +1515,15 @@ class ModuleScope(Scope): ...@@ -1515,8 +1515,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:
type = PyrexTypes.PyExtensionType( if nogil:
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size) 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.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