Author: Armin Rigo <[email protected]>
Branch: stmgc-static-barrier
Changeset: r66153:c7ed6268e742
Date: 2013-08-14 17:45 +0200
http://bitbucket.org/pypy/pypy/changeset/c7ed6268e742/
Log: in-progress: use the 5 barriers
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
@@ -24,7 +24,7 @@
res = self.interpret(f1, [-5])
assert res == 42
assert len(self.writemode) == 0
- assert self.barriers == ['P2R']
+ assert self.barriers == ['A2R']
def test_simple_write(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -37,7 +37,7 @@
self.interpret(f1, [4])
assert x1.foo == 4
assert len(self.writemode) == 1
- assert self.barriers == ['P2W']
+ assert self.barriers == ['A2W']
def test_multiple_reads(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed),
@@ -58,7 +58,7 @@
res = self.interpret(f1, [4])
assert res == -81
assert len(self.writemode) == 0
- assert self.barriers == ['P2R']
+ assert self.barriers == ['A2R']
def test_malloc(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -81,7 +81,7 @@
self.interpret(f1, [4])
assert len(self.writemode) == 2
- assert self.barriers == ['P2W', 'r2w']
+ assert self.barriers == ['A2W', 'V2W']
def test_repeat_read_barrier_after_malloc(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -95,7 +95,7 @@
self.interpret(f1, [4])
assert len(self.writemode) == 1
- assert self.barriers == ['P2R']
+ assert self.barriers == ['A2R']
def test_write_may_alias(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -109,10 +109,10 @@
y = lltype.malloc(X, immortal=True)
res = self.interpret(f1, [x, y])
assert res == 36
- assert self.barriers == ['P2R', 'P2W', 'p2r']
+ assert self.barriers == ['A2R', 'A2W', 'q2r']
res = self.interpret(f1, [x, x])
assert res == 42
- assert self.barriers == ['P2R', 'P2W', 'P2R']
+ assert self.barriers == ['A2R', 'A2W', 'Q2R']
def test_write_cannot_alias(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -127,7 +127,7 @@
y = lltype.malloc(Y, immortal=True)
res = self.interpret(f1, [x, y])
assert res == 36
- assert self.barriers == ['P2R', 'P2W']
+ assert self.barriers == ['A2R', 'A2W']
def test_call_external_random_effects(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -140,7 +140,7 @@
x = lltype.malloc(X, immortal=True); x.foo = 6
res = self.interpret(f1, [x])
assert res == 36
- assert self.barriers == ['P2R', 'p2r']
+ assert self.barriers == ['A2R', 'a2r']
def test_call_external_no_random_effects(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -157,7 +157,7 @@
x = lltype.malloc(X, immortal=True); x.foo = 6
res = self.interpret(f1, [x])
assert res == 36
- assert self.barriers == ['P2R']
+ assert self.barriers == ['A2R']
def test_pointer_compare_0(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -190,10 +190,10 @@
y = lltype.malloc(X, immortal=True)
res = self.interpret(f1, [x, y])
assert res == 0
- assert self.barriers == ['P2W', '=']
+ assert self.barriers == ['A2W', '=']
res = self.interpret(f1, [x, x])
assert res == 1
- assert self.barriers == ['P2W', '=']
+ assert self.barriers == ['A2W', '=']
def test_pointer_compare_3(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -204,10 +204,10 @@
y = lltype.malloc(X, immortal=True)
res = self.interpret(f1, [x, y])
assert res == 1
- assert self.barriers == ['P2W', '=']
+ assert self.barriers == ['A2W', '=']
res = self.interpret(f1, [x, x])
assert res == 0
- assert self.barriers == ['P2W', '=']
+ assert self.barriers == ['A2W', '=']
def test_pointer_compare_4(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -219,10 +219,10 @@
y = lltype.malloc(X, immortal=True)
res = self.interpret(f1, [x, y])
assert res == 1
- assert self.barriers == ['P2W', 'P2W']
+ assert self.barriers == ['A2W', 'A2W']
res = self.interpret(f1, [x, x])
assert res == 0
- assert self.barriers == ['P2W', 'P2W']
+ assert self.barriers == ['A2W', 'A2W']
def test_simple_loop(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -235,7 +235,7 @@
res = self.interpret(f1, [x, 5])
assert res == 0
# for now we get this. Later, we could probably optimize it
- assert self.barriers == ['P2W', 'p2w', 'p2w', 'p2w', 'p2w']
+ assert self.barriers == ['A2W', 'a2w', 'a2w', 'a2w', 'a2w']
def test_subclassing(self):
class X:
@@ -261,11 +261,11 @@
res = self.interpret(f1, [10])
assert res == 42 + 10
- assert self.barriers == ['p2r', 'p2r', 'p2r'] # from 3 blocks (could be
+ assert self.barriers == ['a2r', 'a2r', 'a2r'] # from 3 blocks (could be
# optimized later)
res = self.interpret(f1, [-10])
assert res == 815
- assert self.barriers == ['p2r', 'p2r']
+ assert self.barriers == ['a2r', 'a2r']
def test_write_barrier_repeated(self):
class X:
@@ -278,7 +278,7 @@
return y
res = self.interpret(f1, [10])
- assert self.barriers == ['P2W', 'r2w']
+ assert self.barriers == ['A2W', 'r2w']
external_stuff = rffi.llexternal('external_stuff', [], lltype.Void,
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
@@ -2,7 +2,7 @@
from rpython.rtyper.llinterp import LLFrame
from rpython.rtyper.test.test_llinterp import get_interpreter, clear_tcache
from rpython.translator.stm.transform import STMTransformer
-from rpython.translator.stm.writebarrier import NEEDS_BARRIER
+from rpython.translator.stm.writebarrier import needs_barrier
from rpython.conftest import option
@@ -33,9 +33,9 @@
if isinstance(p, _stmptr):
return p._category
if not p:
- return 'N'
+ return None
if p._solid:
- return 'P' # allocated with immortal=True
+ return 'A' # allocated with immortal=True
raise AssertionError("unknown category on %r" % (p,))
def interpret(self, fn, args):
@@ -76,14 +76,16 @@
def check_category(self, p, expected):
cat = self.get_category_or_null(p)
- assert cat in 'NPRW'
+ assert cat in 'AQRVW' or cat is None
+ if expected is not None:
+ assert cat is not None and cat >= expected
return cat
def op_stm_barrier(self, kind, obj):
frm, middledigit, to = kind
assert middledigit == '2'
cat = self.check_category(obj, frm)
- if not NEEDS_BARRIER[cat, to]:
+ if not needs_barrier(cat, to):
# a barrier, but with no effect
self.llinterpreter.tester.barriers.append(kind.lower())
return obj
@@ -96,32 +98,38 @@
return ptr2
def op_stm_ptr_eq(self, obj1, obj2):
- self.check_category(obj1, 'P')
- self.check_category(obj2, 'P')
+ self.check_category(obj1, None)
+ self.check_category(obj2, None)
self.llinterpreter.tester.barriers.append('=')
return obj1 == obj2
def op_getfield(self, obj, field):
- if not obj._TYPE.TO._immutable_field(field):
- self.check_category(obj, 'R')
+ if obj._TYPE.TO._immutable_field(field):
+ expected = 'I'
+ else:
+ expected = 'R'
+ self.check_category(obj, expected)
return LLFrame.op_getfield(self, obj, field)
def op_setfield(self, obj, fieldname, fieldvalue):
- if not obj._TYPE.TO._immutable_field(fieldname):
- self.check_category(obj, 'W')
- # convert R -> P 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:
- _stmptr._category.__set__(p, 'P')
+ self.check_category(obj, 'W')
+ # 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:
+ _stmptr._category.__set__(p, 'Q')
return LLFrame.op_setfield(self, obj, fieldname, fieldvalue)
def op_cast_pointer(self, RESTYPE, obj):
- cat = self.check_category(obj, 'P')
+ cat = self.check_category(obj, None)
p = opimpl.op_cast_pointer(RESTYPE, obj)
return _stmptr(p, cat)
op_cast_pointer.need_result_type = True
def op_malloc(self, obj, flags):
+ # convert all existing pointers W -> V
+ for p in self.all_stm_ptrs():
+ if p._category == 'W':
+ _stmptr._category.__set__(p, 'V')
p = LLFrame.op_malloc(self, obj, flags)
ptr2 = _stmptr(p, 'W')
self.llinterpreter.tester.writemode.add(ptr2._obj)
diff --git a/rpython/translator/stm/transform.py
b/rpython/translator/stm/transform.py
--- a/rpython/translator/stm/transform.py
+++ b/rpython/translator/stm/transform.py
@@ -11,6 +11,7 @@
def __init__(self, translator):
self.translator = translator
+ self.barrier_counts = {}
def transform(self):
assert not hasattr(self.translator, 'stm_transformation_applied')
@@ -30,6 +31,8 @@
self.collect_analyzer = CollectAnalyzer(self.translator)
for graph in self.translator.graphs:
insert_stm_barrier(self, graph)
+ for key, value in sorted(self.barrier_counts.items()):
+ log("%s: %d barriers" % (key, value[0]))
del self.write_analyzer
del self.collect_analyzer
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
@@ -9,15 +9,6 @@
'malloc_nonmovable', 'malloc_nonmovable_varsize',
])
-NEEDS_BARRIER = {
- ('P', 'R'): True,
- ('P', 'W'): True,
- ('R', 'R'): False,
- ('R', 'W'): True,
- ('W', 'R'): False,
- ('W', 'W'): False,
- }
-
def unwraplist(list_v):
for v in list_v:
if isinstance(v, Constant):
@@ -42,23 +33,32 @@
return OUTER._immutable_interiorfield(unwraplist(op.args[1:-1]))
raise AssertionError(op)
+def needs_barrier(frm, to):
+ return to > frm
+
def insert_stm_barrier(stmtransformer, graph):
"""This function uses the following characters for 'categories':
- * 'P': a general pointer
+ * 'A': any general pointer
+ * 'I': not a stub (immut_read_barrier was applied)
+ * 'Q': same as R, except needs a repeat_read_barrier
* 'R': the read barrier was applied
+ * 'V': same as W, except needs a repeat_write_barrier
* 'W': the write barrier was applied
+
+ The letters are chosen so that a barrier is needed to change a
+ pointer from category x to category y if and only if y > x.
"""
graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
def get_category(v):
- return category.get(v, 'P')
+ return category.get(v, 'A')
def get_category_or_null(v):
if isinstance(v, Constant) and not v.value:
- return 'N'
- return category.get(v, 'P')
+ return None
+ return category.get(v, 'A')
def renamings_get(v):
if v not in renamings:
@@ -77,26 +77,31 @@
wants_a_barrier = {}
expand_comparison = set()
for op in block.operations:
- # [1] XXX we can't leave getarraysize or the immutable getfields
- # fully unmodified. We'd need at least some lightweight
- # read barrier to detect stubs. For now we just put a
- # regular read barrier.
- if (op.opname in ('getfield', 'getarrayitem',
- 'getinteriorfield',
- 'getarraysize', 'getinteriorarraysize', # XXX [1]
- ) and
- op.result.concretetype is not lltype.Void and
- op.args[0].concretetype.TO._gckind == 'gc' and
- True): #not is_immutable(op)): XXX see [1]
+ is_getter = (op.opname in ('getfield', 'getarrayitem',
+ 'getinteriorfield') and
+ op.result.concretetype is not lltype.Void and
+ op.args[0].concretetype.TO._gckind == 'gc')
+ if (op.opname in ('getarraysize', 'getinteriorarraysize')
+ or (is_getter and is_immutable(op))):
+ # we can't leave getarraysize or the immutable getfields
+ # fully unmodified: we need at least immut_read_barrier
+ # to detect stubs.
+ wants_a_barrier[op] = 'I'
+
+ elif is_getter:
+ # the non-immutable getfields need a regular read barrier
wants_a_barrier[op] = 'R'
+
elif (op.opname in ('setfield', 'setarrayitem',
'setinteriorfield') and
op.args[-1].concretetype is not lltype.Void and
- op.args[0].concretetype.TO._gckind == 'gc' and
- not is_immutable(op)):
+ op.args[0].concretetype.TO._gckind == 'gc'):
+ # setfields need a regular write barrier
wants_a_barrier[op] = 'W'
+
elif (op.opname in ('ptr_eq', 'ptr_ne') and
op.args[0].concretetype.TO._gckind == 'gc'):
+ # GC pointer comparison might need special care
expand_comparison.add(op)
#
if wants_a_barrier or expand_comparison:
@@ -119,22 +124,20 @@
v_holder = renamings.setdefault(v, [v])
v = v_holder[0]
frm = get_category(v)
- if NEEDS_BARRIER[frm, to]:
- c_info = Constant('%s2%s' % (frm, to), lltype.Void)
+ if needs_barrier(frm, to):
+ try:
+ b = stmtransformer.barrier_counts[frm, to]
+ except KeyError:
+ c_info = Constant('%s2%s' % (frm, to), lltype.Void)
+ b = [0, c_info]
+ stmtransformer.barrier_counts[frm, to] = b
+ b[0] += 1
+ c_info = b[1]
w = varoftype(v.concretetype)
newop = SpaceOperation('stm_barrier', [c_info, v], w)
newoperations.append(newop)
v_holder[0] = w
category[w] = to
- if to == 'W':
- # if any of the other vars in the same path
- # points to the same object, they must lose
- # their read-status now
- for u in block.getvariables():
- if get_category(u) == 'R' \
- and u.concretetype == v.concretetype:
- category[u] = 'P'
-
#
newop = SpaceOperation(op.opname,
[renamings_get(v) for v in op.args],
@@ -144,7 +147,7 @@
if op in expand_comparison:
cats = (get_category_or_null(newop.args[0]),
get_category_or_null(newop.args[1]))
- if 'N' not in cats and cats != ('W', 'W'):
+ if None not in cats and (cats[0] < 'V' or cats[1] < 'V'):
if newop.opname == 'ptr_ne':
v = varoftype(lltype.Bool)
negop = SpaceOperation('bool_not', [v],
@@ -155,28 +158,30 @@
if stmtransformer.collect_analyzer.analyze(op):
# this operation can collect: we bring all 'W'
- # categories back to 'R', because we would need
- # another stm_write_barrier on them afterwards
+ # categories back to 'V', because we would need
+ # a repeat_write_barrier on them afterwards
for v, cat in category.items():
if cat == 'W':
- category[v] = 'R'
+ category[v] = 'V'
effectinfo = stmtransformer.write_analyzer.analyze(
op, graphinfo=graphinfo)
if effectinfo:
if effectinfo is top_set:
# this operation can perform random writes: any
- # 'R'-category object falls back to 'P' because
- # we would need another stm_read_barrier()
+ # 'R'-category object falls back to 'Q' because
+ # we would need a repeat_read_barrier()
for v, cat in category.items():
if cat == 'R':
- category[v] = 'P'
+ category[v] = 'Q'
else:
# the same, but only on objects of the right types
types = set([entry[1] for entry in effectinfo])
for v in category.keys():
if v.concretetype in types and category[v] == 'R':
- category[v] = 'P'
+ category[v] = 'Q'
+ # XXX this is likely not general enough: we need
+ # to consider 'types' or any base type
if op.opname in MALLOCS:
category[op.result] = 'W'
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit