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

arigo at codespeak.net arigo at codespeak.net
Tue Dec 1 17:51:15 CET 2009


Author: arigo
Date: Tue Dec  1 17:51:14 2009
New Revision: 69812

Modified:
   pypy/trunk/pypy/jit/backend/llgraph/runner.py
   pypy/trunk/pypy/jit/backend/model.py
   pypy/trunk/pypy/jit/backend/test/runner_test.py
   pypy/trunk/pypy/jit/backend/x86/assembler.py
   pypy/trunk/pypy/jit/backend/x86/runner.py
   pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py
   pypy/trunk/pypy/jit/metainterp/compile.py
   pypy/trunk/pypy/jit/metainterp/pyjitpl.py
   pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py
Log:
(cfbolz, arigo)
Kill ResumeDescr.fail_arg_types, because it can be reconstructed
from information that the backend needs to save anyway.  Add the
cpu.make_boxes_from_latest_value() interface to do that.  Saves
a byte per fail_arg on every guard.

Small renamings in the corresponding logic in x86/assembler.py.


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 Dec  1 17:51:14 2009
@@ -166,6 +166,13 @@
             if op.is_guard():
                 faildescr = op.descr
                 assert isinstance(faildescr, history.AbstractFailDescr)
+                faildescr._fail_args_types = []
+                for box in op.fail_args:
+                    if box is None:
+                        type = history.HOLE
+                    else:
+                        type = box.type
+                    faildescr._fail_args_types.append(type)
                 fail_index = self.get_fail_descr_number(faildescr)
                 index = llimpl.compile_add_fail(c, fail_index)
                 faildescr._compiled_fail = c, index
@@ -235,6 +242,23 @@
         token = llimpl.get_frame_forced_token(self.latest_frame)
         return self.cast_adr_to_int(token)
 
+    def make_boxes_from_latest_values(self, faildescr):
+        inputargs_and_holes = []
+        for i in range(len(faildescr._fail_args_types)):
+            boxtype = faildescr._fail_args_types[i]
+            if boxtype == history.INT:
+                box = history.BoxInt(self.get_latest_value_int(i))
+            elif boxtype == history.REF:
+                box = self.ts.BoxRef(self.get_latest_value_ref(i))
+            elif boxtype == history.FLOAT:
+                box = history.BoxFloat(self.get_latest_value_float(i))
+            elif boxtype == history.HOLE:
+                box = None
+            else:
+                assert False, "bad box type: num=%d" % ord(boxtype)
+            inputargs_and_holes.append(box)
+        return inputargs_and_holes
+
     # ----------
 
     def get_exception(self):

Modified: pypy/trunk/pypy/jit/backend/model.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/model.py	(original)
+++ pypy/trunk/pypy/jit/backend/model.py	Tue Dec  1 17:51:14 2009
@@ -83,6 +83,12 @@
         same FORCE_TOKEN result as the one in the just-failed loop."""
         raise NotImplementedError
 
+    def make_boxes_from_latest_value(self, faildescr):
+        """Build a list of Boxes (and None for holes) that contains
+        the current values, as would be returned by calls to
+        get_latest_value_xxx()."""
+        raise NotImplementedError
+
     def get_exception(self):
         raise NotImplementedError
 

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 Dec  1 17:51:14 2009
@@ -238,6 +238,32 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
+    def test_make_boxes_from_latest_values(self):
+        i0 = BoxInt()
+        i1 = BoxInt()
+        i2 = BoxInt()
+        faildescr1 = BasicFailDescr(1)
+        looptoken = LoopToken()
+        operations = [
+            ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
+            ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
+            ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1),
+            ResOperation(rop.JUMP, [i1], None, descr=looptoken),
+            ]
+        inputargs = [i0]
+        operations[2].fail_args = [None, i1, None]
+        self.cpu.compile_loop(inputargs, operations, looptoken)
+
+        self.cpu.set_future_value_int(0, 2)
+        fail = self.cpu.execute_token(looptoken)
+        assert fail is faildescr1
+        boxes = self.cpu.make_boxes_from_latest_values(faildescr1)
+        assert len(boxes) == 3
+        assert boxes[0] is None
+        assert isinstance(boxes[1], BoxInt)
+        assert boxes[1].value == 10
+        assert boxes[2] is None
+
     def test_finish(self):
         i0 = BoxInt()
         class UntouchableFailDescr(AbstractFailDescr):

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 Dec  1 17:51:14 2009
@@ -1,8 +1,8 @@
 import sys, os
 import ctypes
 from pypy.jit.backend.llsupport import symbolic
-from pypy.jit.metainterp.history import Const, Box, BoxPtr, INT, REF, FLOAT
-from pypy.jit.metainterp.history import AbstractFailDescr
+from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
+from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT
 from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory
 from pypy.rpython.lltypesystem.rclass import OBJECT
 from pypy.rpython.lltypesystem.lloperation import llop
@@ -798,9 +798,9 @@
     DESCR_INT       = 0x01
     DESCR_FLOAT     = 0x02
     DESCR_SPECIAL   = 0x03
-    DESCR_FROMSTACK = 8
-    DESCR_STOP      = 0 | DESCR_SPECIAL
-    DESCR_HOLE      = 4 | DESCR_SPECIAL
+    CODE_FROMSTACK  = 4*8
+    CODE_STOP       = 0 | DESCR_SPECIAL
+    CODE_HOLE       = 4 | DESCR_SPECIAL
 
     def write_failure_recovery_description(self, mc, failargs, locs):
         for i in range(len(failargs)):
@@ -816,7 +816,7 @@
                     raise AssertionError("bogus kind")
                 loc = locs[i]
                 if isinstance(loc, MODRM):
-                    n = self.DESCR_FROMSTACK + loc.position
+                    n = self.CODE_FROMSTACK//4 + loc.position
                 else:
                     assert isinstance(loc, REG)
                     n = loc.op
@@ -825,9 +825,9 @@
                     mc.writechr((n & 0x7F) | 0x80)
                     n >>= 7
             else:
-                n = self.DESCR_HOLE
+                n = self.CODE_HOLE
             mc.writechr(n)
-        mc.writechr(self.DESCR_STOP)
+        mc.writechr(self.CODE_STOP)
         # preallocate the fail_boxes
         i = len(failargs) - 1
         if i >= 0:
@@ -844,7 +844,7 @@
             # 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 >= self.CODE_FROMSTACK:
                 # 'code' identifies a stack location
                 if code > 0x7F:
                     shift = 7
@@ -857,15 +857,15 @@
                         if nextcode <= 0x7F:
                             break
                 kind = code & 3
-                code = (code >> 2) - self.DESCR_FROMSTACK
+                code = (code - self.CODE_FROMSTACK) >> 2
                 if kind == self.DESCR_FLOAT:
                     size = 2
                 else:
                     size = 1
                 loc = X86StackManager.stack_pos(code, size)
-            elif code == self.DESCR_STOP:
+            elif code == self.CODE_STOP:
                 break
-            elif code == self.DESCR_HOLE:
+            elif code == self.CODE_HOLE:
                 continue
             else:
                 # 'code' identifies a register
@@ -878,6 +878,39 @@
             arglocs.append(loc)
         return arglocs[:]
 
+    def make_boxes_from_latest_values(self, bytecode):
+        bytecode = rffi.cast(rffi.UCHARP, bytecode)
+        boxes = []
+        while 1:
+            # decode the next instruction from the bytecode
+            code = rffi.cast(lltype.Signed, bytecode[0])
+            bytecode = rffi.ptradd(bytecode, 1)
+            kind = code & 3
+            while code > 0x7F:
+                code = rffi.cast(lltype.Signed, bytecode[0])
+                bytecode = rffi.ptradd(bytecode, 1)
+            index = len(boxes)
+            if kind == self.DESCR_INT:
+                box = BoxInt(self.fail_boxes_int.getitem(index))
+            elif kind == self.DESCR_REF:
+                box = BoxPtr(self.fail_boxes_ptr.getitem(index))
+                # clear after reading (xxx duplicates
+                # get_latest_value_ref())
+                self.fail_boxes_ptr.setitem(index, lltype.nullptr(
+                    llmemory.GCREF.TO))
+            elif kind == self.DESCR_FLOAT:
+                box = BoxFloat(self.fail_boxes_float.getitem(index))
+            else:
+                assert kind == self.DESCR_SPECIAL
+                if code == self.CODE_STOP:
+                    break
+                elif code == self.CODE_HOLE:
+                    box = None
+                else:
+                    assert 0, "bad code"
+            boxes.append(box)
+        return boxes
+
     def grab_frame_values(self, bytecode, frame_addr, allregisters):
         # no malloc allowed here!!
         self.fail_ebp = allregisters[16 + ebp.op]
@@ -887,7 +920,7 @@
             # 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 >= self.CODE_FROMSTACK:
                 if code > 0x7F:
                     shift = 7
                     code &= 0x7F
@@ -900,7 +933,7 @@
                             break
                 # load the value from the stack
                 kind = code & 3
-                code = (code >> 2) - self.DESCR_FROMSTACK
+                code = (code - self.CODE_FROMSTACK) >> 2
                 stackloc = frame_addr + get_ebp_ofs(code)
                 value = rffi.cast(rffi.LONGP, stackloc)[0]
                 if kind == self.DESCR_FLOAT:
@@ -910,10 +943,10 @@
                 # 'code' identifies a register: load its value
                 kind = code & 3
                 if kind == self.DESCR_SPECIAL:
-                    if code == self.DESCR_HOLE:
+                    if code == self.CODE_HOLE:
                         num += 1
                         continue
-                    assert code == self.DESCR_STOP
+                    assert code == self.CODE_STOP
                     break
                 code >>= 2
                 if kind == self.DESCR_FLOAT:

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 Dec  1 17:51:14 2009
@@ -62,6 +62,10 @@
     def get_latest_force_token(self):
         return self.assembler.fail_ebp + FORCE_INDEX_OFS
 
+    def make_boxes_from_latest_values(self, faildescr):
+        return self.assembler.make_boxes_from_latest_values(
+            faildescr._x86_failure_recovery_bytecode)
+
     def execute_token(self, executable_token):
         addr = executable_token._x86_bootstrap_code
         func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr)

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py	Tue Dec  1 17:51:14 2009
@@ -42,8 +42,8 @@
             Assembler386.DESCR_INT   + 4*(8+100),
             Assembler386.DESCR_REF   + 4*(8+101),
             Assembler386.DESCR_FLOAT + 4*(8+110),
-            Assembler386.DESCR_HOLE,
-            Assembler386.DESCR_HOLE,
+            Assembler386.CODE_HOLE,
+            Assembler386.CODE_HOLE,
             Assembler386.DESCR_INT   + 4*ebx.op,
             Assembler386.DESCR_REF   + 4*esi.op,
             Assembler386.DESCR_FLOAT + 4*xmm2.op]
@@ -52,7 +52,7 @@
         double_byte_nums.append((num & 0x7F) | 0x80)
         double_byte_nums.append(num >> 7)
     assert mc.content == (nums[:3] + double_byte_nums + nums[6:] +
-                          [assembler.DESCR_STOP])
+                          [assembler.CODE_STOP])
 
     # also test rebuild_faillocs_from_descr(), which should not
     # reproduce the holes at all
@@ -65,6 +65,35 @@
     assert ([loc.assembler() for loc in newlocs] ==
             [loc.assembler() for loc in locs if loc is not None])
 
+    # finally, test make_boxes_from_latest_values(), which should
+    # reproduce the holes
+    expected_classes = [BoxInt, BoxPtr, BoxFloat,
+                        BoxInt, BoxPtr, BoxFloat,
+                        type(None), type(None),
+                        BoxInt, BoxPtr, BoxFloat]
+    ptrvalues = {}
+    S = lltype.GcStruct('S')
+    for i, cls in enumerate(expected_classes):
+        if cls == BoxInt:
+            assembler.fail_boxes_int.setitem(i, 1000 + i)
+        elif cls == BoxPtr:
+            s = lltype.malloc(S)
+            s_ref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+            ptrvalues[i] = s_ref
+            assembler.fail_boxes_ptr.setitem(i, s_ref)
+        elif cls == BoxFloat:
+            assembler.fail_boxes_float.setitem(i, 42.5 + i)
+    boxes = assembler.make_boxes_from_latest_values(bytecode_addr)
+    assert len(boxes) == len(locs) == len(expected_classes)
+    for i, (box, expected_class) in enumerate(zip(boxes, expected_classes)):
+        assert type(box) is expected_class
+        if expected_class == BoxInt:
+            assert box.value == 1000 + i
+        elif expected_class == BoxPtr:
+            assert box.value == ptrvalues[i]
+        elif expected_class == BoxFloat:
+            assert box.value == 42.5 + i
+
 # ____________________________________________________________
 
 def test_failure_recovery_func_no_floats():
@@ -136,7 +165,7 @@
     descr_bytecode = []
     for i, (kind, loc) in enumerate(content):
         if kind == 'hole':
-            num = Assembler386.DESCR_HOLE
+            num = Assembler386.CODE_HOLE
         else:
             if kind == 'float':
                 value, lo, hi = get_random_float()
@@ -174,7 +203,7 @@
                 num >>= 7
         descr_bytecode.append(num)
 
-    descr_bytecode.append(Assembler386.DESCR_STOP)
+    descr_bytecode.append(Assembler386.CODE_STOP)
     descr_bytecode.append(0xC3)   # fail_index = 0x1C3
     descr_bytecode.append(0x01)
     descr_bytecode.append(0x00)

Modified: pypy/trunk/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/compile.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/compile.py	Tue Dec  1 17:51:14 2009
@@ -215,13 +215,6 @@
     def store_final_boxes(self, guard_op, boxes):
         guard_op.fail_args = boxes
         self.guard_opnum = guard_op.opnum
-        fail_arg_types = [history.HOLE] * len(boxes)
-        for i in range(len(boxes)):
-            box = boxes[i]
-            if box:
-                fail_arg_types[i] = box.type
-        self.fail_arg_types = fail_arg_types
-        # XXX ^^^ kill this attribute
 
     def handle_fail(self, metainterp_sd):
         from pypy.jit.metainterp.pyjitpl import MetaInterp
@@ -253,7 +246,7 @@
         from pypy.jit.metainterp.resume import force_from_resumedata
         metainterp = MetaInterp(self.metainterp_sd)
         metainterp.history = None    # blackholing
-        liveboxes = metainterp.load_values_from_failure(self)
+        liveboxes = metainterp.cpu.make_boxes_from_latest_values(self)
         virtualizable_boxes, data = force_from_resumedata(metainterp,
                                                           liveboxes, self)
         vinfo.write_boxes(virtualizable, virtualizable_boxes)

Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py	Tue Dec  1 17:51:14 2009
@@ -1692,7 +1692,7 @@
     def initialize_state_from_guard_failure(self, resumedescr, must_compile):
         # guard failure: rebuild a complete MIFrame stack
         self.in_recursion = -1 # always one portal around
-        inputargs_and_holes = self.load_values_from_failure(resumedescr)
+        inputargs_and_holes = self.cpu.make_boxes_from_latest_values(resumedescr)
         if must_compile:
             self.history = history.History(self.cpu)
             self.history.inputargs = [box for box in inputargs_and_holes if box]
@@ -1702,25 +1702,6 @@
             self.history = None   # this means that is_blackholing() is true
         self.rebuild_state_after_failure(resumedescr, inputargs_and_holes)
 
-    def load_values_from_failure(self, resumedescr):
-        cpu = self.cpu
-        fail_arg_types = resumedescr.fail_arg_types
-        inputargs_and_holes = []
-        for i in range(len(fail_arg_types)):
-            boxtype = fail_arg_types[i]
-            if boxtype == history.INT:
-                box = history.BoxInt(cpu.get_latest_value_int(i))
-            elif boxtype == history.REF:
-                box = cpu.ts.BoxRef(cpu.get_latest_value_ref(i))
-            elif boxtype == history.FLOAT:
-                box = history.BoxFloat(cpu.get_latest_value_float(i))
-            elif boxtype == history.HOLE:
-                box = None
-            else:
-                assert False, "bad box type: num=%d" % ord(boxtype)
-            inputargs_and_holes.append(box)
-        return inputargs_and_holes
-
     def initialize_virtualizable(self, original_boxes):
         vinfo = self.staticdata.virtualizable_info
         if vinfo is not None:

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 Dec  1 17:51:14 2009
@@ -134,8 +134,8 @@
     class FakeCPU:
         ts = llhelper
 
-        def get_latest_value_int(self, index):
-            return index
+        def make_boxes_from_latest_values(self, faildescr):
+            return [BoxInt(0), None, BoxInt(2), None, BoxInt(4)]
         
     class FakeStaticData:
         cpu = FakeCPU()
@@ -150,10 +150,6 @@
     class FakeResumeDescr:
         pass
     resumedescr = FakeResumeDescr()
-    resumedescr.fail_arg_types = [history.INT, history.HOLE,
-                                  history.INT, history.HOLE,
-                                  history.INT]
-
     metainterp.initialize_state_from_guard_failure(resumedescr, True)
 
     inp = metainterp.history.inputargs



More information about the Pypy-commit mailing list