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