[pypy-svn] pypy out-of-line-guards: * X86 support for invalidating call assembler

fijal commits-noreply at bitbucket.org
Sun Jan 2 15:08:18 CET 2011


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: out-of-line-guards
Changeset: r40324:c34c158d2b2f
Date: 2011-01-02 15:54 +0200
http://bitbucket.org/pypy/pypy/changeset/c34c158d2b2f/

Log:	* X86 support for invalidating call assembler
	* Clean up invalidating to support both jumps (that invalidate
	everything) and call_assemblers (that patch back to tmp_token)

diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -69,7 +69,8 @@
             # cases of cycles, but at least it helps in simple tests of
             # test_memgr.py)
             if descr is not looptoken:
-                looptoken.record_jump_to(descr)
+                looptoken.record_jump_to(descr,
+                                         op.getopnum() == rop.CALL_ASSEMBLER)
             op.setdescr(None)    # clear reference, mostly for tests
     # mostly for tests: make sure we don't keep a reference to the LoopToken
     loop.token = None

diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -491,22 +491,29 @@
     def get_invalidate_asm(self, TP, fieldname):
         def invalidate_asm(arg):
             next = getattr(arg, fieldname)
+            all = []
             while next:
-                prev = next
-                llx =  llmemory.weakref_deref(ropaque.ROPAQUE, prev.address)
+                llx = llmemory.weakref_deref(ropaque.ROPAQUE, next.address)
                 if llx:
-                    x = ropaque.cast_ropaque_to_obj(history.LoopToken, llx)
-                    x.invalidated = True
-                    compiled = x.compiled_loop_token.compiled_version
-                    llimpl.mark_as_invalid(compiled)
-                    for elem in x._back_looptokens:
-                        token = elem()
-                        if token:
-                            tk = token.compiled_loop_token.compiled_version
-                            llimpl.invalidate_call_asm(tk,
-                                                       x.compiled_loop_token)
-                                
+                    all.append(ropaque.cast_ropaque_to_obj(history.LoopToken,
+                                                           llx))
                 next = next.next
+
+            while all:
+                next = all.pop()
+                next.invalidated = True
+                compiled = next.compiled_loop_token.compiled_version
+                llimpl.mark_as_invalid(compiled)
+                for elem in next._back_looptokens_call_asm:
+                    token = elem()
+                    if token:
+                        tk = token.compiled_loop_token.compiled_version
+                        llimpl.invalidate_call_asm(tk,
+                                                   next.compiled_loop_token)
+                for elem in next._back_looptokens:
+                    elem = elem()
+                    if elem:
+                        all.append(elem)
         return invalidate_asm
 
 class OOtypeCPU_xxx_disabled(BaseCPU):

diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -749,11 +749,15 @@
         # For memory management of assembled loops
         self._keepalive_target_looktokens = {}      # set of other LoopTokens
         self._back_looptokens = []
+        self._back_looptokens_call_asm = []
         # the reverse of the _keepalive_target_looktokens dict
 
-    def record_jump_to(self, target_loop_token):
+    def record_jump_to(self, target_loop_token, is_call_asm=False):
         self._keepalive_target_looktokens[target_loop_token] = None
-        target_loop_token._back_looptokens.append(weakref.ref(self))
+        if is_call_asm:
+            target_loop_token._back_looptokens_call_asm.append(weakref.ref(self))
+        else:
+            target_loop_token._back_looptokens.append(weakref.ref(self))
 
     def __repr__(self):
         return '<Loop %d, gen=%d>' % (self.number, self.generation)

diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -435,6 +435,9 @@
     def consider_guard_no_exception(self, op):
         self.perform_guard(op, [], None)
 
+    def consider_guard_not_invalidated(self, op):
+        self.perform_guard(op, [], None)
+
     def consider_guard_exception(self, op):
         loc = self.rm.make_sure_var_in_reg(op.getarg(0))
         box = TempBox()

diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -2,6 +2,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib import ropaque
 from pypy.jit.metainterp import history, compile
 from pypy.jit.backend.x86.assembler import Assembler386
 from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS

diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -267,7 +267,7 @@
             # entry_loop_token is also kept alive by any loop that used
             # to point to old_token.  Actually freeing old_token early
             # is a pointless optimization (it is tiny).
-            old_token.record_jump_to(entry_loop_token)
+            old_token.record_jump_to(entry_loop_token, False)
 
     # ----------
 

diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -311,17 +311,10 @@
 
 def _invalidate_call_asm(from_loop, ctl):
     for op in from_loop.operations:
-        if op.opnum == rop.CALL_ASSEMBLER or op.opnum == rop.JUMP:
-            if op.descr is None:
-                continue
+        if op.opnum == rop.CALL_ASSEMBLER:
             call_target = op.descr().compiled_loop_token
             if call_target is ctl:
-                tmp = op.descr()._tmp_token.compiled_loop_token
-                if hasattr(call_target, 'redirected'):
-                    import pdb
-                    pdb.set_trace()
-                _redirect_call_assembler(call_target, tmp,
-                                         op.descr()._tmp_token)
+                op.descr = weakref.ref(op.descr()._tmp_token)
         if op.is_guard() and op.jump_target is not None:
             _invalidate_call_asm(op.jump_target, to_loop)
 

diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -130,6 +130,8 @@
         assert self.memcpy_addr != 0, "setup_once() not called?"
         self.pending_guard_tokens = []
         self.mc = codebuf.MachineCodeBlockWrapper()
+        self.invalidate_adr = rffi.cast(lltype.Signed,
+                                        looptoken._x86_asm_invalidated)
         if self.datablockwrapper is None:
             allblocks = self.get_asmmemmgr_blocks(looptoken)
             self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr,
@@ -140,6 +142,7 @@
         self.mc = None
         self.looppos = -1
         self.currently_compiling_loop = None
+        self.invalidate_adr = 0
 
     def finish_once(self):
         if self._debug:
@@ -216,6 +219,10 @@
             # Arguments should be unique
             assert len(set(inputargs)) == len(inputargs)
 
+        looptoken._x86_asm_invalidated = lltype.malloc(rffi.CArray(
+            lltype.Signed), 1, flavor='raw', track_allocation=False)
+        # XXX wrong, free it one day
+        looptoken._x86_asm_invalidated[0] = 0
         self.setup(looptoken)
         self.currently_compiling_loop = looptoken
         funcname = self._find_debug_merge_point(operations)
@@ -254,10 +261,6 @@
         looptoken._x86_bootstrap_code = rawstart + bootstrappos
         looptoken._x86_loop_code = rawstart + self.looppos
         looptoken._x86_direct_bootstrap_code = rawstart + directbootstrappos
-        looptoken._x86_asm_invalidated = lltype.malloc(rffi.CArray(
-            lltype.Signed), 1, flavor='raw', track_allocation=False)
-        # XXX wrong, free it one day
-        looptoken._x86_asm_invalidated[0] = 0
         self.teardown()
         # oprofile support
         if self.cpu.profile_agent is not None:
@@ -486,7 +489,7 @@
         if IS_X86_64:
             return self._assemble_bootstrap_direct_call_64(arglocs, jmppos, stackdepth)
         # XXX pushing ebx esi and edi is a bit pointless, since we store
-        #     all regsiters anyway, for the case of guard_not_forced
+        #     all registers anyway, for the case of guard_not_forced
         # XXX this can be improved greatly. Right now it'll behave like
         #     a normal call
         nonfloatlocs, floatlocs = arglocs
@@ -1275,6 +1278,11 @@
         #
         self.implement_guard(guard_token, 'NE')
 
+    def genop_guard_guard_not_invalidated(self, ign_1, guard_op, guard_token,
+                                          locs, ign_2):
+        self.mc.CMP(heap(self.invalidate_adr), imm0)
+        self.implement_guard(guard_token, 'NZ')
+
     def implement_guard_recovery(self, guard_opnum, faildescr, failargs,
                                                                fail_locs):
         exc = (guard_opnum == rop.GUARD_EXCEPTION or


More information about the Pypy-commit mailing list