Author: Armin Rigo <[email protected]>
Branch: stm-thread-2
Changeset: r58982:47e9f6ca045d
Date: 2012-11-18 13:18 +0100
http://bitbucket.org/pypy/pypy/changeset/47e9f6ca045d/
Log: Re-import the parts of the old transform.py that insert
'turn_inevitable' around unsupported operations.
diff --git a/pypy/translator/stm/inevitable.py
b/pypy/translator/stm/inevitable.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/stm/inevitable.py
@@ -0,0 +1,80 @@
+from pypy.rpython.lltypesystem import lltype, lloperation
+from pypy.translator.stm.writebarrier import is_immutable
+from pypy.objspace.flow.model import SpaceOperation, Constant
+from pypy.translator.unsimplify import varoftype
+
+
+ALWAYS_ALLOW_OPERATIONS = set([
+ 'direct_call', 'force_cast', 'keepalive', 'cast_ptr_to_adr',
+ 'debug_print', 'debug_assert', 'cast_opaque_ptr', 'hint',
+ 'indirect_call', 'stack_current', 'gc_stack_bottom',
+ 'cast_current_ptr_to_int', # this variant of 'cast_ptr_to_int' is ok
+ 'jit_force_virtual', 'jit_force_virtualizable',
+ 'jit_force_quasi_immutable', 'jit_marker', 'jit_is_virtual',
+ 'jit_record_known_class',
+ 'gc_identityhash', 'gc_id',
+ 'gc_adr_of_root_stack_top',
+ ])
+ALWAYS_ALLOW_OPERATIONS |= set(lloperation.enum_tryfold_ops())
+
+for opname, opdesc in lloperation.LL_OPERATIONS.iteritems():
+ if opname.startswith('stm_'):
+ ALWAYS_ALLOW_OPERATIONS.add(opname)
+
+GETTERS = set(['getfield', 'getarrayitem', 'getinteriorfield'])
+SETTERS = set(['setfield', 'setarrayitem', 'setinteriorfield'])
+MALLOCS = set(['malloc', 'malloc_varsize',
+ 'malloc_nonmovable', 'malloc_nonmovable_varsize'])
+
+# ____________________________________________________________
+
+def should_turn_inevitable_getter_setter(op):
+ # Getters and setters are allowed if their first argument is a GC pointer.
+ # If it is a RAW pointer, and it is a read from a non-immutable place,
+ # and it doesn't use the hint 'stm_dont_track_raw_accesses', then they
+ # turn inevitable.
+ S = op.args[0].concretetype.TO
+ if S._gckind == 'gc':
+ return False
+ if is_immutable(op):
+ return False
+ if S._hints.get('stm_dont_track_raw_accesses', False):
+ return False
+ return True
+
+def should_turn_inevitable(op):
+ # Always-allowed operations never cause a 'turn inevitable'
+ if op.opname in ALWAYS_ALLOW_OPERATIONS:
+ return False
+ #
+ # Getters and setters
+ if op.opname in GETTERS:
+ if op.result.concretetype is lltype.Void:
+ return False
+ return should_turn_inevitable_getter_setter(op)
+ if op.opname in SETTERS:
+ if op.args[-1].concretetype is lltype.Void:
+ return False
+ return should_turn_inevitable_getter_setter(op)
+ #
+ # Mallocs
+ if op.opname in MALLOCS:
+ flags = op.args[1].value
+ return flags['flavor'] != 'gc'
+ #
+ # Entirely unsupported operations cause a 'turn inevitable'
+ return True
+
+
+def turn_inevitable_op(info):
+ c_info = Constant(info, lltype.Void)
+ return SpaceOperation('stm_become_inevitable', [c_info],
+ varoftype(lltype.Void))
+
+def insert_turn_inevitable(translator, graph):
+ for block in graph.iterblocks():
+ for i in range(len(block.operations)-1, -1, -1):
+ op = block.operations[i]
+ if should_turn_inevitable(op):
+ inev_op = turn_inevitable_op(op.opname)
+ block.operations.insert(i, inev_op)
diff --git a/pypy/translator/stm/test/test_inevitable.py
b/pypy/translator/stm/test/test_inevitable.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/stm/test/test_inevitable.py
@@ -0,0 +1,116 @@
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.llinterp import LLFrame
+from pypy.rpython.test import test_llinterp
+from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
+from pypy.translator.stm.inevitable import insert_turn_inevitable
+from pypy.conftest import option
+
+
+class LLSTMInevFrame(LLFrame):
+ def op_stm_become_inevitable(self, info):
+ assert info is not None
+ if self.llinterpreter.inevitable_cause is None:
+ self.llinterpreter.inevitable_cause = info
+
+
+class TestTransform:
+
+ def interpret_inevitable(self, fn, args):
+ clear_tcache()
+ interp, self.graph = get_interpreter(fn, args, view=False)
+ interp.frame_class = LLSTMInevFrame
+ self.translator = interp.typer.annotator.translator
+ insert_turn_inevitable(self.translator, self.graph)
+ if option.view:
+ self.translator.view()
+ #
+ interp.inevitable_cause = None
+ result = interp.eval_graph(self.graph, args)
+ return interp.inevitable_cause
+
+
+ def test_simple_no_inevitable(self):
+ X = lltype.GcStruct('X', ('foo', lltype.Signed))
+ x1 = lltype.malloc(X, immortal=True)
+ x1.foo = 42
+
+ def f1(n):
+ x1.foo = n
+
+ res = self.interpret_inevitable(f1, [4])
+ assert res is None
+
+ def test_unsupported_op(self):
+ X = lltype.Struct('X', ('foo', lltype.Signed))
+
+ def f1():
+ addr = llmemory.raw_malloc(llmemory.sizeof(X))
+ llmemory.raw_free(addr)
+
+ res = self.interpret_inevitable(f1, [])
+ assert res == 'raw_malloc'
+
+ def test_raw_getfield(self):
+ X = lltype.Struct('X', ('foo', lltype.Signed))
+ x1 = lltype.malloc(X, immortal=True)
+ x1.foo = 42
+
+ def f1():
+ return x1.foo
+
+ res = self.interpret_inevitable(f1, [])
+ assert res == 'getfield'
+
+ def test_raw_getfield_immutable(self):
+ X = lltype.Struct('X', ('foo', lltype.Signed),
+ hints={'immutable': True})
+ x1 = lltype.malloc(X, immortal=True)
+ x1.foo = 42
+
+ def f1():
+ return x1.foo
+
+ res = self.interpret_inevitable(f1, [])
+ assert res is None
+
+ def test_raw_getfield_with_hint(self):
+ X = lltype.Struct('X', ('foo', lltype.Signed),
+ hints={'stm_dont_track_raw_accesses': True})
+ x1 = lltype.malloc(X, immortal=True)
+ x1.foo = 42
+
+ def f1():
+ return x1.foo
+
+ res = self.interpret_inevitable(f1, [])
+ assert res is None
+
+ def test_raw_setfield(self):
+ X = lltype.Struct('X', ('foo', lltype.Signed))
+ x1 = lltype.malloc(X, immortal=True)
+ x1.foo = 42
+
+ def f1(n):
+ x1.foo = n
+
+ res = self.interpret_inevitable(f1, [43])
+ assert res == 'setfield'
+
+ def test_malloc_no_inevitable(self):
+ X = lltype.GcStruct('X', ('foo', lltype.Signed))
+
+ def f1():
+ return lltype.malloc(X)
+
+ res = self.interpret_inevitable(f1, [])
+ assert res is None
+
+ def test_raw_malloc(self):
+ X = lltype.Struct('X', ('foo', lltype.Signed))
+
+ def f1():
+ p = lltype.malloc(X, flavor='raw')
+ lltype.free(p, flavor='raw')
+
+ res = self.interpret_inevitable(f1, [])
+ assert res == 'malloc'
diff --git a/pypy/translator/stm/test/test_transform2.py
b/pypy/translator/stm/test/test_writebarrier.py
rename from pypy/translator/stm/test/test_transform2.py
rename to pypy/translator/stm/test/test_writebarrier.py
--- a/pypy/translator/stm/test/test_transform2.py
+++ b/pypy/translator/stm/test/test_writebarrier.py
@@ -1,124 +1,10 @@
-from pypy.rpython.lltypesystem import lltype, rffi, opimpl
-from pypy.rpython.llinterp import LLFrame
-from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
-from pypy.objspace.flow.model import Constant
-from pypy.translator.stm.transform2 import STMTransformer
-from pypy.translator.stm.transform2 import MORE_PRECISE_CATEGORIES
-from pypy.conftest import option
-
-
-class _stmptr(lltype._ptr):
- """Like lltype._ptr, but also keeps a current category level"""
-
- __slots__ = ['_category', '_original_ptr']
-
- def __init__(self, ptr, category):
- lltype._ptr.__init__(self, ptr._TYPE, ptr._obj0, ptr._solid)
- _stmptr._category.__set__(self, category)
- _stmptr._original_ptr.__set__(self, ptr)
-
- def __eq__(self, other):
- return self._original_ptr == other
-
-
-class BaseTestTransform(object):
-
- def build_state(self):
- self.writemode = set()
- self.barriers = []
-
- def get_category(self, p):
- if isinstance(p, _stmptr):
- return p._category
- if not p:
- return 'N'
- if p._solid:
- return 'G' # allocated with immortal=True
- raise AssertionError("unknown category on %r" % (p,))
-
- def interpret(self, fn, args):
- self.build_state()
- clear_tcache()
- interp, self.graph = get_interpreter(fn, args, view=False)
- interp.tester = self
- interp.frame_class = LLSTMFrame
- #
- self.translator = interp.typer.annotator.translator
- self.stmtransformer = STMTransformer(self.translator)
- self.stmtransformer.transform()
- if option.view:
- self.translator.view()
- #
- result = interp.eval_graph(self.graph, args)
- return result
-
-
-class LLSTMFrame(LLFrame):
-
- def all_stm_ptrs(self):
- for frame in self.llinterpreter.frame_stack:
- for value in frame.bindings.values():
- if isinstance(value, _stmptr):
- yield value
-
- def get_category(self, p):
- return self.llinterpreter.tester.get_category(p)
-
- def check_category(self, p, expected):
- cat = self.get_category(p)
- assert cat in MORE_PRECISE_CATEGORIES[expected]
- return cat
-
- def op_stm_barrier(self, kind, obj):
- frm, middledigit, to = kind
- assert middledigit == '2'
- cat = self.check_category(obj, frm)
- if cat in MORE_PRECISE_CATEGORIES[to]:
- # a barrier, but with no effect
- self.llinterpreter.tester.barriers.append(kind.lower())
- return obj
- else:
- # a barrier, calling a helper
- ptr2 = _stmptr(obj, to)
- if to == 'W':
- self.llinterpreter.tester.writemode.add(ptr2._obj)
- self.llinterpreter.tester.barriers.append(kind)
- return ptr2
-
- def op_stm_ptr_eq(self, obj1, obj2):
- self.check_category(obj1, 'P')
- self.check_category(obj2, 'P')
- 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')
- 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 -> O 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, 'O')
- return LLFrame.op_setfield(self, obj, fieldname, fieldvalue)
-
- def op_cast_pointer(self, RESTYPE, obj):
- cat = self.check_category(obj, 'P')
- p = opimpl.op_cast_pointer(RESTYPE, obj)
- return _stmptr(p, cat)
- op_cast_pointer.need_result_type = True
-
- def op_malloc(self, obj, flags):
- p = LLFrame.op_malloc(self, obj, flags)
- ptr2 = _stmptr(p, 'W')
- self.llinterpreter.tester.writemode.add(ptr2._obj)
- return ptr2
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.translator.stm.test.transform2_support import BaseTestTransform
class TestTransform(BaseTestTransform):
+ do_write_barrier = True
+ do_turn_inevitable = False
def test_simple_read(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
diff --git a/pypy/translator/stm/test/test_transform2.py
b/pypy/translator/stm/test/transform2_support.py
copy from pypy/translator/stm/test/test_transform2.py
copy to pypy/translator/stm/test/transform2_support.py
--- a/pypy/translator/stm/test/test_transform2.py
+++ b/pypy/translator/stm/test/transform2_support.py
@@ -1,9 +1,8 @@
-from pypy.rpython.lltypesystem import lltype, rffi, opimpl
+from pypy.rpython.lltypesystem import lltype, opimpl
from pypy.rpython.llinterp import LLFrame
from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
-from pypy.objspace.flow.model import Constant
from pypy.translator.stm.transform2 import STMTransformer
-from pypy.translator.stm.transform2 import MORE_PRECISE_CATEGORIES
+from pypy.translator.stm.writebarrier import MORE_PRECISE_CATEGORIES
from pypy.conftest import option
@@ -45,7 +44,10 @@
#
self.translator = interp.typer.annotator.translator
self.stmtransformer = STMTransformer(self.translator)
- self.stmtransformer.transform()
+ if self.do_write_barrier:
+ self.stmtransformer.transform_write_barrier()
+ if self.do_turn_inevitable:
+ self.stmtransformer.transform_turn_inevitable()
if option.view:
self.translator.view()
#
@@ -116,247 +118,3 @@
ptr2 = _stmptr(p, 'W')
self.llinterpreter.tester.writemode.add(ptr2._obj)
return ptr2
-
-
-class TestTransform(BaseTestTransform):
-
- def test_simple_read(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- x1 = lltype.malloc(X, immortal=True)
- x1.foo = 42
- x2 = lltype.malloc(X, immortal=True)
- x2.foo = 81
-
- def f1(n):
- if n > 1:
- return x2.foo
- else:
- return x1.foo
-
- res = self.interpret(f1, [4])
- assert res == 81
- assert len(self.writemode) == 0
- res = self.interpret(f1, [-5])
- assert res == 42
- assert len(self.writemode) == 0
- assert self.barriers == ['G2R']
-
- def test_simple_write(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- x1 = lltype.malloc(X, immortal=True)
- x1.foo = 42
-
- def f1(n):
- x1.foo = n
-
- self.interpret(f1, [4])
- assert x1.foo == 4
- assert len(self.writemode) == 1
- assert self.barriers == ['G2W']
-
- def test_multiple_reads(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed),
- ('bar', lltype.Signed))
- x1 = lltype.malloc(X, immortal=True)
- x1.foo = 6
- x1.bar = 7
- x2 = lltype.malloc(X, immortal=True)
- x2.foo = 81
- x2.bar = -1
-
- def f1(n):
- if n > 1:
- return x2.foo * x2.bar
- else:
- return x1.foo * x1.bar
-
- res = self.interpret(f1, [4])
- assert res == -81
- assert len(self.writemode) == 0
- assert self.barriers == ['G2R']
-
- def test_malloc(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(n):
- p = lltype.malloc(X)
- p.foo = n
-
- self.interpret(f1, [4])
- assert len(self.writemode) == 1
- assert self.barriers == []
-
- def test_write_may_alias(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(p, q):
- x1 = p.foo
- q.foo = 7
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- y = lltype.malloc(X, immortal=True)
- res = self.interpret(f1, [x, y])
- assert res == 36
- assert self.barriers == ['P2R', 'P2W', 'o2r']
- res = self.interpret(f1, [x, x])
- assert res == 42
- assert self.barriers == ['P2R', 'P2W', 'O2R']
-
- def test_write_cannot_alias(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- Y = lltype.GcStruct('Y', ('foo', lltype.Signed))
- def f1(p, q):
- x1 = p.foo
- q.foo = 7
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- y = lltype.malloc(Y, immortal=True)
- res = self.interpret(f1, [x, y])
- assert res == 36
- assert self.barriers == ['P2R', 'P2W']
-
- def test_call_external_random_effects(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(p):
- x1 = p.foo
- external_stuff()
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- res = self.interpret(f1, [x])
- assert res == 36
- assert self.barriers == ['P2R', 'p2r']
-
- def test_call_external_no_random_effects(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- external_stuff = rffi.llexternal('external_stuff2', [], lltype.Void,
- _callable=lambda: None,
- random_effects_on_gcobjs=False,
- threadsafe=False)
- def f1(p):
- x1 = p.foo
- external_stuff()
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- res = self.interpret(f1, [x])
- assert res == 36
- assert self.barriers == ['P2R']
-
- def test_pointer_compare_0(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(x):
- return x != lltype.nullptr(X)
- x = lltype.malloc(X, immortal=True)
- res = self.interpret(f1, [x])
- assert res == 1
- assert self.barriers == []
-
- def test_pointer_compare_1(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(x, y):
- return x != y
- x = lltype.malloc(X, immortal=True)
- y = lltype.malloc(X, immortal=True)
- res = self.interpret(f1, [x, y])
- assert res == 1
- assert self.barriers == ['=']
- res = self.interpret(f1, [x, x])
- assert res == 0
- assert self.barriers == ['=']
-
- def test_pointer_compare_2(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(x, y):
- x.foo = 41
- return x == y
- x = lltype.malloc(X, immortal=True)
- y = lltype.malloc(X, immortal=True)
- res = self.interpret(f1, [x, y])
- assert res == 0
- assert self.barriers == ['P2W', '=']
- res = self.interpret(f1, [x, x])
- assert res == 1
- assert self.barriers == ['P2W', '=']
-
- def test_pointer_compare_3(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(x, y):
- y.foo = 41
- return x != y
- x = lltype.malloc(X, immortal=True)
- y = lltype.malloc(X, immortal=True)
- res = self.interpret(f1, [x, y])
- assert res == 1
- assert self.barriers == ['P2W', '=']
- res = self.interpret(f1, [x, x])
- assert res == 0
- assert self.barriers == ['P2W', '=']
-
- def test_pointer_compare_4(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(x, y):
- x.foo = 40
- y.foo = 41
- return x != y
- x = lltype.malloc(X, immortal=True)
- y = lltype.malloc(X, immortal=True)
- res = self.interpret(f1, [x, y])
- assert res == 1
- assert self.barriers == ['P2W', 'P2W']
- res = self.interpret(f1, [x, x])
- assert res == 0
- assert self.barriers == ['P2W', 'P2W']
-
- def test_simple_loop(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(x, i):
- while i > 0:
- x.foo = i
- i -= 1
- return i
- x = lltype.malloc(X, immortal=True)
- 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']
-
- def test_subclassing(self):
- class X:
- __slots__ = ['foo']
- class Y(X):
- pass
- class Z(X):
- pass
- def f1(i):
- if i > 5:
- x = Y()
- x.foo = 42
- x.ybar = i
- else:
- x = Z()
- x.foo = 815
- x.zbar = 'A'
- external_stuff()
- result = x.foo
- if isinstance(x, Y):
- result += x.ybar
- return result
-
- res = self.interpret(f1, [10])
- assert res == 42 + 10
- assert self.barriers == ['p2r', 'p2r'] # from two blocks (could be
- # optimized later)
- res = self.interpret(f1, [-10])
- assert res == 815
- assert self.barriers == ['p2r']
-
-
-external_stuff = rffi.llexternal('external_stuff', [], lltype.Void,
- _callable=lambda: None,
- random_effects_on_gcobjs=True,
- threadsafe=False)
diff --git a/pypy/translator/stm/transform2.py
b/pypy/translator/stm/transform2.py
--- a/pypy/translator/stm/transform2.py
+++ b/pypy/translator/stm/transform2.py
@@ -1,10 +1,3 @@
-from pypy.objspace.flow.model import SpaceOperation, Constant, Variable
-from pypy.objspace.flow.model import checkgraph, c_last_exception, Block, Link
-from pypy.translator.unsimplify import varoftype, insert_empty_block
-from pypy.rpython.lltypesystem import lltype
-from pypy.translator.backendopt.writeanalyze import WriteAnalyzer, top_set
-
-
class STMTransformer(object):
@@ -14,12 +7,25 @@
def transform(self):
assert not hasattr(self.translator, 'stm_transformation_applied')
self.start_log()
+ self.transform_write_barrier()
+ self.transform_turn_inevitable()
+ self.print_logs()
+ self.translator.stm_transformation_applied = True
+
+ def transform_write_barrier(self):
+ from pypy.translator.backendopt.writeanalyze import WriteAnalyzer
+ from pypy.translator.stm.writebarrier import insert_stm_barrier
+ #
self.write_analyzer = WriteAnalyzer(self.translator)
for graph in self.translator.graphs:
- pre_insert_stm_barrier(self, graph)
+ insert_stm_barrier(self, graph)
del self.write_analyzer
- self.translator.stm_transformation_applied = True
- self.print_logs()
+
+ def transform_turn_inevitable(self):
+ from pypy.translator.stm.inevitable import insert_turn_inevitable
+ #
+ for graph in self.translator.graphs:
+ insert_turn_inevitable(self.translator, graph)
def start_log(self):
from pypy.translator.c.support import log
@@ -28,158 +34,3 @@
def print_logs(self):
from pypy.translator.c.support import log
log.info("Software Transactional Memory transformation applied")
-
-
-MALLOCS = set([
- 'malloc', 'malloc_varsize',
- 'malloc_nonmovable', 'malloc_nonmovable_varsize',
- ])
-
-MORE_PRECISE_CATEGORIES = {
- 'P': 'PGORLWN',
- 'G': 'GN',
- 'O': 'ORLWN',
- 'R': 'RLWN',
- 'L': 'LWN',
- 'W': 'WN',
- 'N': 'N'}
-
-def unwraplist(list_v):
- for v in list_v:
- if isinstance(v, Constant):
- yield v.value
- elif isinstance(v, Variable):
- yield None # unknown
- else:
- raise AssertionError(v)
-
-def is_immutable(op):
- if op.opname in ('getfield', 'setfield'):
- STRUCT = op.args[0].concretetype.TO
- return STRUCT._immutable_field(op.args[1].value)
- if op.opname in ('getarrayitem', 'setarrayitem'):
- ARRAY = op.args[0].concretetype.TO
- return ARRAY._immutable_field()
- if op.opname == 'getinteriorfield':
- OUTER = op.args[0].concretetype.TO
- return OUTER._immutable_interiorfield(unwraplist(op.args[1:]))
- if op.opname == 'setinteriorfield':
- OUTER = op.args[0].concretetype.TO
- return OUTER._immutable_interiorfield(unwraplist(op.args[1:-1]))
- raise AssertionError(op)
-
-
-def pre_insert_stm_barrier(stmtransformer, graph):
- graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
-
- def get_category(v):
- if isinstance(v, Constant):
- if v.value:
- return 'G'
- else:
- return 'N' # NULL
- return category.get(v, 'P')
-
- def renamings_get(v):
- if v not in renamings:
- return v
- v2 = renamings[v][0]
- if v2.concretetype == v.concretetype:
- return v2
- v3 = varoftype(v.concretetype)
- newoperations.append(SpaceOperation('cast_pointer', [v2], v3))
- return v3
-
- for block in graph.iterblocks():
- if block.operations == ():
- continue
- #
- wants_a_barrier = {}
- expand_comparison = set()
- for op in block.operations:
- if (op.opname in ('getfield', 'getarrayitem',
- 'getinteriorfield') and
- op.result.concretetype is not lltype.Void and
- op.args[0].concretetype.TO._gckind == 'gc' and
- not is_immutable(op)):
- wants_a_barrier.setdefault(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)):
- wants_a_barrier[op] = 'W'
- elif (op.opname in ('ptr_eq', 'ptr_ne') and
- op.args[0].concretetype.TO._gckind == 'gc'):
- expand_comparison.add(op)
- #
- if wants_a_barrier or expand_comparison:
- # note: 'renamings' maps old vars to new vars, but cast_pointers
- # are done lazily. It means that the two vars may not have
- # exactly the same type.
- renamings = {} # {original-var: [var-in-newoperations] (len 1)}
- category = {} # {var-in-newoperations: LETTER}
- newoperations = []
- for op in block.operations:
- #
- if op.opname == 'cast_pointer':
- v = op.args[0]
- renamings[op.result] = renamings.setdefault(v, [v])
- continue
- #
- to = wants_a_barrier.get(op)
- if to is not None:
- v = op.args[0]
- v_holder = renamings.setdefault(v, [v])
- v = v_holder[0]
- frm = get_category(v)
- if frm not in MORE_PRECISE_CATEGORIES[to]:
- c_info = Constant('%s2%s' % (frm, to), lltype.Void)
- w = varoftype(v.concretetype)
- newop = SpaceOperation('stm_barrier', [c_info, v], w)
- newoperations.append(newop)
- v_holder[0] = w
- category[w] = to
- #
- newop = SpaceOperation(op.opname,
- [renamings_get(v) for v in op.args],
- op.result)
- newoperations.append(newop)
- #
- if op in expand_comparison:
- cats = ''.join([get_category(v) for v in newop.args])
- if ('N' not in cats and
- cats not in ('LL', 'LW', 'WL', 'WW')):
- if newop.opname == 'ptr_ne':
- v = varoftype(lltype.Bool)
- negop = SpaceOperation('bool_not', [v],
- newop.result)
- newoperations.append(negop)
- newop.result = v
- newop.opname = 'stm_ptr_eq'
- #
- effectinfo = stmtransformer.write_analyzer.analyze(
- op, graphinfo=graphinfo)
- if effectinfo:
- if effectinfo is top_set:
- category.clear()
- else:
- types = set([entry[1] for entry in effectinfo])
- for v in category.keys():
- if v.concretetype in types and category[v] == 'R':
- category[v] = 'O'
- #
- if op.opname in MALLOCS:
- category[op.result] = 'W'
-
- block.operations = newoperations
- #
- for link in block.exits:
- newoperations = []
- for i, v in enumerate(link.args):
- link.args[i] = renamings_get(v)
- if newoperations:
- # must put them in a fresh block along the link
- annotator = stmtransformer.translator.annotator
- newblock = insert_empty_block(annotator, link,
- newoperations)
diff --git a/pypy/translator/stm/transform2.py
b/pypy/translator/stm/writebarrier.py
copy from pypy/translator/stm/transform2.py
copy to pypy/translator/stm/writebarrier.py
--- a/pypy/translator/stm/transform2.py
+++ b/pypy/translator/stm/writebarrier.py
@@ -1,33 +1,7 @@
from pypy.objspace.flow.model import SpaceOperation, Constant, Variable
-from pypy.objspace.flow.model import checkgraph, c_last_exception, Block, Link
from pypy.translator.unsimplify import varoftype, insert_empty_block
from pypy.rpython.lltypesystem import lltype
-from pypy.translator.backendopt.writeanalyze import WriteAnalyzer, top_set
-
-
-
-class STMTransformer(object):
-
- def __init__(self, translator):
- self.translator = translator
-
- def transform(self):
- assert not hasattr(self.translator, 'stm_transformation_applied')
- self.start_log()
- self.write_analyzer = WriteAnalyzer(self.translator)
- for graph in self.translator.graphs:
- pre_insert_stm_barrier(self, graph)
- del self.write_analyzer
- self.translator.stm_transformation_applied = True
- self.print_logs()
-
- def start_log(self):
- from pypy.translator.c.support import log
- log.info("Software Transactional Memory transformation")
-
- def print_logs(self):
- from pypy.translator.c.support import log
- log.info("Software Transactional Memory transformation applied")
+from pypy.translator.backendopt.writeanalyze import top_set
MALLOCS = set([
@@ -69,7 +43,7 @@
raise AssertionError(op)
-def pre_insert_stm_barrier(stmtransformer, graph):
+def insert_stm_barrier(stmtransformer, graph):
graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
def get_category(v):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit