[pypy-commit] pypy gc_no_cleanup_nursery: Kill clear_array_contents and replace with NEW_ARRAY_CLEAR *should* work

fijal noreply at buildbot.pypy.org
Thu Sep 25 11:39:11 CEST 2014


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: gc_no_cleanup_nursery
Changeset: r73695:906a0b752d1f
Date: 2014-09-25 11:38 +0200
http://bitbucket.org/pypy/pypy/changeset/906a0b752d1f/

Log:	Kill clear_array_contents and replace with NEW_ARRAY_CLEAR *should*
	work equally well and it's a cleaner concept

diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -643,20 +643,7 @@
     def bh_new_array(self, length, arraydescr):
         array = lltype.malloc(arraydescr.A, length, zero=True)
         return lltype.cast_opaque_ptr(llmemory.GCREF, array)
-
-    def bh_clear_array_contents(self, a, descr):
-        a = support.cast_arg(lltype.Ptr(descr.A), a)
-        ITEM = descr.A.OF
-        array = a._obj
-        if isinstance(ITEM, lltype.Struct):
-            for i in xrange(array.getlength()):
-                for name, FIELD in ITEM._flds.iteritems():
-                    null = FIELD._defl()
-                    setattr(array.getitem(i), name, null)
-        else:
-            null = ITEM._defl()
-            for i in xrange(array.getlength()):
-                array.setitem(i, null)
+    bh_new_array_clear = bh_new_array
 
     def bh_classof(self, struct):
         struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -592,14 +592,6 @@
     def bh_new(self, sizedescr):
         return self.gc_ll_descr.gc_malloc(sizedescr)
 
-    def bh_clear_array_contents(self, ref, arraydescr):
-        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
-        arraysize = self.bh_arraylen_gc(ref, arraydescr)
-        totalsize = size * arraysize
-        adr = rffi.cast(lltype.Signed, ref) + ofs
-        memset_fn(rffi.cast(llmemory.Address, adr), rffi.cast(rffi.INT, 0),
-                  rffi.cast(rffi.SIZE_T, totalsize))
-
     def bh_new_with_vtable(self, vtable, sizedescr):
         res = self.gc_ll_descr.gc_malloc(sizedescr)
         if self.vtable_offset is not None:
diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -66,9 +66,6 @@
                 continue
             if op.is_guard():
                 self.emit_pending_zeros()
-            elif op.getopnum() == rop.CLEAR_ARRAY_CONTENTS:
-                self.handle_clear_array_contents(op.getdescr(), op.getarg(0))
-                continue
             elif op.can_malloc():
                 self.emitting_an_operation_that_can_collect()
             elif op.getopnum() == rop.LABEL:
@@ -117,7 +114,7 @@
                                   [op.result, ConstInt(classint)], None,
                                   descr=self.gc_ll_descr.fielddescr_vtable)
                 self.newops.append(op)
-        elif opnum == rop.NEW_ARRAY:
+        elif opnum == rop.NEW_ARRAY or opnum == rop.NEW_ARRAY_CLEAR:
             descr = op.getdescr()
             assert isinstance(descr, ArrayDescr)
             self.handle_new_array(descr, op)
@@ -150,14 +147,11 @@
         except KeyError:
             pass
 
-    def clear_varsize_gc_fields(self, kind, descr, result, v_length):
+    def clear_varsize_gc_fields(self, kind, descr, result, v_length, opnum):
         if self.gc_ll_descr.malloc_zero_filled:
             return
         if kind == FLAG_ARRAY:
-            if descr.is_array_of_structs() or descr.is_array_of_pointers():
-                # for the case of array of structs, this is for correctness
-                # only, since in practice all GC arrays of structs are
-                # allocated with malloc(zero=True)
+            if opnum == rop.NEW_ARRAY_CLEAR:
                 self.handle_clear_array_contents(descr, result, v_length)
             return
         if kind == FLAG_STR:
@@ -200,7 +194,7 @@
             # stuff that initializes GC header fields differently
             self.gen_initialize_len(op.result, v_length, arraydescr.lendescr)
             self.clear_varsize_gc_fields(kind, op.getdescr(), op.result,
-                                         v_length)
+                                         v_length, op.getopnum())
             return
         if (total_size >= 0 and
                 self.gen_malloc_nursery(total_size, op.result)):
@@ -218,7 +212,8 @@
                 self.gen_malloc_unicode(v_length, op.result)
             else:
                 raise NotImplementedError(op.getopname())
