[pypy-svn] r79249 - in pypy/branch/jit-free/pypy/jit: backend backend/llgraph backend/test backend/x86 backend/x86/test metainterp

arigo at codespeak.net arigo at codespeak.net
Thu Nov 18 14:55:51 CET 2010


Author: arigo
Date: Thu Nov 18 14:55:49 2010
New Revision: 79249

Modified:
   pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py
   pypy/branch/jit-free/pypy/jit/backend/model.py
   pypy/branch/jit-free/pypy/jit/backend/test/runner_test.py
   pypy/branch/jit-free/pypy/jit/backend/x86/assembler.py
   pypy/branch/jit-free/pypy/jit/backend/x86/test/test_runner.py
   pypy/branch/jit-free/pypy/jit/metainterp/compile.py
   pypy/branch/jit-free/pypy/jit/metainterp/history.py
   pypy/branch/jit-free/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/jit-free/pypy/jit/metainterp/warmspot.py
   pypy/branch/jit-free/pypy/jit/metainterp/warmstate.py
Log:
(antocuni, arigo)

Refactoring the LoopToken class to not have a __del__ any more.
Now the __del__ is on a small class CompiledLoopToken that is
attached by the backend when compiling a new loop.  Solves the
issue of weakrefs to objects that have a __del__.


Modified: pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py	Thu Nov 18 14:55:49 2010
@@ -857,13 +857,13 @@
         global _last_exception
         loop_token = wref_loop_token()
         assert loop_token, "CALL_ASSEMBLER to a target that already died"
-        if hasattr(loop_token, '_llgraph_redirected'):
-            return self._do_call_assembler(loop_token._llgraph_redirected,
-                                           *args)
+        ctl = loop_token.compiled_loop_token
+        if hasattr(ctl, 'redirected'):
+            return self._do_call_assembler(ctl.redirected, *args)
         assert not self._forced
         self._may_force = self.opindex
         try:
-            inpargs = _from_opaque(loop_token._llgraph_compiled_version).inputargs
+            inpargs = _from_opaque(ctl.compiled_version).inputargs
             for i, inparg in enumerate(inpargs):
                 TYPE = inparg.concretetype
                 if TYPE is lltype.Signed:
@@ -1556,11 +1556,13 @@
         do_setfield_gc_int(vable, fielddescr.ofs, 0)
 
 def redirect_call_assembler(cpu, oldlooptoken, newlooptoken):
-    OLD = _from_opaque(oldlooptoken._llgraph_compiled_version).getargtypes()
-    NEW = _from_opaque(newlooptoken._llgraph_compiled_version).getargtypes()
+    oldclt = oldlooptoken.compiled_loop_token
+    newclt = newlooptoken.compiled_loop_token
+    OLD = _from_opaque(oldclt.compiled_version).getargtypes()
+    NEW = _from_opaque(newclt.compiled_version).getargtypes()
     assert OLD == NEW
-    assert not hasattr(oldlooptoken, '_llgraph_redirected')
-    oldlooptoken._llgraph_redirected = weakref.ref(newlooptoken)
+    assert not hasattr(oldclt, 'redirected')
+    oldclt.redirected = weakref.ref(newlooptoken)
 
 # ____________________________________________________________
 

Modified: pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py	Thu Nov 18 14:55:49 2010
@@ -120,28 +120,30 @@
     def compile_bridge(self, faildescr, inputargs, operations,
                        original_loop_token, log=True):
         c = llimpl.compile_start()
-        original_loop_token._llgraph_loop_and_bridges.append(c)
+        clt = original_loop_token.compiled_loop_token
+        clt.loop_and_bridges.append(c)
+        clt.bridges_count += 1
         self._compile_loop_or_bridge(c, inputargs, operations)
         old, oldindex = faildescr._compiled_fail
         llimpl.compile_redirect_fail(old, oldindex, c)
 
-    def compile_loop(self, inputargs, operations, loopdescr, log=True):
+    def compile_loop(self, inputargs, operations, looptoken, log=True):
         """In a real assembler backend, this should assemble the given
         list of operations.  Here we just generate a similar CompiledLoop
         instance.  The code here is RPython, whereas the code in llimpl
         is not.
         """
         c = llimpl.compile_start()
-        if not we_are_translated():
-            assert not hasattr(loopdescr, '_llgraph_loop_and_bridges')
-        loopdescr._llgraph_loop_and_bridges = [c]
-        loopdescr._llgraph_compiled_version = c
+        clt = model.CompiledLoopToken(self, looptoken.number)
+        clt.loop_and_bridges = [c]
+        clt.compiled_version = c
+        looptoken.compiled_loop_token = clt
         self._compile_loop_or_bridge(c, inputargs, operations)
 
