make sure we only optimise builtins and no user defined names, support further optimi...
authorStefan Behnel <scoder@users.berlios.de>
Thu, 26 Nov 2009 19:47:59 +0000 (20:47 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 26 Nov 2009 19:47:59 +0000 (20:47 +0100)
Cython/Compiler/Optimize.py

index 071748fb1fd3783e780873e83bd7a3d7ef763d18..3e5482af9789a2bb934ecc734df952f8a854bf30 100644 (file)
@@ -740,19 +740,22 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
         arg_tuple = node.positional_args
         if not isinstance(arg_tuple, ExprNodes.TupleNode):
             return node
+        args = arg_tuple.args
         return self._dispatch_to_handler(
-            node, function, arg_tuple, node.keyword_args)
+            node, function, args, node.keyword_args)
 
     def visit_SimpleCallNode(self, node):
         self.visitchildren(node)
         function = node.function
-        if not function.type.is_pyobject:
-            return node
-        arg_tuple = node.arg_tuple
-        if not isinstance(arg_tuple, ExprNodes.TupleNode):
-            return node
+        if function.type.is_pyobject:
+            arg_tuple = node.arg_tuple
+            if not isinstance(arg_tuple, ExprNodes.TupleNode):
+                return node
+            args = arg_tuple.args
+        else:
+            args = node.args
         return self._dispatch_to_handler(
-            node, node.function, arg_tuple)
+            node, function, args)
 
     ### cleanup to avoid redundant coercions to/from Python types
 
@@ -823,20 +826,25 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             handler = getattr(self, '_handle_any_%s' % match_name, None)
         return handler
 
-    def _dispatch_to_handler(self, node, function, arg_tuple, kwargs=None):
+    def _dispatch_to_handler(self, node, function, arg_list, kwargs=None):
         if function.is_name:
-            match_name = "_function_%s" % function.name
+            # we only consider functions that are either builtin
+            # Python functions or builtins that were already replaced
+            # into a C function call (defined in the builtin scope)
+            is_builtin = function.entry.is_builtin \
+                         or getattr(function.entry, 'scope', None) is Builtin.builtin_scope
+            if not is_builtin:
+                return node
             function_handler = self._find_handler(
                 "function_%s" % function.name, kwargs)
             if function_handler is None:
                 return node
             if kwargs:
-                return function_handler(node, arg_tuple, kwargs)
+                return function_handler(node, arg_list, kwargs)
             else:
-                return function_handler(node, arg_tuple)
-        elif function.is_attribute:
+                return function_handler(node, arg_list)
+        elif function.is_attribute and function.type.is_pyobject:
             attr_name = function.attribute
-            arg_list = arg_tuple.args
             self_arg = function.obj
             obj_type = self_arg.type
             is_unbound_method = False
@@ -892,7 +900,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
         """Replace dict(a=b,c=d,...) by the underlying keyword dict
         construction which is done anyway.
         """
-        if len(pos_args.args) > 0:
+        if len(pos_args) > 0:
             return node
         if not isinstance(kwargs, ExprNodes.DictNode):
             return node
@@ -910,9 +918,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
         """Replace dict(some_dict) by PyDict_Copy(some_dict) and
         dict([ (a,b) for ... ]) by a literal { a:b for ... }.
         """
-        if len(pos_args.args) != 1:
+        if len(pos_args) != 1:
             return node
-        arg = pos_args.args[0]
+        arg = pos_args[0]
         if arg.type is Builtin.dict_type:
             arg = ExprNodes.NoneCheckNode(
                 arg, "PyExc_TypeError", "'NoneType' is not iterable")
@@ -943,13 +951,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
         """Replace set([a,b,...]) by a literal set {a,b,...} and
         set([ x for ... ]) by a literal { x for ... }.
         """
-        arg_count = len(pos_args.args)
+        arg_count = len(pos_args)
         if arg_count == 0:
             return ExprNodes.SetNode(node.pos, args=[],
                                      type=Builtin.set_type, is_temp=1)
         if arg_count > 1:
             return node
-        iterable = pos_args.args[0]
+        iterable = pos_args[0]
         if isinstance(iterable, (ExprNodes.ListNode, ExprNodes.TupleNode)):
             return ExprNodes.SetNode(node.pos, args=iterable.args,
                                      type=Builtin.set_type, is_temp=1)
@@ -971,20 +979,20 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
     def _handle_simple_function_tuple(self, node, pos_args):
         """Replace tuple([...]) by a call to PyList_AsTuple.
         """
-        if len(pos_args.args) != 1:
+        if len(pos_args) != 1:
             return node
-        list_arg = pos_args.args[0]
+        list_arg = pos_args[0]
         if list_arg.type is not Builtin.list_type:
             return node
         if not isinstance(list_arg, (ExprNodes.ComprehensionNode,
                                      ExprNodes.ListNode)):
-            pos_args.args[0] = ExprNodes.NoneCheckNode(
+            pos_args[0] = ExprNodes.NoneCheckNode(
                 list_arg, "PyExc_TypeError",
                 "'NoneType' object is not iterable")
 
         return ExprNodes.PythonCapiCallNode(
             node.pos, "PyList_AsTuple", self.PyList_AsTuple_func_type,
-            args = pos_args.args,
+            args = pos_args,
             is_temp = node.is_temp
             )
 
@@ -1004,22 +1012,21 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             ])
 
     def _handle_simple_function_getattr(self, node, pos_args):
-        args = pos_args.args
-        if len(args) == 2:
+        if len(pos_args) == 2:
             node = ExprNodes.PythonCapiCallNode(
                 node.pos, "PyObject_GetAttr", self.PyObject_GetAttr2_func_type,
-                args = args,
+                args = pos_args,
                 is_temp = node.is_temp
                 )
-        elif len(args) == 3:
+        elif len(pos_args) == 3:
             node = ExprNodes.PythonCapiCallNode(
                 node.pos, "__Pyx_GetAttr3", self.PyObject_GetAttr3_func_type,
                 utility_code = Builtin.getattr3_utility_code,
-                args = args,
+                args = pos_args,
                 is_temp = node.is_temp
                 )
         else:
-            self._error_wrong_arg_count('getattr', node, args, '2 or 3')
+            self._error_wrong_arg_count('getattr', node, pos_args, '2 or 3')
         return node
 
     Pyx_Type_func_type = PyrexTypes.CFuncType(
@@ -1028,12 +1035,11 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             ])
 
     def _handle_simple_function_type(self, node, pos_args):
-        args = pos_args.args
-        if len(args) != 1:
+        if len(pos_args) != 1:
             return node
         node = ExprNodes.PythonCapiCallNode(
             node.pos, "__Pyx_Type", self.Pyx_Type_func_type,
-                args = args,
+                args = pos_args,
                 is_temp = node.is_temp,
                 utility_code = pytype_utility_code,
                 )