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
80359387
Commit
80359387
authored
Oct 31, 2009
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
optimise MyType.__new__(MyType) into a tp_new() slot call
parent
7138b1d2
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
206 additions
and
1 deletion
+206
-1
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+64
-1
tests/errors/tp_new_errors.pyx
tests/errors/tp_new_errors.pyx
+29
-0
tests/run/tp_new.pyx
tests/run/tp_new.pyx
+113
-0
No files found.
Cython/Compiler/Optimize.py
View file @
80359387
...
...
@@ -7,6 +7,7 @@ import UtilNodes
import
TypeSlots
import
Symtab
import
Options
import
Naming
from
Code
import
UtilityCode
from
StringEncoding
import
EncodedString
,
BytesLiteral
...
...
@@ -851,7 +852,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
method_handler
=
self
.
_find_handler
(
"method_%s_%s"
%
(
type_name
,
function
.
attribute
),
kwargs
)
if
method_handler
is
None
:
return
node
method_handler
=
self
.
_find_handler
(
"methodany_%s"
%
function
.
attribute
,
kwargs
)
if
method_handler
is
None
:
return
node
if
self_arg
is
not
None
:
arg_list
=
[
self_arg
]
+
list
(
arg_list
)
if
kwargs
:
...
...
@@ -1030,6 +1034,55 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
)
return
node
### special methods
def
_handle_simple_methodany___new__
(
self
,
node
,
args
,
is_unbound_method
):
"""Replace 'exttype.__new__(exttype)' by a call to exttype->tp_new()
"""
obj
=
node
.
function
.
obj
if
not
is_unbound_method
or
len
(
args
)
!=
1
:
return
node
type_arg
=
args
[
0
]
if
not
obj
.
is_name
or
not
type_arg
.
is_name
:
# play safe
return
node
if
obj
.
type
!=
Builtin
.
type_type
or
type_arg
.
type
!=
Builtin
.
type_type
:
# not a known type, play safe
return
node
if
not
type_arg
.
type_entry
or
not
obj
.
type_entry
:
if
obj
.
name
!=
type_arg
.
name
:
return
node
# otherwise, we know it's a type and we know it's the same
# type for both - that should do
elif
type_arg
.
type_entry
!=
obj
.
type_entry
:
# different types - do what CPython does at runtime
error
(
type_arg
.
pos
,
"%s.__new__(%s) is not safe, use %s.__new__()"
%
(
obj
.
type_entry
.
name
,
type_arg
.
type_entry
.
name
,
type_arg
.
type_entry
.
name
))
return
node
return_type
=
None
if
obj
.
type_entry
:
return_type
=
obj
.
type_entry
.
type
if
return_type
is
None
and
type_arg
.
type_entry
:
return_type
=
type_arg
.
type_entry
.
type
if
return_type
is
None
:
return_type
=
PyrexTypes
.
py_object_type
# FIXME: we could potentially look up the actual tp_new C method
# of the extension type and call that instead of the generic slot
func_type
=
PyrexTypes
.
CFuncType
(
return_type
,
[
PyrexTypes
.
CFuncTypeArg
(
"type"
,
PyrexTypes
.
py_object_type
,
None
)
])
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_tp_new"
,
func_type
,
args
=
args
,
utility_code
=
tpnew_utility_code
,
is_temp
=
node
.
is_temp
)
### methods of builtin types
PyObject_Append_func_type
=
PyrexTypes
.
CFuncType
(
...
...
@@ -1317,6 +1370,16 @@ static INLINE PyObject* __Pyx_Type(PyObject* o) {
)
tpnew_utility_code
=
UtilityCode
(
proto
=
"""
static INLINE PyObject* __Pyx_tp_new(PyObject* type_obj) {
return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new(
(PyTypeObject*)(type_obj), %(TUPLE)s, NULL));
}
"""
%
{
'TUPLE'
:
Naming
.
empty_tuple
}
)
class
ConstantFolding
(
Visitor
.
VisitorTransform
,
SkipDeclarations
):
"""Calculate the result of constant expressions to store it in
``expr_node.constant_result``, and replace trivial cases by their
...
...
tests/errors/tp_new_errors.pyx
0 → 100644
View file @
80359387
cdef
class
MyType
:
def
__init__
(
self
):
print
"INIT"
cdef
class
MySubType
(
MyType
):
def
__init__
(
self
):
print
"INIT"
cdef
class
MyOtherType
:
def
__init__
(
self
):
print
"INIT"
def
make_new
():
m
=
MyType
.
__new__
(
MyType
)
m
=
MyOtherType
.
__new__
(
MyOtherType
)
return
m
def
make_new_error
():
m
=
MySubType
.
__new__
(
MyType
)
m
=
MyOtherType
.
__new__
(
MyType
)
m
=
MyOtherType
.
__new__
(
MySubType
)
return
m
_ERRORS
=
"""
20:32: MySubType.__new__(MyType) is not safe, use MyType.__new__()
21:34: MyOtherType.__new__(MyType) is not safe, use MyType.__new__()
22:37: MyOtherType.__new__(MySubType) is not safe, use MySubType.__new__()
"""
tests/run/tp_new.pyx
0 → 100644
View file @
80359387
cimport
cython
cdef
class
MyType
:
def
__init__
(
self
):
print
"INIT"
cdef
class
MySubType
(
MyType
):
def
__init__
(
self
):
print
"INIT"
class
MyClass
(
object
):
def
__init__
(
self
):
print
"INIT"
class
MyTypeSubClass
(
MyType
):
def
__init__
(
self
):
print
"INIT"
# only this can be safely optimised:
@
cython
.
test_assert_path_exists
(
'//PythonCapiCallNode'
)
@
cython
.
test_fail_if_path_exists
(
'//SimpleCallNode/AttributeNode'
)
def
make_new
():
"""
>>> isinstance(make_new(), MyType)
True
"""
m
=
MyType
.
__new__
(
MyType
)
return
m
@
cython
.
test_assert_path_exists
(
'//PythonCapiCallNode'
)
@
cython
.
test_fail_if_path_exists
(
'//SimpleCallNode/AttributeNode'
)
def
make_new_builtin
():
"""
>>> isinstance(make_new_builtin(), tuple)
True
"""
m
=
dict
.
__new__
(
dict
)
m
=
list
.
__new__
(
list
)
m
=
tuple
.
__new__
(
tuple
)
return
m
# these cannot:
@
cython
.
test_assert_path_exists
(
'//SimpleCallNode/AttributeNode'
)
@
cython
.
test_fail_if_path_exists
(
'//PythonCapiCallNode'
)
def
make_new_pyclass
():
"""
>>> isinstance(make_new_pyclass(), MyTypeSubClass)
True
"""
m
=
MyClass
.
__new__
(
MyClass
)
m
=
MyTypeSubClass
.
__new__
(
MyTypeSubClass
)
return
m
@
cython
.
test_assert_path_exists
(
'//SimpleCallNode/AttributeNode'
)
@
cython
.
test_fail_if_path_exists
(
'//PythonCapiCallNode'
)
def
make_new_args
(
type
t1
=
None
,
type
t2
=
None
):
"""
>>> isinstance(make_new_args(), MyType)
True
>>> isinstance(make_new_args(MyType), MyType)
True
>>> isinstance(make_new_args(MyType, MyType), MyType)
True
>>> isinstance(make_new_args(MyType, MySubType), MySubType)
Traceback (most recent call last):
TypeError: tp_new.MyType.__new__(tp_new.MySubType) is not safe, use tp_new.MySubType.__new__()
>>> isinstance(make_new_args(MySubType, MyType), MyType)
Traceback (most recent call last):
TypeError: tp_new.MySubType.__new__(tp_new.MyType): tp_new.MyType is not a subtype of tp_new.MySubType
"""
if
t1
is
None
:
t1
=
MyType
if
t2
is
None
:
t2
=
MyType
m
=
t1
.
__new__
(
t2
)
return
m
@
cython
.
test_assert_path_exists
(
'//SimpleCallNode/AttributeNode'
)
@
cython
.
test_fail_if_path_exists
(
'//PythonCapiCallNode'
)
def
make_new_none
(
type
t1
=
None
,
type
t2
=
None
):
"""
>>> isinstance(make_new_none(), MyType)
Traceback (most recent call last):
TypeError: object.__new__(X): X is not a type object (NoneType)
"""
m
=
t1
.
__new__
(
t2
)
return
m
@
cython
.
test_assert_path_exists
(
'//SimpleCallNode/AttributeNode'
)
@
cython
.
test_fail_if_path_exists
(
'//PythonCapiCallNode'
)
def
make_new_none_typed
(
tuple
t1
=
None
,
tuple
t2
=
None
):
"""
>>> isinstance(make_new_none(), MyType)
Traceback (most recent call last):
TypeError: object.__new__(X): X is not a type object (NoneType)
"""
m
=
t1
.
__new__
(
t2
)
return
m
@
cython
.
test_assert_path_exists
(
'//SimpleCallNode/AttributeNode'
)
@
cython
.
test_fail_if_path_exists
(
'//PythonCapiCallNode'
)
def
make_new_untyped
(
t
):
"""
>>> make_new_untyped(None)
Traceback (most recent call last):
TypeError: object.__new__(X): X is not a type object (NoneType)
"""
m
=
t
.
__new__
(
t
)
return
m
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