[pypy-svn] r70276 - in pypy/branch/jit-delayed-write/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Sat Dec 26 15:08:03 CET 2009


Author: arigo
Date: Sat Dec 26 15:08:01 2009
New Revision: 70276

Modified:
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py
Log:
In-progress.


Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py	Sat Dec 26 15:08:01 2009
@@ -63,7 +63,11 @@
     def get_args_for_fail(self, modifier):
         pass
 
-    def make_virtual_info(self, modifier, fieldnums):
+    def get_backstore(self):
+        return (None, None)
+
+    def make_virtual_info(self, modifier, fieldnums,
+                          backstore_num, backstore_descr):
         raise NotImplementedError # should not be called on this level
 
     def is_constant(self):
@@ -138,10 +142,12 @@
 
 
 class AbstractVirtualValue(OptValue):
-    _attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo')
+    _attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo',
+               'backstore_field')
     box = None
     level = LEVEL_NONNULL
     _cached_vinfo = None
+    backstore_field = None     # the fielddescr from lazy_setfields
 
     def __init__(self, optimizer, keybox, source_op=None):
         self.optimizer = optimizer
@@ -160,19 +166,40 @@
             self._really_force()
         return self.box
 
-    def make_virtual_info(self, modifier, fieldnums):
-        vinfo = self._cached_vinfo 
-        if vinfo is not None and resume.tagged_list_eq(
-                vinfo.fieldnums, fieldnums):
+    def get_backstore(self):
+        if self.backstore_field is None:
+            return (None, None)
+        heapopt = self.optimizer.heap_op_optimizer
+        try:
+            op = heapopt.lazy_setfields[self.backstore_field]
+        except KeyError:
+            self.backstore_field = None
+            return (None, None)
+        if self.optimizer.getvalue(op.args[1]) is not self:
+            self.backstore_field = None
+            return (None, None)
+        return (op.args[0], self.backstore_field)
+
+    def make_virtual_info(self, modifier, fieldnums,
+                          backstore_num, backstore_descr):
+        vinfo = self._cached_vinfo
+        if vinfo is not None and vinfo.equals(fieldnums, backstore_num,
+                                              backstore_descr):
             return vinfo
         vinfo = self._make_virtual(modifier)
-        vinfo.fieldnums = fieldnums
+        vinfo.set_content(fieldnums, backstore_num, backstore_descr)
         self._cached_vinfo = vinfo
         return vinfo
 
     def _make_virtual(self, modifier):
         raise NotImplementedError("abstract base")
 
+    def register_virtual_fields(self, modifier, fieldboxes):
+        modifier.register_virtual_fields(self.keybox, fieldboxes)
+        parentbox, parentdescr = self.get_backstore()
+        if parentdescr is not None:
+            modifier.register_box(parentbox)
+
 def get_fielddescrlist_cache(cpu):
     if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
         result = descrlist_dict()
@@ -238,7 +265,7 @@
             # we have already seen the very same keybox
             lst = self._get_field_descr_list()
             fieldboxes = [self._fields[ofs].get_key_box() for ofs in lst]
-            modifier.register_virtual_fields(self.keybox, fieldboxes)
+            self.register_virtual_fields(modifier, fieldboxes)
             for ofs in lst:
                 fieldvalue = self._fields[ofs]
                 fieldvalue.get_args_for_fail(modifier)
@@ -306,7 +333,7 @@
             itemboxes = []
             for itemvalue in self._items:
                 itemboxes.append(itemvalue.get_key_box())
-            modifier.register_virtual_fields(self.keybox, itemboxes)
+            self.register_virtual_fields(modifier, itemboxes)
             for itemvalue in self._items:
                 if itemvalue is not self.constvalue:
                     itemvalue.get_args_for_fail(modifier)
@@ -535,6 +562,7 @@
         self.newoperations.append(op)
 
     def store_final_boxes_in_guard(self, op):
+        self.heap_op_optimizer.force_lazy_setfields_for_guard()
         descr = op.descr
         assert isinstance(descr, compile.ResumeGuardDescr)
         modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
@@ -918,7 +946,6 @@
         if op.is_ovf():
             return
         if op.is_guard():
-            self.force_all_lazy_setfields_of_nonvirtuals()
             return
         opnum = op.opnum
         if (opnum == rop.SETFIELD_GC or
@@ -957,6 +984,9 @@
         except KeyError:
             return
         del self.lazy_setfields[descr]
+        fieldvalue = self.optimizer.getvalue(op.args[1])
+        if isinstance(fieldvalue, AbstractVirtualValue):
+            fieldvalue.backstore_field = None
         self.optimizer._emit_operation(op)
 
     def force_all_lazy_setfields(self):
@@ -965,15 +995,26 @@
                 self.force_lazy_setfield(descr)
             del self.lazy_setfields_descrs[:]
 
-    def force_all_lazy_setfields_of_nonvirtuals(self):
+    def force_lazy_setfields_for_guard(self):
         for descr in self.lazy_setfields_descrs:
             try:
                 op = self.lazy_setfields[descr]
             except KeyError:
                 continue
+            # the only really interesting case that we need to handle in the
+            # guards' resume data is that of a virtual object that is stored
+            # into a field of a non-virtual object.  The later object cannot
+            # actually be virtual here (verified by an assert), but the
+            # former object 'fieldvalue' can be.
+            value = self.optimizer.getvalue(op.args[0])
+            assert not value.is_virtual()
             fieldvalue = self.optimizer.getvalue(op.args[1])
-            if not fieldvalue.is_virtual():
-                self.force_lazy_setfield(descr)
+            if fieldvalue.is_virtual():
+                assert isinstance(fieldvalue, AbstractVirtualValue)
+                if fieldvalue.backstore_field is descr:
+                    # this is the case that can be handled by resume data
+                    continue
+            self.force_lazy_setfield(descr)
 
     def force_lazy_setfield_if_necessary(self, op, value, write=False):
         try:
@@ -1003,6 +1044,8 @@
     def optimize_SETFIELD_GC(self, op, value, fieldvalue):
         self.force_lazy_setfield_if_necessary(op, value, write=True)
         self.lazy_setfields[op.descr] = op
+        if isinstance(fieldvalue, AbstractVirtualValue):
+            fieldvalue.backstore_field = op.descr
         # remember the result of future reads of the field
         self.cache_field_value(op.descr, value, fieldvalue, write=True)
 

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py	Sat Dec 26 15:08:01 2009
@@ -252,8 +252,6 @@
         if (isinstance(box, Box) and box not in self.liveboxes_from_env
                                  and box not in self.liveboxes):
             self.liveboxes[box] = UNASSIGNED
-            return True
-        return False
 
     def _register_boxes(self, boxes):
         for box in boxes:
@@ -298,6 +296,7 @@
         return liveboxes[:]
 
     def _number_virtuals(self, liveboxes, values, num_env_virtuals):
+        # !! 'liveboxes' is a list that is extend()ed in-place !!
         memo = self.memo
         new_liveboxes = [None] * memo.num_cached_boxes()
         count = 0
@@ -339,7 +338,13 @@
                 value = values[virtualbox]
                 fieldnums = [self._gettagged(box)
                              for box in fieldboxes]
-                vinfo = value.make_virtual_info(self, fieldnums)
+                backstore_box, backstore_descr = value.get_backstore()
+                if backstore_descr is not None:
+                    backstore_num = self._gettagged(backstore_box)
+                else:
+                    backstore_num = NULLREF
+                vinfo = value.make_virtual_info(self, fieldnums,
+                                                backstore_num, backstore_descr)
                 # if a new vinfo instance is made, we get the fieldnums list we
                 # pass in as an attribute. hackish.
                 if vinfo.fieldnums is not fieldnums:
@@ -366,11 +371,47 @@
                 return self.liveboxes_from_env[box]
             return self.liveboxes[box]
 
+
+class BackstoreRef(object):
+    # Used to say that a virtual object must, after being created because
+    # of a guard failure, be stored back on the given field of the given
+    # non-virtual object.  For lazy setfields.  Limited to one place per
+    # virtual for now.
+    def __init__(self, parentdescr, parentnum):
+        self.parentdescr = parentdescr
+        self.parentnum = parentnum
+
+    def setfields(self, metainterp, box, fn_decode_box):
+        parentbox = fn_decode_box(self.parentnum)
+        metainterp.execute_and_record(rop.SETFIELD_GC, self.parentdescr,
+                                      parentbox, box)
+
 class AbstractVirtualInfo(object):
+    backstore_ref = None
+
     def allocate(self, metainterp):
         raise NotImplementedError
+
     def setfields(self, metainterp, box, fn_decode_box):
-        raise NotImplementedError
+        if self.backstore_ref is not None:
+            self.backstore_ref.setfields(metainterp, box, fn_decode_box)
+
+    def equals(self, fieldnums, backstore_num, backstore_descr):
+        return (tagged_list_eq(self.fieldnums, fieldnums) and
+                self.backstore_equals(backstore_num, backstore_descr))
+
+    def backstore_equals(self, backstore_num, backstore_descr):
+        if backstore_descr is None:
+            return self.backstore_ref is None
+        else:
+            return (self.backstore_ref is not None and
+                    self.backstore_ref.parentdescr == backstore_descr and
+                    self.backstore_ref.parentnum == backstore_num)
+
+    def set_content(self, fieldnums, backstore_num, backstore_descr):
+        self.fieldnums = fieldnums
+        if backstore_descr is not None:
+            self.backstore_ref = BackstoreRef(backstore_descr, backstore_num)
 
 
 class AbstractVirtualStructInfo(AbstractVirtualInfo):
@@ -384,6 +425,7 @@
             metainterp.execute_and_record(rop.SETFIELD_GC,
                                           self.fielddescrs[i],
                                           box, fieldbox)
+        AbstractVirtualInfo.setfields(self, metainterp, box, fn_decode_box)
 
     def debug_prints(self):
         assert len(self.fielddescrs) == len(self.fieldnums)
@@ -434,6 +476,7 @@
             metainterp.execute_and_record(rop.SETARRAYITEM_GC,
                                           self.arraydescr,
                                           box, ConstInt(i), itembox)
+        AbstractVirtualInfo.setfields(self, metainterp, box, fn_decode_box)
 
     def debug_prints(self):
         debug_print("\tvarrayinfo", self.arraydescr)

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py	Sat Dec 26 15:08:01 2009
@@ -87,18 +87,39 @@
 
 def test_reuse_vinfo():
     class FakeVInfo(object):
-        pass
+        def set_content(self, fieldnums, backstore_num, backstore_descr):
+            self.fieldnums = fieldnums
+            self.backstore_num = backstore_num
+            self.backstore_descr = backstore_descr
+        def equals(self, fieldnums, backstore_num, backstore_descr):
+            return (self.fieldnums == fieldnums and
+                    self.backstore_num == backstore_num and
+                    self.backstore_descr == backstore_descr)
     class FakeVirtualValue(optimizeopt.AbstractVirtualValue):
         def _make_virtual(self, *args):
             return FakeVInfo()
     v1 = FakeVirtualValue(None, None, None)
-    vinfo1 = v1.make_virtual_info(None, [1, 2, 4])
-    vinfo2 = v1.make_virtual_info(None, [1, 2, 4])
+    vinfo1 = v1.make_virtual_info(None, [1, 2, 4], None, None)
+    vinfo2 = v1.make_virtual_info(None, [1, 2, 4], None, None)
     assert vinfo1 is vinfo2
-    vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+    vinfo3 = v1.make_virtual_info(None, [1, 2, 6], None, None)
     assert vinfo3 is not vinfo2
-    vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+    vinfo4 = v1.make_virtual_info(None, [1, 2, 6], None, None)
     assert vinfo3 is vinfo4
+    #
+    descr = object()
+    descr2 = object()
+    vinfo1 = v1.make_virtual_info(None, [1, 2, 4], None, None)
+    vinfo2 = v1.make_virtual_info(None, [1, 2, 4], 6, descr)
+    assert vinfo1 is not vinfo2
+    vinfo3 = v1.make_virtual_info(None, [1, 2, 4], 6, descr)
+    assert vinfo3 is vinfo2
+    vinfo4 = v1.make_virtual_info(None, [1, 2, 4], 5, descr)
+    assert vinfo4 is not vinfo3
+    vinfo5 = v1.make_virtual_info(None, [1, 2, 4], 5, descr2)
+    assert vinfo5 is not vinfo4
+    vinfo6 = v1.make_virtual_info(None, [1, 2, 4], 5, descr2)
+    assert vinfo6 is vinfo5
 
 def test_descrlist_dict():
     from pypy.jit.metainterp import optimizeutil
@@ -2060,6 +2081,54 @@
             where p7v is a node_vtable, valuedescr=iv
             ''')
 
+    def test_expand_fail_lazy_setfield_1(self):
+        self.make_fail_descr()
+        ops = """
+        [p1, i2, i3]
+        p2 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        guard_true(i3, descr=fdescr) [p1]
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        expected = """
+        [p1, i2, i3]
+        guard_true(i3, descr=fdescr) [p1, i2]
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+        self.check_expanded_fail_descr('''p1
+            where p2 is a node_vtable, valuedescr=i2 --> p1.nextdescr
+            ''')
+
+    def test_expand_fail_lazy_setfield_2(self):
+        self.make_fail_descr()
+        ops = """
+        [i2, i3]
+        p2 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(ConstPtr(myptr), p2, descr=nextdescr)
+        guard_true(i3, descr=fdescr) []
+        i4 = int_neg(i2)
+        setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+        jump(i2, i4)
+        """
+        expected = """
+        [i2, i3]
+        guard_true(i3, descr=fdescr) [i2]
+        i4 = int_neg(i2)
+        setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+        jump(i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not', expected)
+        self.check_expanded_fail_descr('''
+            where p2 is a node_vtable, valuedescr=i2 --> myptr.nextdescr
+            ''')
+
 
 class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
 

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py	Sat Dec 26 15:08:01 2009
@@ -40,6 +40,24 @@
     assert not tagged_list_eq([tag(1, TAGBOX)], [tag(-2, TAGBOX)])
     assert not tagged_list_eq([tag(1, TAGBOX), tag(-2, TAGBOX)], [tag(1, TAGBOX)])
 
+def test_vinfo():
+    v1 = AbstractVirtualInfo()
+    v1.set_content([1, 2, 4], -1, None)
+    assert v1.backstore_ref is None
+    assert v1.equals([1, 2, 4], -1, None)
+    assert not v1.equals([1, 2, 6], -1, None)
+    assert not v1.equals([1, 2, 4], 3, object())
+    #
+    v2 = AbstractVirtualInfo()
+    descr = object()
+    v2.set_content([1, 2, 4], 3, descr)
+    assert v2.backstore_ref is not None
+    assert v2.backstore_ref.parentdescr is descr
+    assert v2.backstore_ref.parentnum == 3
+    assert v2.equals([1, 2, 4], 3, descr)
+    assert not v2.equals([1, 2, 4], 2, descr)
+    assert not v2.equals([1, 2, 4], 3, object())
+
 class MyMetaInterp:
     _already_allocated_resume_virtuals = None
 
@@ -960,6 +978,73 @@
     assert ptr.a == 111
     assert ptr.b == lltype.nullptr(LLtypeMixin.NODE)
 
+
+def test_virtual_adder_make_virtual_backstore():
+    b2s, b4s, b5s = [BoxPtr(), BoxPtr(), BoxPtr()]
+    c1s = ConstInt(111)
+    storage = Storage()
+    memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier.liveboxes_from_env = {}
+    modifier.liveboxes = {}
+    modifier.vfieldboxes = {}
+
+    class FakeOptimizer(object):
+        class cpu:
+            pass
+        def getvalue(self, box):
+            return {b2s: v2, b4s: v4}[box]
+    fakeoptimizer = FakeOptimizer()
+    class HeapOpOptimizer(object):
+        pass
+    fakeoptimizer.heap_op_optimizer = HeapOpOptimizer()
+    class FakeSetFieldOperation(object):
+        args = [b2s, b4s]
+    fakeoptimizer.heap_op_optimizer.lazy_setfields = {
+        LLtypeMixin.nextdescr: FakeSetFieldOperation()}
+
+    v4 = VirtualValue(fakeoptimizer, ConstAddr(LLtypeMixin.node_vtable_adr2,
+                                                LLtypeMixin.cpu), b4s)
+    v4.backstore_field = LLtypeMixin.nextdescr
+    v4.setfield(LLtypeMixin.valuedescr, OptValue(c1s))
+    v4.setfield(LLtypeMixin.otherdescr, OptValue(b5s))
+    v4._cached_sorted_fields = [LLtypeMixin.valuedescr, LLtypeMixin.otherdescr]
+
+    v2 = OptValue(b2s)
+
+    v4.register_virtual_fields(modifier, [c1s, b5s])
+    liveboxes = []
+    modifier._number_virtuals(liveboxes, {b4s: v4}, 0)
+    assert liveboxes == [b2s, b5s]
+    storage.rd_consts = memo.consts[:]
+    storage.rd_numb = None
+    # resume
+    demo55.next = lltype.nullptr(LLtypeMixin.NODE)
+    b2t = BoxPtr(demo55o)
+    b5t = BoxPtr(demo66o)
+    newboxes = _resume_remap(liveboxes, [b2s, b5s], b2t, b5t)
+
+    metainterp = MyMetaInterp()
+    reader = ResumeDataReader(storage, newboxes, metainterp)
+    assert len(reader.virtuals) == 1
+    b4t = reader._decode_box(modifier._gettagged(b4s))
+    trace = metainterp.trace
+    b4new = (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr2,
+                                         LLtypeMixin.cpu)],
+                              b4t, None)
+    b4set1 = (rop.SETFIELD_GC, [b4t, c1s], None, LLtypeMixin.valuedescr)
+    b4set2 = (rop.SETFIELD_GC, [b4t, b5t], None, LLtypeMixin.otherdescr)
+    b2set = (rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.nextdescr)
+    expected = [b4new, b4set1, b4set2, b2set]
+
+    for x, y in zip(expected, trace):
+        assert x == y
+    ptr = demo55.next
+    assert ptr.value == 111
+    ptr = lltype.cast_pointer(lltype.Ptr(LLtypeMixin.NODE2), ptr)
+    assert ptr.other == demo66
+
+
 def test_invalidation_needed():
     class options:
         failargs_limit = 10



More information about the Pypy-commit mailing list