Author: Armin Rigo <[email protected]>
Branch: stmgc-static-barrier
Changeset: r66286:3588acc12b00
Date: 2013-08-22 10:50 +0200
http://bitbucket.org/pypy/pypy/changeset/3588acc12b00/

Log:    Improve generation of write barriers: we only need to check
        GCFLAG_WRITEBARRIER when we're writing a GC pointer into the object.

diff --git a/rpython/translator/stm/funcgen.py 
b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -52,11 +52,14 @@
     category_change = op.args[0].value
     frm, middle, to = category_change
     assert middle == '2'
+    assert frm < to
     if to == 'W':
         if frm >= 'V':
             funcname = 'stm_repeat_write_barrier'
         else:
             funcname = 'stm_write_barrier'
+    elif to == 'V':
+        funcname = 'stm_write_barrier_noptr'
     elif to == 'R':
         if frm >= 'Q':
             funcname = 'stm_repeat_read_barrier'
diff --git a/rpython/translator/stm/src_stm/et.c 
b/rpython/translator/stm/src_stm/et.c
--- a/rpython/translator/stm/src_stm/et.c
+++ b/rpython/translator/stm/src_stm/et.c
@@ -1340,9 +1340,13 @@
              and then free B, which will not be used any more. */
           size_t size = stmgc_size(B);
           assert(B->h_tid & GCFLAG_BACKUP_COPY);
+          /* if h_original was 0, it must stay that way and not point
+             to itself. (B->h_original may point to P) */
+          revision_t h_original = P->h_original;
           memcpy(((char *)P) + offsetof(struct stm_object_s, h_revision),
                  ((char *)B) + offsetof(struct stm_object_s, h_revision),
                  size - offsetof(struct stm_object_s, h_revision));
+          P->h_original = h_original;
           assert(!(P->h_tid & GCFLAG_BACKUP_COPY));
           stmgcpage_free(B);
           dprintf(("abort: free backup at %p\n", B));
diff --git a/rpython/translator/stm/src_stm/extra.c 
b/rpython/translator/stm/src_stm/extra.c
--- a/rpython/translator/stm/src_stm/extra.c
+++ b/rpython/translator/stm/src_stm/extra.c
@@ -92,6 +92,8 @@
             return (revision_t)p;
         }
 
+        assert(p->h_original != (revision_t)p);
+
         dprintf(("stm_id(%p) has orig fst: %p\n", 
                  p, (gcptr)p->h_original));
         return p->h_original;
diff --git a/rpython/translator/stm/src_stm/nursery.c 
b/rpython/translator/stm/src_stm/nursery.c
--- a/rpython/translator/stm/src_stm/nursery.c
+++ b/rpython/translator/stm/src_stm/nursery.c
@@ -176,11 +176,23 @@
 
             stm_copy_to_old_id_copy(obj, id_obj);
             fresh_old_copy = id_obj;
+            fresh_old_copy->h_original = 0;
             obj->h_tid &= ~GCFLAG_HAS_ID;
+
+            /* priv_from_prot's backup->h_originals already point
+               to id_obj */
         } 
         else {
             /* make a copy of it outside */
             fresh_old_copy = create_old_object_copy(obj);
+
+            if (obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED
+                && !(obj->h_original)) {
+                /* the object's backup copy still has 
+                   a h_original that is NULL*/
+                gcptr B = (gcptr)obj->h_revision;
+                B->h_original = (revision_t)fresh_old_copy;
+            }
         }
         
         obj->h_tid |= GCFLAG_MOVED;
diff --git a/rpython/translator/stm/src_stm/revision 
b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-50d9d16d6327
+49c3e0a47ab4
diff --git a/rpython/translator/stm/src_stm/stmgc.h 
b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -85,6 +85,10 @@
    - stm_repeat_write_barrier() can be used on an object on which
      we already did stm_write_barrier(), but a potential collection
      can have occurred.
