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

arigo at codespeak.net arigo at codespeak.net
Sun Dec 6 18:08:41 CET 2009


Author: arigo
Date: Sun Dec  6 18:08:41 2009
New Revision: 69924

Modified:
   pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.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/resoperation.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/warmspot.py
Log:
Done!  Now all that's left is many small bugs here and there...


Modified: pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py	Sun Dec  6 18:08:41 2009
@@ -782,7 +782,8 @@
     def test_virtual_ref(self):
         # if VIRTUAL_REF reaches the backend, it should just be a SAME_AS
         u_box = self.alloc_unicode(u"hello\u1234")
-        r = self.execute_operation(rop.VIRTUAL_REF, [u_box], 'ref')
+        r = self.execute_operation(rop.VIRTUAL_REF, [u_box, ConstInt(2)],
+                                   'ref')
         assert r.value == u_box.value
 
     def test_jump(self):

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py	Sun Dec  6 18:08:41 2009
@@ -237,23 +237,50 @@
         from pypy.jit.metainterp.pyjitpl import MetaInterp
         metainterp = MetaInterp(metainterp_sd)
         token = metainterp_sd.cpu.get_latest_force_token()
-        data = self.fetch_data(token)
-        if data is None:
-            data = []
-        metainterp._already_allocated_resume_virtuals = data
+        all_virtuals = self.fetch_data(token)
+        if all_virtuals is None:
+            all_virtuals = []
+        metainterp._already_allocated_resume_virtuals = all_virtuals
         self.counter = -2     # never compile
         return metainterp.handle_guard_failure(self)
 
-    def force_virtualizable(self, vinfo, virtualizable, force_token):
+    @staticmethod
+    def force_now(cpu, token):
+        # Called during a residual call from the assembler, if the code
+        # actually needs to force one of the virtualrefs or the virtualizable.
+        # Implemented by forcing *all* virtualrefs and the virtualizable.
+        faildescr = cpu.force(token)
+        assert isinstance(faildescr, ResumeGuardForcedDescr)
+        faildescr.handle_async_forcing(token)
+
+    def handle_async_forcing(self, force_token):
         from pypy.jit.metainterp.pyjitpl import MetaInterp
         from pypy.jit.metainterp.resume import force_from_resumedata
-        metainterp = MetaInterp(self.metainterp_sd)
+        from pypy.jit.metainterp.virtualref import forced_single_vref
+        # To handle the forcing itself, we create a temporary MetaInterp
+        # as a convenience to move the various data to its proper place.
+        metainterp_sd = self.metainterp_sd
+        metainterp = MetaInterp(metainterp_sd)
         metainterp.history = None    # blackholing
-        liveboxes = metainterp.cpu.make_boxes_from_latest_values(self)
-        virtualizable_boxes, data = force_from_resumedata(metainterp,
-                                                          liveboxes, self)
-        vinfo.write_boxes(virtualizable, virtualizable_boxes)
-        self.save_data(force_token, data)
+        liveboxes = metainterp_sd.cpu.make_boxes_from_latest_values(self)
+        #
+        expect_virtualizable = metainterp_sd.virtualizable_info is not None
+        forced_data = force_from_resumedata(metainterp, liveboxes, self,
+                                            expect_virtualizable)
+        virtualizable_boxes, virtualref_boxes, all_virtuals = forced_data
+        #
+        # Handle virtualref_boxes: mark each JIT_VIRTUAL_REF as forced
+        for i in range(0, len(virtualref_boxes), 2):
+            virtualbox = virtualref_boxes[i]
+            vrefbox = virtualref_boxes[i+1]
+            forced_single_vref(vrefbox.getref_base(), virtualbox.getref_base())
+        # Handle virtualizable_boxes: store them on the real virtualizable now
+        if expect_virtualizable:
+            metainterp.virtualizable_boxes = virtualizable_boxes
+            metainterp.synchronize_virtualizable()
+        # Handle all_virtuals: keep them for later blackholing from the
+        # future failure of the GUARD_NOT_FORCED
+        self.save_data(force_token, all_virtuals)
 
     def save_data(self, key, value):
         globaldata = self.metainterp_sd.globaldata

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	Sun Dec  6 18:08:41 2009
@@ -740,12 +740,14 @@
         value = self.getvalue(op.args[0])
         if not value.is_virtual():   # virtual_ref(non-virtual) gives bad
             raise compile.GiveUp     # results, so don't bother compiling it
+        indexbox = op.args[1]
         #
         # get some constants (these calls are all 'memo')
         from pypy.jit.metainterp import virtualref
-        c_cls = virtualref.get_jit_virtual_ref_const_class(self.cpu)
-        descr_virtual_token = virtualref.get_descr_virtual_token(self.cpu)
-        descr_forced = virtualref.get_descr_forced(self.cpu)
+        cpu = self.cpu
+        c_cls = virtualref.get_jit_virtual_ref_const_class(cpu)
+        descr_virtual_token = virtualref.get_descr_virtual_token(cpu)
+        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,
@@ -755,6 +757,7 @@
         tokenbox = BoxInt()
         self.emit_operation(ResOperation(rop.FORCE_TOKEN, [], tokenbox))
         vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
+        vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
 
     def optimize_GETFIELD_GC(self, op):
         value = self.getvalue(op.args[0])

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	Sun Dec  6 18:08:41 2009
@@ -891,7 +891,8 @@
         obj = box.getref_base()
         vref = virtualref.virtual_ref_during_tracing(obj)
         resbox = history.BoxPtr(vref)
-        self.metainterp.history.record(rop.VIRTUAL_REF, [box], resbox)
+        cindex = history.ConstInt(len(self.metainterp.virtualref_boxes) // 2)
+        self.metainterp.history.record(rop.VIRTUAL_REF, [box, cindex], resbox)
         # Note: we allocate a JIT_VIRTUAL_REF here
         # (in virtual_ref_during_tracing()), in order to detect when
         # the virtual escapes during tracing already.  We record it as a

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py	Sun Dec  6 18:08:41 2009
@@ -206,7 +206,7 @@
     'NEW_WITH_VTABLE/1',
     'NEW_ARRAY/1d',
     'FORCE_TOKEN/0',
-    'VIRTUAL_REF/1',
+    'VIRTUAL_REF/2',
     '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
 
     'SETARRAYITEM_GC/3d',

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py	Sun Dec  6 18:08:41 2009
@@ -441,7 +441,8 @@
             debug_print("\t\t", str(untag(i)))
 
 
-def rebuild_from_resumedata(metainterp, newboxes, storage, expects_virtualizables):
+def rebuild_from_resumedata(metainterp, newboxes, storage,
+                            expects_virtualizables):
     resumereader = ResumeDataReader(storage, newboxes, metainterp)
     virtualizable_boxes = None
     if expects_virtualizables:
@@ -458,9 +459,14 @@
     metainterp.framestack.reverse()
     return virtualizable_boxes, virtualref_boxes
 
-def force_from_resumedata(metainterp, newboxes, storage):
+def force_from_resumedata(metainterp, newboxes, storage,
+                          expects_virtualizables):
     resumereader = ResumeDataReader(storage, newboxes, metainterp)
-    return resumereader.consume_boxes(), resumereader.virtuals
+    virtualizable_boxes = None
+    if expects_virtualizables:
+        virtualizable_boxes = resumereader.consume_boxes()
+    virtualref_boxes = resumereader.consume_boxes()
+    return virtualizable_boxes, virtualref_boxes, resumereader.virtuals
 
 
 class ResumeDataReader(object):

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	Sun Dec  6 18:08:41 2009
@@ -164,7 +164,37 @@
                 exctx.topframeref = None
         #
         self.meta_interp(f, [15])
-        self.check_loops(new_with_vtable=0)
+        self.check_loops({})     # because we aborted tracing
+
+    def test_simple_force_sometimes(self):
+        myjitdriver = JitDriver(greens = [], reds = ['n'])
+        #
+        class XY:
+            pass
+        class ExCtx:
+            pass
+        exctx = ExCtx()
+        #
+        @dont_look_inside
+        def externalfn(n):
+            if n == 13:
+                exctx.m = exctx.topframeref().n
+            return 1
+        #
+        def f(n):
+            while n > 0:
+                myjitdriver.can_enter_jit(n=n)
+                myjitdriver.jit_merge_point(n=n)
+                xy = XY()
+                xy.n = n
+                exctx.topframeref = virtual_ref(xy)
+                n -= externalfn(n)
+                virtual_ref_finish(exctx.topframeref)
+                exctx.topframeref = None
+            return exctx.m
+        #
+        res = self.meta_interp(f, [30])
+        assert res == 13
 
 
 class TestLLtype(VRefTests, LLJitMixin):

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py	Sun Dec  6 18:08:41 2009
@@ -200,19 +200,16 @@
             return True
 
     def force_now(self, virtualizable):
-        token = virtualizable.vable_token
-        virtualizable.vable_token = self.TOKEN_NONE
-        if token == self.TOKEN_TRACING:
+        if virtualizable.vable_token == self.TOKEN_TRACING:
             # The values in the virtualizable are always correct during
             # tracing.  We only need to reset vable_token to TOKEN_NONE
             # as a marker for the tracing, to tell it that this
             # virtualizable escapes.
-            pass
+            virtualizable.vable_token = self.TOKEN_NONE
         else:
             from pypy.jit.metainterp.compile import ResumeGuardForcedDescr
-            faildescr = self.cpu.force(token)
-            assert isinstance(faildescr, ResumeGuardForcedDescr)
-            faildescr.force_virtualizable(self, virtualizable, token)
+            ResumeGuardForcedDescr.force_now(self.cpu, token)
+            assert virtualizable.vable_token == self.TOKEN_NONE
     force_now._dont_inline_ = True
 
 # ____________________________________________________________

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py	Sun Dec  6 18:08:41 2009
@@ -4,7 +4,7 @@
 from pypy.jit.metainterp import history
 
 
-def replace_force_virtual_with_call(make_helper_func, graphs):
+def replace_force_virtual_with_call(warmrunnerdesc, graphs):
     # similar to rvirtualizable2.replace_force_virtualizable_with_call().
     c_funcptr = None
     count = 0
@@ -15,18 +15,14 @@
                     # first compute c_funcptr, but only if there is any
                     # 'jit_force_virtual' around
                     if c_funcptr is None:
-                        FUNC = lltype.FuncType([rclass.OBJECTPTR],
-                                               rclass.OBJECTPTR)
-                        funcptr = make_helper_func(
-                            lltype.Ptr(FUNC),
-                            force_virtual_if_necessary)
-                        c_funcptr = inputconst(lltype.typeOf(funcptr), funcptr)
+                        c_funcptr = get_force_virtual_fnptr(warmrunnerdesc)
                     #
                     op.opname = 'direct_call'
                     op.args = [c_funcptr, op.args[0]]
                     count += 1
     if c_funcptr is not None:
-        log("replaced %d 'jit_force_virtual' with %r" % (count, funcptr))
+        log("replaced %d 'jit_force_virtual' with %r" % (count,
+                                                         c_funcptr.value))
 
 # ____________________________________________________________
 
@@ -35,6 +31,7 @@
 JIT_VIRTUAL_REF = lltype.GcStruct('JitVirtualRef',
                                   ('super', rclass.OBJECT),
                                   ('virtual_token', lltype.Signed),
+                                  ('virtualref_index', lltype.Signed),
                                   ('forced', rclass.OBJECTPTR))
 jit_virtual_ref_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True,
                                        flavor='raw')
