Author: Maciej Fijalkowski <[email protected]>
Branch: gc_no_cleanup_nursery
Changeset: r73322:381a8a3875fd
Date: 2014-09-05 12:45 -0600
http://bitbucket.org/pypy/pypy/changeset/381a8a3875fd/

Log:    implement clear array contents

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
@@ -630,19 +630,22 @@
 
     def bh_new(self, sizedescr):
         return lltype.cast_opaque_ptr(llmemory.GCREF,
-                                      lltype.malloc(sizedescr.S, zero=True))
+                                      lltype.malloc(sizedescr.S))
 
     def bh_new_with_vtable(self, vtable, descr):
-        result = lltype.malloc(descr.S, zero=True)
+        result = lltype.malloc(descr.S)
         result_as_objptr = lltype.cast_pointer(rclass.OBJECTPTR, result)
         result_as_objptr.typeptr = support.cast_from_int(rclass.CLASSTYPE,
                                                          vtable)
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
     def bh_new_array(self, length, arraydescr):
-        array = lltype.malloc(arraydescr.A, length, zero=True)
+        array = lltype.malloc(arraydescr.A, length)
         return lltype.cast_opaque_ptr(llmemory.GCREF, array)
 
+    def bh_clear_array_contents(self, array, arraydescr):
+        pass # I think arrays are zero-initialized here anyhow
+
     def bh_classof(self, struct):
         struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
         result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
diff --git a/rpython/jit/backend/llsupport/gc.py 
b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -18,10 +18,12 @@
 from rpython.jit.backend.llsupport.descr import get_call_descr
 from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
 from rpython.memory.gctransform import asmgcroot
+from rpython.jit.codewriter.effectinfo import EffectInfo
 
 # ____________________________________________________________
 
 class GcLLDescription(GcCache):
+    malloc_zero_filled = True
 
     def __init__(self, gcdescr, translator=None, rtyper=None):
         GcCache.__init__(self, translator is not None, rtyper)
@@ -32,6 +34,15 @@
             self.fielddescr_vtable = get_field_descr(self, rclass.OBJECT,
                                                      'typeptr')
         self._generated_functions = []
+        self.memset_ptr = rffi.llexternal('memset', [lltype.Signed, rffi.INT,
+                                                     rffi.SIZE_T], lltype.Void,
+                                                     sandboxsafe=True,
+                                                     _nowrapper=True)
+        self.memset_ptr_as_int = heaptracker.adr2int(
+            llmemory.cast_ptr_to_adr(self.memset_ptr))
+        ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE)
+        self.memset_descr = get_call_descr(self, [lltype.Signed, rffi.INT,
+                                                  rffi.SIZE_T], lltype.Void, 
ei)
 
     def _setup_str(self):
         self.str_descr     = get_array_descr(self, rstr.STR)
@@ -377,6 +388,7 @@
         from rpython.memory.gcheader import GCHeaderBuilder
         self.GCClass = self.layoutbuilder.GCClass
         self.moving_gc = self.GCClass.moving_gc
+        self.malloc_zero_filled = self.GCClass.malloc_zero_filled
         self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
         self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
         self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
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
@@ -591,6 +591,13 @@
     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
+        self.gc_ll_descr.memset_ptr(adr, 1, 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
@@ -1,7 +1,7 @@
 from rpython.rlib.rarithmetic import ovfcheck
 from rpython.rtyper.lltypesystem import llmemory
 from rpython.jit.metainterp import history
-from rpython.jit.metainterp.history import ConstInt, BoxPtr, ConstPtr
+from rpython.jit.metainterp.history import ConstInt, BoxPtr, ConstPtr, BoxInt
 from rpython.jit.metainterp.resoperation import ResOperation, rop
 from rpython.jit.codewriter import heaptracker
 from rpython.jit.backend.llsupport.symbolic import WORD
@@ -59,6 +59,10 @@
             if op.is_malloc():
                 self.handle_malloc_operation(op)
                 continue
+            elif op.getopnum() == rop.CLEAR_ARRAY_CONTENTS:
+                if not self.gc_ll_descr.malloc_zero_filled:
+                    self.handle_clear_array_contents(op)
+                continue
             elif op.can_malloc():
                 self.emitting_an_operation_that_can_collect()
             elif op.getopnum() == rop.LABEL:
@@ -157,6 +161,26 @@
             else:
                 raise NotImplementedError(op.getopname())
 
+    def handle_clear_array_contents(self, op):
+        # XXX this maybe should go to optimizer, so we can remove extra ops?
+        arraydescr = op.getdescr()
+        ofs, size, _ = self.cpu.unpack_arraydescr_size(arraydescr)
+        v_arr = op.getarg(0)
+        v_arr_plus_ofs = BoxInt()
+        v_arrsize = BoxInt()
+        v_totalsize = BoxInt()
+        gcdescr = self.gc_ll_descr
+        ops = [
+            ResOperation(rop.INT_ADD, [v_arr, ConstInt(size)], v_arr_plus_ofs),
+            ResOperation(rop.ARRAYLEN_GC, [v_arr], v_arrsize, 
descr=arraydescr),
+            ResOperation(rop.INT_MUL, [v_arrsize, ConstInt(size)], 
v_totalsize),
+            ResOperation(rop.CALL, [ConstInt(gcdescr.memset_ptr_as_int),
+                                    v_arr_plus_ofs,
+                                    ConstInt(0), v_totalsize], None,
+                                    descr=gcdescr.memset_descr),
+        ]
+        self.newops.extend(ops)
+
     def gen_malloc_frame(self, frame_info, frame, size_box):
         descrs = self.gc_ll_descr.getframedescrs(self.cpu)
         if self.gc_ll_descr.kind == 'boehm':
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
@@ -4439,3 +4439,21 @@
         res = self.execute_operation(rop.CAST_FLOAT_TO_SINGLEFLOAT,
                                    [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
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
@@ -315,7 +315,8 @@
             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:
+            if (op.has_no_side_effect() and op.result not in self.longevity
+                and op.opnum != rop.CLEAR_ARRAY_CONTENTS):
                 i += 1
                 self.possibly_free_vars_for_op(op)
                 continue
diff --git a/rpython/jit/codewriter/jtransform.py 
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -615,12 +615,41 @@
             op1 = SpaceOperation('new_array', [op.args[2], arraydescr],
                                  op.result)
             if self._has_gcptrs_in(ARRAY):
-                return [op1, SpaceOperation('zero_gc_pointers', [op.result],
-                                            None)]
+                return self.zero_contents(op1, op.result, ARRAY,
+                                          only_gc_pointers=True)
             if op.args[1].value.get('zero', False):
-                return [op1, SpaceOperation('zero_contents', [op.result], 
None)]
+                return self.zero_contents(op1, op.result, ARRAY)
             return op1
 
+    def zero_contents(self, prev_op, v, TYPE, only_gc_pointers=False):
+        ops = [prev_op]
+        if isinstance(TYPE, lltype.Struct):
+            for name, FIELD in TYPE._flds.iteritems():
+                if (not only_gc_pointers or
+                    isinstance(FIELD, lltype.Ptr) and FIELD._needsgc()):
+                    c_name = Constant(name, lltype.Void)
+                    c_null = Constant(FIELD._defl(), FIELD)
+                    op = SpaceOperation('setfield', [v, c_name, c_null],
+                                        None)
+                    self.extend_with(ops, self.rewrite_op_setfield(op))
+        elif isinstance(TYPE, lltype.Array):
+            arraydescr = self.cpu.arraydescrof(TYPE)
+            ops.append(SpaceOperation('clear_array_contents',
+                                      [v, arraydescr], None))
+        else:
+            raise TypeError("Expected struct or array, got '%r'", (TYPE,))
+        if len(ops) == 1:
+            return ops[0]
+        return ops
+
+    def extend_with(self, l, ops):
+        if ops is None:
+            return
+        if isinstance(ops, list):
+            l.extend(ops)
+        else:
+            l.append(ops)
+
     def rewrite_op_free(self, op):
         d = op.args[1].value.copy()
         assert d['flavor'] == 'raw'
@@ -893,9 +922,10 @@
         sizedescr = self.cpu.sizeof(STRUCT)
         op1 = SpaceOperation(opname, [sizedescr], op.result)
         if true_zero:
-            return [op1, SpaceOperation('zero_contents', [op.result], None)]
+            return self.zero_contents(op1, op.result, STRUCT)
         if self._has_gcptrs_in(STRUCT):
-            return [op1, SpaceOperation('zero_gc_pointers', [op.result], None)]
+            return self.zero_contents(op1, op.result, STRUCT,
+                                      only_gc_pointers=True)
         return op1
 
     def _has_gcptrs_in(self, STRUCT):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py 
b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -538,12 +538,11 @@
     op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
     assert op1.opname == 'new'
     assert op1.args == [('sizedescr', S)]
-    assert op2.opname == 'zero_gc_pointers'
-    assert op2.args == [v]
+    assert op2.opname == 'setfield_gc_r'
+    assert op2.args[0] == v
 
 def test_malloc_new_zero_2():
-    SS = lltype.GcStruct('SS')
-    S = lltype.GcStruct('S', ('x', lltype.Ptr(SS)))
+    S = lltype.GcStruct('S', ('x', lltype.Signed))
     v = varoftype(lltype.Ptr(S))
     op = SpaceOperation('malloc', [Constant(S, lltype.Void),
                                    Constant({'flavor': 'gc',
@@ -551,8 +550,8 @@
     op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
     assert op1.opname == 'new'
     assert op1.args == [('sizedescr', S)]
-    assert op2.opname == 'zero_contents'
-    assert op2.args == [v]
+    assert op2.opname == 'setfield_gc_i'
+    assert op2.args[0] == v
 
 def test_malloc_new_with_vtable():
     vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
@@ -1063,7 +1062,7 @@
     op = SpaceOperation('malloc_varsize', [c_A, c_flags, v1], v2)
     op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
     assert op1.opname == 'new_array'
-    assert op2.opname == 'zero_contents'
+    assert op2.opname == 'clear_array_contents'
 
 def test_str_concat():
     # test that the oopspec is present and correctly transformed
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
@@ -1345,6 +1345,10 @@
         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
@@ -335,6 +335,7 @@
                          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/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -396,6 +396,10 @@
     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
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
@@ -492,6 +492,9 @@
     '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',
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to