[pypy-svn] r70066 - in pypy/branch/virtual-forcing/pypy/jit: backend/test metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Fri Dec 11 12:10:22 CET 2009


Author: arigo
Date: Fri Dec 11 12:10:21 2009
New Revision: 70066

Modified:
   pypy/branch/virtual-forcing/pypy/jit/backend/test/support.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
Log:
Finally found a simple workaround for the next issue in the pypy-c-jit.
It's quite a bit hackish but it is easy because it works purely locally
in pyjitpl.py.


Modified: pypy/branch/virtual-forcing/pypy/jit/backend/test/support.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/test/support.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/test/support.py	Fri Dec 11 12:10:21 2009
@@ -100,6 +100,9 @@
     def check_aborted_count(self, *args, **kwds):
         pass
 
+    def check_aborted_count_at_least(self, *args, **kwds):
+        pass
+
     def interp_operations(self, *args, **kwds):
         py.test.skip("interp_operations test skipped")
 

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py	Fri Dec 11 12:10:21 2009
@@ -750,7 +750,7 @@
         descr_virtualref_index = virtualref.get_descr_virtualref_index(cpu)
         #
         # Replace the VIRTUAL_REF operation with a virtual structure of type
-        # 'vref.JIT_VIRTUAL_REF'.  The virtual structure may be forced soon,
+        # 'jit_virtual_ref'.  The jit_virtual_ref structure may be forced soon,
         # but the point is that doing so does not force the original structure.
         op = ResOperation(rop.NEW_WITH_VTABLE, [c_cls], op.result)
         vrefvalue = self.make_virtual(c_cls, op.result, op)

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py	Fri Dec 11 12:10:21 2009
@@ -917,8 +917,30 @@
         lastbox = metainterp.virtualref_boxes.pop()
         assert box.getref_base() == lastbox.getref_base()
         if not metainterp.is_blackholing():
+            if vrefbox.getref_base():
+                metainterp.history.record(rop.VIRTUAL_REF_FINISH,
+                                          [vrefbox, lastbox], None)
+
+    def cancel_tracking_virtual_ref(self, argboxes):
+        # if the most recent vref points to an object that escapes in a
+        # residual call (i.e. is in argboxes), then cancel its special
+        # treatment and allow it to escape.  XXX check and document more, or
+        # find another approach -- see test_recursive_call in test_virtualref
+        metainterp = self.metainterp
+        if metainterp.is_blackholing():
+            return
+        if len(metainterp.virtualref_boxes) == 0:
+            return
+        lastbox = metainterp.virtualref_boxes[-2]
+        if lastbox not in argboxes:
+            return
+        vrefbox = metainterp.virtualref_boxes[-1]
+        if vrefbox.getref_base():
             metainterp.history.record(rop.VIRTUAL_REF_FINISH,
                                       [vrefbox, lastbox], None)
+            ConstRef = metainterp.cpu.ts.ConstRef
+            nullbox = ConstRef(ConstRef.value)
+            metainterp.virtualref_boxes[-1] = nullbox
 
     # ------------------------------
 
@@ -1023,6 +1045,7 @@
     def do_residual_call(self, argboxes, descr, exc):
         effectinfo = descr.get_extra_info()
         if effectinfo is None or effectinfo.forces_virtual_or_virtualizable:
+            self.cancel_tracking_virtual_ref(argboxes)
             # residual calls require attention to keep virtualizables in-sync
             self.metainterp.vable_and_vrefs_before_residual_call()
             # xxx do something about code duplication
@@ -1433,6 +1456,7 @@
         self.staticdata.stats.aborted()
         self.staticdata.profiler.end_tracing()
         self.staticdata.profiler.start_blackhole()
+    switch_to_blackhole._dont_inline_ = True
 
     def switch_to_blackhole_if_trace_too_long(self):
         if not self.is_blackholing():
@@ -1766,9 +1790,11 @@
         for i in range(1, len(self.virtualref_boxes), 2):
             vrefbox = self.virtualref_boxes[i]
             vref = vrefbox.getref_base()
+            if not vref:
+                continue
             virtualref.tracing_before_residual_call(vref)
-            # the FORCE_TOKEN is already set at runtime in each vrefs when
-            # they are created, by optimizeopt.py.
+            # the FORCE_TOKEN is already set at runtime in each vref when
+            # it is created, by optimizeopt.py.
         #
         vinfo = self.staticdata.virtualizable_info
         if vinfo is not None:
@@ -1791,6 +1817,8 @@
             for i in range(1, len(self.virtualref_boxes), 2):
                 vrefbox = self.virtualref_boxes[i]
                 vref = vrefbox.getref_base()