-        self.clear_varsize_gc_fields(kind, op.getdescr(), op.result, v_length)
+        self.clear_varsize_gc_fields(kind, op.getdescr(), op.result, v_length,
+                                     op.getopnum())
 
     def handle_clear_array_contents(self, arraydescr, v_arr, v_length=None):
         # XXX more work here to reduce or remove the ZERO_ARRAY in some cases
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2036,6 +2036,14 @@
                                     'ref', descr=arraydescr)
         assert r1.value != r2.value
         a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1.value)
+        assert len(a) == 342
+
+    def test_new_array_clear(self):
+        A = lltype.GcArray(lltype.Signed)
+        arraydescr = self.cpu.arraydescrof(A)
+        r1 = self.execute_operation(rop.NEW_ARRAY_CLEAR, [BoxInt(342)],
+                                    'ref', descr=arraydescr)
+        a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1.value)
         assert a[0] == 0
         assert len(a) == 342
 
@@ -4440,24 +4448,6 @@
                                    [boxfloat(12.5)], 'int')
         assert res.getint() == struct.unpack("I", struct.pack("f", 12.5))[0]
 
-    def test_clear_array_contents(self):
-        from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
-        if not isinstance(self.cpu, AbstractLLCPU):
-            py.test.skip("pointless test on non-asm")
-        oldval = self.cpu.gc_ll_descr.malloc_zero_filled
-        self.cpu.gc_ll_descr.malloc_zero_filled = False
-        try:
-            A = lltype.GcArray(lltype.Signed)
-            a = lltype.malloc(A, 3)
-            a[1] = 13
-            descr = self.cpu.arraydescrof(A)
-            ref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
-            self.execute_operation(rop.CLEAR_ARRAY_CONTENTS,
-                                   [BoxPtr(ref)], 'void', descr=descr)
-            assert a[1] == 0
-        finally:
-            self.cpu.gc_ll_descr.malloc_zero_filled = oldval
-
     def test_zero_ptr_field(self):
         T = lltype.GcStruct('T')
         S = lltype.GcStruct('S', ('x', lltype.Ptr(T)))
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -316,8 +316,7 @@
             self.assembler.mc.mark_op(op)
             self.rm.position = i
             self.xrm.position = i
-            if (op.has_no_side_effect() and op.result not in self.longevity
-                and op.opnum != rop.CLEAR_ARRAY_CONTENTS):
+            if op.has_no_side_effect() and op.result not in self.longevit:
                 i += 1
                 self.possibly_free_vars_for_op(op)
                 continue
diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -1346,10 +1346,6 @@
         vtable = heaptracker.descr2vtable(cpu, descr)
         return cpu.bh_new_with_vtable(vtable, descr)
 
-    @arguments("cpu", "r", "d")
-    def bhimpl_clear_array_contents(cpu, ref, descr):
-        cpu.bh_clear_array_contents(ref, descr)    
-
     @arguments("cpu", "r", returns="i")
     def bhimpl_guard_class(cpu, struct):
         return cpu.bh_classof(struct)
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -337,7 +337,6 @@
                          rop.CALL_MALLOC_NURSERY,
                          rop.CALL_MALLOC_NURSERY_VARSIZE,
                          rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME,
-                         rop.CLEAR_ARRAY_CONTENTS,
                          rop.LABEL,
                          ):      # list of opcodes never executed by pyjitpl
                 continue
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py b/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -150,10 +150,10 @@
     def test_nonmatching_arraystruct_1(self):
         ops = """
         [p1, f0]
-        p2 = new_array(3, descr=complexarraydescr)
+        p2 = new_array_clear(3, descr=complexarraydescr)
         setinteriorfield_gc(p2, 2, f0, descr=complexrealdescr)
         label(p2, f0)
-        p4 = new_array(3, descr=complexarraydescr)
+        p4 = new_array_clear(3, descr=complexarraydescr)
         setinteriorfield_gc(p4, 2, f0, descr=compleximagdescr)
         jump(p4, f0)
         """
@@ -163,10 +163,10 @@
     def test_nonmatching_arraystruct_2(self):
         ops = """
         [p1, f0]
-        p2 = new_array(3, descr=complexarraydescr)
+        p2 = new_array_clear(3, descr=complexarraydescr)
         setinteriorfield_gc(p2, 2, f0, descr=complexrealdescr)
         label(p2, f0)
-        p4 = new_array(2, descr=complexarraydescr)
+        p4 = new_array_clear(2, descr=complexarraydescr)
         setinteriorfield_gc(p4, 0, f0, descr=complexrealdescr)
         jump(p4, f0)
         """
@@ -198,7 +198,7 @@
     def test_not_virtual_arraystruct(self):
         ops = """
         [p1]
-        p3 = new_array(3, descr=complexarraydescr)
+        p3 = new_array_clear(3, descr=complexarraydescr)
         label(p3)
         p4 = escape()
         jump(p4)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -940,7 +940,7 @@
     def test_virtual_array_of_struct(self):
         ops = """
         [f0, f1, f2, f3]
-        p0 = new_array(2, descr=complexarraydescr)
+        p0 = new_array_clear(2, descr=complexarraydescr)
         setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
         setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
         setinteriorfield_gc(p0, 1, f3, descr=compleximagdescr)
@@ -966,7 +966,7 @@
     def test_virtual_array_of_struct_forced(self):
         ops = """
         [f0, f1]
-        p0 = new_array(1, descr=complexarraydescr)
+        p0 = new_array_clear(1, descr=complexarraydescr)
         setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
         setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
         f2 = getinteriorfield_gc(p0, 0, descr=complexrealdescr)
@@ -978,7 +978,7 @@
         expected = """
         [f0, f1]
         f2 = float_mul(f0, f1)
-        p0 = new_array(1, descr=complexarraydescr)
+        p0 = new_array_clear(1, descr=complexarraydescr)
         setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
         setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
         i0 = escape(f2, p0)
@@ -989,7 +989,7 @@
     def test_virtual_array_of_struct_len(self):
         ops = """
         []
-        p0 = new_array(2, descr=complexarraydescr)
+        p0 = new_array_clear(2, descr=complexarraydescr)
         i0 = arraylen_gc(p0)
         finish(i0)
         """
@@ -5466,33 +5466,6 @@
         """
         self.optimize_loop(ops, expected)
 
-    def test_virtual_clear_array_contents(self):
-        ops = """
-        []
-        p0 = new_array(2, descr=arraydescr)
-        clear_array_contents(p0, descr=arraydescr)
-        """
-        expected = """
-        []
-        """
-        self.optimize_loop(ops, expected)
-
-    def test_virtual_clear_array_contents_escape(self):
-        ops = """
-        []
-        p0 = new_array(2, descr=arraydescr)
-        clear_array_contents(p0, descr=arraydescr)
-        escape(p0)
-        """
-        expected = """
-        []
-        p0 = new_array(2, descr=arraydescr)
-        setarrayitem_gc(p0, 0, 0, descr=arraydescr)
-        setarrayitem_gc(p0, 1, 0, descr=arraydescr)
-        escape(p0)
-        """
-        self.optimize_loop(ops, expected)
-
 
 class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
     pass
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -4023,8 +4023,7 @@
     def test_arraycopy_dest_not_virtual(self):
         ops = '''
         []
-        p1 = new_array(3, descr=arraydescr)
-        clear_array_contents(p1, descr=arraydescr)
+        p1 = new_array_clear(3, descr=arraydescr)
         p2 = new_array(3, descr=arraydescr)
         setarrayitem_gc(p1, 2, 10, descr=arraydescr)
         setarrayitem_gc(p2, 2, 13, descr=arraydescr)
diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py
--- a/rpython/jit/metainterp/optimizeopt/virtualize.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualize.py
@@ -264,11 +264,16 @@
 
 class VArrayValue(AbstractVArrayValue):
 
-    def __init__(self, arraydescr, constvalue, size, keybox, source_op=None):
+    def __init__(self, arraydescr, constvalue, size, keybox, source_op=None,
+                 clear=False):
         AbstractVirtualValue.__init__(self, keybox, source_op)
         self.arraydescr = arraydescr
         self.constvalue = constvalue
-        self._items = [None] * size
+        if clear:
+            self._items = [constvalue] * size
+        else:
+            self._items = [None] * size
+        self.clear = clear
 
     def getlength(self):
         return len(self._items)
@@ -279,10 +284,6 @@
     def set_item_value(self, i, newval):
         self._items[i] = newval
 
-    def initialize_with_zeros(self, optimizer):
-        for i in range(len(self._items)):
-            self._items[i] = optimizer.new_const_item(self.arraydescr)
-
     def getitem(self, index):
         res = self._items[index]
         return res
@@ -316,7 +317,11 @@
         self.box = box = self.source_op.result
         for index in range(len(self._items)):
             subvalue = self._items[index]
-            if subvalue is not None:
+            if subvalue is None:
+                continue
+            if subvalue is self.constvalue and self.clear:
+                continue
+            else:
                 subbox = subvalue.force_box(optforce)
                 op = ResOperation(rop.SETARRAYITEM_GC,
                                   [box, ConstInt(index), subbox], None,
@@ -344,9 +349,6 @@
         assert isinstance(itemvalue, optimizer.OptValue)
         self._items[index][ofs] = itemvalue
 
-    def initialize_with_zeros(self, optimizer):
-        assert False, "should never happen"
-
     def _really_force(self, optforce):
         assert self.source_op is not None
         if not we_are_translated():
@@ -497,12 +499,15 @@
         self.make_equal_to(box, vvalue)
         return vvalue
 
-    def make_varray(self, arraydescr, size, box, source_op=None):
+    def make_varray(self, arraydescr, size, box, source_op=None,
+                    clear=False):
         if arraydescr.is_array_of_structs():
+            assert clear
             vvalue = VArrayStructValue(arraydescr, size, box, source_op)
         else:
             constvalue = self.new_const_item(arraydescr)
-            vvalue = VArrayValue(arraydescr, constvalue, size, box, source_op)
+            vvalue = VArrayValue(arraydescr, constvalue, size, box, source_op,
+                                 clear=clear)
         self.make_equal_to(box, vvalue)
         return vvalue
 
@@ -674,13 +679,13 @@
         else:
             self.emit_operation(op)
 
-    def optimize_CLEAR_ARRAY_CONTENTS(self, op):
-        v = self.getvalue(op.getarg(0))
-        if v.is_virtual():
-            # initialize the items, since we need to store zeros
-            v.initialize_with_zeros(self.optimizer)
-            return
-        self.emit_operation(op)
+    def optimize_NEW_ARRAY_CLEAR(self, op):
+        sizebox = self.get_constant_box(op.getarg(0))
+        if sizebox is not None:
+            self.make_varray(op.getdescr(), sizebox.getint(), op.result, op,
+                             clear=True)
+        else:
+            self.emit_operation(op)        
 
     def optimize_CALL(self, op):
         effectinfo = op.getdescr().get_extra_info()
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
@@ -396,10 +396,6 @@
     def opimpl_new(self, sizedescr):
         return self.metainterp.execute_new(sizedescr)
 
-    @arguments("box", "descr")
-    def opimpl_clear_array_contents(self, box, descr):
-        self.metainterp.execute_and_record(rop.CLEAR_ARRAY_CONTENTS, descr, box)
-
     @arguments("descr")
     def opimpl_new_with_vtable(self, sizedescr):
         cpu = self.metainterp.cpu
@@ -410,6 +406,10 @@
     def opimpl_new_array(self, lengthbox, itemsizedescr):
         return self.metainterp.execute_new_array(itemsizedescr, lengthbox)
 
+    @arguments("box", "descr")
+    def opimpl_new_array_clear(self, lengthbox, itemsizedescr):
+        return self.metainterp.execute_new_array_clear(itemsizedescr, lengthbox)
+
     @specialize.arg(1)
     def _do_getarrayitem_gc_any(self, op, arraybox, indexbox, arraydescr):
         tobox = self.metainterp.heapcache.getarrayitem(
@@ -1917,6 +1917,12 @@
         self.heapcache.new_array(resbox, lengthbox)
         return resbox
 
+    def execute_new_array_clear(self, itemsizedescr, lengthbox):
+        resbox = self.execute_and_record(rop.NEW_ARRAY_CLEAR, itemsizedescr,
+                                         lengthbox)
+        self.heapcache.new_array(resbox, lengthbox)
+        return resbox
+
     def execute_setfield_gc(self, fielddescr, box, valuebox):
         self.execute_and_record(rop.SETFIELD_GC, fielddescr, box, valuebox)
         self.heapcache.setfield(box, valuebox, fielddescr)
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
@@ -493,9 +493,6 @@
     'MARK_OPAQUE_PTR/1b',
     # this one has no *visible* side effect, since the virtualizable
     # must be forced, however we need to execute it anyway
-    'CLEAR_ARRAY_CONTENTS/1d',
-    # this one does not *really* have a side effect since it's equivalent
-    # to array just coming zeroed
     '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
 
     'INCREMENT_DEBUG_COUNTER/1',
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
@@ -981,7 +981,11 @@
 
     def allocate_array(self, length, arraydescr):
         lengthbox = ConstInt(length)
-        return self.metainterp.execute_new_array(arraydescr, lengthbox)
+        if (arraydescr.is_array_of_structs() or
+            arraydescr.is_array_of_pointers()):
+            return self.metainterp.execute_new_array_clear(arraydescr,
+                                                           lengthbox)
+        return self.metainterp.execute_new_array(arraydescr, lengthbox)        
 
     def allocate_raw_buffer(self, size):
         cic = self.metainterp.staticdata.callinfocollection


More information about the pypy-commit mailing list