@@ -58,6 +55,10 @@
     return cpu.fielddescrof(JIT_VIRTUAL_REF, 'virtual_token')
 
 @specialize.memo()
+def get_descr_virtualref_index(cpu):
+    return cpu.fielddescrof(JIT_VIRTUAL_REF, 'virtualref_index')
+
+ at specialize.memo()
 def get_descr_forced(cpu):
     return cpu.fielddescrof(JIT_VIRTUAL_REF, 'forced')
 
@@ -74,17 +75,45 @@
     vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
     return vref.virtual_token != TOKEN_TRACING
 
+def forced_single_vref(gcref, real_object):
+    assert real_object
+    vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
+    assert (vref.virtual_token != TOKEN_NONE and
+            vref.virtual_token != TOKEN_TRACING)
+    vref.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
+    vref.virtual_token = TOKEN_NONE
+
 # ____________________________________________________________
 
-def force_virtual_if_necessary(inst):
-    if not inst or inst.typeptr != jit_virtual_ref_vtable:
-        return inst    # common, fast case
-    return force_virtual(inst)
+def get_force_virtual_fnptr(warmrunnerdesc):
+    cpu = warmrunnerdesc.cpu
+    #
+    def force_virtual_if_necessary(inst):
+        if not inst or inst.typeptr != jit_virtual_ref_vtable:
+            return inst    # common, fast case
+        return force_virtual(cpu, inst)
+    #
+    FUNC = lltype.FuncType([rclass.OBJECTPTR], rclass.OBJECTPTR)
+    funcptr = warmrunnerdesc.helper_func(
+        lltype.Ptr(FUNC),
+        force_virtual_if_necessary)
+    return inputconst(lltype.typeOf(funcptr), funcptr)
 
-def force_virtual(inst):
+def force_virtual(cpu, inst):
     vref = lltype.cast_pointer(lltype.Ptr(JIT_VIRTUAL_REF), inst)
-    if not vref.forced:
-        xxxx
-    vref.virtual_token = TOKEN_NONE
+    token = vref.virtual_token
+    if token != TOKEN_NONE:
+        if token == TOKEN_TRACING:
+            # The "virtual" is not a virtual at all during tracing.
+            # We only need to reset virtual_token to TOKEN_NONE
+            # as a marker for the tracing, to tell it that this
+            # "virtual" escapes.
+            vref.virtual_token = TOKEN_NONE
+        else:
+            assert not vref.forced
+            from pypy.jit.metainterp.compile import ResumeGuardForcedDescr
+            ResumeGuardForcedDescr.force_now(cpu, token)
+            assert vref.virtual_token == TOKEN_NONE
+    assert vref.forced
     return vref.forced
 force_virtual._dont_inline_ = True

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/warmspot.py	Sun Dec  6 18:08:41 2009
@@ -604,8 +604,7 @@
         if self.cpu.ts.name != 'lltype':
             py.test.skip("rewrite_force_virtual: port it to ootype")
         all_graphs = self.translator.graphs
-        virtualref.replace_force_virtual_with_call(self.helper_func,
-                                                   all_graphs)
+        virtualref.replace_force_virtual_with_call(self, all_graphs)
 
 
 def decode_hp_hint_args(op):



More information about the Pypy-commit mailing list