+                if not vref:
+                    continue
                 if virtualref.tracing_after_residual_call(vref):
                     # this vref escaped during CALL_MAY_FORCE.
                     escapes = True
@@ -1849,6 +1877,8 @@
         for i in range(0, len(virtualref_boxes), 2):
             virtualbox = virtualref_boxes[i]
             vrefbox = virtualref_boxes[i+1]
+            if not vrefbox.getref_base():
+                continue
             virtualref.continue_tracing(vrefbox.getref_base(),
                                         virtualbox.getref_base())
         #

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_basic.py	Fri Dec 11 12:10:21 2009
@@ -52,6 +52,8 @@
         assert get_stats().exec_jumps <= maxcount
     def check_aborted_count(self, count):
         assert get_stats().aborted_count == count
+    def check_aborted_count_at_least(self, count):
+        assert get_stats().aborted_count >= count
 
     def meta_interp(self, *args, **kwds):
         kwds['CPUClass'] = self.CPUClass

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py	Fri Dec 11 12:10:21 2009
@@ -106,7 +106,7 @@
                 # we call virtual_ref(x).)
                 exctx.topframeref = vref_None
                 virtual_ref_finish(x)
-                # 'vref' is allowed to escape, and even be forced, even after
+                # 'x' is allowed to escape, and even be forced, even after
                 # the call to finish().
                 g(vref)
                 n -= 1
@@ -144,6 +144,7 @@
         res = self.meta_interp(f, [-4])
         assert res == 16 * 19
         self.check_loops({})      # because we aborted tracing
+        self.check_aborted_count_at_least(1)
 
     def test_simple_no_access(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -208,6 +209,7 @@
         #
         self.meta_interp(f, [15])
         self.check_loops({})     # because we aborted tracing
+        self.check_aborted_count_at_least(1)
 
     def test_simple_force_sometimes(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -344,7 +346,6 @@
         exctx = ExCtx()
         #
         def f(n):
-            later = None
             while n > 0:
                 myjitdriver.can_enter_jit(n=n)
                 myjitdriver.jit_merge_point(n=n)
@@ -359,6 +360,70 @@
         res = self.meta_interp(f, [15])
         assert res == 1
         self.check_loops({})      # because we aborted tracing
+        self.check_aborted_count_at_least(1)
+
+    def test_recursive_call_1(self):
+        myjitdriver = JitDriver(greens = [], reds = ['n', 'frame', 'rec'])
+        #
+        class XY:
+            pass
+        class ExCtx:
+            pass
+        exctx = ExCtx()
+        #
+        def f(frame, n, reclevel):
+            while n > 0:
+                myjitdriver.can_enter_jit(n=n, frame=frame, rec=reclevel)
+                myjitdriver.jit_merge_point(n=n, frame=frame, rec=reclevel)
+                if reclevel == 0:
+                    return n
+                xy = XY()
+                exctx.topframeref = virtual_ref(xy)
+                m = f(xy, n, reclevel-1)
+                assert m == n
+                n -= 1
+                exctx.topframeref = vref_None
+                virtual_ref_finish(xy)
+            return 2
+        def main(n, reclevel):
+            return f(XY(), n, reclevel)
+        #
+        res = self.meta_interp(main, [15, 1])
+        assert res == main(15, 1)
+        self.check_aborted_count(0)
+
+    def test_recursive_call_2(self):
+        myjitdriver = JitDriver(greens = [], reds = ['n', 'frame', 'rec'])
+        #
+        class XY:
+            n = 0
+        class ExCtx:
+            pass
+        exctx = ExCtx()
+        #
+        def f(frame, n, reclevel):
+            while n > 0:
+                myjitdriver.can_enter_jit(n=n, frame=frame, rec=reclevel)
+                myjitdriver.jit_merge_point(n=n, frame=frame, rec=reclevel)
+                frame.n += 1
+                xy = XY()
+                xy.n = n
+                exctx.topframeref = virtual_ref(xy)
+                if reclevel > 0:
+                    m = f(xy, frame.n, reclevel-1)
+                    assert xy.n == m
+                    n -= 1
+                else:
+                    n -= 2
+                exctx.topframeref = vref_None
+                virtual_ref_finish(xy)
+            return frame.n
+        def main(n, reclevel):
+            return f(XY(), n, reclevel)
+        #
+        res = self.meta_interp(main, [10, 2])
+        assert res == main(10, 2)
+        self.check_aborted_count(0)
 
 
 class TestLLtype(VRefTests, LLJitMixin):



More information about the Pypy-commit mailing list