[pypy-svn] r69897 - in pypy/branch/virtual-forcing/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Fri Dec 4 15:58:02 CET 2009


Author: arigo
Date: Fri Dec  4 15:58:01 2009
New Revision: 69897

Modified:
   pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_vref.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/warmspot.py
Log:
Small progress, clean-ups, unification of some concepts with
virtualizable.py.


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  4 15:58:01 2009
@@ -889,9 +889,16 @@
     @arguments("box")
     def opimpl_virtual_ref(self, box):
         obj = box.getref_base()
-        res = vref.virtual_ref_during_tracing(self.metainterp, obj)
+        res = vref.virtual_ref_during_tracing(obj)
+        self.metainterp.all_virtual_refs.append(res)
         resbox = history.BoxPtr(res)
         self.metainterp.history.record(rop.VIRTUAL_REF, [box], resbox)
+        # Note: we create a JIT_VIRTUAL_REF here, in order to detect when
+        # the virtual escapes during tracing already.  We record it as a
+        # VIRTUAL_REF operation, although the backend sees this operation
+        # as a no-op.  The point is that the backend should not really see
+        # it in practice, as optimizeopt.py should either kill it or
+        # replace it with a NEW_WITH_VTABLE followed by SETFIELD_GCs.
         self.make_result_box(resbox)
 
     # ------------------------------
@@ -1203,13 +1210,13 @@
 class MetaInterp(object):
     in_recursion = 0
     _already_allocated_resume_virtuals = None
-    _force_token_mem = None
 
     def __init__(self, staticdata):
         self.staticdata = staticdata
         self.cpu = staticdata.cpu
         self.portal_trace_positions = []
         self.greenkey_of_huge_function = None
+        self.all_virtual_refs = []
 
     def is_blackholing(self):
         return self.history is None
@@ -1766,7 +1773,12 @@
             self.load_fields_from_virtualizable()
 
     def virtual_after_residual_call(self):
-        if self.is_blackholing() or not vref.was_forced(self):
+        if self.is_blackholing():
+            return
+        for gcref in self.all_virtual_refs:
+            if vref.was_forced(gcref):
+                break
+        else:
             return
         # during tracing, more precisely during the CALL_MAY_FORCE, at least
         # one of the vrefs was read.  If we continue to trace and make

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_vref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_vref.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_vref.py	Fri Dec  4 15:58:01 2009
@@ -1,5 +1,6 @@
 import py
 from pypy.rlib.jit import JitDriver, dont_look_inside, virtual_ref
+from pypy.rlib.objectmodel import compute_unique_id
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 
 
@@ -59,7 +60,9 @@
         exctx = ExCtx()
         #
         @dont_look_inside
-        def externalfn():
+        def externalfn(n):
+            if n > 1000:
+                return compute_unique_id(exctx.topframeref())
             return 1
         #
         def f(n):
@@ -67,12 +70,14 @@
                 myjitdriver.can_enter_jit(n=n)
                 myjitdriver.jit_merge_point(n=n)
                 xy = XY()
+                xy.next1 = XY()
+                xy.next2 = XY()
                 exctx.topframeref = virtual_ref(xy)
-                n -= externalfn()
+                n -= externalfn(n)
                 exctx.topframeref = None
         #
         self.meta_interp(f, [15])
-        self.check_loops(new_with_vtable=0)
+        self.check_loops(new_with_vtable=1)     # the vref, not the XYs
 
     def test_simple_force_always(self):
         py.test.skip("in-progress")

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	Fri Dec  4 15:58:01 2009
@@ -11,8 +11,8 @@
 
 
 class VirtualizableInfo:
-    token_none    = 0
-    token_tracing = -1
+    TOKEN_NONE    = 0
+    TOKEN_TRACING = -1
 
     def __init__(self, warmrunnerdesc):
         self.warmrunnerdesc = warmrunnerdesc
@@ -177,7 +177,7 @@
         return rvirtualizable2.match_virtualizable_type(TYPE, self.VTYPEPTR)
 
     def reset_vable_token(self, virtualizable):
-        virtualizable.vable_token = self.token_none
+        virtualizable.vable_token = self.TOKEN_NONE
 
     def clear_vable_token(self, virtualizable):
         if virtualizable.vable_token:
@@ -186,14 +186,14 @@
 
     def tracing_before_residual_call(self, virtualizable):
         assert not virtualizable.vable_token
-        virtualizable.vable_token = self.token_tracing
+        virtualizable.vable_token = self.TOKEN_TRACING
 
     def tracing_after_residual_call(self, virtualizable):
         if virtualizable.vable_token:
             # not modified by the residual call; assert that it is still
             # set to 'tracing_vable_rti' and clear it.
-            assert virtualizable.vable_token == self.token_tracing
-            virtualizable.vable_token = self.token_none
+            assert virtualizable.vable_token == self.TOKEN_TRACING
+            virtualizable.vable_token = self.TOKEN_NONE
             return False
         else:
             # marker "modified during residual call" set.
@@ -201,10 +201,10 @@
 
     def force_now(self, virtualizable):
         token = virtualizable.vable_token
-        virtualizable.vable_token = self.token_none
-        if token == self.token_tracing:
+        virtualizable.vable_token = self.TOKEN_NONE
+        if token == self.TOKEN_TRACING:
             # The values in the virtualizable are always correct during
