[pypy-commit] pypy improve-consecutive-dict-lookups: sort out the issue with interiorfielddescrs (I think) and dicts
fijal
noreply at buildbot.pypy.org
Wed Mar 19 20:55:35 CET 2014
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: improve-consecutive-dict-lookups
Changeset: r70098:2cf24861ad15
Date: 2014-03-19 21:48 +0200
http://bitbucket.org/pypy/pypy/changeset/2cf24861ad15/
Log: sort out the issue with interiorfielddescrs (I think) and dicts
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -93,12 +93,14 @@
])
def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
+ readonly_descrs_interiorfields,
write_descrs_fields, write_descrs_arrays,
+ write_descrs_interiorfields,
extraeffect=EF_CAN_RAISE,
oopspecindex=OS_NONE,
can_invalidate=False,
call_release_gil_target=llmemory.NULL,
- extradescr=None):
+ extradescrs=None):
key = (frozenset_or_none(readonly_descrs_fields),
frozenset_or_none(readonly_descrs_arrays),
frozenset_or_none(write_descrs_fields),
@@ -123,18 +125,21 @@
result = object.__new__(cls)
result.readonly_descrs_fields = readonly_descrs_fields
result.readonly_descrs_arrays = readonly_descrs_arrays
+ result.readonly_descrs_interiorfields = readonly_descrs_interiorfields
if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \
extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE:
result.write_descrs_fields = []
result.write_descrs_arrays = []
+ result.write_descrs_interiorfields = []
else:
result.write_descrs_fields = write_descrs_fields
result.write_descrs_arrays = write_descrs_arrays
+ result.write_descrs_interiorfields = write_descrs_interiorfields
result.extraeffect = extraeffect
result.can_invalidate = can_invalidate
result.oopspecindex = oopspecindex
- result.extradescr = extradescr
+ result.extradescrs = extradescrs
result.call_release_gil_target = call_release_gil_target
if result.check_can_raise():
assert oopspecindex in cls._OS_CANRAISE
@@ -166,7 +171,7 @@
return None
return frozenset(x)
-EffectInfo.MOST_GENERAL = EffectInfo(None, None, None, None,
+EffectInfo.MOST_GENERAL = EffectInfo(None, None, None, None, None, None,
EffectInfo.EF_RANDOM_EFFECTS,
can_invalidate=True)
@@ -181,14 +186,18 @@
if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
readonly_descrs_fields = None
readonly_descrs_arrays = None
+ readonly_descrs_interiorfields = None
write_descrs_fields = None
write_descrs_arrays = None
+ write_descrs_interiorfields = None
extraeffect = EffectInfo.EF_RANDOM_EFFECTS
else:
readonly_descrs_fields = []
readonly_descrs_arrays = []
+ readonly_descrs_interiorfields = []
write_descrs_fields = []
write_descrs_arrays = []
+ write_descrs_interiorfields = []
def add_struct(descrs_fields, (_, T, fieldname)):
T = deref(T)
@@ -202,6 +211,17 @@
descr = cpu.arraydescrof(ARRAY)
descrs_arrays.append(descr)
+ def add_interiorfield(descrs_interiorfields, (_, T, fieldname)):
+ T = deref(T)
+ if not isinstance(T, lltype.Array):
+ return # let's not consider structs for now
+ if not consider_array(T):
+ return
+ if getattr(T.OF, fieldname) is lltype.Void:
+ return
+ descr = cpu.interiorfielddescrof(T, fieldname)
+ descrs_interiorfields.append(descr)
+
for tup in effects:
if tup[0] == "struct":
add_struct(write_descrs_fields, tup)
@@ -209,6 +229,12 @@
tupw = ("struct",) + tup[1:]
if tupw not in effects:
add_struct(readonly_descrs_fields, tup)
+ elif tup[0] == "interiorfield":
+ add_interiorfield(write_descrs_interiorfields, tup)
+ elif tup[0] == "readinteriorfield":
+ tupw = ('interiorfield',) + tup[1:]
+ if tupw not in effects:
+ add_interiorfield(readonly_descrs_interiorfields, tup)
elif tup[0] == "array":
add_array(write_descrs_arrays, tup)
elif tup[0] == "readarray":
@@ -220,8 +246,10 @@
#
return EffectInfo(readonly_descrs_fields,
readonly_descrs_arrays,
+ readonly_descrs_interiorfields,
write_descrs_fields,
write_descrs_arrays,
+ write_descrs_interiorfields,
extraeffect,
oopspecindex,
can_invalidate,
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1852,10 +1852,12 @@
EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
def _handle_dict_lookup_call(self, op, oopspec_name, args):
- extradescr = self.cpu.fielddescrof(op.args[1].concretetype.TO,
- 'entries')
+ extradescr1 = self.cpu.fielddescrof(op.args[1].concretetype.TO,
+ 'entries')
+ extradescr2 = self.cpu.interiorfielddescrof(
+ op.args[1].concretetype.TO.entries.TO, 'key')
return self._handle_oopspec_call(op, args, EffectInfo.OS_DICT_LOOKUP,
- extradescr=extradescr)
+ extradescr=[extradescr1, extradescr2])
def _handle_rgc_call(self, op, oopspec_name, args):
if oopspec_name == 'rgc.ll_shrink_array':
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -177,6 +177,8 @@
self.cached_arrayitems = {}
# cached dict items: {dict descr: {(optval, index): box-or-const}}
self.cached_dict_reads = {}
+ # cache of corresponding array descrs
+ self.corresponding_array_descrs = {}
#
self._lazy_setfields_and_arrayitems = []
self._remove_guard_not_invalidated = False
@@ -185,10 +187,12 @@
def force_at_end_of_preamble(self):
self.cached_dict_reads.clear()
+ self.corresponding_array_descrs.clear()
self.force_all_lazy_setfields_and_arrayitems()
def flush(self):
self.cached_dict_reads.clear()
+ self.corresponding_array_descrs.clear()
self.force_all_lazy_setfields_and_arrayitems()
self.emit_postponed_op()
@@ -301,11 +305,14 @@
self.emit_operation(op)
def _optimize_CALL_DICT_LOOKUP(self, op):
- descr = op.getdescr().get_extra_info().extradescr
- if descr in self.cached_dict_reads:
- d = self.cached_dict_reads[descr]
+ descrs = op.getdescr().get_extra_info().extradescrs
+ descr1 = descrs[0]
+ descr2 = descrs[1]
+ if descr1 in self.cached_dict_reads:
+ d = self.cached_dict_reads[descr1]
else:
- d = self.cached_dict_reads[descr] = args_dict()
+ d = self.cached_dict_reads[descr1] = args_dict()
+ self.corresponding_array_descrs[descr2] = descr1
args = self.optimizer.make_args_key(op)
try:
res_v = d[args]
@@ -339,6 +346,13 @@
self.force_lazy_setfield(fielddescr, can_cache=False)
for arraydescr in effectinfo.write_descrs_arrays:
self.force_lazy_setarrayitem(arraydescr, can_cache=False)
+ for descr in effectinfo.write_descrs_interiorfields:
+ if descr in self.corresponding_array_descrs:
+ dictdescr = self.corresponding_array_descrs.pop(descr)
+ try:
+ del self.cached_dict_reads[dictdescr]
+ except KeyError:
+ pass # someone did it already
if effectinfo.check_forces_virtual_or_virtualizable():
vrefinfo = self.optimizer.metainterp_sd.virtualref_info
self.force_lazy_setfield(vrefinfo.descr_forced)
diff --git a/rpython/jit/metainterp/test/test_dict.py b/rpython/jit/metainterp/test/test_dict.py
--- a/rpython/jit/metainterp/test/test_dict.py
+++ b/rpython/jit/metainterp/test/test_dict.py
@@ -253,6 +253,28 @@
assert res == f(10)
self.check_simple_loop(call=5)
+ def test_dict_array_write_invalidates_caches(self):
+ driver = JitDriver(greens = [], reds = 'auto')
+ indexes = ['aa', 'b', 'cc']
+
+ def f(n):
+ d = {'aa': 3, 'b': 4, 'cc': 5}
+ s = 0
+ while n > 0:
+ driver.jit_merge_point()
+ index = indexes[n & 1]
+ s += d[index]
+ del d['cc']
+ s += d[index]
+ d['cc'] = 3
+ n -= 1
+ return s
+
+ exp = f(10)
+ res = self.meta_interp(f, [10])
+ assert res == exp
+ self.check_simple_loop(call=7)
+
def test_dict_double_lookup_2(self):
driver = JitDriver(greens = [], reds = 'auto')
indexes = ['aa', 'b', 'cc']
diff --git a/rpython/translator/backendopt/writeanalyze.py b/rpython/translator/backendopt/writeanalyze.py
--- a/rpython/translator/backendopt/writeanalyze.py
+++ b/rpython/translator/backendopt/writeanalyze.py
@@ -1,4 +1,4 @@
-from rpython.flowspace.model import Variable
+from rpython.flowspace.model import Variable, Constant
from rpython.translator.backendopt import graphanalyze
top_set = object()
@@ -37,6 +37,12 @@
return top_set
return result1.union(result2)
+ def _getinteriorname(self, op):
+ if (isinstance(op.args[1], Constant) and
+ isinstance(op.args[1].value, str)):
+ return op.args[1].value
+ return op.args[2].value
+
def analyze_simple_operation(self, op, graphinfo):
if op.opname == "setfield":
if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
@@ -47,8 +53,8 @@
return self._array_result(op.args[0].concretetype)
elif op.opname == "setinteriorfield":
if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
- return self._interiorfield_result(op.args[0].concretetype,
- op.args[2].value)
+ name = self._getinteriorname(op)
+ return self._interiorfield_result(op.args[0].concretetype, name)
return empty_set
def _array_result(self, TYPE):
@@ -107,7 +113,7 @@
return frozenset([
("readarray", op.args[0].concretetype)])
elif op.opname == "getinteriorfield":
- return frozenset([
- ("readinteriorfield", op.args[0].concretetype,
- op.args[2].value)])
+ name = self._getinteriorname(op)
+ return frozenset([("readinteriorfield", op.args[0].concretetype,
+ name)])
return WriteAnalyzer.analyze_simple_operation(self, op, graphinfo)
More information about the pypy-commit
mailing list