Commits

Maciej Fijalkowski  committed b5fe11b Merge

merge default

  • Participants
  • Parent commits 427b988, 3e3517a

Comments (0)

Files changed (5)

File rpython/jit/backend/llsupport/rewrite.py

      - Add COND_CALLs to the write barrier before SETFIELD_GC and
        SETARRAYITEM_GC operations.
 
-    recent_mallocs contains a dictionary of variable -> None. If a variable
-    is in the dictionary, next setfields can be called without a write barrier,
-    because the variable got allocated after the last potentially collecting
-    resop
+    'write_barrier_applied' contains a dictionary of variable -> None.
+    If a variable is in the dictionary, next setfields can be called without
+    a write barrier.  The idea is that an object that was freshly allocated
+    or already write_barrier'd don't need another write_barrier if there
+    was no potentially collecting resop inbetween.
     """
 
     _previous_size = -1
         self.cpu = cpu
         self.newops = []
         self.known_lengths = {}
-        self.recent_mallocs = {}
+        self.write_barrier_applied = {}
 
     def rewrite(self, operations):
         # we can only remember one malloc since the next malloc can possibly
     def emitting_an_operation_that_can_collect(self):
         # must be called whenever we emit an operation that can collect:
         # forgets the previous MALLOC_NURSERY, if any; and empty the
-        # set 'recent_mallocs', so that future SETFIELDs will generate
+        # set 'write_barrier_applied', so that future SETFIELDs will generate
         # a write barrier as usual.
         self._op_malloc_nursery = None
-        self.recent_mallocs.clear()
+        self.write_barrier_applied.clear()
 
     def _gen_call_malloc_gc(self, args, v_result, descr):
         """Generate a CALL_MALLOC_GC with the given args."""
         self.emitting_an_operation_that_can_collect()
         op = ResOperation(rop.CALL_MALLOC_GC, args, v_result, descr)
         self.newops.append(op)
-        # mark 'v_result' as freshly malloced
-        self.recent_mallocs[v_result] = None
+        # mark 'v_result' as freshly malloced, so not needing a write barrier
+        self.write_barrier_applied[v_result] = None
 
     def gen_malloc_fixedsize(self, size, typeid, v_result):
         """Generate a CALL_MALLOC_GC(malloc_fixedsize_fn, ...).
                           [ConstInt(kind), ConstInt(itemsize), v_length],
                           v_result, descr=arraydescr)
         self.newops.append(op)
-        self.recent_mallocs[v_result] = None
+        self.write_barrier_applied[v_result] = None
         return True
 
     def gen_malloc_nursery_varsize_frame(self, sizebox, v_result):
                           v_result)
 
         self.newops.append(op)
-        self.recent_mallocs[v_result] = None
+        self.write_barrier_applied[v_result] = None
 
     def gen_malloc_nursery(self, size, v_result):
         """Try to generate or update a CALL_MALLOC_NURSERY.
         self.newops.append(op)
         self._previous_size = size
         self._v_last_malloced_nursery = v_result
-        self.recent_mallocs[v_result] = None
+        self.write_barrier_applied[v_result] = None
         return True
 
     def gen_initialize_tid(self, v_newgcobj, tid):
 
     def handle_write_barrier_setfield(self, op):
         val = op.getarg(0)
-        # no need for a write barrier in the case of previous malloc
-        if val not in self.recent_mallocs:
+        if val not in self.write_barrier_applied:
             v = op.getarg(1)
             if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
                                          bool(v.value)): # store a non-NULL
-                self.gen_write_barrier(op.getarg(0), v)
-                op = op.copy_and_change(rop.SETFIELD_RAW)
+                self.gen_write_barrier(val)
+                #op = op.copy_and_change(rop.SETFIELD_RAW)
         self.newops.append(op)
 
     def handle_write_barrier_setinteriorfield(self, op):
         val = op.getarg(0)
-        # no need for a write barrier in the case of previous malloc
-        if val not in self.recent_mallocs:
+        if val not in self.write_barrier_applied:
             v = op.getarg(2)
             if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
                                          bool(v.value)): # store a non-NULL
-                self.gen_write_barrier(op.getarg(0), v)
-                op = op.copy_and_change(rop.SETINTERIORFIELD_RAW)
+                self.gen_write_barrier(val)
+                #op = op.copy_and_change(rop.SETINTERIORFIELD_RAW)
         self.newops.append(op)
 
     def handle_write_barrier_setarrayitem(self, op):
         val = op.getarg(0)
-        # no need for a write barrier in the case of previous malloc
-        if val not in self.recent_mallocs:
+        if val not in self.write_barrier_applied:
             v = op.getarg(2)
             if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
                                          bool(v.value)): # store a non-NULL
-                self.gen_write_barrier_array(op.getarg(0),
-                                             op.getarg(1), v)
-                op = op.copy_and_change(rop.SETARRAYITEM_RAW)
+                self.gen_write_barrier_array(val, op.getarg(1))
+                #op = op.copy_and_change(rop.SETARRAYITEM_RAW)
         self.newops.append(op)
 
-    def gen_write_barrier(self, v_base, v_value):
+    def gen_write_barrier(self, v_base):
         write_barrier_descr = self.gc_ll_descr.write_barrier_descr
-        args = [v_base, v_value]
+        args = [v_base]
         self.newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
                                         descr=write_barrier_descr))
+        self.write_barrier_applied[v_base] = None
 
-    def gen_write_barrier_array(self, v_base, v_index, v_value):
+    def gen_write_barrier_array(self, v_base, v_index):
         write_barrier_descr = self.gc_ll_descr.write_barrier_descr
         if write_barrier_descr.has_write_barrier_from_array(self.cpu):
             # If we know statically the length of 'v', and it is not too
             length = self.known_lengths.get(v_base, LARGE)
             if length >= LARGE:
                 # unknown or too big: produce a write_barrier_from_array
-                args = [v_base, v_index, v_value]
+                args = [v_base, v_index]
                 self.newops.append(
                     ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, None,
                                  descr=write_barrier_descr))
+                # a WB_ARRAY is not enough to prevent any future write
+                # barriers, so don't add to 'write_barrier_applied'!
                 return
         # fall-back case: produce a write_barrier
-        self.gen_write_barrier(v_base, v_value)
+        self.gen_write_barrier(v_base)
 
     def round_up_for_allocation(self, size):
         if not self.gc_ll_descr.round_up:

File rpython/jit/backend/llsupport/test/test_gc.py

         rewriter = gc.GcRewriterAssembler(gc_ll_descr, None)
         newops = rewriter.newops
         v_base = BoxPtr()
-        v_value = BoxPtr()
-        rewriter.gen_write_barrier(v_base, v_value)
+        rewriter.gen_write_barrier(v_base)
         assert llop1.record == []
         assert len(newops) == 1
         assert newops[0].getopnum() == rop.COND_CALL_GC_WB
         assert newops[0].getarg(0) == v_base
-        assert newops[0].getarg(1) == v_value
         assert newops[0].result is None
         wbdescr = newops[0].getdescr()
         assert is_valid_int(wbdescr.jit_wb_if_flag)

File rpython/jit/backend/llsupport/test/test_rewrite.py

             jump()
         """, """
             [p1, p2]
-            cond_call_gc_wb(p1, p2, descr=wbdescr)
-            setfield_raw(p1, p2, descr=tzdescr)
+            cond_call_gc_wb(p1, descr=wbdescr)
+            setfield_gc(p1, p2, descr=tzdescr)
             jump()
         """)
 
             jump()
         """, """
             [p1, i2, p3]
-            cond_call_gc_wb(p1, p3, descr=wbdescr)
-            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            cond_call_gc_wb(p1, descr=wbdescr)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
         """)
 
             setfield_gc(p1, 8111, descr=tiddescr)
             setfield_gc(p1, 129, descr=clendescr)
             call(123456)
-            cond_call_gc_wb(p1, p3, descr=wbdescr)
-            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            cond_call_gc_wb(p1, descr=wbdescr)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
         """)
 
             setfield_gc(p1, 8111, descr=tiddescr)
             setfield_gc(p1, 130, descr=clendescr)
             call(123456)
-            cond_call_gc_wb_array(p1, i2, p3, descr=wbdescr)
-            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            cond_call_gc_wb_array(p1, i2, descr=wbdescr)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
         """)
 
             jump()
         """, """
             [p1, i2, p3]
-            cond_call_gc_wb_array(p1, i2, p3, descr=wbdescr)
-            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            cond_call_gc_wb_array(p1, i2, descr=wbdescr)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
         """)
 
             setfield_gc(p1, 8111, descr=tiddescr)
             setfield_gc(p1, 5, descr=clendescr)
             label(p1, i2, p3)
-            cond_call_gc_wb_array(p1, i2, p3, descr=wbdescr)
-            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            cond_call_gc_wb_array(p1, i2, descr=wbdescr)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
         """)
 
             jump(p1, p2)
         """, """
             [p1, p2]
-            cond_call_gc_wb(p1, p2, descr=wbdescr)
-            setinteriorfield_raw(p1, 0, p2, descr=interiorzdescr)
+            cond_call_gc_wb(p1, descr=wbdescr)
+            setinteriorfield_gc(p1, 0, p2, descr=interiorzdescr)
             jump(p1, p2)
         """, interiorzdescr=interiorzdescr)
 
             p1 = call_malloc_nursery_varsize(1, 1, i0, \
                                 descr=strdescr)
             setfield_gc(p1, i0, descr=strlendescr)
-            cond_call_gc_wb(p0, p1, descr=wbdescr)
-            setfield_raw(p0, p1, descr=tzdescr)
+            cond_call_gc_wb(p0, descr=wbdescr)
+            setfield_gc(p0, p1, descr=tzdescr)
             jump()
         """)
 
             p0 = call_malloc_nursery(%(tdescr.size)d)
             setfield_gc(p0, 5678, descr=tiddescr)
             label(p0, p1)
-            cond_call_gc_wb(p0, p1, descr=wbdescr)
-            setfield_raw(p0, p1, descr=tzdescr)
+            cond_call_gc_wb(p0, descr=wbdescr)
+            setfield_gc(p0, p1, descr=tzdescr)
             jump()
         """)
 
+    def test_multiple_writes(self):
+        self.check_rewrite("""
+            [p0, p1, p2]
+            setfield_gc(p0, p1, descr=tzdescr)
+            setfield_gc(p0, p2, descr=tzdescr)
+            jump(p1, p2, p0)
+        """, """
+            [p0, p1, p2]
+            cond_call_gc_wb(p0, descr=wbdescr)
+            setfield_gc(p0, p1, descr=tzdescr)
+            setfield_gc(p0, p2, descr=tzdescr)
+            jump(p1, p2, p0)
+        """)
+
     def test_rewrite_call_assembler(self):
         self.check_rewrite("""
         [i0, f0]

File rpython/jit/backend/test/runner_test.py

             s = lltype.malloc(S)
             s.tid = value
             sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
-            t = lltype.malloc(S)
-            tgcref = lltype.cast_opaque_ptr(llmemory.GCREF, t)
             del record[:]
             self.execute_operation(rop.COND_CALL_GC_WB,
-                                   [BoxPtr(sgcref), ConstPtr(tgcref)],
+                                   [BoxPtr(sgcref)],
                                    'void', descr=WriteBarrierDescr())
             if cond:
                 assert record == [rffi.cast(lltype.Signed, sgcref)]
             sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
             del record[:]
             self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
-                       [BoxPtr(sgcref), ConstInt(123), BoxPtr(sgcref)],
+                       [BoxPtr(sgcref), ConstInt(123)],
                        'void', descr=WriteBarrierDescr())
             if cond:
                 assert record == [rffi.cast(lltype.Signed, sgcref)]
                 del record[:]
                 box_index = BoxIndexCls((9<<7) + 17)
                 self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
-                           [BoxPtr(sgcref), box_index, BoxPtr(sgcref)],
+                           [BoxPtr(sgcref), box_index],
                            'void', descr=WriteBarrierDescr())
                 if cond in [0, 1]:
                     assert record == [rffi.cast(lltype.Signed, s.data)]

File rpython/jit/metainterp/resoperation.py

     'SETFIELD_RAW/2d',
     'STRSETITEM/3',
     'UNICODESETITEM/3',
-    'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier)
-    'COND_CALL_GC_WB_ARRAY/3d', # [objptr, arrayindex, newvalue] (write barr.)
+    'COND_CALL_GC_WB/1d',       # [objptr] (for the write barrier)
+    'COND_CALL_GC_WB_ARRAY/2d', # [objptr, arrayindex] (write barr. for array)
     'DEBUG_MERGE_POINT/*',      # debugging only
     'JIT_DEBUG/*',              # debugging only
     'VIRTUAL_REF_FINISH/2',   # removed before it's passed to the backend