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

arigo at codespeak.net arigo at codespeak.net
Mon Jun 22 23:24:35 CEST 2009


Author: arigo
Date: Mon Jun 22 23:24:33 2009
New Revision: 65872

Modified:
   pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_virtualizable.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py
Log:
Arrays in virtualizables, step 1.


Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	Mon Jun 22 23:24:33 2009
@@ -350,6 +350,7 @@
         self.seen_blocks[block] = True
         self.free_vars = 0
         self.var_positions = {}
+        self.vable_array_vars = {}
         for arg in self.force_block_args_order(block):
             self.register_var(arg, verbose=False)
         self.emit(label(block))
@@ -792,11 +793,18 @@
         if RESULT is lltype.Void:
             return
         # check for virtualizable
-        if self.is_virtualizable_getset(op):
+        try:
+            if self.is_virtualizable_getset(op):
+                vinfo = self.codewriter.metainterp_sd.virtualizable_info
+                index = vinfo.static_field_to_extra_box[op.args[1].value]
+                self.emit('getfield_vable', index)
+                self.register_var(op.result)
+                return
+        except VirtualizableArrayField:
+            # xxx hack hack hack
             vinfo = self.codewriter.metainterp_sd.virtualizable_info
-            index = vinfo.field_to_extra_box[op.args[1].value]
-            self.emit('getfield_vable', index)
-            self.register_var(op.result)
+            index = vinfo.array_field_counter[op.args[1].value]
+            self.vable_array_vars[op.result] = index
             return
         # check for deepfrozen structures that force constant-folding
         if deref(v_inst.concretetype)._hints.get('immutable'):
@@ -826,7 +834,7 @@
         # check for virtualizable
         if self.is_virtualizable_getset(op):
             vinfo = self.codewriter.metainterp_sd.virtualizable_info
-            index = vinfo.field_to_extra_box[op.args[1].value]
+            index = vinfo.static_field_to_extra_box[op.args[1].value]
             self.emit('setfield_vable', index, self.var_position(v_value))
             return
         argname = getattr(deref(v_inst.concretetype), '_gckind', 'gc')
@@ -847,10 +855,15 @@
         # XXX check more carefully; for now assumes that every access of
         # an object of exactly the type VTYPEPTR is a virtualizable access
         vinfo = self.codewriter.metainterp_sd.virtualizable_info
-        if vinfo is not None:
-            return op.args[0].concretetype == vinfo.VTYPEPTR
-        else:
+        if vinfo is None:
+            return False
+        if op.args[0].concretetype != vinfo.VTYPEPTR:
             return False
+        if op.args[1].value in vinfo.static_field_to_extra_box:
+            return True
+        if op.args[1].value in vinfo.array_fields:
+            raise VirtualizableArrayField
+        return False
 
     def handle_getfield_typeptr(self, op):
         # special-casing for getting the typeptr of an object
@@ -866,6 +879,13 @@
         assert ARRAY._gckind == 'gc'
         if self._array_of_voids(ARRAY):
             return
+        if op.args[0] in self.vable_array_vars:     # for virtualizables
+            self.emit('getarrayitem_vable',
+                      self.vable_array_vars[op.args[0]],
+                      self.var_position(op.args[1]))
+            self.register_var(op.result)
+            return
+        # normal case follows
         arraydescr = self.cpu.arraydescrof(ARRAY)
         self.emit('getarrayitem_gc')
         self.emit(self.var_position(op.args[0]))
@@ -878,6 +898,12 @@
         assert ARRAY._gckind == 'gc'
         if self._array_of_voids(ARRAY):
             return
+        if op.args[0] in self.vable_array_vars:     # for virtualizables
+            self.emit('setarrayitem_vable',
+                      self.vable_array_vars[op.args[0]],
+                      self.var_position(op.args[1]),
+                      self.var_position(op.args[2]))
+            return
         arraydescr = self.cpu.arraydescrof(ARRAY)
         self.emit('setarrayitem_gc')
         self.emit(self.var_position(op.args[0]))
@@ -1368,3 +1394,6 @@
     newstartblock.closeblock(Link([v_res], newgraph.returnblock))
     newgraph.ts_stub_for = graph
     return newgraph
+
+class VirtualizableArrayField(Exception):
+    pass

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	Mon Jun 22 23:24:33 2009
@@ -464,6 +464,27 @@
         self.metainterp.synchronize_virtualizable()
         # XXX only the index'th field needs to be synchronized, really
 
+    def _get_arrayitem_vable_index(self, pc, arrayindex, indexbox):
+        indexbox = self.implement_guard_value(pc, indexbox)
+        vinfo = self.metainterp.staticdata.virtualizable_info
+        virtualizable_box = self.metainterp.virtualizable_boxes[-1]
+        virtualizable = virtualizable_box.getptr(vinfo.VTYPEPTR)
+        return vinfo.get_index_in_array(virtualizable, arrayindex,
+                                        indexbox.getint())
+
+    @arguments("orgpc", "int", "box")
+    def opimpl_getarrayitem_vable(self, pc, arrayindex, indexbox):
+        self.metainterp.check_synchronized_virtualizable()
+        index = self._get_arrayitem_vable_index(pc, arrayindex, indexbox)
+        resbox = self.metainterp.virtualizable_boxes[index]
+        self.make_result_box(resbox)
+    @arguments("orgpc", "int", "box", "box")
+    def opimpl_setarrayitem_vable(self, pc, arrayindex, indexbox, valuebox):
+        index = self._get_arrayitem_vable_index(pc, arrayindex, indexbox)
+        self.metainterp.virtualizable_boxes[index] = valuebox
+        self.metainterp.synchronize_virtualizable()
+        # XXX only the index'th field needs to be synchronized, really
+
     def perform_call(self, jitcode, varargs):
         if (isinstance(self.metainterp.history, history.BlackHole) and
             jitcode.calldescr is not None):
@@ -1359,7 +1380,7 @@
     def initialize_virtualizable(self, original_boxes):
         vinfo = self.staticdata.virtualizable_info
         if vinfo is not None:
-            virtualizable_box = original_boxes[vinfo.index_in_boxes]
+            virtualizable_box = original_boxes[vinfo.index_of_virtualizable]
             virtualizable = virtualizable_box.getptr(vinfo.VTYPEPTR)
             # The field 'virtualizable_boxes' is not even present
             # if 'virtualizable_info' is None.  Check for that first.
@@ -1418,11 +1439,12 @@
         vinfo = self.staticdata.virtualizable_info
         if vinfo is not None:
             # xxx only write back the fields really modified
-            vbox = self.virtualizable_boxes[vinfo.num_extra_boxes]
-            for i in range(vinfo.num_extra_boxes):
+            vbox = self.virtualizable_boxes[vinfo.num_static_extra_boxes]
+            for i in range(vinfo.num_static_extra_boxes):
                 fieldbox = self.virtualizable_boxes[i]
                 self.execute_and_record(rop.SETFIELD_GC, [vbox, fieldbox],
-                                        descr=vinfo.field_descrs[i])
+                                        descr=vinfo.static_field_descrs[i])
+            # XXX use array_field_descrs too!
 
 class GenerateMergePoint(Exception):
     def __init__(self, args, target_loop):

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	Mon Jun 22 23:24:33 2009
@@ -23,12 +23,11 @@
         ('vable_base', llmemory.Address),
         ('vable_rti', VABLERTIPTR),
         ('inst_x', lltype.Signed),
-        ('inst_l', lltype.Ptr(lltype.GcArray(lltype.Signed))),
         ('inst_node', lltype.Ptr(NODE)),
         hints = {'virtualizable2': True,
                  'virtuals':()},
         adtmeths = {'access': VirtualizableAccessor()})
-    XY._adtmeths['access'].initialize(XY, ['inst_x', 'inst_node', 'inst_l'])
+    XY._adtmeths['access'].initialize(XY, ['inst_x', 'inst_node'])
 
     xy_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
     heaptracker.set_testing_vtable_for_gcstruct(XY, xy_vtable, 'XY')
@@ -126,6 +125,56 @@
         assert res == 10180
         self.check_loops(getfield_gc=0, setfield_gc=0)
 
+    # ------------------------------
+
+    XY2 = lltype.GcStruct(
+        'XY2',
+        ('parent', rclass.OBJECT),
+        ('vable_base', llmemory.Address),
+        ('vable_rti', VABLERTIPTR),
+        ('inst_x', lltype.Signed),
+        ('inst_l1', lltype.Ptr(lltype.GcArray(lltype.Signed))),
+        ('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))),
+        hints = {'virtualizable2': True,
+                 'virtuals':()},
+        adtmeths = {'access': VirtualizableAccessor()})
+    XY2._adtmeths['access'].initialize(XY, ['inst_x', 'inst_l1[*]',
+                                            'inst_l2[*]'])
+
+    xy2_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
+    heaptracker.set_testing_vtable_for_gcstruct(XY2, xy2_vtable, 'XY2')
+
+    def setup2(self):
+        xy2 = lltype.malloc(self.XY2)
+        xy2.vable_rti = lltype.nullptr(VABLERTIPTR.TO)
+        xy2.parent.typeptr = self.xy2_vtable
+        return xy2
+
+    def test_access_list_fields(self):
+        myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
+                                virtualizables = ['xy2'])
+        ARRAY = lltype.GcArray(lltype.Signed)
+        def f(n):
+            xy2 = self.setup2()
+            xy2.inst_x = 100
+            xy2.inst_l1 = lltype.malloc(ARRAY, 3)
+            xy2.inst_l1[0] = -9999999
+            xy2.inst_l1[1] = -9999999
+            xy2.inst_l1[2] = 3001
+            xy2.inst_l2 = lltype.malloc(ARRAY, 2)
+            xy2.inst_l2[0] = 80
+            xy2.inst_l2[1] = -9999999
+            while n > 0:
+                myjitdriver.can_enter_jit(xy2=xy2, n=n)
+                myjitdriver.jit_merge_point(xy2=xy2, n=n)
+                xy2.inst_l1[2] += xy2.inst_l2[0]
+                n -= 1
+            return xy2.inst_l1[2]
+        res = self.meta_interp(f, [16])
+        assert res == 3001 + 16 * 80
+        self.check_loops(getfield_gc=0, setfield_gc=0,
+                         getarrayitem_gc=0, setarrayitem_gc=0)
+
 
 class ImplicitVirtualizableTests:
 

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py	Mon Jun 22 23:24:33 2009
@@ -471,47 +471,105 @@
         assert len(jitdriver.virtualizables) == 1    # for now
         [vname] = jitdriver.virtualizables
         index = len(jitdriver.greens) + jitdriver.reds.index(vname)
+        self.index_of_virtualizable = index
         VTYPEPTR = warmrunnerdesc.JIT_ENTER_FUNCTYPE.ARGS[index]
-        self.fields = VTYPEPTR.TO._adtmeths['access'].redirected_fields
-        FIELDTYPES = [getattr(VTYPEPTR.TO, name) for name in self.fields]
         self.VTYPEPTR = VTYPEPTR
-        self.index_in_boxes = index
-        self.num_extra_boxes = len(self.fields)
-        self.field_to_extra_box = dict([(name, i)
-                                      for (i, name) in enumerate(self.fields)])
-        self.extra_types = [history.getkind(TYPE) for TYPE in FIELDTYPES]
+        #
+        all_fields = VTYPEPTR.TO._adtmeths['access'].redirected_fields
+        static_fields = []
+        array_fields = []
+        for name in all_fields:
+            if name.endswith('[*]'):
+                array_fields.append(name[:-3])
+            else:
+                static_fields.append(name)
+        self.static_fields = static_fields
+        self.array_fields = array_fields
+        #
+        FIELDTYPES = [getattr(VTYPEPTR.TO, name) for name in static_fields]
+        ARRAYITEMTYPES = []
+        for name in array_fields:
+            ARRAYPTR = getattr(VTYPEPTR.TO, name)
+            assert isinstance(ARRAYPTR, lltype.Ptr)
+            assert isinstance(ARRAYPTR.TO, lltype.GcArray)
+            ARRAYITEMTYPES.append(ARRAYPTR.TO.OF)
+        #
+        self.num_static_extra_boxes = len(static_fields)
+        self.static_field_to_extra_box = dict(
+            [(name, i) for (i, name) in enumerate(static_fields)])
+        self.array_field_counter = dict(
+            [(name, i) for (i, name) in enumerate(array_fields)])
+        self.static_extra_types = [history.getkind(TYPE)
+                                   for TYPE in FIELDTYPES]
+        self.arrayitem_extra_types = [history.getkind(ITEM)
+                                      for ITEM in ARRAYITEMTYPES]
         cpu = warmrunnerdesc.cpu
-        self.field_descrs = [cpu.fielddescrof(VTYPEPTR.TO, name)
-                             for name in self.fields]
+        self.static_field_descrs = [cpu.fielddescrof(VTYPEPTR.TO, name)
+                                    for name in static_fields]
+        self.array_field_descrs = [
+            cpu.arraydescrof(getattr(VTYPEPTR.TO, name).TO)
+            for name in array_fields]
         #
         def read_boxes(cpu, virtualizable):
             boxes = []
-            for _, fieldname in unroll_fields:
+            for _, fieldname in unroll_static_fields:
                 x = getattr(virtualizable, fieldname)
                 boxes.append(wrap(cpu, x))
+            for _, fieldname in unroll_array_fields:
+                lst = getattr(virtualizable, fieldname)
+                for i in range(len(lst)):
+                    boxes.append(wrap(cpu, lst[i]))
             return boxes
         #
         def write_boxes(virtualizable, boxes):
-            assert len(boxes) >= self.num_extra_boxes
             i = 0
-            for FIELDTYPE, fieldname in unroll_fields:
+            for FIELDTYPE, fieldname in unroll_static_fields:
                 x = unwrap(FIELDTYPE, boxes[i])
                 setattr(virtualizable, fieldname, x)
                 i = i + 1
+            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
+                lst = getattr(virtualizable, fieldname)
+                for j in range(len(lst)):
+                    x = unwrap(ARRAYITEMTYPE, boxes[i])
+                    lst[j] = x
+                    i = i + 1
+            assert len(boxes) == i + 1
         #
         def check_boxes(virtualizable, boxes):
             # for debugging
-            assert len(boxes) >= self.num_extra_boxes
             i = 0
-            for FIELDTYPE, fieldname in unroll_fields:
+            for FIELDTYPE, fieldname in unroll_static_fields:
                 x = unwrap(FIELDTYPE, boxes[i])
                 assert getattr(virtualizable, fieldname) == x
                 i = i + 1
+            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
+                lst = getattr(virtualizable, fieldname)
+                for j in range(len(lst)):
+                    x = unwrap(ARRAYITEMTYPE, boxes[i])
+                    assert lst[j] == x
+                    i = i + 1
+            assert len(boxes) == i + 1
+        #
+        def get_index_in_array(virtualizable, arrayindex, index):
+            index += self.num_static_extra_boxes
+            j = 0
+            for _, fieldname in unroll_array_fields:
+                if arrayindex == j:
+                    return index
+                lst = getattr(virtualizable, fieldname)
+                index += len(lst)
+                j = j + 1
+            else:
+                assert False, "invalid arrayindex"
         #
-        unroll_fields = unrolling_iterable(zip(FIELDTYPES, self.fields))
+        unroll_static_fields = unrolling_iterable(zip(FIELDTYPES,
+                                                      static_fields))
+        unroll_array_fields = unrolling_iterable(zip(ARRAYITEMTYPES,
+                                                     array_fields))
         self.read_boxes = read_boxes
         self.write_boxes = write_boxes
         self.check_boxes = check_boxes
+        self.get_index_in_array = get_index_in_array
 
     def _freeze_(self):
         return True
@@ -601,11 +659,13 @@
     metainterp_sd = warmrunnerdesc.metainterp_sd
     vinfo = metainterp_sd.virtualizable_info
     if vinfo is None:
-        extra_vable_fields = []
+        vable_static_fields = []
+        vable_array_fields = []
     else:
-        extra_vable_fields = unrolling_iterable(vinfo.fields)
-        red_args_types = unrolling_iterable(list(red_args_types) +
-                                            vinfo.extra_types)
+        vable_static_fields = unrolling_iterable(
+            zip(vinfo.static_extra_types, vinfo.static_fields))
+        vable_array_fields = unrolling_iterable(
+            zip(vinfo.arrayitem_extra_types, vinfo.array_fields))
     #
     if num_green_args:
         MAX_HASH_TABLE_BITS = 28
@@ -630,27 +690,37 @@
                 i = i + 1
             return True
         def set_future_values(self, *redargs):
-            cpu = metainterp_sd.cpu
-            if vinfo is not None:
-                virtualizable = redargs[vinfo.index_in_boxes]
-                for vable_field_name in extra_vable_fields:
-                    x = getattr(virtualizable, vable_field_name)
-                    redargs = redargs + (x,)
-            j = 0
+            i = 0
             for typecode in red_args_types:
-                value = redargs[j]
-                if typecode == 'ptr':
-                    ptrvalue = lltype.cast_opaque_ptr(llmemory.GCREF, value)
-                    cpu.set_future_value_ptr(j, ptrvalue)
-                elif typecode == 'obj':
-                    objvalue = ootype.cast_to_object(value)
-                    cpu.set_future_value_obj(j, objvalue)
-                elif typecode == 'int':
-                    intvalue = lltype.cast_primitive(lltype.Signed, value)
-                    cpu.set_future_value_int(j, intvalue)
-                else:
-                    assert False
-                j = j + 1
+                set_future_value(i, redargs[i], typecode)
+                i = i + 1
+            if vinfo is not None:
+                virtualizable = redargs[vinfo.index_of_virtualizable]
+                for typecode, fieldname in vable_static_fields:
+                    x = getattr(virtualizable, fieldname)
+                    set_future_value(i, x, typecode)
+                    i = i + 1
+                for typecode, fieldname in vable_array_fields:
+                    lst = getattr(virtualizable, fieldname)
+                    for j in range(len(lst)):
+                        x = lst[j]
+                        set_future_value(i, x, typecode)
+                        i = i + 1
+
+    def set_future_value(j, value, typecode):
+        cpu = metainterp_sd.cpu
+        if typecode == 'ptr':
+            ptrvalue = lltype.cast_opaque_ptr(llmemory.GCREF, value)
+            cpu.set_future_value_ptr(j, ptrvalue)
+        elif typecode == 'obj':
+            objvalue = ootype.cast_to_object(value)
+            cpu.set_future_value_obj(j, objvalue)
+        elif typecode == 'int':
+            intvalue = lltype.cast_primitive(lltype.Signed, value)
+            cpu.set_future_value_int(j, intvalue)
+        else:
+            assert False
+    set_future_value._annspecialcase_ = 'specialize:arg(2)'
 
     class WarmEnterState:
         def __init__(self):



More information about the Pypy-commit mailing list