[pypy-svn] r75289 - in pypy/trunk/pypy/jit: backend backend/x86 metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Fri Jun 11 21:44:19 CEST 2010


Author: arigo
Date: Fri Jun 11 21:44:17 2010
New Revision: 75289

Modified:
   pypy/trunk/pypy/jit/backend/model.py
   pypy/trunk/pypy/jit/backend/x86/assembler.py
   pypy/trunk/pypy/jit/backend/x86/regalloc.py
   pypy/trunk/pypy/jit/metainterp/pyjitpl.py
   pypy/trunk/pypy/jit/metainterp/test/test_recursive.py
   pypy/trunk/pypy/jit/metainterp/virtualizable.py
   pypy/trunk/pypy/jit/metainterp/warmspot.py
Log:
Merge branch/jit-call-assembler: finish the handling of the fast path
in CALL_ASSEMBLER.  Also tests and fixes a bug: in the fast path, we
have to clear the vable_token of the virtualizable.


Modified: pypy/trunk/pypy/jit/backend/model.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/model.py	(original)
+++ pypy/trunk/pypy/jit/backend/model.py	Fri Jun 11 21:44:17 2010
@@ -7,7 +7,10 @@
     # assembler_helper_ptr - a pointer to helper to call after a direct
     #                        assembler call
     portal_calldescr = None
+    done_with_this_frame_void_v = -1
     done_with_this_frame_int_v = -1
+    done_with_this_frame_ref_v = -1
+    done_with_this_frame_float_v = -1
 
     def __init__(self):
         self.fail_descr_list = []

Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/assembler.py	Fri Jun 11 21:44:17 2010
@@ -1364,28 +1364,79 @@
         descr = op.descr
         assert isinstance(descr, LoopToken)
         assert len(arglocs) - 2 == len(descr._x86_arglocs[0])
+        #
+        # Write a call to the direct_bootstrap_code of the target assembler
         self._emit_call(rel32(descr._x86_direct_bootstrap_code), arglocs, 2,
                         tmp=eax)
         mc = self._start_block()
-        mc.CMP(eax, imm(self.cpu.done_with_this_frame_int_v))
-        mc.JE(rel8_patched_later)
+        if op.result is None:
+            assert result_loc is None
+            value = self.cpu.done_with_this_frame_void_v
+        else:
+            kind = op.result.type
+            if kind == INT:
+                assert result_loc is eax
+                value = self.cpu.done_with_this_frame_int_v
+            elif kind == REF:
+                assert result_loc is eax
+                value = self.cpu.done_with_this_frame_ref_v
+            elif kind == FLOAT:
+                value = self.cpu.done_with_this_frame_float_v
+            else:
+                raise AssertionError(kind)
+        mc.CMP(eax, imm(value))
+        mc.JE(rel8_patched_later)    # goto B if we get 'done_with_this_frame'
         je_location = mc.get_relative_pos()
+        #
+        # Path A: use assembler_helper_adr
         self._emit_call(rel32(self.assembler_helper_adr), [eax, arglocs[1]], 0,
                         tmp=ecx, force_mc=True, mc=mc)
-        mc.JMP(rel8_patched_later)
+        if isinstance(result_loc, MODRM64):
+            mc.FSTP(result_loc)
+        #else: result_loc is already either eax or None, checked below
+        mc.JMP(rel8_patched_later)     # done
         jmp_location = mc.get_relative_pos()
+        #
+        # Path B: fast path.  Must load the return value, and reset the token
         offset = jmp_location - je_location
         assert 0 < offset <= 127
         mc.overwrite(je_location - 1, [chr(offset)])
-        mc.MOV(eax, heap(self.fail_boxes_int.get_addr_for_num(0)))
+        #
+        # Reset the vable token --- XXX really too much special logic here:-(
+        if self.cpu.index_of_virtualizable >= 0:
+            from pypy.jit.backend.llsupport.descr import BaseFieldDescr
+            fielddescr = self.cpu.vable_token_descr
+            assert isinstance(fielddescr, BaseFieldDescr)
+            ofs = fielddescr.offset
+            mc.MOV(eax, arglocs[1])
+            mc.MOV(addr_add(eax, imm(ofs)), imm(0))
+            # in the line above, TOKEN_NONE = 0
+        #
+        if op.result is not None:
+            # load the return value from fail_boxes_xxx[0]
+            kind = op.result.type
+            if kind == FLOAT:
+                xmmtmp = X86XMMRegisterManager.all_regs[0]
+                adr = self.fail_boxes_float.get_addr_for_num(0)
+                mc.MOVSD(xmmtmp, heap64(adr))
+                mc.MOVSD(result_loc, xmmtmp)
+            else:
+                assert result_loc is eax
+                if kind == INT:
+                    adr = self.fail_boxes_int.get_addr_for_num(0)
+                    mc.MOV(eax, heap(adr))
+                elif kind == REF:
+                    adr = self.fail_boxes_ptr.get_addr_for_num(0)
+                    mc.XOR(eax, eax)
+                    mc.XCHG(eax, heap(adr))
+                else:
+                    raise AssertionError(kind)
+        #
+        # Here we join Path A and Path B again
         offset = mc.get_relative_pos() - jmp_location
-        assert 0 < offset <= 127
+        assert 0 <= offset <= 127
         mc.overwrite(jmp_location - 1, [chr(offset)])
         self._stop_block()