-    def free_loop_and_bridges(self, looptoken):
-        for c in looptoken._llgraph_loop_and_bridges:
+    def free_loop_and_bridges(self, compiled_loop_token):
+        for c in compiled_loop_token.loop_and_bridges:
             llimpl.mark_as_free(c)
-        model.AbstractCPU.free_loop_and_bridges(self, looptoken)
+        model.AbstractCPU.free_loop_and_bridges(self, compiled_loop_token)
 
     def _compile_loop_or_bridge(self, c, inputargs, operations):
         var2index = {}
@@ -216,7 +218,7 @@
         if op.getopnum() == rop.JUMP:
             targettoken = op.getdescr()
             assert isinstance(targettoken, history.LoopToken)
-            compiled_version = targettoken._llgraph_compiled_version
+            compiled_version = targettoken.compiled_loop_token.compiled_version
             llimpl.compile_add_jump_target(c, compiled_version)
         elif op.getopnum() == rop.FINISH:
             faildescr = op.getdescr()
@@ -226,7 +228,7 @@
             assert False, "unknown operation"
 
     def _execute_token(self, loop_token):
-        compiled_version = loop_token._llgraph_compiled_version
+        compiled_version = loop_token.compiled_loop_token.compiled_version
         frame = llimpl.new_frame(self.is_oo, self)
         # setup the frame
         llimpl.frame_clear(frame, compiled_version)

Modified: pypy/branch/jit-free/pypy/jit/backend/model.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/model.py	(original)
+++ pypy/branch/jit-free/pypy/jit/backend/model.py	Thu Nov 18 14:55:49 2010
@@ -1,3 +1,4 @@
+from pypy.rlib.debug import debug_start, debug_print, debug_stop
 from pypy.jit.metainterp import history, compile
 
 
@@ -41,8 +42,9 @@
 
     def compile_loop(self, inputargs, operations, looptoken, log=True):
         """Assemble the given loop.
-        Extra attributes should be put in the LoopToken to
-        point to the compiled loop in assembler.
+        Should create and attach a fresh CompiledLoopToken to
+        looptoken.compiled_loop_token and stick extra attributes
+        on it to point to the compiled loop in assembler.
         """
         raise NotImplementedError
 
@@ -120,7 +122,7 @@
         oldlooptoken so that from now own they will call newlooptoken."""
         raise NotImplementedError
 
-    def free_loop_and_bridges(self, looptoken):
+    def free_loop_and_bridges(self, compiled_loop_token):
         """This method is called to free resources (machine code,
         references to resume guards, etc.) allocated by the compilation
         of a loop and all bridges attached to it.  After this call, the
@@ -133,10 +135,10 @@
         # resume descrs are the largest consumers of memory (about 3x
         # more than the assembler, in the case of the x86 backend).
         lst = self.fail_descr_list
-        for n in looptoken.faildescr_indices:
+        for n in compiled_loop_token.faildescr_indices:
             lst[n] = None
-        self.fail_descr_free_list.extend(looptoken.faildescr_indices)
-        # We expect 'looptoken' to be itself garbage-collected soon.
+        self.fail_descr_free_list.extend(compiled_loop_token.faildescr_indices)
+        # We expect 'compiled_loop_token' to be itself garbage-collected soon.
 
     @staticmethod
     def sizeof(S):
@@ -262,3 +264,24 @@
 
     def force(self, force_token):
         raise NotImplementedError
+
+
+class CompiledLoopToken(object):
+    def __init__(self, cpu, number):
+        self.cpu = cpu
+        self.number = number
+        self.bridges_count = 0
+        # This growing list gives the 'descr_number' of all fail descrs
+        # that belong to this loop or to a bridge attached to it.
+        # Filled by the frontend calling record_faildescr_index().
+        self.faildescr_indices = []
+
+    def record_faildescr_index(self, n):
+        self.faildescr_indices.append(n)
+
+    def __del__(self):
+        debug_start("jit-free-looptoken")
+        debug_print("Freeing loop #", self.number, 'with',
+                    self.bridges_count, 'attached bridges')
+        self.cpu.free_loop_and_bridges(self)
+        debug_stop("jit-free-looptoken")

Modified: pypy/branch/jit-free/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/jit-free/pypy/jit/backend/test/runner_test.py	Thu Nov 18 14:55:49 2010
@@ -199,7 +199,7 @@
         ]
         bridge[1].setfailargs([i1b])
 
-        self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
+        self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken)
 
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
@@ -233,7 +233,7 @@
         ]
         bridge[1].setfailargs([i1b])
 
-        self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
+        self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken)
 
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
@@ -1050,7 +1050,7 @@
             ResOperation(rop.JUMP, [f3] + fboxes2[1:], None, descr=looptoken),
         ]
 
-        self.cpu.compile_bridge(faildescr1, fboxes2, bridge)
+        self.cpu.compile_bridge(faildescr1, fboxes2, bridge, looptoken)
 
         for i in range(len(fboxes)):
             self.cpu.set_future_value_float(i, 13.5 + 6.73 * i)

Modified: pypy/branch/jit-free/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/jit-free/pypy/jit/backend/x86/assembler.py	Thu Nov 18 14:55:49 2010
@@ -7,6 +7,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
 from pypy.tool.uid import fixid
+from pypy.jit.backend.model import CompiledLoopToken
 from pypy.jit.backend.x86.regalloc import (RegAlloc, X86RegisterManager,
                                            X86XMMRegisterManager, get_ebp_ofs,
                                            _get_scale)
@@ -305,6 +306,8 @@
                _x86_arglocs
                _x86_debug_checksum
         """
+        looptoken.compiled_loop_token = CompiledLoopToken(self.cpu,
+                                                          looptoken.number)
         if not we_are_translated():
             # Arguments should be unique
             assert len(set(inputargs)) == len(inputargs)

Modified: pypy/branch/jit-free/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/x86/test/test_runner.py	(original)
+++ pypy/branch/jit-free/pypy/jit/backend/x86/test/test_runner.py	Thu Nov 18 14:55:49 2010
@@ -338,6 +338,7 @@
         faildescr1 = BasicFailDescr(1)
         faildescr2 = BasicFailDescr(2)
         looptoken = LoopToken()
+        looptoken.number = 17
         class FakeString(object):
             def __init__(self, val):
                 self.val = val
@@ -356,7 +357,7 @@
         operations[3].setfailargs([i1])
         self.cpu.compile_loop(inputargs, operations, looptoken)
         name, loopaddress, loopsize = agent.functions[0]
-        assert name == "Loop # 0: hello"
+        assert name == "Loop # 17: hello"
         assert loopaddress <= looptoken._x86_loop_code
         assert loopsize >= 40 # randomish number
 

Modified: pypy/branch/jit-free/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/compile.py	(original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/compile.py	Thu Nov 18 14:55:49 2010
@@ -42,8 +42,8 @@
     name = metainterp.staticdata.stats.name_for_new_loop()
     return TreeLoop(name)
 
-def make_loop_token(cpu, nb_args, jitdriver_sd):
-    loop_token = LoopToken(cpu)
+def make_loop_token(nb_args, jitdriver_sd):
+    loop_token = LoopToken()
     loop_token.specnodes = [prebuiltNotSpecNode] * nb_args
     loop_token.outermost_jitdriver_sd = jitdriver_sd
     return loop_token
@@ -61,8 +61,8 @@
         if isinstance(descr, ResumeDescr):
             descr.wref_original_loop_token = wref   # stick it there
             n = descr.index
-            if n >= 0:       # we also record the resumedescr in this list
-                looptoken.faildescr_indices.append(n)
+            if n >= 0:       # we also record the resumedescr number
+                looptoken.compiled_loop_token.record_faildescr_index(n)
         elif isinstance(descr, LoopToken):
             # for a JUMP or a CALL_ASSEMBLER: record it as a potential jump.
             # (the following test is not enough to prevent more complicated
@@ -89,9 +89,8 @@
     h_ops = history.operations
     loop.operations = [h_ops[i].clone() for i in range(start, len(h_ops))]
     metainterp_sd = metainterp.staticdata
-    cpu = metainterp.cpu
     jitdriver_sd = metainterp.jitdriver_sd
-    loop_token = make_loop_token(cpu, len(loop.inputargs), jitdriver_sd)
+    loop_token = make_loop_token(len(loop.inputargs), jitdriver_sd)
     loop.token = loop_token
     loop.operations[-1].setdescr(loop_token)     # patch the target of the JUMP
     try:
@@ -155,7 +154,6 @@
     if not we_are_translated():
         show_loop(metainterp_sd)
         TreeLoop.check_consistency_of(inputargs, operations)
-    original_loop_token.bridges_count += 1
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
     try:
@@ -512,12 +510,11 @@
         # a loop at all but ends in a jump to the target loop.  It starts
         # with completely unoptimized arguments, as in the interpreter.
         metainterp_sd = metainterp.staticdata
-        cpu = metainterp.cpu
         jitdriver_sd = metainterp.jitdriver_sd
         redargs = new_loop.inputargs
         # We make a new LoopToken for this entry bridge, and stick it
         # to every guard in the loop.
-        new_loop_token = make_loop_token(cpu, len(redargs), jitdriver_sd)
+        new_loop_token = make_loop_token(len(redargs), jitdriver_sd)
         new_loop.token = new_loop_token
         send_loop_to_backend(metainterp_sd, new_loop, "entry bridge")
         # send the new_loop to warmspot.py, to be called directly the next time
@@ -601,7 +598,7 @@
     """
     # 'redboxes' is only used to know the types of red arguments.
     inputargs = [box.clonebox() for box in redboxes]
-    loop_token = make_loop_token(cpu, len(inputargs), jitdriver_sd)
+    loop_token = make_loop_token(len(inputargs), jitdriver_sd)
     # 'nb_red_args' might be smaller than len(redboxes),
     # because it doesn't include the virtualizable boxes.
     nb_red_args = jitdriver_sd.num_red_args

Modified: pypy/branch/jit-free/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/history.py	Thu Nov 18 14:55:49 2010
@@ -5,7 +5,6 @@
 from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic
 from pypy.rlib.objectmodel import compute_hash, compute_unique_id
 from pypy.rlib.rarithmetic import intmask, r_longlong
-from pypy.rlib.debug import debug_start, debug_print, debug_stop
 from pypy.tool.uid import uid
 from pypy.conftest import option
 
@@ -731,40 +730,28 @@
     outermost_jitdriver_sd = None
     # specnodes = ...
     # and more data specified by the backend when the loop is compiled
-    cpu = None
     number = -1
     generation = r_longlong(0)
-    bridges_count = 0
+    # one purpose of LoopToken is to keep alive the CompiledLoopToken
+    # returned by the backend.  When the LoopToken goes away, the
+    # CompiledLoopToken has its __del__ called, which frees the assembler
+    # memory and the ResumeGuards.
+    compiled_loop_token = None
 
-    def __init__(self, cpu=None):
-        self.cpu = cpu
-        # See get_fail_descr_number() in backend/model.py: this growing
-        # list gives the 'descr_number' of all fail descrs that belong to
-        # this loop or to a bridge attached to it.
-        self.faildescr_indices = []
+    def __init__(self):
         # For memory management of assembled loops
         self._keepalive_target_looktokens = {}      # set of other LoopTokens
 
     def record_jump_to(self, target_loop_token):
         self._keepalive_target_looktokens[target_loop_token] = None
 
-    def __del__(self):
-        if self.generation > r_longlong(0):
-            # MemoryManager.keep_loop_alive() has been called on this
-            # loop token, which means that it has been successfully
-            # compiled by the backend.  Free it now.
-            debug_start("jit-free-looptoken")
-            debug_print("Freeing loop #", self.number, 'with',
-                        self.bridges_count, 'attached bridges')
-            self.cpu.free_loop_and_bridges(self)
-            debug_stop("jit-free-looptoken")
-
     def __repr__(self):
         return '<Loop %d, gen=%d>' % (self.number, self.generation)
 
     def repr_of_descr(self):
         return '<Loop%d>' % self.number
 
+
 class TreeLoop(object):
     inputargs = None
     operations = None

Modified: pypy/branch/jit-free/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/pyjitpl.py	Thu Nov 18 14:55:49 2010
@@ -1,4 +1,4 @@
-import py, os, sys, weakref
+import py, os, sys
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.unroll import unrolling_iterable

Modified: pypy/branch/jit-free/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/warmspot.py	Thu Nov 18 14:55:49 2010
@@ -816,10 +816,6 @@
     # ____________________________________________________________
 
     def execute_token(self, loop_token):
-        self.metainterp_sd.profiler.start_running()
-        debug_start("jit-running")
         fail_descr = self.cpu.execute_token(loop_token)
-        debug_stop("jit-running")
-        self.metainterp_sd.profiler.end_running()
         self.memory_manager.keep_loop_alive(loop_token)
         return fail_descr

Modified: pypy/branch/jit-free/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/warmstate.py	(original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/warmstate.py	Thu Nov 18 14:55:49 2010
@@ -344,7 +344,11 @@
 
             # ---------- execute assembler ----------
             while True:     # until interrupted by an exception
+                metainterp_sd.profiler.start_running()
+                debug_start("jit-running")
                 fail_descr = warmrunnerdesc.execute_token(loop_token)
+                debug_stop("jit-running")
+                metainterp_sd.profiler.end_running()
                 loop_token = None     # for test_memmgr
                 if vinfo is not None:
                     vinfo.reset_vable_token(virtualizable)



More information about the Pypy-commit mailing list