[pypy-svn] r62953 - in pypy/branch/pyjitpl5/pypy/jit/metainterp: . test

fijal at codespeak.net fijal at codespeak.net
Sat Mar 14 15:44:10 CET 2009


Author: fijal
Date: Sat Mar 14 15:44:08 2009
New Revision: 62953

Modified:
   pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/specnode.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_virtualizable.py
Log:
A controversial checkin - try to reuse logic for virtualizables for
always_virtuals (they're more or less the same after all). Tests that showcase
problems with bridges


Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py	Sat Mar 14 15:44:08 2009
@@ -10,6 +10,7 @@
                                           SpecNodeWithBox,
                                           DelayedFixedListSpecNode,
                                           VirtualFixedListSpecNode,
+                                          VirtualizableListSpecNode,
                                           )
 from pypy.jit.metainterp import executor
 from pypy.rlib.objectmodel import we_are_translated
@@ -26,12 +27,18 @@
         assert other.arraydescr == self.arraydescr
         return True
 
+class FixedClass(Const):
+    def equals(self, other):
+        assert isinstance(other, FixedClass)
+        return True
+
 class CancelInefficientLoop(Exception):
-    pass
+    def __init__(self, *args):
+        import pdb
+        pdb.set_trace()
 
 FLAG_ALLOCATIONS      = 0x0
 FLAG_LIST_ALLOCATIONS = 0x1
-FLAG_PREBULT_OBJECTS  = 0x2
 FLAG_BOXES_FROM_FRAME = 0x3
 FLAG_SHIFT            = 2
 FLAG_MASK             = 0x3
@@ -47,11 +54,9 @@
         self.setfields = []
         # the same as above, but for lists and for running setitem
         self.list_allocations = []
-        # objects that are "always virtual"
-        self.prebuilt_objects = []
         self.setitems = []
 
-    def deal_with_box(self, box, nodes, liveboxes, memo, cpu):
+    def deal_with_box(self, box, nodes, liveboxes, memo):
         if isinstance(box, Const) or box not in nodes:
             virtual = False
             virtualized = False
@@ -64,26 +69,20 @@
             virtual = instnode.virtual
             virtualized = instnode.virtualized
         if virtual:
-            if instnode.always_virtual:
-                res = ((len(self.prebuilt_objects) << FLAG_SHIFT)
-                       | FLAG_PREBULT_OBJECTS)
-                self.prebuilt_objects.append(instnode.source.constbox())
+            if isinstance(instnode.cls.source, FixedList):
+                ld = instnode.cls.source
+                assert isinstance(ld, FixedList)
+                alloc_offset = len(self.list_allocations)
+                ad = ld.arraydescr
+                self.list_allocations.append((ad, instnode.cursize))
+                res = (alloc_offset << FLAG_SHIFT) | FLAG_LIST_ALLOCATIONS
             else:
-                if isinstance(instnode.cls.source, FixedList):
-                    ld = instnode.cls.source
-                    assert isinstance(ld, FixedList)
-                    alloc_offset = len(self.list_allocations)
-                    ad = ld.arraydescr
-                    self.list_allocations.append((ad, instnode.cursize))
-                    res = (alloc_offset << FLAG_SHIFT) | FLAG_LIST_ALLOCATIONS
-                else:
-                    alloc_offset = len(self.allocations)
-                    self.allocations.append(instnode.cls.source.getint())
-                    res = (alloc_offset << FLAG_SHIFT) | FLAG_ALLOCATIONS
+                alloc_offset = len(self.allocations)
+                self.allocations.append(instnode.cls.source.getint())
+                res = (alloc_offset << FLAG_SHIFT) | FLAG_ALLOCATIONS
             memo[box] = res
             for ofs, node in instnode.curfields.items():
-                num = self.deal_with_box(node.source, nodes, liveboxes, memo,
-                                         cpu)
+                num = self.deal_with_box(node.source, nodes, liveboxes, memo)
                 if isinstance(instnode.cls.source, FixedList):
                     ld = instnode.cls.source
                     assert isinstance(ld, FixedList)
@@ -95,9 +94,14 @@
             memo[box] = res
             liveboxes.append(box)
             for ofs, node in instnode.curfields.items():
-                num = self.deal_with_box(node.source, nodes, liveboxes, memo,
-                                         cpu)
-                self.setfields.append((res, ofs, num))
+                num = self.deal_with_box(node.source, nodes, liveboxes,
+                                         memo)
+                if instnode.cls and isinstance(instnode.cls.source, FixedList):
+                    ld = instnode.cls.source
+                    assert isinstance(ld, FixedList)
+                    self.setitems.append((res, ld.arraydescr, ofs, num))
+                else:
+                    self.setfields.append((res, ofs, num))
         else:
             res = (len(liveboxes) << FLAG_SHIFT) | FLAG_BOXES_FROM_FRAME
             memo[box] = res
@@ -137,8 +141,6 @@
         self.expanded_fields = r_dict(av_eq, av_hash)
         self.cursize = -1
         self.vdesc = None # for virtualizables
-        self.always_virtual = False # a flag that is set on objects
-        # passed around, that are virtuals stored on virtualizables
 
     def is_nonzero(self):
         return self.cls is not None or self.nonzero
@@ -146,34 +148,31 @@
     def is_zero(self):
         return self.const and not self.source.getptr_base()
 
-    def escape_if_startbox(self, memo, escape_self=True):
+    def escape_if_startbox(self, memo):
         if self in memo:
             return
         memo[self] = None
         if self.startbox:
-            if escape_self:
-                self.escaped = True
-            else:
-                self.always_virtual = True
+            self.escaped = True
         if not self.virtualized:
             for node in self.curfields.values():
                 node.escape_if_startbox(memo)
         else:
             for key, node in self.curfields.items():
-                if self.vdesc is not None and not av_list_in(self.vdesc, key):
-                    esc_self = True
-                else:
-                    esc_self = False
-                node.escape_if_startbox(memo, esc_self)
+                if self.vdesc is not None and av_list_in(self.vdesc, key):
+                    node.virtualized = True
+                    if node.cls is None:
+                        node.cls = InstanceNode(FixedClass(), const=True)
+                node.escape_if_startbox(memo)
             # we also need to escape fields that are only read, never written,
             # if they're not marked specifically as ones that does not escape
             for key, node in self.origfields.items():
                 if key not in self.curfields:
-                    if self.vdesc is not None and not av_list_in(self.vdesc, key):
-                        esc_self = True
-                    else:
-                        esc_self = False
-                    node.escape_if_startbox(memo, esc_self)
+                    if self.vdesc is not None and av_list_in(self.vdesc, key):
+                        node.virtualized = True
+                        if node.cls is None:
+                            node.cls = InstanceNode(FixedClass(), const=True)
+                    node.escape_if_startbox(memo)
 
     def add_to_dependency_graph(self, other, dep_graph):
         dep_graph.append((self, other))
@@ -201,12 +200,9 @@
                 return NotSpecNode()
             return FixedClassSpecNode(known_class)
         if not other.escaped:
+            assert self is not other
             fields = []
-            if self is other:
-                d = self.origfields.copy()
-                d.update(other.curfields)
-            else:
-                d = other.curfields
+            d = other.curfields
             lst = d.keys()
             sort_descrs(lst)
             for ofs in lst:
@@ -240,18 +236,21 @@
             sort_descrs(offsets)
             fields = []
             for ofs in offsets:
-                if ofs in self.origfields and ofs in other.curfields:
+                if ofs in other.curfields:
                     node = other.curfields[ofs]
+                    if ofs not in self.origfields:
+                        box = node.source.clonebox()
+                        self.origfields[ofs] = InstanceNode(box, escaped=False)
+                        self.origfields[ofs].cls = node.cls
+                        nodes[box] = self.origfields[ofs]
                     specnode = self.origfields[ofs].intersect(node, nodes)
-                elif ofs in self.origfields:
+                else:
+                    # ofs in self.origfields:
                     node = self.origfields[ofs]
                     specnode = node.intersect(node, nodes)
-                else:
-                    # ofs in other.curfields
-                    node = other.curfields[ofs]
-                    self.origfields[ofs] = InstanceNode(node.source.clonebox())
-                    specnode = NotSpecNode()
                 fields.append((ofs, specnode))
+            if isinstance(known_class, FixedList):
+                return VirtualizableListSpecNode(known_class, fields)
             return VirtualizableSpecNode(known_class, fields)
 
     def __repr__(self):
@@ -522,7 +521,7 @@
         op = op.clone()
         for box in old_boxes:
             indices.append(storage.deal_with_box(box, self.nodes,
-                                                 liveboxes, memo, self.cpu))
+                                                 liveboxes, memo))
         rev_boxes = {}
         for i in range(len(liveboxes)):
             box = liveboxes[i]
@@ -574,9 +573,16 @@
 
     def optimize_getfield(self, instnode, ofs, box):
         assert isinstance(ofs, AbstractValue)
-        if instnode.virtual or instnode.virtualized:
+        if instnode.virtual:
             assert ofs in instnode.curfields
             return True # this means field is never actually
+        elif instnode.virtualized:
+            if ofs in instnode.curfields:
+                return True
+            # this means field comes from a virtualizable but is never
+            # written. Cool, simply make the result constant
+            self.nodes[box] = InstanceNode(box.constbox(), const=True)
+            return True
         elif ofs in instnode.cleanfields:
             self.nodes[box] = instnode.cleanfields[ofs]
             return True
@@ -721,6 +727,7 @@
                 instnode = self.getnode(op.args[0])
                 # we know the result is constant if instnode is a virtual,
                 # a constant, or known to be non-zero.
+                # XXX what about virtualizables?
                 if instnode.virtual or instnode.const or instnode.is_nonzero():
                     box = op.result
                     instnode = InstanceNode(box.constbox(), const=True)
@@ -805,6 +812,8 @@
         return True
 
     def match(self, old_operations):
+        import pdb
+        pdb.set_trace()
         old_mp = old_operations[0]
         jump_op = self.loop.operations[-1]
         assert jump_op.opnum == rop.JUMP
@@ -826,12 +835,10 @@
             old_specnode.adapt_to(new_instnode)
 
 class Chooser(object):
-    def __init__(self, boxes_from_frame, allocated_boxes, allocated_lists,
-                 prebuilt_objects):
+    def __init__(self, boxes_from_frame, allocated_boxes, allocated_lists):
         self.boxes_from_frame = boxes_from_frame
         self.allocated_lists = allocated_lists
         self.allocated_boxes = allocated_boxes
-        self.prebuilt_objects = prebuilt_objects
 
     def box_from_index(self, index):
         ofs = index >> FLAG_SHIFT
@@ -842,10 +849,8 @@
             return self.allocated_boxes[ofs]
         elif where_from == FLAG_LIST_ALLOCATIONS:
             return self.allocated_lists[ofs]
-        elif where_from == FLAG_PREBULT_OBJECTS:
-            return self.prebuilt_objects[ofs]
         else:
-            assert 0, "I can't count to 4"    
+            assert 0, "Should not happen"
 
 def rebuild_boxes_from_guard_failure(guard_op, metainterp, boxes_from_frame):
     allocated_boxes = []
@@ -867,8 +872,7 @@
         listbox = metainterp.execute_and_record(rop.NEW_ARRAY,
                                                 [sizebox], ad)
         allocated_lists.append(listbox)
-    chooser = Chooser(boxes_from_frame, allocated_boxes, allocated_lists,
-                      storage.prebuilt_objects)
+    chooser = Chooser(boxes_from_frame, allocated_boxes, allocated_lists)
     for index_in_alloc, ofs, index_in_arglist in storage.setfields:
         fieldbox = chooser.box_from_index(index_in_arglist)
         box = chooser.box_from_index(index_in_alloc)

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/specnode.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/specnode.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/specnode.py	Sat Mar 14 15:44:08 2009
@@ -139,7 +139,7 @@
             subspecnode.adapt_to(instnode.curfields[ofs])
 
 class VirtualizedSpecNode(SpecNodeWithFields):
-
+    
     def expand_boxlist(self, instnode, newboxlist, start):
         newboxlist.append(instnode.source)
         SpecNodeWithFields.expand_boxlist(self, instnode, newboxlist, start)
@@ -217,10 +217,44 @@
     def equals(self, other):
         if not isinstance(other, VirtualizableSpecNode):
             return False
+        return SpecNodeWithFields.equals(self, other)        
+
+    def adapt_to(self, instnode):
+        instnode.virtualized = True
+        VirtualizedSpecNode.adapt_to(self, instnode)
+
+class VirtualizableListSpecNode(VirtualizedSpecNode):
+
+    def equals(self, other):
+        if not isinstance(other, VirtualizableListSpecNode):
+            return False
         return SpecNodeWithFields.equals(self, other)
+    
+    def extract_runtime_data(self, cpu, valuebox, resultlist):
+        from pypy.jit.metainterp.resoperation import rop
+        from pypy.jit.metainterp.optimize import FixedList
+        from pypy.jit.metainterp.history import check_descr
+
+        resultlist.append(valuebox)
+        cls = self.known_class
+        assert isinstance(cls, FixedList)
+        arraydescr = cls.arraydescr
+        check_descr(arraydescr)
+        for ofs, subspecnode in self.fields:
+            fieldbox = executor.execute(cpu, rop.GETARRAYITEM_GC,
+                                        [valuebox, ofs], arraydescr)
+            subspecnode.extract_runtime_data(cpu, fieldbox, resultlist)
+
+    def adapt_to(self, instnode):
+        instnode.virtualized = True
+        VirtualizedSpecNode.adapt_to(self, instnode)
 
 class VirtualSpecNode(SpecNodeWithFields):
 
+    def adapt_to(self, instnode):
+        instnode.virtual = True
+        SpecNodeWithFields.adapt_to(self, instnode)
+
     def mutate_nodes(self, instnode):
         SpecNodeWithFields.mutate_nodes(self, instnode)
         instnode.virtual = True
@@ -240,7 +274,7 @@
 
    def mutate_nodes(self, instnode):
        VirtualSpecNode.mutate_nodes(self, instnode)
-       instnode.known_length = self.known_length
+       instnode.cursize = self.known_length
 
    def equals(self, other):
        if not isinstance(other, VirtualFixedListSpecNode):

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_virtualizable.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_virtualizable.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_virtualizable.py	Sat Mar 14 15:44:08 2009
@@ -277,8 +277,6 @@
         class BaseFrame(object):
             _virtualizable2_ = True
 
-            _always_virtual_ = ['x']
-
             def __init__(self, x):
                 self.x = x
 
@@ -335,11 +333,12 @@
                 node = frame.node
                 subnode = node.node
                 g(subnode)
-                frame.node = Node(SubNode(subnode.x + 1))
+                frame.node.node = SubNode(subnode.x + 1)
                 n -= 1
             return n
 
         res = self.meta_interp(f, [10], policy=StopAtXPolicy(g))
+        self.check_loops(getfield_gc=1)
         assert res == 0
 
     def test_external_pass(self):
@@ -421,7 +420,43 @@
         self.check_loops(setarrayitem_gc=0)
         self.check_loop_count(3)
         assert res == 3
-            
+
+    def test_virtual_obj_on_always_virtual(self):
+        py.test.skip("XYz")
+        jitdriver = JitDriver(greens = [], reds = ['frame', 'n', 's'],
+                              virtualizables = ['frame'])
+
+        class Frame(object):
+            _virtualizable2_ = True
+
+            _always_virtual_ = ['l']
+
+            def __init__(self, l):
+                self.l = l
+
+        class Stuff(object):
+            def __init__(self, elem):
+                self.elem = elem
+
+        def f(n):
+            frame = Frame([Stuff(3), Stuff(4)])
+            s = 0
+            while n > 0:
+                jitdriver.can_enter_jit(frame=frame, n=n, s=s)
+                jitdriver.jit_merge_point(frame=frame, n=n, s=s)
+                if n % 2:
+                    s += frame.l[0].elem
+                    frame.l[0] = Stuff(n)
+                else:
+                    s += frame.l[1].elem
+                    frame.l[1] = Stuff(n)
+                n -= 1
+            return s
+
+        res = self.meta_interp(f, [30], listops=True)
+        self.check_loops(getfield_gc=1)
+        assert res == f(30)
+        
 
     def test_external_read(self):
         py.test.skip("Fails")



More information about the Pypy-commit mailing list