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):
self.gil_error()
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:
error(self.pos, "Assignment of Python object not allowed without gil")
......@@ -1656,6 +1658,9 @@ class StringNode(PyConstNode):
is_identifier = None
unicode_value = None
# XXX: Let the StringNode can be used in nogil extension initializing
nogil_check = None
def calculate_constant_result(self):
if self.unicode_value is not None:
# only the Unicode value is portable across Py2/3
......@@ -2249,6 +2254,9 @@ class NameNode(AtomicExprNode):
code.error_goto_if_null(self.result(), self.pos)))
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:
# Raise UnboundLocalError for objects and memoryviewslices
raise_unbound = (
......@@ -5442,6 +5450,18 @@ 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
......@@ -7157,9 +7177,12 @@ class AttributeNode(ExprNode):
# (AnalyseExpressionsTransform)
self.member = self.entry.cname
return "((struct %s *)%s%s%s)->%s" % (
obj.type.vtabstruct_cname, obj_code, self.op,
obj.type.vtabslot_cname, self.member)
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)
elif self.result_is_used:
return self.member
# Generating no code at all for unused access to optimised builtin
......@@ -8810,6 +8833,11 @@ 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(),
......
......@@ -1104,6 +1104,7 @@ 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":
......@@ -1114,6 +1115,14 @@ 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.putln(
"// nogil"
)
code.putln(
"size_t ob_refcnt;"
)
else:
code.putln(
"PyObject_HEAD")
......
......@@ -3273,6 +3273,8 @@ class DefNodeWrapper(FuncDefNode):
# different code types.
for arg in self.args:
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):
pass # will fail later
elif arg.hdr_type and not arg.hdr_type.is_pyobject:
......@@ -4636,6 +4638,7 @@ class CClassDefNode(ClassDefNode):
# doc string or None
# body StatNode or None
# entry Symtab.Entry
# nogil boolean
# base_type PyExtensionType or None
# buffer_defaults_node DictNode or None Declares defaults for a buffer
# buffer_defaults_pos
......@@ -4645,6 +4648,7 @@ class CClassDefNode(ClassDefNode):
buffer_defaults_pos = None
typedef_flag = False
api = False
nogil = False
objstruct_name = None
typeobj_name = None
check_size = None
......@@ -4685,6 +4689,7 @@ class CClassDefNode(ClassDefNode):
typedef_flag=self.typedef_flag,
check_size = self.check_size,
api=self.api,
nogil=self.nogil,
buffer_defaults=self.buffer_defaults(env),
shadow=self.shadow)
......@@ -4773,6 +4778,7 @@ class CClassDefNode(ClassDefNode):
visibility=self.visibility,
typedef_flag=self.typedef_flag,
api=self.api,
nogil=self.nogil,
buffer_defaults=self.buffer_defaults(env),
shadow=self.shadow)
......
......@@ -1630,6 +1630,7 @@ if VALUE is not None:
if stats:
node.body.stats += stats
if (node.visibility != 'extern'
and not node.nogil
and not node.scope.lookup('__reduce__')
and not node.scope.lookup('__reduce_ex__')):
self._inject_pickle_methods(node)
......
......@@ -1482,7 +1482,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, check_size=None,
typedef_flag=0, api=0, nogil=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
......@@ -1515,8 +1515,15 @@ class ModuleScope(Scope):
# Make a new entry if needed
#
if not entry or shadow:
type = PyrexTypes.PyExtensionType(
name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
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.pos = pos
type.buffer_defaults = buffer_defaults
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