Author: Carl Friedrich Bolz <cfb...@gmx.de>
Branch: optinfo-into-bridges
Changeset: r87736:6e71ace09797
Date: 2016-10-12 20:10 +0200
http://bitbucket.org/pypy/pypy/changeset/6e71ace09797/

Log:    optimize heap knowledge too (just simple cases, only GC objects, no
        lazy getfields, no arrays)

diff --git a/rpython/jit/metainterp/compile.py 
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -102,7 +102,7 @@
                                    self.call_pure_results,
                                    self.inline_short_preamble,
                                    self.box_names_memo,
-                                   self.resumestorage.rd_numb)
+                                   self.resumestorage)
 
 class UnrolledLoopData(CompileData):
     """ This represents label() ops jump with extra info that's from the
diff --git a/rpython/jit/metainterp/optimizeopt/bridgeopt.py 
b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
--- a/rpython/jit/metainterp/optimizeopt/bridgeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
@@ -15,9 +15,43 @@
 #            (the class is found by actually looking at the runtime value)
 #            the bits are bunched in bunches of 7
 #
+# ---- heap knowledge
+# <length>
+# (<box1> <descr> <box2>) length times, if getfield(box1, descr) == box2
+#                         both boxes should be in the liveboxes
+#
 # ----
 
-def serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, memo):
+def tag_box(box, liveboxes_from_env, memo):
+    from rpython.jit.metainterp.history import Const
+    # XXX bit of code duplication (but it's a subset)
+    if isinstance(box, Const):
+        return memo.getconst(box)
+    else:
+        return liveboxes_from_env[box] # has to exist
+
+def decode_box(resumestorage, tagged, liveboxes, cpu):
+    from rpython.jit.metainterp.resume import untag, TAGCONST, TAGINT, TAGBOX
+    from rpython.jit.metainterp.resume import NULLREF, TAG_CONST_OFFSET, 
tagged_eq
+    from rpython.jit.metainterp.history import ConstInt
+    num, tag = untag(tagged)
+    if tag == TAGCONST:
+        if tagged_eq(tagged, NULLREF):
+            box = cpu.ts.CONST_NULL
+        else:
+            box = resumestorage.rd_consts[num - TAG_CONST_OFFSET]
+    elif tag == TAGINT:
+        box = ConstInt(num)
+    elif tag == TAGBOX:
+        box = liveboxes[num]
+    else:
+        raise AssertionError("unreachable")
+    return box
+
+def serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, 
liveboxes_from_env, memo):
+    liveboxes_set = set(liveboxes)
+    metainterp_sd = optimizer.metainterp_sd
+
     numb_state.grow(len(liveboxes)) # bit too much
     # class knowledge
     bitfield = 0
@@ -36,9 +70,26 @@
     if shifts:
         numb_state.append_int(bitfield << (7 - shifts))
 
-def deserialize_optimizer_knowledge(optimizer, numb, runtime_boxes, liveboxes):
+    # heap knowledge
+    if optimizer.optheap:
+        triples = optimizer.optheap.serialize_optheap(liveboxes_set)
+        numb_state.grow(len(triples) * 3 + 1)
+        numb_state.append_int(len(triples))
+        for box1, descr, box2 in triples:
+            numb_state.append_short(tag_box(box1, liveboxes_from_env, memo))
+            numb_state.append_int(metainterp_sd.descrs_dct[descr])
+            numb_state.append_short(tag_box(box2, liveboxes_from_env, memo))
+    else:
+        numb_state.grow(1)
+        numb_state.append_int(0)
+
+def deserialize_optimizer_knowledge(optimizer, resumestorage, runtime_boxes, 
liveboxes):
+    numb = resumestorage.rd_numb
+    metainterp_sd = optimizer.metainterp_sd
+
     # skip resume section
     index = skip_resume_section(numb, optimizer)
+
     # class knowledge
     bitfield = 0
     mask = 0
@@ -54,6 +105,20 @@
             cls = optimizer.cpu.ts.cls_of_box(runtime_boxes[i])
             optimizer.make_constant_class(box, cls)
 
+    # heap knowledge
+    length, index = numb_next_item(numb, index)
+    result = []
+    for i in range(length):
+        tagged, index = numb_next_item(numb, index)
+        box1 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
+        tagged, index = numb_next_item(numb, index)
+        descr = metainterp_sd.opcode_descrs[tagged]
+        tagged, index = numb_next_item(numb, index)
+        box2 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
+        result.append((box1, descr, box2))
+    if optimizer.optheap:
+        optimizer.optheap.deserialize_optheap(result)
+
 def skip_resume_section(numb, optimizer):
     startcount, index = numb_next_item(numb, 0)
     return numb_next_n_items(numb, startcount, 0)
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py 
b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -48,6 +48,7 @@
         # that has a non-None entry at
         # info._fields[descr.get_index()]
         # must be in cache_infos
+        assert structop.type == 'r'
         self.cached_structs.append(structop)
         self.cached_infos.append(info)
 
@@ -693,6 +694,37 @@
         self._seen_guard_not_invalidated = True
         return self.emit(op)
 
+    def serialize_optheap(self, liveboxes_set):
+        # XXX wrong complexity?
+        result = []
+        for descr, cf in self.cached_fields.iteritems():
+            if cf._lazy_set:
+                continue # XXX safe default for now
+            parent_descr = descr.get_parent_descr()
+            if not parent_descr.is_object():
+                continue
+            for i, box1 in enumerate(cf.cached_structs):
+                if box1 not in liveboxes_set:
+                    continue
+                structinfo = cf.cached_infos[i]
+                box2 = structinfo.getfield(descr).get_box_replacement()
+                if isinstance(box2, Const) or box2 in liveboxes_set:
+                    result.append((box1, descr, box2))
+        return result
+
+    def deserialize_optheap(self, triples):
+        for box1, descr, box2 in triples:
+            parent_descr = descr.get_parent_descr()
+            assert parent_descr.is_object()
+            structinfo = box1.get_forwarded()
+            if not isinstance(structinfo, info.AbstractVirtualPtrInfo):
+                structinfo = info.InstancePtrInfo(parent_descr)
+                structinfo.init_fields(parent_descr, descr.get_index())
+                box1.set_forwarded(structinfo)
+
+            cf = self.field_cache(descr)
+            structinfo.setfield(descr, box1, box2, optheap=self, cf=cf)
+
 
 dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_',
                                       default=OptHeap.emit)
diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py 
b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
--- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py
+++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
@@ -74,13 +74,13 @@
         descr = self.getfield_op.getdescr()
         if rop.is_getfield(g.opnum):
             cf = optheap.field_cache(descr)
-            opinfo.setfield(preamble_op.getdescr(), self.res, pop,
+            opinfo.setfield(preamble_op.getdescr(), g.getarg(0), pop,
                             optheap, cf)
         else:
             index = g.getarg(1).getint()
             assert index >= 0
             cf = optheap.arrayitem_cache(descr, index)
-            opinfo.setitem(self.getfield_op.getdescr(), index, self.res,
+            opinfo.setitem(self.getfield_op.getdescr(), index, g.getarg(0),
                            pop, optheap, cf)
 
     def repr(self, memo):
diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py 
b/rpython/jit/metainterp/optimizeopt/unroll.py
--- a/rpython/jit/metainterp/optimizeopt/unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/unroll.py
@@ -237,12 +237,12 @@
         return label_vs
 
     def optimize_bridge(self, trace, runtime_boxes, call_pure_results,
-                        inline_short_preamble, box_names_memo, numb):
+                        inline_short_preamble, box_names_memo, resumestorage):
         from rpython.jit.metainterp.optimizeopt.bridgeopt import 
deserialize_optimizer_knowledge
         trace = trace.get_iter()
         self._check_no_forwarding([trace.inputargs])
         deserialize_optimizer_knowledge(self.optimizer,
-                                        numb, runtime_boxes,
+                                        resumestorage, runtime_boxes,
                                         trace.inputargs)
         info, ops = self.optimizer.propagate_all_forward(trace,
             call_pure_results, False)
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1815,6 +1815,9 @@
 
     def setup_descrs(self, descrs):
         self.opcode_descrs = descrs
+        self.descrs_dct = {}
+        for index, descr in enumerate(descrs):
+            self.descrs_dct[descr] = index
 
     def setup_indirectcalltargets(self, indirectcalltargets):
         self.indirectcalltargets = list(indirectcalltargets)
diff --git a/rpython/jit/metainterp/resoperation.py 
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -748,7 +748,6 @@
 
     def __init__(self, r=lltype.nullptr(llmemory.GCREF.TO)):
         self.setref_base(r)
-        self.datatype = 'r'
 
     def reset_value(self):
         self.setref_base(lltype.nullptr(llmemory.GCREF.TO))
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -483,7 +483,7 @@
         self._number_virtuals(liveboxes, optimizer, num_virtuals)
         self._add_pending_fields(optimizer, pending_setfields)
 
-        self._add_optimizer_sections(numb_state, liveboxes)
+        self._add_optimizer_sections(numb_state, liveboxes, liveboxes_from_env)
         storage.rd_numb = numb_state.create_numbering()
         storage.rd_consts = self.memo.consts
         return liveboxes[:]
@@ -603,10 +603,11 @@
                 return self.liveboxes_from_env[box]
             return self.liveboxes[box]
 
-    def _add_optimizer_sections(self, numb_state, liveboxes):
+    def _add_optimizer_sections(self, numb_state, liveboxes, 
liveboxes_from_env):
         # add extra information about things the optimizer learned
         from rpython.jit.metainterp.optimizeopt.bridgeopt import 
serialize_optimizer_knowledge
-        serialize_optimizer_knowledge(self.optimizer, numb_state, liveboxes, 
self.memo)
+        serialize_optimizer_knowledge(
+            self.optimizer, numb_state, liveboxes, liveboxes_from_env, 
self.memo)
 
 class AbstractVirtualInfo(object):
     kind = REF
diff --git a/rpython/jit/metainterp/test/test_bridgeopt.py 
b/rpython/jit/metainterp/test/test_bridgeopt.py
--- a/rpython/jit/metainterp/test/test_bridgeopt.py
+++ b/rpython/jit/metainterp/test/test_bridgeopt.py
@@ -22,6 +22,7 @@
 
 class FakeOptimizer(object):
     metainterp_sd = None
+    optheap = None
 
     def __init__(self, dct={}, cpu=None):
         self.dct = dct
@@ -37,6 +38,10 @@
 class FakeClass(object):
     pass
 
+class FakeStorage(object):
+    def __init__(self, numb):
+        self.rd_numb = numb
+
 def test_simple():
     box1 = InputArgRef()
     box2 = InputArgRef()
@@ -50,16 +55,16 @@
     numb_state.append_int(1) # vinfo
     liveboxes = [InputArgInt(), box2, box1, box3]
 
-    serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, None)
+    serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
 
-    assert numb_state.current[:numb_state._pos] == [1, 0b0100000]
+    assert numb_state.current[:numb_state._pos] == [1, 0b0100000, 0]
 
     rbox1 = InputArgRef()
     rbox2 = InputArgRef()
     rbox3 = InputArgRef()
     after_optimizer = FakeOptimizer(cpu=FakeCPU({rbox1: cls}))
     deserialize_optimizer_knowledge(
-        after_optimizer, numb_state.create_numbering(),
+        after_optimizer, FakeStorage(numb_state.create_numbering()),
         [InputArgInt(), rbox2, rbox1, rbox3], liveboxes)
     assert box1 in after_optimizer.constant_classes
     assert box2 not in after_optimizer.constant_classes
@@ -68,7 +73,7 @@
 
 class TestOptBridge(LLJitMixin):
     # integration tests
-    def test_bridge(self):
+    def test_bridge_guard_class(self):
         myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n', 'a'])
         class A(object):
             def f(self):
@@ -96,3 +101,50 @@
         assert res == f(6, 32, 16)
         self.check_trace_count(3)
         self.check_resops(guard_class=1)
+
+    def test_bridge_field_read(self):
+        myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n', 'a'])
+        class A(object):
+            def f(self):
+                return 1
+        class B(A):
+            def f(self):
+                return 2
+        class M(object):
+            _immutable_fields_ = ['x']
+            def __init__(self, x):
+                self.x = x
+
+        m1 = M(1)
+        m2 = M(2)
+        def f(x, y, n):
+            if x:
+                a = A()
+                a.m = m1
+                a.n = n
+            else:
+                a = B()
+                a.m = m2
+                a.n = n
+            a.x = 0
+            res = 0
+            while y > 0:
+                myjitdriver.jit_merge_point(y=y, n=n, res=res, a=a)
+                n1 = a.n
+                m = jit.promote(a.m)
+                res += m.x
+                a.x += 1
+                if y > n:
+                    res += 1
+                m = jit.promote(a.m)
+                res += m.x
+                res += n1 + a.n
+                y -= 1
+            return res
+        res = self.meta_interp(f, [6, 32, 16])
+        assert res == f(6, 32, 16)
+        self.check_trace_count(3)
+        self.check_resops(guard_value=1)
+        self.check_resops(getfield_gc_i=4) # 3x a.x, 1x a.n
+        self.check_resops(getfield_gc_r=1) # in main loop
+
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to