Commits

Brian Kearns  committed ab0486a

significantly speed up min/max in the non-unrolled case

  • Participants
  • Parent commits a49ec2d

Comments (0)

Files changed (1)

File pypy/module/__builtin__/functional.py

         v = v.add(step)
     return space.newlist(res_w)
 
+min_jitdriver = jit.JitDriver(name='min',
+        greens=['w_type'], reds='auto')
+max_jitdriver = jit.JitDriver(name='max',
+        greens=['w_type'], reds='auto')
+
+def make_min_max(unroll):
+    @specialize.arg(2)
+    def min_max_impl(space, args, implementation_of):
+        if implementation_of == "max":
+            compare = space.gt
+            jitdriver = max_jitdriver
+        else:
+            compare = space.lt
+            jitdriver = min_jitdriver
+        args_w = args.arguments_w
+        if len(args_w) > 1:
+            w_sequence = space.newtuple(args_w)
+        elif len(args_w):
+            w_sequence = args_w[0]
+        else:
+            msg = "%s() expects at least one argument" % (implementation_of,)
+            raise OperationError(space.w_TypeError, space.wrap(msg))
+        w_key = None
+        kwds = args.keywords
+        if kwds:
+            if kwds[0] == "key" and len(kwds) == 1:
+                w_key = args.keywords_w[0]
+            else:
+                msg = "%s() got unexpected keyword argument" % (implementation_of,)
+                raise OperationError(space.w_TypeError, space.wrap(msg))
+
+        w_iter = space.iter(w_sequence)
+        w_type = space.type(w_iter)
+        w_max_item = None
+        w_max_val = None
+        while True:
+            if not unroll:
+                jitdriver.jit_merge_point(w_type=w_type)
+            try:
+                w_item = space.next(w_iter)
+            except OperationError, e:
+                if not e.match(space, space.w_StopIteration):
+                    raise
+                break
+            if w_key is not None:
+                w_compare_with = space.call_function(w_key, w_item)
+            else:
+                w_compare_with = w_item
+            if w_max_item is None or \
+                    space.is_true(compare(w_compare_with, w_max_val)):
+                w_max_item = w_item
+                w_max_val = w_compare_with
+        if w_max_item is None:
+            msg = "arg is an empty sequence"
+            raise OperationError(space.w_ValueError, space.wrap(msg))
+        return w_max_item
+    if unroll:
+        min_max_impl = jit.unroll_safe(min_max_impl)
+    return min_max_impl
+
+min_max_unroll = make_min_max(True)
+min_max_normal = make_min_max(False)
 
 @specialize.arg(2)
-@jit.look_inside_iff(lambda space, args, implementation_of:
-    jit.isconstant(len(args.arguments_w)) and
-    len(args.arguments_w) == 2
-)
 def min_max(space, args, implementation_of):
-    if implementation_of == "max":
-        compare = space.gt
+    if not jit.we_are_jitted() or (jit.isconstant(len(args.arguments_w)) and
+            len(args.arguments_w) == 2):
+        return min_max_unroll(space, args, implementation_of)
     else:
-        compare = space.lt
-    args_w = args.arguments_w
-    if len(args_w) > 1:
-        w_sequence = space.newtuple(args_w)
-    elif len(args_w):
-        w_sequence = args_w[0]
-    else:
-        msg = "%s() expects at least one argument" % (implementation_of,)
-        raise OperationError(space.w_TypeError, space.wrap(msg))
-    w_key = None
-    kwds = args.keywords
-    if kwds:
-        if kwds[0] == "key" and len(kwds) == 1:
-            w_key = args.keywords_w[0]
-        else:
-            msg = "%s() got unexpected keyword argument" % (implementation_of,)
-            raise OperationError(space.w_TypeError, space.wrap(msg))
-
-    w_iter = space.iter(w_sequence)
-    w_max_item = None
-    w_max_val = None
-    while True:
-        try:
-            w_item = space.next(w_iter)
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            break
-        if w_key is not None:
-            w_compare_with = space.call_function(w_key, w_item)
-        else:
-            w_compare_with = w_item
-        if w_max_item is None or \
-                space.is_true(compare(w_compare_with, w_max_val)):
-            w_max_item = w_item
-            w_max_val = w_compare_with
-    if w_max_item is None:
-        msg = "arg is an empty sequence"
-        raise OperationError(space.w_ValueError, space.wrap(msg))
-    return w_max_item
+        return min_max_normal(space, args, implementation_of)
 
 def max(space, __args__):
     """max(iterable[, key=func]) -> value