[pypy-commit] pypy default: Attempting to add a JitDriver to unpackiterable(generator).

arigo noreply at buildbot.pypy.org
Tue Nov 1 13:04:18 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r48642:894e6aa4bb16
Date: 2011-11-01 11:37 +0100
http://bitbucket.org/pypy/pypy/changeset/894e6aa4bb16/

Log:	Attempting to add a JitDriver to unpackiterable(generator).

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -778,6 +778,11 @@
         Raise an OperationError(w_ValueError) if the length is wrong."""
         w_iterator = self.iter(w_iterable)
         if expected_length == -1:
+            # xxx special hack for speed
+            from pypy.interpreter.generator import GeneratorIterator
+            if isinstance(w_iterator, GeneratorIterator):
+                return w_iterator.unpackiterable()
+            # /xxx
             return self._unpackiterable_unknown_length(w_iterator, w_iterable)
         else:
             return self._unpackiterable_known_length(w_iterator,
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -155,3 +155,32 @@
                                                  "interrupting generator of ")
                     break
                 block = block.previous
+
+    def unpackiterable(self):
+        """This is a hack for performance: runs the generator and collects
+        all produced items in a list."""
+        # XXX copied and simplified version of send_ex()
+        space = self.space
+        if self.running:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap('generator already executing'))
+        results_w = []
+        frame = self.frame
+        if frame is None:    # already finished
+            return results_w
+        self.running = True
+        try:
+            while True:
+                jitdriver.jit_merge_point(frame=frame)
+                w_result = frame.execute_frame(space.w_None)
+                # if the frame is now marked as finished, it was RETURNed from
+                if frame.frame_finished_execution:
+                    break
+                results_w.append(w_result)     # YIELDed
+        finally:
+            frame.f_backref = jit.vref_None
+            self.running = False
+            self.frame = None
+        return results_w
+
+jitdriver = jit.JitDriver(greens=['frame.pycode'], reds=['frame'])
diff --git a/pypy/interpreter/test/test_generator.py b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -267,3 +267,9 @@
         assert r.startswith("<generator object myFunc at 0x")
         assert list(g) == [1]
         assert repr(g) == r
+
+    def test_unpackiterable_gen(self):
+        g = (i*i for i in range(-5, 3))
+        assert set(g) == set([0, 1, 4, 9, 16, 25])
+        assert set(g) == set()
+        assert set(i for i in range(0)) == set()


More information about the pypy-commit mailing list