-            # tracing.  We only need to reset vable_token to token_none
+            # 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
@@ -220,11 +220,11 @@
 # The 'vable_token' field of a virtualizable is either 0, -1, or points
 # into the CPU stack to a particular field in the current frame.  It is:
 #
-#   1. 0 (token_none) if not in the JIT at all, except as described below.
+#   1. 0 (TOKEN_NONE) if not in the JIT at all, except as described below.
 #
 #   2. equal to 0 when tracing is in progress; except:
 #
-#   3. equal to -1 (token_tracing) during tracing when we do a residual call,
+#   3. equal to -1 (TOKEN_TRACING) during tracing when we do a residual call,
 #      calling random unknown other parts of the interpreter; it is
 #      reset to 0 as soon as something occurs to the virtualizable.
 #

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py	Fri Dec  4 15:58:01 2009
@@ -2,20 +2,29 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass
 
 
-def replace_force_virtual_with_call(graphs, funcptr):
+def replace_force_virtual_with_call(make_helper_func, graphs):
     # similar to rvirtualizable2.replace_force_virtualizable_with_call().
-    # funcptr should be an ll function pointer with a signature
-    # OBJECTPTR -> OBJECTPTR.
-    c_funcptr = inputconst(lltype.typeOf(funcptr), funcptr)
+    c_funcptr = None
     count = 0
     for graph in graphs:
         for block in graph.iterblocks():
             for op in block.operations:
                 if op.opname == 'jit_force_virtual':
+                    # 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)
+                    #
                     op.opname = 'direct_call'
                     op.args = [c_funcptr, op.args[0]]
                     count += 1
-    log("replaced %d 'jit_force_virtual' with %r" % (count, funcptr))
+    if c_funcptr is not None:
+        log("replaced %d 'jit_force_virtual' with %r" % (count, funcptr))
 
 # ____________________________________________________________
 
@@ -23,39 +32,32 @@
 # we make the low-level type of an RPython class directly
 JIT_VIRTUAL_REF = lltype.GcStruct('JitVirtualRef',
                                   ('super', rclass.OBJECT),
-                                  ('force_token', llmemory.Address),
+                                  ('virtual_token', lltype.Signed),
                                   ('forced', rclass.OBJECTPTR))
 jit_virtual_ref_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True,
                                        flavor='raw')
 
-class ForceTokenMem(object):
-    def __init__(self):
-        self.allocated = lltype.malloc(rffi.CArray(lltype.Signed), 1,
-                                       flavor='raw')
-        self.allocated[0] = 0
-
-    def __del__(self):
-        lltype.free(self.allocated, flavor='raw')
+# The 'virtual_token' field has the same meaning as the 'vable_token' field
+# of a virtualizable.  It is equal to:
+#   * -1 (TOKEN_TRACING) when tracing;
+#   * addr in the CPU stack (set by FORCE_TOKEN) when running the assembler;
+#   * 0 (TOKEN_NONE) after the virtual is forced, if it is forced at all.
+TOKEN_NONE    = 0
+TOKEN_TRACING = -1
 
-def get_force_token(metainterp):
-    if not metainterp._force_token_mem:
-        metainterp._force_token_mem = ForceTokenMem()
-    return llmemory.cast_ptr_to_adr(metainterp._force_token_mem.allocated)
-
-def was_forced(metainterp):
-    if not metainterp._force_token_mem:
-        return False
-    return metainterp._force_token_mem.allocated[0] == -1
-
-def virtual_ref_during_tracing(metainterp, real_object):
+def virtual_ref_during_tracing(real_object):
+    assert real_object
     vref = lltype.malloc(JIT_VIRTUAL_REF)
     p = lltype.cast_pointer(rclass.OBJECTPTR, vref)
     p.typeptr = jit_virtual_ref_vtable
-    vref.force_token = get_force_token(metainterp)
+    vref.virtual_token = TOKEN_TRACING
     vref.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
-    assert vref.forced
     return lltype.cast_opaque_ptr(llmemory.GCREF, vref)
 
+def was_forced(gcref):
+    vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
+    return vref.virtual_token != TOKEN_TRACING
+
 # ____________________________________________________________
 
 def force_virtual_if_necessary(inst):
@@ -65,10 +67,8 @@
 
 def force_virtual(inst):
     vref = lltype.cast_pointer(lltype.Ptr(JIT_VIRTUAL_REF), inst)
-    if vref.force_token:
-        if not vref.forced:
-            xxxx
-        vref.force_token.signed[0] = -1
-        vref.force_token = llmemory.NULL
+    if not vref.forced:
+        xxxx
+    vref.virtual_token = TOKEN_NONE
     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	Fri Dec  4 15:58:01 2009
@@ -603,11 +603,8 @@
     def rewrite_force_virtual(self):
         if self.cpu.ts.name != 'lltype':
             py.test.skip("rewrite_force_virtual: port it to ootype")
-        FUNC = lltype.FuncType([rclass.OBJECTPTR], rclass.OBJECTPTR)
-        funcptr = self.helper_func(lltype.Ptr(FUNC),
-                                   vref.force_virtual_if_necessary)
         all_graphs = self.translator.graphs
-        vref.replace_force_virtual_with_call(all_graphs, funcptr)
+        vref.replace_force_virtual_with_call(self.helper_func, all_graphs)
 
 
 def decode_hp_hint_args(op):



More information about the Pypy-commit mailing list