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