+
+   - stm_write_barrier_noptr() is a slightly cheaper version of
+     stm_write_barrier(), for when we are going to write
+     non-gc-pointers into the object.
 */
 #if 0     // (optimized version below)
 gcptr stm_read_barrier(gcptr);
@@ -92,6 +96,7 @@
 gcptr stm_repeat_read_barrier(gcptr);
 gcptr stm_immut_read_barrier(gcptr);
 gcptr stm_repeat_write_barrier(gcptr);   /* <= always returns its argument */
+gcptr stm_write_barrier_noptr(gcptr);
 #endif
 
 /* start a new transaction, calls callback(), and when it returns
@@ -205,19 +210,25 @@
      :  (obj))
 
 #define stm_repeat_read_barrier(obj)                            \
-    (UNLIKELY((obj)->h_tid & (GCFLAG_PUBLIC_TO_PRIVATE | GCFLAG_MOVED)) ? \
+    (UNLIKELY(((obj)->h_tid & (GCFLAG_PUBLIC_TO_PRIVATE |       \
+                               GCFLAG_MOVED)) != 0) ?           \
         stm_RepeatReadBarrier(obj)                              \
      :  (obj))
 
 #define stm_immut_read_barrier(obj)                             \
-    (UNLIKELY((obj)->h_tid & GCFLAG_STUB) ?                     \
+    (UNLIKELY(((obj)->h_tid & GCFLAG_STUB) != 0) ?              \
         stm_ImmutReadBarrier(obj)                               \
      :  (obj))
 
 #define stm_repeat_write_barrier(obj)                           \
-    (UNLIKELY((obj)->h_tid & GCFLAG_WRITE_BARRIER) ?            \
+    (UNLIKELY(((obj)->h_tid & GCFLAG_WRITE_BARRIER) != 0) ?     \
         stm_RepeatWriteBarrier(obj)                             \
      :  (obj))
 
+#define stm_write_barrier_noptr(obj)                            \
+    (UNLIKELY((obj)->h_revision != stm_private_rev_num) ?       \
+        stm_WriteBarrier(obj)                                   \
+     :  (obj))
+
 
 #endif
diff --git a/rpython/translator/stm/test/test_writebarrier.py 
b/rpython/translator/stm/test/test_writebarrier.py
--- a/rpython/translator/stm/test/test_writebarrier.py
+++ b/rpython/translator/stm/test/test_writebarrier.py
@@ -38,6 +38,20 @@
         self.interpret(f1, [4])
         assert x1.foo == 4
         assert len(self.writemode) == 1
+        assert self.barriers == ['I2V']
+
+    def test_simple_write_pointer(self):
+        T = lltype.GcStruct('T')
+        X = lltype.GcStruct('X', ('foo', lltype.Ptr(T)))
+        t1 = lltype.malloc(T, immortal=True)
+        x1 = lltype.malloc(X, immortal=True, zero=True)
+
+        def f1(n):
+            x1.foo = t1
+
+        self.interpret(f1, [4])
+        assert x1.foo == t1
+        assert len(self.writemode) == 1
         assert self.barriers == ['I2W']
 
     def test_multiple_reads(self):
@@ -71,10 +85,9 @@
         assert len(self.writemode) == 1
         assert self.barriers == []
 
-    def test_repeat_write_barrier_after_malloc(self):
+    def test_dont_repeat_write_barrier_after_malloc_if_not_a_ptr(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
-        x1 = lltype.malloc(X, immortal=True)
-        x1.foo = 6
+        x1 = lltype.malloc(X, immortal=True, zero=True)
         def f1(n):
             x1.foo = n
             lltype.malloc(X)
@@ -82,6 +95,21 @@
 
         self.interpret(f1, [4])
         assert len(self.writemode) == 2
+        assert self.barriers == ['I2V']
+
+    def test_repeat_write_barrier_after_malloc(self):
+        T = lltype.GcStruct('T')
+        X = lltype.GcStruct('X', ('foo', lltype.Ptr(T)))
+        t1 = lltype.malloc(T, immortal=True)
+        t2 = lltype.malloc(T, immortal=True)
+        x1 = lltype.malloc(X, immortal=True, zero=True)
+        def f1(n):
+            x1.foo = t1
+            lltype.malloc(X)
+            x1.foo = t2
+
+        self.interpret(f1, [4])
+        assert len(self.writemode) == 2
         assert self.barriers == ['I2W', 'V2W']
 
     def test_repeat_read_barrier_after_malloc(self):
@@ -110,10 +138,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 36
-        assert self.barriers == ['A2R', 'A2W', 'q2r']
+        assert self.barriers == ['A2R', 'A2V', 'q2r']
         res = self.interpret(f1, [x, x])
         assert res == 42
-        assert self.barriers == ['A2R', 'A2W', 'Q2R']
+        assert self.barriers == ['A2R', 'A2V', 'Q2R']
 
     def test_write_cannot_alias(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -128,7 +156,7 @@
         y = lltype.malloc(Y, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 36
-        assert self.barriers == ['A2R', 'A2W']
+        assert self.barriers == ['A2R', 'A2V']
 
     def test_call_external_release_gil(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -203,10 +231,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 0
-        assert self.barriers == ['A2W', '=']
+        assert self.barriers == ['A2V', '=']
         res = self.interpret(f1, [x, x])
         assert res == 1
-        assert self.barriers == ['A2W', '=']
+        assert self.barriers == ['A2V', '=']
 
     def test_pointer_compare_3(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -217,10 +245,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 1
-        assert self.barriers == ['A2W', '=']
+        assert self.barriers == ['A2V', '=']
         res = self.interpret(f1, [x, x])
         assert res == 0
-        assert self.barriers == ['A2W', '=']
+        assert self.barriers == ['A2V', '=']
 
     def test_pointer_compare_4(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -232,10 +260,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 1
-        assert self.barriers == ['A2W', 'A2W']
+        assert self.barriers == ['A2V', 'A2V']
         res = self.interpret(f1, [x, x])
         assert res == 0
-        assert self.barriers == ['A2W', 'A2W']
+        assert self.barriers == ['A2V', 'A2V']
 
     def test_simple_loop(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -248,7 +276,7 @@
         res = self.interpret(f1, [x, 5])
         assert res == 0
         # for now we get this.  Later, we could probably optimize it
-        assert self.barriers == ['A2W', 'a2w', 'a2w', 'a2w', 'a2w']
+        assert self.barriers == ['A2V', 'a2v', 'a2v', 'a2v', 'a2v']
 
     def test_subclassing(self):
         class X:
@@ -292,12 +320,12 @@
             y = make_y(i)
             external_any_gcobj()
             prev = y.ybar          # a2r
-            handle(y)              # inside handle(): a2r, r2w
+            handle(y)              # inside handle(): a2r, r2v
             return prev + y.ybar   # q2r
 
         res = self.interpret(f1, [10])
         assert res == 21
-        assert self.barriers == ['a2r', 'a2r', 'r2w', 'q2r']
+        assert self.barriers == ['a2r', 'a2r', 'r2v', 'q2r']
 
     def test_subclassing_2(self):
         class X:
@@ -317,12 +345,12 @@
                 y = Y(); y.foo = -13; y.ybar = i
             external_any_gcobj()
             prev = x.foo           # a2r
-            handle(y)              # inside handle(): a2r, r2w
+            handle(y)              # inside handle(): a2r, r2v
             return prev + x.foo    # q2r
 
         res = self.interpret(f1, [10])
         assert res == 84
-        assert self.barriers == ['a2r', 'a2r', 'r2w', 'q2r']
+        assert self.barriers == ['a2r', 'a2r', 'r2v', 'q2r']
 
     def test_subclassing_gcref(self):
         Y = lltype.GcStruct('Y', ('foo', lltype.Signed),
@@ -340,12 +368,12 @@
                 x = lltype.cast_opaque_ptr(llmemory.GCREF, y)
             external_any_gcobj()
             prev = lltype.cast_opaque_ptr(YPTR, x).foo           # a2r
-            handle(y)                            # inside handle(): a2r, r2w
+            handle(y)                            # inside handle(): a2r, r2v
             return prev + lltype.cast_opaque_ptr(YPTR, x).ybar   # q2r?
 
         res = self.interpret(f1, [10])
         assert res == 42 + 11
-        assert self.barriers == ['a2r', 'a2r', 'r2w', 'a2r']
+        assert self.barriers == ['a2r', 'a2r', 'r2v', 'a2r']
         # Ideally we should get [... 'q2r'] but getting 'a2r' is not wrong
         # either.  This is because from a GCREF the only thing we can do is
         # cast_opaque_ptr, which is not special-cased in writebarrier.py.
@@ -354,10 +382,12 @@
         class X:
             pass
         x = X()
+        x2 = X()
+        x3 = X()
         def f1(i):
-            x.a = i   # write barrier
+            x.a = x2  # write barrier
             y = X()   # malloc
-            x.a += 1  # write barrier again
+            x.a = x3  # write barrier again
             return y
 
         res = self.interpret(f1, [10])
@@ -375,7 +405,7 @@
 
         res = self.interpret(f1, [4])
         assert res == 4
-        assert self.barriers == ['a2w', 'a2i']
+        assert self.barriers == ['a2v', 'a2i']
 
     def test_read_immutable_prebuilt(self):
         class Foo:
diff --git a/rpython/translator/stm/test/transform_support.py 
b/rpython/translator/stm/test/transform_support.py
--- a/rpython/translator/stm/test/transform_support.py
+++ b/rpython/translator/stm/test/transform_support.py
@@ -93,7 +93,7 @@
         else:
             # a barrier, calling a helper
             ptr2 = _stmptr(obj, to)
-            if to == 'W':
+            if to >= 'V':
                 self.llinterpreter.tester.writemode.add(ptr2._obj)
             self.llinterpreter.tester.barriers.append(kind)
             return ptr2
@@ -115,7 +115,11 @@
 
     def op_setfield(self, obj, fieldname, fieldvalue):
         if obj._TYPE.TO._gckind == 'gc':
-            self.check_category(obj, 'W')
+            T = lltype.typeOf(fieldvalue)
+            if isinstance(T, lltype.Ptr) and T.TO._gckind == 'gc':
+                self.check_category(obj, 'W')
+            else:
+                self.check_category(obj, 'V')
             # convert R -> Q all other pointers to the same object we can find
             for p in self.all_stm_ptrs():
                 if p._category == 'R' and p._T == obj._T and p == obj:
diff --git a/rpython/translator/stm/writebarrier.py 
b/rpython/translator/stm/writebarrier.py
--- a/rpython/translator/stm/writebarrier.py
+++ b/rpython/translator/stm/writebarrier.py
@@ -111,7 +111,13 @@
                   op.args[-1].concretetype is not lltype.Void and
                   op.args[0].concretetype.TO._gckind == 'gc'):
                 # setfields need a regular write barrier
-                wants_a_barrier[op] = 'W'
+                T = op.args[-1].concretetype
+                if isinstance(T, lltype.Ptr) and T.TO._gckind == 'gc':
+                    wants_a_barrier[op] = 'W'
+                else:
+                    # a write of a non-gc pointer doesn't need to check for
+                    # the GCFLAG_WRITEBARRIER
+                    wants_a_barrier[op] = 'V'
 
             elif (op.opname in ('ptr_eq', 'ptr_ne') and
                   op.args[0].concretetype.TO._gckind == 'gc'):
@@ -186,8 +192,6 @@
                     for v, cat in category.items():
                         if cat == 'W':
                             category[v] = 'V'
-                    # XXX the V2W barrier is only necessary when we're
-                    # writing pointers, not if we're writing ints
 
                 effectinfo = stmtransformer.write_analyzer.analyze(
                     op, graphinfo=graphinfo)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to