Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
83047799
Commit
83047799
authored
Feb 05, 2019
by
gsamain
Committed by
Xavier Thompson
Jun 18, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Gwenael: Remove nogil extension and introduce refcounted cypclass
parent
6521ad76
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
324 additions
and
383 deletions
+324
-383
Cython/Compiler/Code.py
Cython/Compiler/Code.py
+26
-3
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+55
-31
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+15
-16
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+50
-24
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+18
-27
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+57
-213
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+15
-17
Cython/Compiler/UtilNodes.py
Cython/Compiler/UtilNodes.py
+8
-2
Cython/Utility/CyObjects.cpp
Cython/Utility/CyObjects.cpp
+75
-0
Cython/Utility/ObjectHandling.c
Cython/Utility/ObjectHandling.c
+0
-45
nogil_test/nogil_extension.pyx
nogil_test/nogil_extension.pyx
+4
-4
test.pyx
test.pyx
+1
-1
No files found.
Cython/Compiler/Code.py
View file @
83047799
...
...
@@ -2039,7 +2039,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
(
";"
)
...
...
@@ -2050,8 +2050,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
))
...
...
@@ -2084,6 +2084,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
):
...
...
Cython/Compiler/ExprNodes.py
View file @
83047799
...
...
@@ -782,7 +782,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
):
"""
...
...
@@ -824,7 +827,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
(
...
...
@@ -847,6 +853,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
())
...
...
@@ -1837,7 +1845,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
):
...
...
@@ -2319,8 +2330,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
...
...
@@ -2426,6 +2438,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
:
...
...
@@ -2537,6 +2553,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"
)
...
...
@@ -4135,6 +4167,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
:
...
...
@@ -5555,18 +5589,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
...
...
@@ -6069,6 +6091,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
)
...
...
@@ -7073,6 +7097,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
:
...
...
@@ -7223,12 +7249,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
...
...
@@ -7329,6 +7352,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
(
...
...
@@ -8827,8 +8855,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
:
...
...
@@ -8886,11 +8912,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
(),
...
...
@@ -13519,7 +13540,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
)
...
...
Cython/Compiler/ModuleNode.py
View file @
83047799
...
...
@@ -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
from
.StringEncoding
import
EncodedString
,
encoded_string_or_bytes_literal
...
...
@@ -980,17 +980,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>"
:
...
...
@@ -1001,7 +1005,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
):
...
...
@@ -1084,6 +1090,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
...
...
@@ -1197,7 +1207,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"
:
...
...
@@ -1208,16 +1217,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"
)
...
...
Cython/Compiler/Nodes.py
View file @
83047799
...
...
@@ -7,7 +7,7 @@ from __future__ import absolute_import
import
cython
cython
.
declare
(
sys
=
object
,
os
=
object
,
copy
=
object
,
Builtin
=
object
,
error
=
object
,
warning
=
object
,
Naming
=
object
,
PyrexTypes
=
object
,
py_object_type
=
object
,
ModuleScope
=
object
,
LocalScope
=
object
,
ClosureScope
=
object
,
py_object_type
=
object
,
cy_object_type
=
object
,
ModuleScope
=
object
,
LocalScope
=
object
,
ClosureScope
=
object
,
StructOrUnionScope
=
object
,
PyClassScope
=
object
,
CppClassScope
=
object
,
UtilityCode
=
object
,
EncodedString
=
object
,
error_type
=
object
,
_py_int_types
=
object
)
...
...
@@ -20,7 +20,7 @@ from .Errors import error, warning, InternalError, CompileError
from
.
import
Naming
from
.
import
PyrexTypes
from
.
import
TypeSlots
from
.PyrexTypes
import
py_object_type
,
error_type
from
.PyrexTypes
import
py_object_type
,
cy_object_type
,
error_type
from
.Symtab
import
(
ModuleScope
,
LocalScope
,
ClosureScope
,
PropertyScope
,
StructOrUnionScope
,
PyClassScope
,
CppClassScope
,
TemplateScope
,
punycodify_name
)
...
...
@@ -956,7 +956,10 @@ class CArgDeclNode(Node):
default
.
make_owned_reference
(
code
)
result
=
default
.
result
()
if
overloaded_assignment
else
default
.
result_as
(
self
.
type
)
code
.
putln
(
"%s = %s;"
%
(
target
,
result
))
code
.
put_giveref
(
default
.
result
(),
self
.
type
)
if
self
.
type
.
is_cyp_class
:
code
.
put_cygiveref
(
default
.
result
())
else
:
code
.
put_giveref
(
default
.
result
(),
self
.
type
)
default
.
generate_post_assignment_code
(
code
)
default
.
free_temps
(
code
)
...
...
@@ -1008,6 +1011,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
error
(
self
.
pos
,
"Unrecognised type modifier combination"
)
elif
self
.
name
==
"object"
and
not
self
.
module_path
:
type
=
py_object_type
elif
self
.
name
==
"cyobject"
:
type
=
cy_object_type
self
.
arg_name
=
EncodedString
(
self
.
name
)
elif
self
.
name
is
None
:
if
self
.
is_self_arg
and
env
.
is_c_class_scope
:
#print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
...
...
@@ -1474,7 +1480,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
error
(
self
.
pos
,
"Required template parameters must precede optional template parameters."
)
self
.
entry
=
env
.
declare_cpp_class
(
self
.
name
,
None
,
self
.
pos
,
self
.
cname
,
base_classes
=
[],
visibility
=
self
.
visibility
,
templates
=
template_types
)
base_classes
=
[],
visibility
=
self
.
visibility
,
templates
=
template_types
,
cypclass
=
self
.
cypclass
)
def
analyse_declarations
(
self
,
env
):
if
self
.
templates
is
None
:
...
...
@@ -1491,10 +1497,24 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
return
True
else
:
error
(
self
.
pos
,
"Base class '%s' not a struct or class."
%
base_class
)
base_class_types
=
filter
(
base_ok
,
[
b
.
analyse
(
scope
or
env
)
for
b
in
self
.
base_classes
])
base_types_list
=
[
b
.
analyse
(
scope
or
env
)
for
b
in
self
.
base_classes
]
if
self
.
cypclass
:
cyobject_base
=
False
for
base_type
in
base_types_list
:
cyobject_base
=
cyobject_base
or
base_type
is
cy_object_type
or
base_type
.
is_cyp_class
if
not
cyobject_base
:
cyobject_class
=
CSimpleBaseTypeNode
(
self
.
pos
,
name
=
"cyobject"
,
module_path
=
[],
is_basic_c_type
=
0
,
signed
=
0
,
complex
=
0
,
longness
=
0
,
is_self_arg
=
0
,
templates
=
None
)
self
.
base_classes
.
append
(
cyobject_class
)
base_types_list
.
append
(
cyobject_class
.
analyse
(
scope
or
env
))
base_class_types
=
filter
(
base_ok
,
base_types_list
)
self
.
entry
=
env
.
declare_cpp_class
(
self
.
name
,
scope
,
self
.
pos
,
self
.
cname
,
base_class_types
,
visibility
=
self
.
visibility
,
templates
=
template_types
)
self
.
cname
,
base_class_types
,
visibility
=
self
.
visibility
,
templates
=
template_types
,
cypclass
=
self
.
cypclass
)
if
self
.
entry
is
None
:
return
self
.
entry
.
is_cpp_class
=
1
...
...
@@ -1832,7 +1852,7 @@ class FuncDefNode(StatNode, BlockNode):
init
=
""
return_type
=
self
.
return_type
if
not
return_type
.
is_void
:
if
return_type
.
is_pyobject
:
if
return_type
.
is_pyobject
or
return_type
.
is_cyp_class
:
init
=
" = NULL"
elif
return_type
.
is_memoryviewslice
:
init
=
' = '
+
return_type
.
literal_code
(
return_type
.
default_value
)
...
...
@@ -1966,6 +1986,9 @@ class FuncDefNode(StatNode, BlockNode):
elif
is_cdef
and
entry
.
cf_is_reassigned
:
code
.
put_var_incref_memoryviewslice
(
entry
,
have_gil
=
code
.
funcstate
.
gil_owned
)
# We have to Cy_INCREF the nogil classes (ccdef'ed ones)
elif
entry
.
type
.
is_cyp_class
and
len
(
entry
.
cf_assignments
)
>
1
:
code
.
put_cyincref
(
entry
.
cname
)
for
entry
in
lenv
.
var_entries
:
if
entry
.
is_arg
and
entry
.
cf_is_reassigned
and
not
entry
.
in_closure
:
if
entry
.
xdecref_cleanup
:
...
...
@@ -2148,13 +2171,16 @@ class FuncDefNode(StatNode, BlockNode):
if
not
entry
.
used
or
entry
.
in_closure
:
continue
if
entry
.
type
.
is_pyobject
:
if
entry
.
type
.
is_pyobject
or
entry
.
type
.
is_cyp_class
:
if
entry
.
is_arg
and
not
entry
.
cf_is_reassigned
:
continue
if
entry
.
type
.
needs_refcounting
:
assure_gil
(
'success'
)
# FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code
.
put_var_xdecref
(
entry
,
have_gil
=
gil_owned
[
'success'
])
if
entry
.
type
.
is_cyp_class
:
code
.
put_cyxdecref
(
entry
.
cname
)
else
:
# FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code
.
put_var_xdecref
(
entry
,
have_gil
=
gil_owned
[
'success'
])
# Decref any increfed args
for
entry
in
lenv
.
arg_entries
:
...
...
@@ -2170,9 +2196,13 @@ class FuncDefNode(StatNode, BlockNode):
continue
if
entry
.
type
.
needs_refcounting
:
assure_gil
(
'success'
)
# FIXME use entry.xdecref_cleanup - del arg seems to be the problem
code
.
put_var_xdecref
(
entry
,
have_gil
=
gil_owned
[
'success'
])
if
entry
.
type
.
is_cyp_class
:
# We must check for NULL because it is possible to have
# NULL as a valid cypclass (with a typecast)
code
.
put_cyxdecref
(
entry
.
cname
)
else
:
# FIXME use entry.xdecref_cleanup - del arg seems to be the problem
code
.
put_var_xdecref
(
entry
,
have_gil
=
gil_owned
[
'success'
])
if
self
.
needs_closure
:
assure_gil
(
'success'
)
code
.
put_decref
(
Naming
.
cur_scope_cname
,
lenv
.
scope_class
.
type
)
...
...
@@ -2185,6 +2215,9 @@ class FuncDefNode(StatNode, BlockNode):
if
err_val
is
None
and
default_retval
:
err_val
=
default_retval
# FIXME: why is err_val not used?
code
.
put_xgiveref
(
Naming
.
retval_cname
,
return_type
)
# We can always return a CythonExtensionType as it is nogil-compliant
if
self
.
return_type
.
is_cyp_class
:
code
.
put_cyxgiveref
(
Naming
.
retval_cname
)
if
self
.
entry
.
is_special
and
self
.
entry
.
name
==
"__hash__"
:
# Returning -1 for __hash__ is supposed to signal an error
...
...
@@ -3376,8 +3409,6 @@ 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
:
...
...
@@ -4908,7 +4939,6 @@ 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
...
...
@@ -4918,7 +4948,6 @@ class CClassDefNode(ClassDefNode):
buffer_defaults_pos
=
None
typedef_flag
=
False
api
=
False
nogil
=
False
objstruct_name
=
None
typeobj_name
=
None
check_size
=
None
...
...
@@ -4963,7 +4992,6 @@ 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
)
...
...
@@ -5052,7 +5080,6 @@ 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
)
...
...
@@ -6192,8 +6219,6 @@ class DelStatNode(StatNode):
error
(
arg
.
pos
,
"Deletion of global C variable"
)
elif
arg
.
type
.
is_ptr
and
arg
.
type
.
base_type
.
is_cpp_class
:
self
.
cpp_check
(
env
)
elif
arg
.
type
.
is_struct_or_union
and
arg
.
type
.
nogil
:
pass
# del nogil extension
elif
arg
.
type
.
is_cpp_class
:
error
(
arg
.
pos
,
"Deletion of non-heap C++ object"
)
elif
arg
.
is_subscript
and
arg
.
base
.
type
is
Builtin
.
bytearray_type
:
...
...
@@ -6222,9 +6247,7 @@ class DelStatNode(StatNode):
arg
.
generate_evaluation_code
(
code
)
code
.
putln
(
"delete %s;"
%
arg
.
result
())
arg
.
generate_disposal_code
(
code
)
elif
arg
.
type
.
is_struct_or_union
and
hasattr
(
arg
.
type
,
"nogil"
)
and
arg
.
type
.
nogil
:
code
.
putln
(
"free(&%s);"
%
arg
.
result
())
# else error reported earlier
# else error reported earlier
def
annotate
(
self
,
code
):
for
arg
in
self
.
args
:
...
...
@@ -6341,6 +6364,9 @@ class ReturnStatNode(StatNode):
# Use specialised default handling for "return None".
value
=
None
if
self
.
return_type
.
is_cyp_class
:
code
.
put_cyxdecref
(
Naming
.
retval_cname
)
if
value
:
value
.
generate_evaluation_code
(
code
)
if
self
.
return_type
.
is_memoryviewslice
:
...
...
Cython/Compiler/Parsing.py
View file @
83047799
...
...
@@ -2235,7 +2235,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
)
...
...
@@ -2249,21 +2249,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
:
...
...
@@ -2280,8 +2279,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'
:
...
...
@@ -2292,7 +2289,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
)
...
...
@@ -3068,9 +3065,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"
)
...
...
@@ -3081,7 +3080,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'
):
...
...
@@ -3276,7 +3275,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
,
...
...
@@ -3295,13 +3294,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
,
...
...
@@ -3329,7 +3323,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
...
...
@@ -3530,12 +3524,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
))
...
...
@@ -3574,8 +3565,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
):
...
...
@@ -3756,7 +3746,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
()
module_path
=
[]
class_name
=
p_ident
(
s
)
...
...
@@ -3787,7 +3778,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'
)
...
...
@@ -3816,7 +3807,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
...
...
Cython/Compiler/PyrexTypes.py
View file @
83047799
...
...
@@ -245,6 +245,7 @@ class PyrexType(BaseType):
is_cfunction
=
0
is_struct_or_union
=
0
is_cpp_class
=
0
is_cyp_class
=
0
is_cpp_string
=
0
is_struct
=
0
is_enum
=
0
...
...
@@ -1325,215 +1326,6 @@ class PyObjectType(PyrexType):
return
cname
class
CythonObjectType
(
PyrexType
):
#
# Base class for all nogil extension object types (reference-counted).
#
name
=
"cythonobject"
is_pyobject
=
0
default_value
=
"0"
declaration_value
=
"0"
buffer_defaults
=
None
is_extern
=
False
is_subclassed
=
False
is_gc_simple
=
False
def
__str__
(
self
):
return
"Cython object"
def
__repr__
(
self
):
return
"<CythonObjectType>"
def
can_coerce_to_pyobject
(
self
,
env
):
return
False
def
can_coerce_from_pyobject
(
self
,
env
):
return
False
def
default_coerced_ctype
(
self
):
"""The default C type that this Python type coerces to, or None."""
return
None
def
assignable_from
(
self
,
src_type
):
# except for pointers, conversion will be attempted
# return not src_type.is_ptr or src_type.is_string or src_type.is_pyunicode_ptr
return
False
def
declaration_code
(
self
,
entity_code
,
for_display
=
0
,
dll_linkage
=
None
,
pyrex
=
0
):
raise
NotImplementedError
(
"Calling declartion_code on Cython object"
)
if
pyrex
or
for_display
:
base_code
=
"object"
else
:
base_code
=
public_decl
(
"PyObject"
,
dll_linkage
)
entity_code
=
"*%s"
%
entity_code
return
self
.
base_declaration_code
(
base_code
,
entity_code
)
def
as_pyobject
(
self
,
cname
):
raise
NotImplementedError
(
"Calling as_pyobject on Cython object"
)
if
(
not
self
.
is_complete
())
or
self
.
is_extension_type
:
return
"(PyObject *)"
+
cname
else
:
return
cname
def
py_type_name
(
self
):
raise
NotImplementedError
(
"Calling py_type_name on Cython object"
)
return
"cythonobject"
def
__lt__
(
self
,
other
):
"""
Make sure we sort highest, as instance checking on py_type_name
('object') is always true
"""
return
False
def
global_init_code
(
self
,
entry
,
code
):
raise
NotImplementedError
(
"Calling global_init_code on Cython object"
)
code
.
put_init_var_to_py_none
(
entry
,
nanny
=
False
)
def
check_for_null_code
(
self
,
cname
):
raise
NotImplementedError
(
"Calling check_for_null_code on Cython object"
)
return
cname
class
CythonExtensionType
(
CythonObjectType
):
#
# A Cython extension type with nogil flag
# TODO: This type may need big amend
#
# name string
# scope CClassScope Attribute namespace
# visibility string
# typedef_flag boolean
# base_type PyExtensionType or None
# nogil boolean
# module_name string or None Qualified name of defining module
# objstruct_cname string Name of PyObject struct
# objtypedef_cname string Name of PyObject struct typedef
# typeobj_cname string or None C code fragment referring to type object
# typeptr_cname string or None Name of pointer to external type object
# vtabslot_cname string Name of C method table member
# vtabstruct_cname string Name of C method table struct
# vtabptr_cname string Name of pointer to C method table
# vtable_cname string Name of C method table definition
# early_init boolean Whether to initialize early (as opposed to during module execution).
# defered_declarations [thunk] Used to declare class hierarchies in order
# check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match
is_extension_type
=
1
is_struct
=
1
is_struct_or_union
=
1
nogil
=
1
is_pyobject
=
0
has_attributes
=
1
early_init
=
1
objtypedef_cname
=
None
def
__init__
(
self
,
name
,
typedef_flag
,
base_type
,
is_external
=
0
,
check_size
=
None
):
self
.
name
=
name
self
.
scope
=
None
self
.
typedef_flag
=
typedef_flag
if
base_type
is
not
None
:
base_type
.
is_subclassed
=
True
self
.
base_type
=
base_type
self
.
nogil
=
False
self
.
module_name
=
None
self
.
objstruct_cname
=
None
self
.
typeobj_cname
=
None
self
.
typeptr_cname
=
None
self
.
vtabslot_cname
=
None
self
.
vtabstruct_cname
=
None
self
.
vtabptr_cname
=
None
self
.
vtable_cname
=
None
self
.
is_external
=
is_external
self
.
check_size
=
check_size
or
'warn'
self
.
defered_declarations
=
[]
def
set_scope
(
self
,
scope
):
self
.
scope
=
scope
if
scope
:
scope
.
parent_type
=
self
def
needs_nonecheck
(
self
):
return
True
def
subtype_of_resolved_type
(
self
,
other_type
):
if
other_type
.
is_extension_type
or
other_type
.
is_builtin_type
:
return
self
is
other_type
or
(
self
.
base_type
and
self
.
base_type
.
subtype_of
(
other_type
))
else
:
return
other_type
is
py_object_type
def
typeobj_is_available
(
self
):
# Do we have a pointer to the type object?
return
self
.
typeptr_cname
def
typeobj_is_imported
(
self
):
# If we don't know the C name of the type object but we do
# know which module it's defined in, it will be imported.
return
self
.
typeobj_cname
is
None
and
self
.
module_name
is
not
None
def
assignable_from
(
self
,
src_type
):
if
self
==
src_type
:
return
True
if
isinstance
(
src_type
,
PyExtensionType
):
if
src_type
.
base_type
is
not
None
:
return
self
.
assignable_from
(
src_type
.
base_type
)
if
isinstance
(
src_type
,
BuiltinObjectType
):
# FIXME: This is an ugly special case that we currently
# keep supporting. It allows users to specify builtin
# types as external extension types, while keeping them
# compatible with the real builtin types. We already
# generate a warning for it. Big TODO: remove!
return
(
self
.
module_name
==
'__builtin__'
and
self
.
name
==
src_type
.
name
)
return
False
def
declaration_code
(
self
,
entity_code
,
for_display
=
0
,
dll_linkage
=
None
,
pyrex
=
0
,
deref
=
0
):
if
pyrex
or
for_display
:
base_code
=
self
.
name
else
:
if
self
.
typedef_flag
:
objstruct
=
self
.
objstruct_cname
else
:
objstruct
=
"struct %s"
%
self
.
objstruct_cname
base_code
=
public_decl
(
objstruct
,
dll_linkage
)
if
deref
:
assert
not
entity_code
else
:
entity_code
=
"*%s"
%
entity_code
return
self
.
base_declaration_code
(
base_code
,
entity_code
)
def
type_test_code
(
self
,
py_arg
,
notnone
=
False
):
none_check
=
"((%s) == Py_None)"
%
py_arg
type_check
=
"likely(__Pyx_TypeTest(%s, %s))"
%
(
py_arg
,
self
.
typeptr_cname
)
if
notnone
:
return
type_check
else
:
return
"likely(%s || %s)"
%
(
none_check
,
type_check
)
def
attributes_known
(
self
):
return
self
.
scope
is
not
None
def
__str__
(
self
):
return
self
.
name
def
__repr__
(
self
):
return
"<CythonExtensionType %s%s>"
%
(
self
.
scope
.
class_name
,
(
""
,
" typedef"
)[
self
.
typedef_flag
])
def
py_type_name
(
self
):
if
not
self
.
module_name
:
return
self
.
name
return
"__import__(%r, None, None, ['']).%s"
%
(
self
.
module_name
,
self
.
name
)
builtin_types_that_cannot_create_refcycles
=
set
([
'object'
,
'bool'
,
'int'
,
'long'
,
'float'
,
'complex'
,
'bytearray'
,
'bytes'
,
'unicode'
,
'str'
,
'basestring'
...
...
@@ -2920,8 +2712,9 @@ class CPtrType(CPointerBaseType):
return
self
.
base_type
.
pointer_assignable_from_resolved_type
(
other_type
)
else
:
return
0
if
(
self
.
base_type
.
is_cpp_class
and
other_type
.
is_ptr
and
other_type
.
base_type
.
is_cpp_class
and
other_type
.
base_type
.
is_subclass
(
self
.
base_type
)):
if
(
self
.
base_type
.
is_cpp_class
and
(
other_type
.
is_ptr
and
other_type
.
base_type
.
is_cpp_class
and
other_type
.
base_type
.
is_subclass
(
self
.
base_type
)
or
other_type
.
is_cyp_class
and
other_type
.
is_subclass
(
self
.
base_type
))):
return
1
if
other_type
.
is_array
or
other_type
.
is_ptr
:
return
self
.
base_type
.
is_void
or
self
.
base_type
.
same_as
(
other_type
.
base_type
)
...
...
@@ -3898,7 +3691,7 @@ class CppClassType(CType):
subtypes
=
[
'templates'
]
def
__init__
(
self
,
name
,
scope
,
cname
,
base_classes
,
templates
=
None
,
template_type
=
None
):
def
__init__
(
self
,
name
,
scope
,
cname
,
base_classes
,
templates
=
None
,
template_type
=
None
,
nogil
=
0
):
self
.
name
=
name
self
.
cname
=
cname
self
.
scope
=
scope
...
...
@@ -3912,6 +3705,7 @@ class CppClassType(CType):
else
:
self
.
specializations
=
{}
self
.
is_cpp_string
=
cname
in
cpp_string_conversions
self
.
nogil
=
nogil
def
use_conversion_utility
(
self
,
from_or_to
):
pass
...
...
@@ -4070,7 +3864,9 @@ class CppClassType(CType):
return
self
.
specializations
[
key
]
template_values
=
[
t
.
specialize
(
values
)
for
t
in
self
.
templates
]
specialized
=
self
.
specializations
[
key
]
=
\
CppClassType
(
self
.
name
,
None
,
self
.
cname
,
[],
template_values
,
template_type
=
self
)
CppClassType
(
self
.
name
,
None
,
self
.
cname
,
[],
template_values
,
template_type
=
self
)
\
if
not
self
.
is_cyp_class
else
\
CypClassType
(
self
.
name
,
None
,
self
.
cname
,
[],
template_values
,
template_type
=
self
)
# Need to do these *after* self.specializations[key] is set
# to avoid infinite recursion on circular references.
specialized
.
base_classes
=
[
b
.
specialize
(
values
)
for
b
in
self
.
base_classes
]
...
...
@@ -4223,6 +4019,8 @@ class CppClassType(CType):
# Make it "nogil" if the base classes allow it.
nogil
=
True
for
base
in
self
.
base_classes
:
if
base
is
cy_object_type
:
continue
base_constructor
=
base
.
scope
.
lookup
(
'<init>'
)
if
base_constructor
and
not
base_constructor
.
type
.
nogil
:
nogil
=
False
...
...
@@ -4237,6 +4035,50 @@ class CppClassType(CType):
error
(
pos
,
"C++ class must have a nullary constructor to be %s"
%
msg
)
class
CypClassType
(
CppClassType
):
is_cyp_class
=
1
def
declaration_code
(
self
,
entity_code
,
for_display
=
0
,
dll_linkage
=
None
,
pyrex
=
0
,
template_params
=
None
):
if
entity_code
:
entity_code
=
"*%s"
%
entity_code
return
super
(
CypClassType
,
self
).
declaration_code
(
entity_code
,
for_display
=
for_display
,
dll_linkage
=
dll_linkage
,
pyrex
=
pyrex
,
template_params
=
template_params
)
def
check_nullary_constructor
(
self
,
pos
,
msg
=
"stack allocated"
):
# We are wrapping the constructor => we manipulate the object through pointers like PyExtTypes => don't care about this check
return
def
cast_code
(
self
,
expr_code
):
return
"((%s)%s)"
%
(
self
.
declaration_code
(
''
),
expr_code
)
def
assignable_from_resolved_type
(
self
,
other_type
):
if
other_type
.
is_ptr
and
other_type
.
base_type
.
is_cpp_class
and
other_type
.
base_type
.
is_subclass
(
self
):
return
1
return
super
(
CypClassType
,
self
).
assignable_from_resolved_type
(
other_type
)
def
get_constructor
(
self
,
pos
):
# This is (currently) only called by new statements.
# In cypclass, it means direct memory allocation:
# regardless of __init__ presence/absence,
# new is forced to be called without any arguments,
# and doesn't call any __init__
# (the mapping from cython __init__ to c++ constructors isn't done
# for cypclass, instead a default empty constructor is declared,
# and calls to __init__ are performed by wrappers)
# As we do not care about declared __init__ in the scope,
# we just return a correct but fake entry.
from
.
import
Symtab
init_type
=
CFuncType
(
c_void_type
,
[],
nogil
=
1
)
init_cname
=
"__unused__"
init_name
=
"<unused>"
init_entry
=
Symtab
.
Entry
(
init_name
,
init_cname
,
init_type
,
pos
=
pos
)
init_entry
.
is_cfunction
=
1
return
init_entry
class
TemplatePlaceholderType
(
CType
):
def
__init__
(
self
,
name
,
optional
=
False
):
...
...
@@ -4497,6 +4339,8 @@ unspecified_type = UnspecifiedType()
py_object_type
=
PyObjectType
()
cy_object_type
=
CypClassType
(
'cyobject'
,
None
,
"CyObject"
,
None
)
c_void_type
=
CVoidType
()
c_uchar_type
=
CIntType
(
0
,
UNSIGNED
)
...
...
Cython/Compiler/Symtab.py
View file @
83047799
...
...
@@ -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"
)
...
...
@@ -1573,7 +1577,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
...
...
@@ -1606,15 +1610,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
:
...
...
@@ -2334,8 +2331,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
:
...
...
@@ -2571,6 +2567,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"
)
...
...
Cython/Compiler/UtilNodes.py
View file @
83047799
...
...
@@ -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
)
...
...
Cython/Utility/CyObjects.cpp
0 → 100644
View file @
83047799
/////////////// 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
;
}
Cython/Utility/ObjectHandling.c
View file @
83047799
...
...
@@ -1851,51 +1851,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);
}
}
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 ///////////////
...
...
nogil_test/nogil_extension.pyx
View file @
83047799
...
...
@@ -32,7 +32,7 @@ from libc.stdio cimport printf
# cdef class SomeMemory:
c
def
class
SomeMemory
nogil
:
c
cdef
class
SomeMemory
:
"""
This is a cdef class which is also called
a extensino type. It is a kind of C struct
...
...
@@ -41,7 +41,7 @@ cdef class SomeMemory nogil:
We would like to be able to define "nogil"
extension types:
c
def class SomeMemory nogil
:
c
cdef class SomeMemory
:
where all methods are "nogil" and memory
allocation does not depend on python runtime
...
...
@@ -54,10 +54,10 @@ cdef class SomeMemory nogil:
# self.b = b
pass
cdef
void
cdealloc
(
self
)
nogil
:
cdef
void
cdealloc
(
self
):
pass
cdef
void
foo1
(
self
)
nogil
:
cdef
void
foo1
(
self
):
"""
It is possible to define native C/Cython methods
that release the GIL (cool...)
...
...
test.pyx
View file @
83047799
...
...
@@ -31,7 +31,7 @@ from libc.stdio cimport printf
# cdef class SomeMemory:
c
def
class
SomeMemory
nogil
:
c
cdef
class
SomeMemory
:
"""
This is a cdef class which is also called
a extensino type. It is a kind of C struct
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment