[pypy-commit] pypy default: Change COND_CALL_GC_WB to not take as argument the new pointer value,

arigo noreply at buildbot.pypy.org
Sat Aug 17 12:06:08 CEST 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r66179:d3f189146d50
Date: 2013-08-17 11:55 +0200
http://bitbucket.org/pypy/pypy/changeset/d3f189146d50/

Log:	Change COND_CALL_GC_WB to not take as argument the new pointer
	value, but only the target object. The backends don't use this
	anyway. It lets us optimize more in rewrite.py: no need for several
	write barriers if there are several setfields to the same object.

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
@@ -26,10 +26,11 @@
      - 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
@@ -42,7 +43,7 @@
         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
@@ -221,18 +222,18 @@
     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, ...).
@@ -315,7 +316,7 @@
                           [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):
@@ -327,7 +328,7 @@
                           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.
@@ -360,7 +361,7 @@
         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):
@@ -382,45 +383,42 @@
 
     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
@@ -430,13 +428,15 @@
             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:
diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py b/rpython/jit/backend/llsupport/test/test_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_rewrite.py
@@ -561,8 +561,8 @@
             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()
         """)
 
@@ -575,8 +575,8 @@
             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()
         """)
 
@@ -595,8 +595,8 @@
             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()
         """)
 
@@ -616,8 +616,8 @@
             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()
         """)
 
@@ -628,8 +628,8 @@
             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()
         """)
 
@@ -647,8 +647,8 @@
             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()
         """)
 
@@ -666,8 +666,8 @@
             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)
 
@@ -733,8 +733,8 @@
             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()
         """)
 
@@ -750,11 +750,25 @@
             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]
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
@@ -502,8 +502,8 @@
     '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


More information about the pypy-commit mailing list