Author: Armin Rigo <[email protected]>
Branch: stm
Changeset: r51712:d8e6a730661d
Date: 2012-01-23 18:26 +0100
http://bitbucket.org/pypy/pypy/changeset/d8e6a730661d/
Log: Implement proper immutability detection in {get,set}interiorfield().
This lets *all* our RPython-level 'string[index]' be considered as
immutable reads, which is likely essential for performance.
diff --git a/pypy/translator/stm/llstminterp.py
b/pypy/translator/stm/llstminterp.py
--- a/pypy/translator/stm/llstminterp.py
+++ b/pypy/translator/stm/llstminterp.py
@@ -124,6 +124,38 @@
self.check_stm_mode(lambda m: False)
assert 0
+ def opstm_getinteriorfield(self, struct, *fields):
+ STRUCT = lltype.typeOf(struct).TO
+ if STRUCT._immutable_interiorfield(fields):
+ # immutable field reads are always allowed
+ return LLFrame.op_getinteriorfield(self, struct, *fields)
+ elif STRUCT._gckind == 'raw':
+ # raw getfields are allowed outside a regular transaction
+ self.check_stm_mode(lambda m: m != "regular_transaction")
+ return LLFrame.op_getinteriorfield(self, struct, *fields)
+ else:
+ # mutable 'getfields' are always forbidden for now
+ self.check_stm_mode(lambda m: False)
+ assert 0
+
+ def opstm_setinteriorfield(self, struct, *fields_and_newvalue):
+ fields = fields_and_newvalue[:-1]
+ newvalue = fields_and_newvalue[-1]
+ STRUCT = lltype.typeOf(struct).TO
+ if STRUCT._immutable_interiorfield(fields):
+ # immutable field writes (i.e. initializing writes) should
+ # always be fine, because they should occur into newly malloced
+ # structures
+ LLFrame.op_setinteriorfield(self, struct, *fields_and_newvalue)
+ elif STRUCT._gckind == 'raw':
+ # raw setfields are allowed outside a regular transaction
+ self.check_stm_mode(lambda m: m != "regular_transaction")
+ LLFrame.op_setinteriorfield(self, struct, *fields_and_newvalue)
+ else:
+ # mutable 'setfields' are always forbidden for now
+ self.check_stm_mode(lambda m: False)
+ assert 0
+
def opstm_malloc(self, TYPE, flags):
# non-GC must not occur in a regular transaction,
# but can occur in inevitable mode or outside a transaction
diff --git a/pypy/translator/stm/test/test_transform.py
b/pypy/translator/stm/test/test_transform.py
--- a/pypy/translator/stm/test/test_transform.py
+++ b/pypy/translator/stm/test/test_transform.py
@@ -98,8 +98,11 @@
assert summary(graph) == {'stm_setarrayitem': 1}
eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
+STRLIKE = lltype.GcStruct('STRLIKE', # no 'immutable' in this version
+ ('chars', lltype.Array(lltype.Char)))
+
def test_getinteriorfield():
- p = lltype.malloc(rstr.STR, 100, immortal=True)
+ p = lltype.malloc(STRLIKE, 100, immortal=True)
p.chars[42] = 'X'
def func(p):
return p.chars[42]
@@ -110,12 +113,32 @@
assert res == 'X'
def test_setinteriorfield():
+ p = lltype.malloc(STRLIKE, 100, immortal=True)
+ def func(p):
+ p.chars[42] = 'Y'
+ interp, graph = get_interpreter(func, [p])
+ transform_graph(graph)
+ assert summary(graph) == {'stm_setinteriorfield': 1}
+ res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
+
+def test_getstrchar():
+ p = lltype.malloc(rstr.STR, 100, immortal=True)
+ p.chars[42] = 'X'
+ def func(p):
+ return p.chars[42]
+ interp, graph = get_interpreter(func, [p])
+ transform_graph(graph)
+ assert summary(graph) == {'getinteriorfield': 1}
+ res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
+ assert res == 'X'
+
+def test_setstrchar():
p = lltype.malloc(rstr.STR, 100, immortal=True)
def func(p):
p.chars[42] = 'Y'
interp, graph = get_interpreter(func, [p])
transform_graph(graph)
- assert summary(graph) == {'stm_setinteriorfield': 1}
+ assert summary(graph) == {'setinteriorfield': 1}
res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
def test_unsupported_operation():
diff --git a/pypy/translator/stm/transform.py b/pypy/translator/stm/transform.py
--- a/pypy/translator/stm/transform.py
+++ b/pypy/translator/stm/transform.py
@@ -164,7 +164,7 @@
OUTER = op.args[0].concretetype.TO
if op.result.concretetype is lltype.Void:
op1 = op
- elif OUTER._hints.get('immutable'):
+ elif OUTER._immutable_interiorfield(unwraplist(op.args[1:])):
op1 = op
elif OUTER._gckind == 'raw':
turn_inevitable(newoperations, "getinteriorfield-raw")
@@ -177,7 +177,7 @@
OUTER = op.args[0].concretetype.TO
if op.args[-1].concretetype is lltype.Void:
op1 = op
- elif OUTER._hints.get('immutable'):
+ elif OUTER._immutable_interiorfield(unwraplist(op.args[1:-1])):
op1 = op
elif OUTER._gckind == 'raw':
turn_inevitable(newoperations, "setinteriorfield-raw")
@@ -232,3 +232,12 @@
def turn_inevitable_and_proceed(newoperations, op):
turn_inevitable(newoperations, op.opname)
newoperations.append(op)
+
+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)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit