[pypy-svn] r69581 - in pypy/trunk/pypy: jit/backend jit/backend/cli jit/backend/llgraph jit/backend/llsupport jit/backend/test jit/backend/x86 jit/backend/x86/test jit/metainterp jit/metainterp/test objspace/std

arigo at codespeak.net arigo at codespeak.net
Tue Nov 24 15:35:33 CET 2009


Author: arigo
Date: Tue Nov 24 15:35:31 2009
New Revision: 69581

Added:
   pypy/trunk/pypy/jit/backend/test/test_model.py
      - copied unchanged from r69580, pypy/branch/shorter-guard-path-2/pypy/jit/backend/test/test_model.py
   pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py
      - copied unchanged from r69580, pypy/branch/shorter-guard-path-2/pypy/jit/backend/x86/test/test_assembler.py
Modified:
   pypy/trunk/pypy/jit/backend/cli/method.py
   pypy/trunk/pypy/jit/backend/cli/runner.py
   pypy/trunk/pypy/jit/backend/llgraph/runner.py
   pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
   pypy/trunk/pypy/jit/backend/model.py
   pypy/trunk/pypy/jit/backend/test/runner_test.py
   pypy/trunk/pypy/jit/backend/test/test_ll_random.py
   pypy/trunk/pypy/jit/backend/test/test_random.py
   pypy/trunk/pypy/jit/backend/x86/assembler.py
   pypy/trunk/pypy/jit/backend/x86/regalloc.py
   pypy/trunk/pypy/jit/backend/x86/ri386setup.py
   pypy/trunk/pypy/jit/backend/x86/runner.py
   pypy/trunk/pypy/jit/backend/x86/support.py
   pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py
   pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py
   pypy/trunk/pypy/jit/backend/x86/test/test_runner.py
   pypy/trunk/pypy/jit/metainterp/compile.py
   pypy/trunk/pypy/jit/metainterp/history.py
   pypy/trunk/pypy/jit/metainterp/logger.py
   pypy/trunk/pypy/jit/metainterp/pyjitpl.py
   pypy/trunk/pypy/jit/metainterp/test/test_compile.py
   pypy/trunk/pypy/jit/metainterp/test/test_logger.py
   pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py
   pypy/trunk/pypy/jit/metainterp/warmstate.py
   pypy/trunk/pypy/objspace/std/multimethod.py
Log:
Merge the branch shorter-guard-path:

 * Cancel a previous refactoring that moved
   the numbering of the guard descrs to the front-end.  Instead, move
   that counting to AbstractCPU.

 * Generate much shorter failure paths from the x86 backend:
   generate_quick_failure() writes just a jump to control code which
   can itself do the guard recovery by reading some byte-compressed
   data.

 * Guards in x86 don't need to store the attribute _x86_faillocs
   any more.

 * Improve the testing of "machine code block full".
   Although it is still a bit random, now it runs all
   runner tests a second time with a 1KB limit.


Modified: pypy/trunk/pypy/jit/backend/cli/method.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/cli/method.py	(original)
+++ pypy/trunk/pypy/jit/backend/cli/method.py	Tue Nov 24 15:35:31 2009
@@ -268,9 +268,6 @@
         try:
             return self.cpu.failing_ops.index(op)
         except ValueError:
-            descr = op.descr
-            assert isinstance(descr, history.AbstractFailDescr)            
-            descr.get_index()
             self.cpu.failing_ops.append(op)
             return len(self.cpu.failing_ops)-1
 

Modified: pypy/trunk/pypy/jit/backend/cli/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/cli/runner.py	(original)
+++ pypy/trunk/pypy/jit/backend/cli/runner.py	Tue Nov 24 15:35:31 2009
@@ -135,9 +135,7 @@
         func = cliloop.funcbox.holder.GetFunc()
         func(self.get_inputargs())
         op = self.failing_ops[self.inputargs.get_failed_op()]
-        descr = op.descr
-        assert isinstance(descr, AbstractFailDescr)
-        return descr.get_index()
+        return op.descr
         
     def set_future_value_int(self, index, intvalue):
         self.get_inputargs().set_int(index, intvalue)

Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/trunk/pypy/jit/backend/llgraph/runner.py	Tue Nov 24 15:35:31 2009
@@ -88,6 +88,7 @@
 
     def __init__(self, rtyper, stats=None, translate_support_code=False,
                  annmixlevel=None, gcdescr=None):
+        model.AbstractCPU.__init__(self)
         self.rtyper = rtyper
         self.translate_support_code = translate_support_code
         self.stats = stats or MiniStats()
@@ -167,7 +168,7 @@
             if op.is_guard():
                 faildescr = op.descr
                 assert isinstance(faildescr, history.AbstractFailDescr)
-                fail_index = faildescr.get_index()
+                fail_index = self.get_fail_descr_number(faildescr)
                 index = llimpl.compile_add_fail(c, fail_index)
                 faildescr._compiled_fail = c, index
                 for box in op.fail_args:
@@ -195,8 +196,7 @@
             llimpl.compile_add_jump_target(c, compiled_version)
         elif op.opnum == rop.FINISH:
             faildescr = op.descr
-            assert isinstance(faildescr, history.AbstractFailDescr)
-            index = faildescr.get_index()
+            index = self.get_fail_descr_number(faildescr)
             llimpl.compile_add_fail(c, index)
         else:
             assert False, "unknown operation"
@@ -213,7 +213,7 @@
         fail_index = llimpl.frame_execute(frame)
         # we hit a FAIL operation.
         self.latest_frame = frame
-        return fail_index
+        return self.get_fail_descr_from_number(fail_index)
 
     def set_future_value_int(self, index, intvalue):
         llimpl.set_future_value_int(index, intvalue)

Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py	(original)
+++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py	Tue Nov 24 15:35:31 2009
@@ -20,6 +20,7 @@
     def __init__(self, rtyper, stats, translate_support_code=False,
                  gcdescr=None):
         from pypy.jit.backend.llsupport.gc import get_ll_description
+        AbstractCPU.__init__(self)
         self.rtyper = rtyper
         self.stats = stats
         self.translate_support_code = translate_support_code
@@ -149,8 +150,8 @@
             on_leave_jitted_hook()
 
         def on_leave_jitted_save_exc():
-            on_leave_jitted_hook()
             save_exception()
+            on_leave_jitted_hook()
 
         self.on_leave_jitted_noexc = on_leave_jitted_noexc
         self.on_leave_jitted_save_exc = on_leave_jitted_save_exc

Modified: pypy/trunk/pypy/jit/backend/model.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/model.py	(original)
+++ pypy/trunk/pypy/jit/backend/model.py	Tue Nov 24 15:35:31 2009
@@ -1,6 +1,25 @@
+from pypy.jit.metainterp import history
+
+
 class AbstractCPU(object):
     supports_floats = False
 
+    def __init__(self):
+        self.fail_descr_list = []
+
+    def get_fail_descr_number(self, descr):
+        assert isinstance(descr, history.AbstractFailDescr)
+        n = descr.index
+        if n < 0:
+            lst = self.fail_descr_list
+            n = len(lst)
+            lst.append(descr)
+            descr.index = n
+        return n
+
+    def get_fail_descr_from_number(self, n):
+        return self.fail_descr_list[n]
+
     def set_class_sizes(self, class_sizes):
         self.class_sizes = class_sizes
 

Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/trunk/pypy/jit/backend/test/runner_test.py	Tue Nov 24 15:35:31 2009
@@ -39,7 +39,7 @@
             else:
                 raise NotImplementedError(box)
         res = self.cpu.execute_token(looptoken)
-        if res == operations[-1].descr.index:
+        if res is operations[-1].descr:
             self.guard_failed = False
         else:
             self.guard_failed = True
@@ -102,7 +102,7 @@
         fail = self.cpu.execute_token(looptoken)
         res = self.cpu.get_latest_value_int(0)
         assert res == 3        
-        assert fail == 1
+        assert fail.identifier == 1
 
     def test_compile_loop(self):
         i0 = BoxInt()
@@ -121,7 +121,7 @@
         self.cpu.compile_loop(inputargs, operations, looptoken)
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 2
+        assert fail.identifier == 2
         res = self.cpu.get_latest_value_int(0)
         assert res == 10
 
@@ -142,7 +142,7 @@
         self.cpu.compile_loop(inputargs, operations, looptoken)
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 2
+        assert fail.identifier == 2
         res = self.cpu.get_latest_value_int(2)
         assert res == 10
 
@@ -200,7 +200,7 @@
 
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 2
+        assert fail.identifier == 2
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
@@ -234,7 +234,7 @@
 
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 2
+        assert fail.identifier == 2
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
@@ -242,9 +242,9 @@
         i0 = BoxInt()
         class UntouchableFailDescr(AbstractFailDescr):
             def __setattr__(self, name, value):
+                if name == 'index':
+                    return AbstractFailDescr.__setattr__(self, name, value)
                 py.test.fail("finish descrs should not be touched")
-            def get_index(self):
-                return 7
         faildescr = UntouchableFailDescr() # to check that is not touched
         looptoken = LoopToken()
         operations = [
@@ -253,7 +253,7 @@
         self.cpu.compile_loop([i0], operations, looptoken)
         self.cpu.set_future_value_int(0, 99)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 7
+        assert fail is faildescr
         res = self.cpu.get_latest_value_int(0)
         assert res == 99
 
@@ -263,7 +263,7 @@
             ]
         self.cpu.compile_loop([], operations, looptoken)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 7
+        assert fail is faildescr
         res = self.cpu.get_latest_value_int(0)
         assert res == 42
 
@@ -273,7 +273,7 @@
             ]
         self.cpu.compile_loop([], operations, looptoken)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 7
+        assert fail is faildescr
 
     def test_execute_operations_in_env(self):
         cpu = self.cpu
@@ -357,9 +357,9 @@
                 self.cpu.set_future_value_int(1, y)
                 fail = self.cpu.execute_token(looptoken)
                 if (z == boom) ^ reversed:
-                    assert fail == 1
+                    assert fail.identifier == 1
                 else:
-                    assert fail == 2
+                    assert fail.identifier == 2
                 if z != boom:
                     assert self.cpu.get_latest_value_int(0) == z
                 assert not self.cpu.get_exception()
@@ -832,7 +832,7 @@
                     assert 0
             #
             fail = self.cpu.execute_token(looptoken)
-            assert fail == 15
+            assert fail.identifier == 15
             #
             dstvalues = values[:]
             for _ in range(11):
@@ -884,7 +884,7 @@
         for i in range(len(fboxes)):
             self.cpu.set_future_value_float(i, 13.5 + 6.73 * i)
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 2
+        assert fail.identifier == 2
         res = self.cpu.get_latest_value_float(0)
         assert res == 8.5
         for i in range(1, len(fboxes)):
@@ -935,7 +935,7 @@
                 assert 0
         #
         fail = self.cpu.execute_token(looptoken)
-        assert fail == 1
+        assert fail.identifier == 1
 
 
 class LLtypeBackendTest(BaseBackendTest):

Modified: pypy/trunk/pypy/jit/backend/test/test_ll_random.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/test/test_ll_random.py	(original)
+++ pypy/trunk/pypy/jit/backend/test/test_ll_random.py	Tue Nov 24 15:35:31 2009
@@ -4,6 +4,7 @@
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.metainterp.history import ConstInt, ConstPtr
 from pypy.jit.metainterp.history import ConstAddr, BoxPtr, BoxInt
+from pypy.jit.metainterp.history import BasicFailDescr
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.rarithmetic import intmask
 from pypy.rpython.llinterp import LLException
@@ -464,7 +465,7 @@
         descr = builder.cpu.calldescrof(TP, TP.ARGS, TP.RESULT)
         self.put(builder, args, descr)
         op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None,
-                          descr=builder.make_fail_descr())
+                          descr=BasicFailDescr())
         op.fail_args = fail_subset
         builder.loop.operations.append(op)
 
@@ -486,7 +487,7 @@
         _, vtableptr = builder.get_random_structure_type_and_vtable(r)
         exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu)
         op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(),
-                          descr=builder.make_fail_descr())
+                          descr=BasicFailDescr())
         op.fail_args = builder.subset_of_intvars(r)
         op._exc_box = None
         builder.should_fail_by = op
@@ -509,7 +510,7 @@
         assert builder.cpu.get_exception()
         builder.cpu.clear_exception()
         op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(),
-                          descr=builder.make_fail_descr())
+                          descr=BasicFailDescr())
         op.fail_args = fail_subset
         builder.loop.operations.append(op)
 
@@ -527,7 +528,7 @@
         assert builder.cpu.get_exception()
         builder.cpu.clear_exception()
         op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr(),
-                          descr=builder.make_fail_descr())
+                          descr=BasicFailDescr())
         op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu)
         op.fail_args = builder.subset_of_intvars(r)
         builder.should_fail_by = op
@@ -553,7 +554,7 @@
                 break
         other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu)
         op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr(),
-                          descr=builder.make_fail_descr())
+                          descr=BasicFailDescr())
         op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu)
         op.fail_args = builder.subset_of_intvars(r)
         builder.should_fail_by = op

Modified: pypy/trunk/pypy/jit/backend/test/test_random.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/test/test_random.py	(original)
+++ pypy/trunk/pypy/jit/backend/test/test_random.py	Tue Nov 24 15:35:31 2009
@@ -18,8 +18,6 @@
         self.operations = subops
 
 class OperationBuilder(object):
-    failnumbering = 0
-    
     def __init__(self, cpu, loop, vars):
         self.cpu = cpu
         self.loop = loop
@@ -36,12 +34,6 @@
         self.counter = 0
         assert len(self.intvars) == len(dict.fromkeys(self.intvars))
 
-    @classmethod
-    def make_fail_descr(cls):
-        descr = BasicFailDescr(cls.failnumbering)
-        cls.failnumbering += 1
-        return descr
-        
     def fork(self, cpu, loop, vars):
         fork = self.__class__(cpu, loop, vars)
         fork.prebuilt_ptr_consts = self.prebuilt_ptr_consts
@@ -282,7 +274,7 @@
             builder.intvars[:] = original_intvars
         else:
             op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None)
-        op.descr = builder.make_fail_descr()
+        op.descr = BasicFailDescr()
         op.fail_args = fail_subset
         builder.loop.operations.append(op)
 
@@ -343,7 +335,7 @@
     def produce_into(self, builder, r):
         op, passing = self.gen_guard(builder, r)
         builder.loop.operations.append(op)
-        op.descr = builder.make_fail_descr()
+        op.descr = BasicFailDescr()
         op.fail_args = builder.subset_of_intvars(r)
         if not passing:
             builder.should_fail_by = op
@@ -559,7 +551,7 @@
                 endvars.append(v)
         r.shuffle(endvars)
         loop.operations.append(ResOperation(rop.FINISH, endvars, None,
-                                            descr=BasicFailDescr(-2)))
+                                            descr=BasicFailDescr()))
         if builder.should_fail_by:
             self.should_fail_by = builder.should_fail_by
             self.guard_op = builder.guard_op
@@ -605,7 +597,7 @@
             else:
                 raise NotImplementedError(box)
         fail = cpu.execute_token(self.loop.token)
-        assert fail == self.should_fail_by.descr.index
+        assert fail is self.should_fail_by.descr
         for i, v in enumerate(self.get_fail_args()):
             if isinstance(v, (BoxFloat, ConstFloat)):
                 value = cpu.get_latest_value_float(i)
@@ -634,7 +626,7 @@
             else:
                 op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box],
                                   BoxPtr())
-            op.descr = self.builder.make_fail_descr()
+            op.descr = BasicFailDescr()
             op.fail_args = []
             return op
 

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	Tue Nov 24 15:35:31 2009
@@ -1,11 +1,12 @@
 import sys, os
 import ctypes
 from pypy.jit.backend.llsupport import symbolic
-from pypy.jit.metainterp.history import Const, Box, BoxPtr, REF, FLOAT
+from pypy.jit.metainterp.history import Const, Box, BoxPtr, INT, REF, FLOAT
 from pypy.jit.metainterp.history import AbstractFailDescr
 from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory
 from pypy.rpython.lltypesystem.rclass import OBJECT
 from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython.annlowlevel import llhelper
 from pypy.tool.uid import fixid
 from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, lower_byte,\
      X86RegisterManager, X86XMMRegisterManager, get_ebp_ofs
@@ -16,6 +17,7 @@
 from pypy.jit.backend.x86.support import NonmovableGrowableArrayFloat,\
      NonmovableGrowableArraySigned, NonmovableGrowableArrayGCREF,\
      CHUNK_SIZE
+from pypy.rlib.debug import debug_print
 
 # our calling convention - we pass first 6 args in registers
 # and the rest stays on the stack
@@ -33,11 +35,24 @@
     return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
 
 class MachineCodeBlockWrapper(object):
-    MC_SIZE = 1024*1024
+    MC_DEFAULT_SIZE = 1024*1024
 
-    def __init__(self):
+    def __init__(self, bigsize):
         self.old_mcs = [] # keepalive
-        self._mc = codebuf.MachineCodeBlock(self.MC_SIZE)
+        self.bigsize = bigsize
+        self._mc = codebuf.MachineCodeBlock(bigsize)
+
+    def bytes_free(self):
+        return self._mc._size - self._mc._pos
+
+    def make_new_mc(self):
+        new_mc = codebuf.MachineCodeBlock(self.bigsize)
+        debug_print('[new machine code block at', new_mc.tell(), ']')
+        self._mc.JMP(rel32(new_mc.tell()))
+        self._mc.done()
+        self.old_mcs.append(self._mc)
+        self._mc = new_mc
+    make_new_mc._dont_inline_ = True
 
     def tell(self):
         return self._mc.tell()
@@ -49,12 +64,8 @@
     def method(self, *args):
         # XXX er.... pretty random number, just to be sure
         #     not to write half-instruction
-        if self._mc._pos + 64 >= self._mc._size:
-            new_mc = codebuf.MachineCodeBlock(self.MC_SIZE)
-            self._mc.JMP(rel32(new_mc.tell()))
-            self._mc.done()
-            self.old_mcs.append(self._mc)
-            self._mc = new_mc
+        if self.bytes_free() < 64:
+            self.make_new_mc()
         getattr(self._mc, name)(*args)    
     method.func_name = name
     return method
@@ -66,7 +77,7 @@
 class Assembler386(object):
     mc = None
     mc2 = None
-    debug_markers = True
+    mc_size = MachineCodeBlockWrapper.MC_DEFAULT_SIZE
 
     def __init__(self, cpu, translate_support_code=False):
         self.cpu = cpu
@@ -79,11 +90,9 @@
         self.fail_boxes_int = NonmovableGrowableArraySigned()
         self.fail_boxes_ptr = NonmovableGrowableArrayGCREF()
         self.fail_boxes_float = NonmovableGrowableArrayFloat()
+        self.setup_failure_recovery()
 
     def leave_jitted_hook(self):
-        # XXX BIG FAT WARNING XXX
-        # At this point, we should not call anyone here, because
-        # RPython-level exception might be set. Here be dragons
         i = 0
         while i < self.fail_boxes_ptr.lgt:
             chunk = self.fail_boxes_ptr.chunks[i]
@@ -113,8 +122,13 @@
             # done
             # we generate the loop body in 'mc'
             # 'mc2' is for guard recovery code
-            self.mc = MachineCodeBlockWrapper()
-            self.mc2 = MachineCodeBlockWrapper()
+            self.mc = MachineCodeBlockWrapper(self.mc_size)
+            self.mc2 = MachineCodeBlockWrapper(self.mc_size)
+            self._build_failure_recovery(False)
+            self._build_failure_recovery(True)
+            if self.cpu.supports_floats:
+                self._build_failure_recovery(False, withfloats=True)
+                self._build_failure_recovery(True, withfloats=True)
 
     def assemble_loop(self, inputargs, operations, looptoken):
         """adds the following attributes to looptoken:
@@ -137,8 +151,12 @@
 
     def assemble_bridge(self, faildescr, inputargs, operations):
         self.make_sure_mc_exists()
+        arglocs = self.rebuild_faillocs_from_descr(
+            faildescr._x86_failure_recovery_bytecode)
+        if not we_are_translated():
+            assert ([loc.assembler() for loc in arglocs] ==
+                    [loc.assembler() for loc in faildescr._x86_debug_faillocs])
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
-        arglocs = faildescr._x86_faillocs
         fail_stack_depth = faildescr._x86_current_stack_depth
         regalloc.prepare_bridge(fail_stack_depth, inputargs, arglocs,
                                 operations)
@@ -150,9 +168,12 @@
             # for the benefit of tests
             faildescr._x86_bridge_stack_depth = stack_depth
         # patch the jump from original guard
+        self.patch_jump(faildescr, adr_bridge)
+
+    def patch_jump(self, faildescr, adr_new_target):
         adr_jump_offset = faildescr._x86_adr_jump_offset
         mc = codebuf.InMemoryCodeBuilder(adr_jump_offset, adr_jump_offset + 4)
-        mc.write(packimm32(adr_bridge - adr_jump_offset - 4))
+        mc.write(packimm32(adr_new_target - adr_jump_offset - 4))
         mc.valgrind_invalidated()
         mc.done()
 
@@ -734,59 +755,284 @@
         #
         return self.implement_guard(addr, self.mc.JNE)
 
-    def _no_const_locs(self, args):
-        """ assert that all args are actually Boxes
-        """
-        for arg in args:
-            assert arg is None or isinstance(arg, Box) # hole
-
     def implement_guard_recovery(self, guard_opnum, faildescr, failargs,
                                                                fail_locs):
-        self._no_const_locs(failargs)
-        addr = self.mc2.tell()
         exc = (guard_opnum == rop.GUARD_EXCEPTION or
                guard_opnum == rop.GUARD_NO_EXCEPTION)
-        faildescr._x86_faillocs = fail_locs
-        self.generate_failure(self.mc2, faildescr, failargs, fail_locs, exc)
+        return self.generate_quick_failure(faildescr, failargs, fail_locs, exc)
+
+    def generate_quick_failure(self, faildescr, failargs, fail_locs, exc):
+        """Generate the initial code for handling a failure.  We try to
+        keep it as compact as possible.  The idea is that this code is
+        executed at most once (and very often, zero times); when
+        executed, it generates a more complete piece of code which can
+        really handle recovery from this particular failure.
+        """
+        fail_index = self.cpu.get_fail_descr_number(faildescr)
+        bytes_needed = 20 + 5 * len(failargs)    # conservative estimate
+        if self.mc2.bytes_free() < bytes_needed:
+            self.mc2.make_new_mc()
+        mc = self.mc2._mc
+        addr = mc.tell()
+        withfloats = False
+        for box in failargs:
+            if box is not None and box.type == FLOAT:
+                withfloats = True
+                break
+        mc.CALL(rel32(self.failure_recovery_code[exc + 2 * withfloats]))
+        # write tight data that describes the failure recovery
+        faildescr._x86_failure_recovery_bytecode = mc.tell()
+        self.write_failure_recovery_description(mc, failargs, fail_locs)
+        # write the fail_index too
+        mc.write(packimm32(fail_index))
+        # for testing the decoding, write a final byte 0xCC
+        if not we_are_translated():
+            mc.writechr(0xCC)
+            faildescr._x86_debug_faillocs = [loc for loc in fail_locs
+                                                 if loc is not None]
         return addr
 
-    def generate_failure(self, mc, faildescr, failargs, locs, exc):
-        pos = mc.tell()
+    DESCR_REF       = 0x00
+    DESCR_INT       = 0x01
+    DESCR_FLOAT     = 0x02
+    DESCR_SPECIAL   = 0x03
+    DESCR_FROMSTACK = 8
+    DESCR_STOP      = 0 | DESCR_SPECIAL
+    DESCR_HOLE      = 4 | DESCR_SPECIAL
+
+    def write_failure_recovery_description(self, mc, failargs, locs):
         for i in range(len(failargs)):
             arg = failargs[i]
-            if arg is None: # hole
+            if arg is not None:
+                if arg.type == REF:
+                    kind = self.DESCR_REF
+                elif arg.type == INT:
+                    kind = self.DESCR_INT
+                elif arg.type == FLOAT:
+                    kind = self.DESCR_FLOAT
+                else:
+                    raise AssertionError("bogus kind")
+                loc = locs[i]
+                if isinstance(loc, MODRM):
+                    n = self.DESCR_FROMSTACK + loc.position
+                else:
+                    assert isinstance(loc, REG)
+                    n = loc.op
+                n = kind + 4*n
+                while n > 0x7F:
+                    mc.writechr((n & 0x7F) | 0x80)
+                    n >>= 7
+            else:
+                n = self.DESCR_HOLE
+            mc.writechr(n)
+        mc.writechr(self.DESCR_STOP)
+        # preallocate the fail_boxes
+        i = len(failargs) - 1
+        if i >= 0:
+            self.fail_boxes_int.get_addr_for_num(i)
+            self.fail_boxes_ptr.get_addr_for_num(i)
+            if self.cpu.supports_floats:
+                self.fail_boxes_float.get_addr_for_num(i)
+
+    def rebuild_faillocs_from_descr(self, bytecode):
+        from pypy.jit.backend.x86.regalloc import X86StackManager
+        bytecode = rffi.cast(rffi.UCHARP, bytecode)
+        arglocs = []
+        while 1:
+            # decode the next instruction from the bytecode
+            code = rffi.cast(lltype.Signed, bytecode[0])
+            bytecode = rffi.ptradd(bytecode, 1)
+            if code >= 4*self.DESCR_FROMSTACK:
+                # 'code' identifies a stack location
+                if code > 0x7F:
+                    shift = 7
+                    code &= 0x7F
+                    while True:
+                        nextcode = rffi.cast(lltype.Signed, bytecode[0])
+                        bytecode = rffi.ptradd(bytecode, 1)
+                        code |= (nextcode & 0x7F) << shift
+                        shift += 7
+                        if nextcode <= 0x7F:
+                            break
+                kind = code & 3
+                code = (code >> 2) - self.DESCR_FROMSTACK
+                if kind == self.DESCR_FLOAT:
+                    size = 2
+                else:
+                    size = 1
+                loc = X86StackManager.stack_pos(code, size)
+            elif code == self.DESCR_STOP:
+                break
+            elif code == self.DESCR_HOLE:
                 continue
+            else:
+                # 'code' identifies a register
+                kind = code & 3
+                code >>= 2
+                if kind == self.DESCR_FLOAT:
+                    loc = xmm_registers[code]
+                else:
+                    loc = registers[code]
+            arglocs.append(loc)
+        return arglocs[:]
+
+    def setup_failure_recovery(self):
+
+        def failure_recovery_func(registers):
+            # no malloc allowed here!!
+            # 'registers' is a pointer to a structure containing the
+            # original value of the registers, optionally the original
+            # value of XMM registers, and finally a reference to the
+            # recovery bytecode.  See _build_failure_recovery() for details.
+            stack_at_ebp = registers[ebp.op]
+            bytecode = rffi.cast(rffi.UCHARP, registers[8])
+            num = 0
+            value_hi = 0
+            while 1:
+                # decode the next instruction from the bytecode
+                code = rffi.cast(lltype.Signed, bytecode[0])
+                bytecode = rffi.ptradd(bytecode, 1)
+                if code >= 4*self.DESCR_FROMSTACK:
+                    if code > 0x7F:
+                        shift = 7
+                        code &= 0x7F
+                        while True:
+                            nextcode = rffi.cast(lltype.Signed, bytecode[0])
+                            bytecode = rffi.ptradd(bytecode, 1)
+                            code |= (nextcode & 0x7F) << shift
+                            shift += 7
+                            if nextcode <= 0x7F:
+                                break
+                    # load the value from the stack
+                    kind = code & 3
+                    code = (code >> 2) - self.DESCR_FROMSTACK
+                    stackloc = stack_at_ebp + get_ebp_ofs(code)
+                    value = rffi.cast(rffi.LONGP, stackloc)[0]
+                    if kind == self.DESCR_FLOAT:
+                        value_hi = value
+                        value = rffi.cast(rffi.LONGP, stackloc - 4)[0]
+                else:
+                    # 'code' identifies a register: load its value
+                    kind = code & 3
+                    if kind == self.DESCR_SPECIAL:
+                        if code == self.DESCR_HOLE:
+                            num += 1
+                            continue
+                        assert code == self.DESCR_STOP
+                        break
+                    code >>= 2
+                    if kind == self.DESCR_FLOAT:
+                        xmmregisters = rffi.ptradd(registers, -16)
+                        value = xmmregisters[2*code]
+                        value_hi = xmmregisters[2*code + 1]
+                    else:
+                        value = registers[code]
+
+                # store the loaded value into fail_boxes_<type>
+                if kind == self.DESCR_INT:
+                    tgt = self.fail_boxes_int.get_addr_for_num(num)
+                elif kind == self.DESCR_REF:
+                    tgt = self.fail_boxes_ptr.get_addr_for_num(num)
+                elif kind == self.DESCR_FLOAT:
+                    tgt = self.fail_boxes_float.get_addr_for_num(num)
+                    rffi.cast(rffi.LONGP, tgt)[1] = value_hi
+                else:
+                    assert 0, "bogus kind"
+                rffi.cast(rffi.LONGP, tgt)[0] = value
+                num += 1
+            #
+            if not we_are_translated():
+                assert bytecode[4] == 0xCC
+            fail_index = rffi.cast(rffi.LONGP, bytecode)[0]
+            return fail_index
+
+        self.failure_recovery_func = failure_recovery_func
+        self.failure_recovery_code = [0, 0, 0, 0]
+
+    _FAILURE_RECOVERY_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP],
+                                                        lltype.Signed))
+
+    def _build_failure_recovery(self, exc, withfloats=False):
+        failure_recovery_func = llhelper(self._FAILURE_RECOVERY_FUNC,
+                                         self.failure_recovery_func)
+        failure_recovery_func = rffi.cast(lltype.Signed,
+                                          failure_recovery_func)
+        mc = self.mc2._mc
+        # Assume that we are called at the beginning, when there is no risk
+        # that 'mc' runs out of space.  Checked by asserts in mc.write().
+        recovery_addr = mc.tell()
+        mc.PUSH(edi)
+        mc.PUSH(esi)
+        mc.PUSH(ebp)
+        mc.PUSH(esp)  # <-- not really used, but needed to take up the space
+        mc.PUSH(ebx)
+        mc.PUSH(edx)
+        mc.PUSH(ecx)
+        mc.PUSH(eax)
+        mc.MOV(esi, esp)
+        if withfloats:
+            mc.SUB(esp, imm(8*8))
+            for i in range(8):
+                mc.MOVSD(mem64(esp, 8*i), xmm_registers[i])
+
+        # we call a provided function that will
+        # - call our on_leave_jitted_hook which will mark
+        #   the fail_boxes_ptr array as pointing to young objects to
+        #   avoid unwarranted freeing
+        # - optionally save exception depending on the flag
+        addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
+        mc.CALL(rel32(addr))
+
+        # the following call saves all values from the stack and from
+        # registers to the right 'fail_boxes_<type>' location.
+        # Note that the registers are saved so far in esi[0] to esi[7],
+        # as pushed above, plus optionally in esi[-16] to esi[-1] for
+        # the XMM registers.  Moreover, esi[8] is a pointer to the recovery
+        # bytecode, pushed just before by the CALL instruction written by
+        # generate_quick_failure().
+        mc.PUSH(esi)
+        mc.CALL(rel32(failure_recovery_func))
+        # returns in eax the fail_index
+
+        # now we return from the complete frame, which starts from
+        # _assemble_bootstrap_code().  The LEA below throws away most
+        # of the frame, including all the PUSHes that we did just above.
+        mc.LEA(esp, addr_add(ebp, imm((-RET_BP + 2) * WORD)))
+        mc.POP(edi)
+        mc.POP(esi)
+        mc.POP(ebx)
+        mc.POP(ebp)
+        mc.RET()
+        self.mc2.done()
+        self.failure_recovery_code[exc + 2 * withfloats] = recovery_addr
+
+    def generate_failure(self, mc, fail_index, locs, exc, locs_are_ref):
+        for i in range(len(locs)):
             loc = locs[i]
             if isinstance(loc, REG):
-                if arg.type == FLOAT:
+                if loc.width == 8:
                     adr = self.fail_boxes_float.get_addr_for_num(i)
                     mc.MOVSD(heap64(adr), loc)
                 else:
-                    if arg.type == REF:
+                    if locs_are_ref[i]:
                         adr = self.fail_boxes_ptr.get_addr_for_num(i)
                     else:
                         adr = self.fail_boxes_int.get_addr_for_num(i)
                     mc.MOV(heap(adr), loc)
-        for i in range(len(failargs)):
-            arg = failargs[i]
-            if arg is None: # hole
-                continue
+        for i in range(len(locs)):
             loc = locs[i]
             if not isinstance(loc, REG):
-                if arg.type == FLOAT:
+                if loc.width == 8:
                     mc.MOVSD(xmm0, loc)
                     adr = self.fail_boxes_float.get_addr_for_num(i)
                     mc.MOVSD(heap64(adr), xmm0)
                 else:
-                    if arg.type == REF:
+                    if locs_are_ref[i]:
                         adr = self.fail_boxes_ptr.get_addr_for_num(i)
                     else:
                         adr = self.fail_boxes_int.get_addr_for_num(i)
                     mc.MOV(eax, loc)
                     mc.MOV(heap(adr), eax)
-        if self.debug_markers:
-            mc.MOV(eax, imm(pos))
-            mc.MOV(heap(self.fail_boxes_int.get_addr_for_num(len(locs))), eax)
 
         # we call a provided function that will
         # - call our on_leave_jitted_hook which will mark
@@ -798,9 +1044,7 @@
 
         # don't break the following code sequence!
         mc = mc._mc
-        mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD))
-        assert isinstance(faildescr, AbstractFailDescr)
-        fail_index = faildescr.get_index()
+        mc.LEA(esp, addr_add(ebp, imm((-RET_BP + 2) * WORD)))
         mc.MOV(eax, imm(fail_index))
         mc.POP(edi)
         mc.POP(esi)

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	Tue Nov 24 15:35:31 2009
@@ -397,8 +397,10 @@
 
     def consider_finish(self, op, ignored):
         locs = [self.loc(v) for v in op.args]
-        self.assembler.generate_failure(self.assembler.mc, op.descr, op.args,
-                                        locs, self.exc)
+        locs_are_ref = [v.type == REF for v in op.args]
+        fail_index = self.assembler.cpu.get_fail_descr_number(op.descr)
+        self.assembler.generate_failure(self.assembler.mc, fail_index, locs,
+                                        self.exc, locs_are_ref)
         self.possibly_free_vars(op.args)
 
     def consider_guard_no_exception(self, op, ignored):

Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/ri386setup.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/ri386setup.py	Tue Nov 24 15:35:31 2009
@@ -459,6 +459,13 @@
 SAHF = Instruction()
 SAHF.mode0(['\x9E'])
 
+LODSB = Instruction()
+LODSB.mode0(['\xAC'])
+
+LODSD = Instruction()
+LODSD.mode0(['\xAD'])
+LODSD.as_alias = "LODSL"
+
 # ------------------------- floating point instructions ------------------
 
 FLDL = Instruction()

Modified: pypy/trunk/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/runner.py	Tue Nov 24 15:35:31 2009
@@ -63,7 +63,7 @@
         addr = executable_token._x86_bootstrap_code
         func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr)
         fail_index = self._execute_call(func)
-        return fail_index
+        return self.get_fail_descr_from_number(fail_index)
 
     def _execute_call(self, func):
         # help flow objspace

Modified: pypy/trunk/pypy/jit/backend/x86/support.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/support.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/support.py	Tue Nov 24 15:35:31 2009
@@ -3,7 +3,8 @@
 from pypy.rlib import rgc
 from pypy.rlib.objectmodel import we_are_translated
 
-CHUNK_SIZE = 1000
+CHUNK_SIZE_BITS = 8
+CHUNK_SIZE = 1 << CHUNK_SIZE_BITS
 
 def new_nonmovable_growable_array(TP):
     ATP = lltype.GcArray(TP)
@@ -34,7 +35,7 @@
         def _no_of(self, i):
             while i >= len(self.chunks) * CHUNK_SIZE:
                 self._grow()
-            return i / CHUNK_SIZE, i % CHUNK_SIZE
+            return i >> CHUNK_SIZE_BITS, i & (CHUNK_SIZE-1)
         _no_of._always_inline_ = True
 
         def setitem(self, i, v):

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py	Tue Nov 24 15:35:31 2009
@@ -21,7 +21,7 @@
         bridge = self.attach_bridge(ops, loop, -2)
         self.cpu.set_future_value_int(0, 0)
         fail = self.run(loop)
-        assert fail == 2
+        assert fail.identifier == 2
         assert self.getint(0) == 21
     
     def test_compile_bridge_deeper(self):
@@ -52,7 +52,7 @@
         assert new > previous
         self.cpu.set_future_value_int(0, 0)
         fail = self.run(loop)
-        assert fail == 2
+        assert fail.identifier == 2
         assert self.getint(0) == 21
         assert self.getint(1) == 22
         assert self.getint(2) == 23
@@ -78,7 +78,7 @@
         bridge = self.attach_bridge(ops, other_loop, 0, looptoken=loop.token)
         self.cpu.set_future_value_int(0, 1)
         fail = self.run(other_loop)
-        assert fail == 1
+        assert fail.identifier == 1
 
     def test_bridge_jumps_to_self_deeper(self):
         loop = self.interpret('''

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py	Tue Nov 24 15:35:31 2009
@@ -92,7 +92,7 @@
     return [pick1(i386.memSIB64) for i in range(COUNT2)]
 
 def xmm_tests():
-    return i386.xmm_registers
+    return i386.xmm_registers[:]
 
 def modrm8_tests():
     return i386.registers8 + [pick1(i386.memSIB8) for i in range(COUNT2)]

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_runner.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_runner.py	Tue Nov 24 15:35:31 2009
@@ -260,7 +260,7 @@
                         self.cpu.set_future_value_int(0, b.value)
                     else:
                         self.cpu.set_future_value_ref(0, b.value)
-                    r = self.cpu.execute_token(looptoken)
+                    self.cpu.execute_token(looptoken)
                     result = self.cpu.get_latest_value_int(0)
                     if guard == rop.GUARD_FALSE:
                         assert result == execute(self.cpu, op, None, b).value
@@ -306,7 +306,7 @@
                     self.cpu.compile_loop(inputargs, ops, looptoken)
                     for i, box in enumerate(inputargs):
                         self.cpu.set_future_value_int(i, box.value)
-                    r = self.cpu.execute_token(looptoken)
+                    self.cpu.execute_token(looptoken)
                     result = self.cpu.get_latest_value_int(0)
                     expected = execute(self.cpu, op, None, a, b).value
                     if guard == rop.GUARD_FALSE:
@@ -314,31 +314,27 @@
                     else:
                         assert result != expected
 
-    def test_overflow_mc(self):
-        from pypy.jit.backend.x86.assembler import MachineCodeBlockWrapper
 
-        orig_size = MachineCodeBlockWrapper.MC_SIZE
-        MachineCodeBlockWrapper.MC_SIZE = 1024
-        old_mc = self.cpu.assembler.mc
-        old_mc2 = self.cpu.assembler.mc2
-        self.cpu.assembler.mc = None
-        try:
-            ops = []
-            base_v = BoxInt()
-            v = base_v
-            for i in range(1024):
-                next_v = BoxInt()
-                ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v))
-                v = next_v
-            ops.append(ResOperation(rop.FINISH, [v], None,
-                                    descr=BasicFailDescr()))
-            looptoken = LoopToken()
-            self.cpu.compile_loop([base_v], ops, looptoken)
-            assert self.cpu.assembler.mc != old_mc   # overflowed
-            self.cpu.set_future_value_int(0, base_v.value)
-            self.cpu.execute_token(looptoken)
-            assert self.cpu.get_latest_value_int(0) == 1024
-        finally:
-            MachineCodeBlockWrapper.MC_SIZE = orig_size
-            self.cpu.assembler.mc = old_mc
-            self.cpu.assembler.mc2 = old_mc2
+class TestX86OverflowMC(TestX86):
+
+    def setup_class(cls):
+        cls.cpu = CPU(rtyper=None, stats=FakeStats())
+        cls.cpu.assembler.mc_size = 1024
+
+    def test_overflow_mc(self):
+        ops = []
+        base_v = BoxInt()
+        v = base_v
+        for i in range(1024):
+            next_v = BoxInt()
+            ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v))
+            v = next_v
+        ops.append(ResOperation(rop.FINISH, [v], None,
+                                descr=BasicFailDescr()))
+        looptoken = LoopToken()
+        old_mc_mc = self.cpu.assembler.mc._mc
+        self.cpu.compile_loop([base_v], ops, looptoken)
+        assert self.cpu.assembler.mc._mc != old_mc_mc   # overflowed
+        self.cpu.set_future_value_int(0, base_v.value)
+        self.cpu.execute_token(looptoken)
+        assert self.cpu.get_latest_value_int(0) == 1024

Modified: pypy/trunk/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/compile.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/compile.py	Tue Nov 24 15:35:31 2009
@@ -113,7 +113,7 @@
     metainterp_sd.log("compiled new " + type)
 
 def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations):
-    n = faildescr.get_index()
+    n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
     metainterp_sd.logger_ops.log_bridge(inputargs, operations, n)
     if not we_are_translated():
         show_loop(metainterp_sd)
@@ -133,14 +133,7 @@
 # ____________________________________________________________
 
 class _DoneWithThisFrameDescr(AbstractFailDescr):
-
-    def __init__(self, lst):
-        "NOT_RPYTHON"        
-        self.index = len(lst)
-        lst.append(self)
-
-    def get_index(self):
-        return self.index
+    pass
 
 class DoneWithThisFrameDescrVoid(_DoneWithThisFrameDescr):
     def handle_fail(self, metainterp_sd):
@@ -173,18 +166,6 @@
         raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value)
 
 
-done_with_this_frame_descrs = []
-done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid(
-                                           done_with_this_frame_descrs)
-done_with_this_frame_descr_int = DoneWithThisFrameDescrInt(
-                                           done_with_this_frame_descrs)
-done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef(
-                                           done_with_this_frame_descrs)
-done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat(
-                                           done_with_this_frame_descrs)
-exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef(
-                                           done_with_this_frame_descrs)
-
 prebuiltNotSpecNode = NotSpecNode()
 
 class TerminatingLoopToken(LoopToken):
@@ -194,22 +175,30 @@
         self.specnodes = [prebuiltNotSpecNode]*nargs
         self.finishdescr = finishdescr
 
-# pseudo loop tokens to make the life of optimize.py easier
-loop_tokens_done_with_this_frame_int = [
-    TerminatingLoopToken(1, done_with_this_frame_descr_int)
-    ]
-loop_tokens_done_with_this_frame_ref = [
-    TerminatingLoopToken(1, done_with_this_frame_descr_ref)
-    ]
-loop_tokens_done_with_this_frame_float = [
-    TerminatingLoopToken(1, done_with_this_frame_descr_float)
-    ]
-loop_tokens_done_with_this_frame_void = [
-    TerminatingLoopToken(0, done_with_this_frame_descr_void)
-    ]
-loop_tokens_exit_frame_with_exception_ref = [
-    TerminatingLoopToken(1, exit_frame_with_exception_descr_ref)
-    ]
+def make_done_loop_tokens():
+    done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid()
+    done_with_this_frame_descr_int = DoneWithThisFrameDescrInt()
+    done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef()
+    done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat()
+    exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef()
+
+    # pseudo loop tokens to make the life of optimize.py easier
+    return {'loop_tokens_done_with_this_frame_int': [
+                TerminatingLoopToken(1, done_with_this_frame_descr_int)
+                ],
+            'loop_tokens_done_with_this_frame_ref': [
+                TerminatingLoopToken(1, done_with_this_frame_descr_ref)
+                ],
+            'loop_tokens_done_with_this_frame_float': [
+                TerminatingLoopToken(1, done_with_this_frame_descr_float)
+                ],
+            'loop_tokens_done_with_this_frame_void': [
+                TerminatingLoopToken(0, done_with_this_frame_descr_void)
+                ],
+            'loop_tokens_exit_frame_with_exception_ref': [
+                TerminatingLoopToken(1, exit_frame_with_exception_descr_ref)
+                ],
+            }
 
 class ResumeDescr(AbstractFailDescr):
     def __init__(self, original_greenkey):
@@ -222,13 +211,6 @@
     def __init__(self, metainterp_sd, original_greenkey):
         ResumeDescr.__init__(self, original_greenkey)
         self.metainterp_sd = metainterp_sd
-        self.index = -1
-
-    def get_index(self):
-        if self.index == -1:
-            globaldata = self.metainterp_sd.globaldata
-            self.index = globaldata.get_fail_descr_number(self)
-        return self.index
 
     def store_final_boxes(self, guard_op, boxes):
         guard_op.fail_args = boxes

Modified: pypy/trunk/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/history.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/history.py	Tue Nov 24 15:35:31 2009
@@ -123,21 +123,16 @@
         return '%r' % (self,)
 
 class AbstractFailDescr(AbstractDescr):
+    index = -1
 
-    def get_index(self):
-        raise NotImplementedError
     def handle_fail(self, metainterp_sd):
         raise NotImplementedError
     def compile_and_attach(self, metainterp, new_loop):
         raise NotImplementedError
 
 class BasicFailDescr(AbstractFailDescr):
-
-    def __init__(self, index=-1):
-        self.index = index
-
-    def get_index(self):
-        return self.index
+    def __init__(self, identifier=None):
+        self.identifier = identifier      # for testing
 
 class AbstractMethDescr(AbstractDescr):
     # the base class of the result of cpu.methdescrof()

Modified: pypy/trunk/pypy/jit/metainterp/logger.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/logger.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/logger.py	Tue Nov 24 15:35:31 2009
@@ -90,8 +90,8 @@
             if op.descr is not None:
                 descr = op.descr
                 if is_guard and self.guard_number:
-                    assert isinstance(descr, AbstractFailDescr)
-                    r = "<Guard%d>" % descr.get_index()
+                    index = self.metainterp_sd.cpu.get_fail_descr_number(descr)
+                    r = "<Guard%d>" % index
                 else:
                     r = self.repr_of_descr(descr)
                 args += ', descr=' +  r

Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py	Tue Nov 24 15:35:31 2009
@@ -1022,6 +1022,8 @@
         self._addr2name_keys = []
         self._addr2name_values = []
 
+        self.__dict__.update(compile.make_done_loop_tokens())
+
     def _freeze_(self):
         return True
 
@@ -1044,8 +1046,7 @@
         else:
             self.num_green_args = 0
             self.state = None
-        self.globaldata = MetaInterpGlobalData(
-                               self, compile.done_with_this_frame_descrs)
+        self.globaldata = MetaInterpGlobalData(self)
 
     def _setup_once(self):
         """Runtime setup needed by the various components of the JIT."""
@@ -1136,11 +1137,10 @@
 # ____________________________________________________________
 
 class MetaInterpGlobalData(object):
-    def __init__(self, staticdata, prebuilt_fail_descr_list):
+    def __init__(self, staticdata):
         self.initialized = False
         self.indirectcall_dict = None
         self.addr2name = None
-        self.fail_descr_list = prebuilt_fail_descr_list[:]
         self.loopnumbering = 0
         #
         state = staticdata.state
@@ -1164,16 +1164,6 @@
             cell.compiled_merge_points = []
         return cell.compiled_merge_points
 
-    def get_fail_descr_number(self, descr):
-        assert isinstance(descr, history.AbstractFailDescr)
-        lst = self.fail_descr_list
-        n = len(lst)
-        lst.append(descr)
-        return n
-
-    def get_fail_descr_from_number(self, n):
-        return self.fail_descr_list[n]
-
 # ____________________________________________________________
 
 class MetaInterp(object):
@@ -1622,16 +1612,16 @@
         if sd.result_type == 'void':
             assert exitbox is None
             exits = []
-            loop_tokens = compile.loop_tokens_done_with_this_frame_void
+            loop_tokens = sd.loop_tokens_done_with_this_frame_void
         elif sd.result_type == 'int':
             exits = [exitbox]
-            loop_tokens = compile.loop_tokens_done_with_this_frame_int
+            loop_tokens = sd.loop_tokens_done_with_this_frame_int
         elif sd.result_type == 'ref':
             exits = [exitbox]
-            loop_tokens = compile.loop_tokens_done_with_this_frame_ref
+            loop_tokens = sd.loop_tokens_done_with_this_frame_ref
         elif sd.result_type == 'float':
             exits = [exitbox]
-            loop_tokens = compile.loop_tokens_done_with_this_frame_float
+            loop_tokens = sd.loop_tokens_done_with_this_frame_float
         else:
             assert False
         self.history.record(rop.JUMP, exits, None)
@@ -1643,7 +1633,8 @@
         self.gen_store_back_in_virtualizable()
         # temporarily put a JUMP to a pseudo-loop
         self.history.record(rop.JUMP, [valuebox], None)
-        loop_tokens = compile.loop_tokens_exit_frame_with_exception_ref
+        sd = self.staticdata
+        loop_tokens = sd.loop_tokens_exit_frame_with_exception_ref
         target_loop_token = compile.compile_new_bridge(self, loop_tokens,
                                                        self.resumekey)
         assert target_loop_token is loop_tokens[0]

Modified: pypy/trunk/pypy/jit/metainterp/test/test_compile.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_compile.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_compile.py	Tue Nov 24 15:35:31 2009
@@ -103,22 +103,3 @@
     assert loop_tokens == [loop_token]
     assert len(cpu.seen) == 0
     assert staticdata.globaldata.loopnumbering == 2    
-
-def test_resumeguarddescr_get_index():
-    from pypy.jit.metainterp.pyjitpl import MetaInterpGlobalData
-
-    class FakeStaticData:
-        state = None
-        virtualizable_info = None
-    gd = MetaInterpGlobalData(FakeStaticData, [])
-    FakeStaticData.globaldata = gd
-
-    rgd = ResumeGuardDescr(FakeStaticData, ())
-
-    fail_index = rgd.get_index()
-    fail_index1 = rgd.get_index()
-
-    assert fail_index == fail_index1
-
-    assert gd.get_fail_descr_from_number(fail_index) is rgd
-

Modified: pypy/trunk/pypy/jit/metainterp/test/test_logger.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_logger.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_logger.py	Tue Nov 24 15:35:31 2009
@@ -6,6 +6,8 @@
 from StringIO import StringIO
 from pypy.jit.metainterp.test.test_optimizeopt import equaloplists
 from pypy.jit.metainterp.history import AbstractDescr, LoopToken, BasicFailDescr
+from pypy.jit.backend.model import AbstractCPU
+
 
 class Descr(AbstractDescr):
     pass
@@ -36,8 +38,8 @@
 
     def make_metainterp_sd(self):
         class FakeMetaInterpSd:
-            class cpu:
-                ts = self.ts
+            cpu = AbstractCPU()
+            cpu.ts = self.ts
             def get_name_from_address(self, addr):
                 return 'Name'
         return FakeMetaInterpSd()
@@ -122,7 +124,7 @@
         pure_parse(output)
         
     def test_guard_descr(self):
-        namespace = {'fdescr': BasicFailDescr(4)}
+        namespace = {'fdescr': BasicFailDescr()}
         inp = '''
         [i0]
         guard_true(i0, descr=fdescr) [i0]
@@ -130,15 +132,14 @@
         loop = pure_parse(inp, namespace=namespace)
         logger = Logger(self.make_metainterp_sd(), guard_number=True)
         output = logger.log_loop(loop)
-        assert output.splitlines()[-1] == "guard_true(i0, descr=<Guard4>) [i0]"
+        assert output.splitlines()[-1] == "guard_true(i0, descr=<Guard0>) [i0]"
         pure_parse(output)
         
-        def boom():
-            raise Exception
-        namespace['fdescr'].get_index = boom
         logger = Logger(self.make_metainterp_sd(), guard_number=False)
         output = logger.log_loop(loop)
-        assert output.splitlines()[-1].startswith("guard_true(i0, descr=<")
+        lastline = output.splitlines()[-1]
+        assert lastline.startswith("guard_true(i0, descr=<")
+        assert not lastline.startswith("guard_true(i0, descr=<Guard")
 
     def test_class_name(self):
         from pypy.rpython.lltypesystem import lltype

Modified: pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py	Tue Nov 24 15:35:31 2009
@@ -38,35 +38,6 @@
         if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST:
             assert hasattr(pyjitpl.MIFrame, 'opimpl_' + opname.lower()), opname
 
-def test_faildescr_numbering():
-    class FakeStaticData:
-        state = None
-        virtualizable_info = None
-
-    fail_descr0 = AbstractFailDescr()
-    lst = [fail_descr0]
-    gd = pyjitpl.MetaInterpGlobalData(FakeStaticData, lst)
-    assert gd.fail_descr_list is not lst
-
-    fail_descr = gd.get_fail_descr_from_number(0)
-    assert fail_descr is fail_descr0
-
-    fail_descr1 = AbstractFailDescr()
-    fail_descr2 = AbstractFailDescr()    
-
-    n1 = gd.get_fail_descr_number(fail_descr1)
-    n2 = gd.get_fail_descr_number(fail_descr2)
-    assert n1 != n2
-
-    fail_descr = gd.get_fail_descr_from_number(n1)
-    assert fail_descr is fail_descr1
-    fail_descr = gd.get_fail_descr_from_number(n2)
-    assert fail_descr is fail_descr2
-
-    # doesn't provide interning on its own
-    n1_1 = gd.get_fail_descr_number(fail_descr1)
-    assert n1_1 != n1
-
 def test_portal_trace_positions():
     jitcode = codewriter.JitCode("f")
     jitcode.code = jitcode.constants = None

Modified: pypy/trunk/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/warmstate.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/warmstate.py	Tue Nov 24 15:35:31 2009
@@ -244,10 +244,9 @@
             while True:     # until interrupted by an exception
                 metainterp_sd.profiler.start_running()
                 debug_start("jit-running")
-                fail_index = metainterp_sd.cpu.execute_token(loop_token)
+                fail_descr = metainterp_sd.cpu.execute_token(loop_token)
                 debug_stop("jit-running")
                 metainterp_sd.profiler.end_running()
-                fail_descr = globaldata.get_fail_descr_from_number(fail_index)
                 loop_token = fail_descr.handle_fail(metainterp_sd)
 
         maybe_compile_and_run._dont_inline_ = True

Modified: pypy/trunk/pypy/objspace/std/multimethod.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/multimethod.py	(original)
+++ pypy/trunk/pypy/objspace/std/multimethod.py	Tue Nov 24 15:35:31 2009
@@ -29,6 +29,9 @@
         self.w_type  = w_type
         self.w_value = w_value
 
+    def __str__(self):
+        return '<FailedToImplement(%s, %s)>' % (self.w_type, self.w_value)
+
 
 def raiseFailedToImplement():
     raise FailedToImplement



More information about the Pypy-commit mailing list