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

arigo at codespeak.net arigo at codespeak.net
Thu Dec 3 23:55:10 CET 2009


Author: arigo
Date: Thu Dec  3 23:55:09 2009
New Revision: 69884

Added:
   pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py   (contents, props changed)
Modified:
   pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.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/warmspot.py
Log:
Support for virtual_ref(), step 2: implement a logic that seems a bit
more correct now.  It allows us to at least detect during tracing when
some place forces a virtual, and give up tracing.



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	Thu Dec  3 23:55:09 2009
@@ -5,7 +5,7 @@
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
 
-from pypy.jit.metainterp import history, compile, resume
+from pypy.jit.metainterp import history, compile, resume, vref
 from pypy.jit.metainterp.history import Const, ConstInt, Box
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp import codewriter, executor
@@ -238,7 +238,7 @@
     for _opimpl in ['int_is_true', 'int_neg', 'int_invert', 'bool_not',
                     'cast_ptr_to_int', 'cast_float_to_int',
                     'cast_int_to_float', 'float_neg', 'float_abs',
-                    'float_is_true', 'virtual_ref',
+                    'float_is_true',
                     ]:
         exec py.code.Source('''
             @arguments("box")
@@ -886,6 +886,14 @@
         return self.metainterp.finishframe_exception(self.exception_box,
                                                      self.exc_value_box)
 
+    @arguments("box")
+    def opimpl_virtual_ref(self, box):
+        obj = box.getref_base()
+        res = vref.virtual_ref_during_tracing(self.metainterp, obj)
+        resbox = history.BoxPtr(res)
+        self.metainterp.history.record(rop.VIRTUAL_REF, [box], resbox)
+        self.make_result_box(resbox)
+
     # ------------------------------
 
     def setup_call(self, argboxes):
@@ -994,6 +1002,7 @@
             # xxx do something about code duplication
             resbox = self.metainterp.execute_and_record_varargs(
                 rop.CALL_MAY_FORCE, argboxes, descr=descr)
+            self.metainterp.virtual_after_residual_call()
             self.metainterp.vable_after_residual_call()
             if resbox is not None:
                 self.make_result_box(resbox)
@@ -1194,6 +1203,7 @@
 class MetaInterp(object):
     in_recursion = 0
     _already_allocated_resume_virtuals = None
+    _force_token_mem = None
 
     def __init__(self, staticdata):
         self.staticdata = staticdata
@@ -1755,6 +1765,15 @@
         if vable_escapes:
             self.load_fields_from_virtualizable()
 
+    def virtual_after_residual_call(self):
+        if self.is_blackholing() or not vref.was_forced(self):
+            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
+        # assembler from there, we will get assembler that probably always
+        # forces a vref.  So we just cancel now.
+        self.switch_to_blackhole()
+
     def handle_exception(self):
         etype = self.cpu.get_exception()
         evalue = self.cpu.get_exc_value()

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py	Thu Dec  3 23:55:09 2009
@@ -944,9 +944,11 @@
                     for block, op in graph.iterblockops()
                         if op.opname == 'direct_call']
 
-        assert direct_calls(f_graph) == ['__init__', 'force_if_necessary', 'll_portal_runner']
-        assert direct_calls(portal_graph) == ['force_if_necessary', 'maybe_enter_jit']
-
+        assert direct_calls(f_graph) == ['__init__',
+                                         'force_virtualizable_if_necessary',
+                                         'll_portal_runner']
+        assert direct_calls(portal_graph)==['force_virtualizable_if_necessary',
+                                            'maybe_enter_jit']
         assert direct_calls(init_graph) == []
 
     def test_virtual_child_frame(self):

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	Thu Dec  3 23:55:09 2009
@@ -20,7 +20,36 @@
         self.interp_operations(f, [])
         self.check_operations_history(virtual_ref=1)
 
+    def test_make_vref_and_force(self):
+        jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
+        #
+        class X:
+            pass
+        class ExCtx:
+            pass
+        exctx = ExCtx()
+        #
+        @dont_look_inside
+        def force_me():
+            return exctx.topframeref().n
+        #
+        def f(n):
+            total = 0
+            while total < 300:
+                jitdriver.can_enter_jit(total=total, n=n)
+                jitdriver.jit_merge_point(total=total, n=n)
+                x = X()
+                x.n = n + 123
+                exctx.topframeref = virtual_ref(x)
+                total += force_me() - 100
+            return total
+        #
+        res = self.meta_interp(f, [-4])
+        assert res == 16 * 19
+        self.check_loops({})      # because we aborted tracing
+
     def test_simple_no_access(self):
+        py.test.skip("in-progress")
         myjitdriver = JitDriver(greens = [], reds = ['n'])
         #
         class XY:

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	Thu Dec  3 23:55:09 2009
@@ -153,15 +153,16 @@
 
     def finish(self):
         #
-        def force_if_necessary(virtualizable):
+        def force_virtualizable_if_necessary(virtualizable):
             if virtualizable.vable_token:
                 self.force_now(virtualizable)
-        force_if_necessary._always_inline_ = True
+        force_virtualizable_if_necessary._always_inline_ = True
         #
         all_graphs = self.warmrunnerdesc.translator.graphs
         ts = self.warmrunnerdesc.cpu.ts
         (_, FUNCPTR) = ts.get_FuncType([self.VTYPEPTR], lltype.Void)
-        funcptr = self.warmrunnerdesc.helper_func(FUNCPTR, force_if_necessary)
+        funcptr = self.warmrunnerdesc.helper_func(
+            FUNCPTR, force_virtualizable_if_necessary)
         rvirtualizable2.replace_force_virtualizable_with_call(
             all_graphs, self.VTYPEPTR, funcptr)
 

Added: pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py
==============================================================================
--- (empty file)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/vref.py	Thu Dec  3 23:55:09 2009
@@ -0,0 +1,74 @@
+from pypy.rpython.rmodel import inputconst, log
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass
+
+
+def replace_force_virtual_with_call(graphs, funcptr):
+    # 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)
+    count = 0
+    for graph in graphs:
+        for block in graph.iterblocks():
+            for op in block.operations:
+                if op.opname == 'jit_force_virtual':
+                    op.opname = 'direct_call'
+                    op.args = [c_funcptr, op.args[0]]
+                    count += 1
+    log("replaced %d 'jit_force_virtual' with %r" % (count, funcptr))
+
+# ____________________________________________________________
+
+
+# we make the low-level type of an RPython class directly
+JIT_VIRTUAL_REF = lltype.GcStruct('JitVirtualRef',
+                                  ('super', rclass.OBJECT),
+                                  ('force_token', llmemory.Address),
+                                  ('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')
+
+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):
+    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.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
+    assert vref.forced
+    return lltype.cast_opaque_ptr(llmemory.GCREF, vref)
+
+# ____________________________________________________________
+
+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 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
+    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	Thu Dec  3 23:55:09 2009
@@ -1,4 +1,4 @@
-import sys
+import sys, py
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\
@@ -17,7 +17,7 @@
 from pypy.translator.unsimplify import call_final_function
 
 from pypy.jit.metainterp import codewriter
-from pypy.jit.metainterp import support, history, pyjitpl, gc
+from pypy.jit.metainterp import support, history, pyjitpl, gc, vref
 from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp
 from pypy.jit.metainterp.policy import JitPolicy
 from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
@@ -177,6 +177,7 @@
                                           )
         self.rewrite_can_enter_jit()
         self.rewrite_set_param()
+        self.rewrite_force_virtual()
         self.add_profiler_finish()
         self.metainterp_sd.finish_setup(optimizer=optimizer)
 
@@ -599,6 +600,15 @@
             op.opname = 'direct_call'
             op.args[:3] = [closures[funcname]]
 
+    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)
+
 
 def decode_hp_hint_args(op):
     # Returns (list-of-green-vars, list-of-red-vars) without Voids.



More information about the Pypy-commit mailing list