Commit fb590561 authored by Stefan Behnel's avatar Stefan Behnel

always split type tuple literals in isinstance() calls to speed up each type test separately

parent 1490f8de
......@@ -2276,11 +2276,14 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
if len(pos_args) != 2:
return node
arg, types = pos_args
temp = None
temps = []
if isinstance(types, ExprNodes.TupleNode):
types = types.args
if len(types) == 1 and not types[0].type is Builtin.type_type:
return node # nothing to improve here
if arg.is_attribute or not arg.is_simple():
arg = temp = UtilNodes.ResultRefNode(arg)
arg = UtilNodes.ResultRefNode(arg)
temps.append(arg)
elif types.type is Builtin.type_type:
types = [types]
else:
......@@ -2311,13 +2314,17 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
type_check_function = '__Pyx_TypeCheck'
type_check_args = [arg, test_type_node]
else:
return node
if not test_type_node.is_literal:
test_type_node = UtilNodes.ResultRefNode(test_type_node)
temps.append(test_type_node)
type_check_function = 'PyObject_IsInstance'
type_check_args = [arg, test_type_node]
test_nodes.append(
ExprNodes.PythonCapiCallNode(
test_type_node.pos, type_check_function, self.Py_type_check_func_type,
args = type_check_args,
is_temp = True,
))
args=type_check_args,
is_temp=True,
))
def join_with_or(a, b, make_binop_node=ExprNodes.binop_node):
or_node = make_binop_node(node.pos, 'or', a, b)
......@@ -2326,7 +2333,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
return or_node
test_node = reduce(join_with_or, test_nodes).coerce_to(node.type, env)
if temp is not None:
for temp in temps[::-1]:
test_node = UtilNodes.EvalWithTempExprNode(temp, test_node)
return test_node
......
......@@ -5,6 +5,10 @@ from cpython.bool cimport bool
cdef class A:
pass
a_as_obj = A
@cython.test_assert_path_exists('//SimpleCallNode//SimpleCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode')
......@@ -18,6 +22,7 @@ def test_non_optimised():
assert isinstance(A(), foo)
return True
@cython.test_assert_path_exists('//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode',
'//PythonCapiFunctionNode[@cname = "PyType_Check"]',
......@@ -104,6 +109,7 @@ def test_optimised():
assert isinstance(A(), <type>untyped_type)
return True
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//SimpleCallNode',
'//SimpleCallNode//PythonCapiCallNode',
......@@ -116,10 +122,14 @@ def test_optimised_tuple():
assert isinstance(int(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A))
assert isinstance(list(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A, a_as_obj))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, a_as_obj, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, a_as_obj, tuple, list, dict, set, slice, type, A))
assert isinstance(0, (int, long))
assert not isinstance(u"xyz", (int, long))
return True
def test_custom():
"""
>>> test_custom()
......@@ -134,6 +144,11 @@ cdef class B:
cdef class C:
pass
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//SimpleCallNode',
'//SimpleCallNode//PythonCapiCallNode',
'//TupleNode//NameNode')
def test_custom_tuple(obj):
"""
>>> test_custom_tuple(A())
......@@ -145,6 +160,7 @@ def test_custom_tuple(obj):
"""
return isinstance(obj, (A,B))
def test_nested(x):
"""
>>> test_nested(1)
......
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