-        if isinstance(result_loc, MODRM64):
-            self.mc.FSTP(result_loc)
-        else:
-            assert result_loc is eax or result_loc is None
         self.mc.CMP(mem(ebp, FORCE_INDEX_OFS), imm(0))
         return self.implement_guard(addr, self.mc.JL)
 

Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/regalloc.py	Fri Jun 11 21:44:17 2010
@@ -640,7 +640,7 @@
         portal_calldescr = self.assembler.cpu.portal_calldescr
         size = portal_calldescr.get_result_size(self.translate_support_code)
         vable_index = self.assembler.cpu.index_of_virtualizable
-        if vable_index != -1:
+        if vable_index >= 0:
             self.rm._sync_var(op.args[vable_index])
             vable = self.fm.loc(op.args[vable_index], 1)
         else:

Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py	Fri Jun 11 21:44:17 2010
@@ -1102,9 +1102,6 @@
         self._addr2name_values = []
 
         self.__dict__.update(compile.make_done_loop_tokens())
-        # store this information for fastpath of call_assembler
-        d = self.loop_tokens_done_with_this_frame_int[0].finishdescr
-        self.cpu.done_with_this_frame_int_v = self.cpu.get_fail_descr_number(d)
 
     def _freeze_(self):
         return True
@@ -1147,6 +1144,12 @@
         RESULT = codewriter.portal_graph.getreturnvar().concretetype
         self.result_type = history.getkind(RESULT)
         #
+        # store this information for fastpath of call_assembler
+        name = self.result_type
+        tokens = getattr(self, 'loop_tokens_done_with_this_frame_%s' % name)
+        num = self.cpu.get_fail_descr_number(tokens[0].finishdescr)
+        setattr(self.cpu, 'done_with_this_frame_%s_v' % name, num)
+        #
         warmrunnerdesc = self.warmrunnerdesc
         if warmrunnerdesc is not None:
             self.num_green_args = warmrunnerdesc.num_green_args

Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py	Fri Jun 11 21:44:17 2010
@@ -1,6 +1,7 @@
 import py
 from pypy.rlib.jit import JitDriver, we_are_jitted, OPTIMIZER_SIMPLE, hint
-from pypy.rlib.jit import unroll_safe
+from pypy.rlib.jit import unroll_safe, dont_look_inside
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 from pypy.jit.codewriter.policy import StopAtXPolicy
 from pypy.rpython.annlowlevel import hlstr
@@ -750,6 +751,60 @@
         res = self.meta_interp(main, [0], inline=True)
         assert res == main(0)
 
+    def test_directly_call_assembler_virtualizable_reset_token(self):
+        from pypy.rpython.lltypesystem import lltype
+        from pypy.rlib.debug import llinterpcall
+
+        class Thing(object):
+            def __init__(self, val):
+                self.val = val
+        
+        class Frame(object):
+            _virtualizable2_ = ['thing']
+        
+        driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
+                           virtualizables = ['frame'],
+                           get_printable_location = lambda codeno : str(codeno),
+                           can_inline = lambda codeno : False)
+
+        @dont_look_inside
+        def check_frame(subframe):
+            if we_are_translated():
+                llinterpcall(lltype.Void, check_ll_frame, subframe)
+        def check_ll_frame(ll_subframe):
+            # This is called with the low-level Struct that is the frame.
+            # Check that the vable_token was correctly reset to zero.
+            # Note that in order for that test to catch failures, it needs
+            # three levels of recursion: the vable_token of the subframe
+            # at the level 2 is set to a non-zero value when doing the
+            # call to the level 3 only.  This used to fail when the test
+            # is run via pypy.jit.backend.x86.test.test_recursive.
+            assert ll_subframe.vable_token == 0
+
+        def main(codeno):
+            frame = Frame()
+            frame.thing = Thing(0)
+            portal(codeno, frame)
+            return frame.thing.val
+
+        def portal(codeno, frame):
+            i = 0
+            while i < 5:
+                driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
+                driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
+                nextval = frame.thing.val
+                if codeno < 2:
+                    subframe = Frame()
+                    subframe.thing = Thing(nextval)
+                    nextval = portal(codeno + 1, subframe)
+                    check_frame(subframe)
+                frame.thing = Thing(nextval + 1)
+                i += 1
+            return frame.thing.val
+
+        res = self.meta_interp(main, [0], inline=True)
+        assert res == main(0)
+
     def test_directly_call_assembler_virtualizable_force(self):
         class Thing(object):
             def __init__(self, val):

Modified: pypy/trunk/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/virtualizable.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/virtualizable.py	Fri Jun 11 21:44:17 2010
@@ -11,7 +11,7 @@
 
 
 class VirtualizableInfo:
-    TOKEN_NONE            = 0
+    TOKEN_NONE            = 0      # must be 0 -- see also x86.call_assembler
     TOKEN_TRACING_RESCALL = -1
 
     def __init__(self, warmrunnerdesc):

Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/warmspot.py	Fri Jun 11 21:44:17 2010
@@ -604,8 +604,10 @@
         if vinfo is not None:
             self.cpu.index_of_virtualizable = (vinfo.index_of_virtualizable -
                                                self.num_green_args)
+            self.cpu.vable_token_descr = vinfo.vable_token_descr
         else:
             self.cpu.index_of_virtualizable = -1
+            self.cpu.vable_token_descr = None
 
         # ____________________________________________________________
         # Now mutate origportalgraph to end with a call to portal_runner_ptr



More information about the Pypy-commit mailing list