Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r83961:b985ddd2357b Date: 2016-04-27 09:16 +0200 http://bitbucket.org/pypy/pypy/changeset/b985ddd2357b/
Log: hg merge bitstring Use bitstrings to compress the lists of read or written descrs that we attach to EffectInfo. It is not necessarily more compact (if there are a lot of tiny lists), but it fixes two problems: * optimizeopt/heap.py: we no longer have the potential problem of having to walk some very large lists of descrs. Now we walk the descrs that are cached at this point, and check if each one is in the bitstring. * backendopt/writeanalyze.py: as a result we can get rid of the arbitrary limit on the size of the lists, which got in the way recently. diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -4577,6 +4577,13 @@ with py.test.raises(AnnotatorError): a.build_types(f, [float]) + def test_Ellipsis_not_rpython(self): + def f(): + return Ellipsis + a = self.RPythonAnnotator() + e = py.test.raises(Exception, a.build_types, f, []) + assert str(e.value) == "Don't know how to represent Ellipsis" + def g(n): return [0, 1, 2, n] diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -479,6 +479,9 @@ all_descrs.append(v) return all_descrs + def fetch_all_descrs(self): + return self.descrs.values() + def calldescrof(self, FUNC, ARGS, RESULT, effect_info): key = ('call', getkind(RESULT), tuple([getkind(A) for A in ARGS]), 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 @@ -1,7 +1,9 @@ +import sys from rpython.jit.metainterp.typesystem import deref, fieldType, arrayItem from rpython.rtyper.rclass import OBJECT from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.translator.backendopt.graphanalyze import BoolGraphAnalyzer +from rpython.tool.algo import bitstring class EffectInfo(object): @@ -110,12 +112,20 @@ can_invalidate=False, call_release_gil_target=_NO_CALL_RELEASE_GIL_TARGET, extradescrs=None): - key = (frozenset_or_none(readonly_descrs_fields), - frozenset_or_none(readonly_descrs_arrays), - frozenset_or_none(readonly_descrs_interiorfields), - frozenset_or_none(write_descrs_fields), - frozenset_or_none(write_descrs_arrays), - frozenset_or_none(write_descrs_interiorfields), + readonly_descrs_fields = frozenset_or_none(readonly_descrs_fields) + readonly_descrs_arrays = frozenset_or_none(readonly_descrs_arrays) + readonly_descrs_interiorfields = frozenset_or_none( + readonly_descrs_interiorfields) + write_descrs_fields = frozenset_or_none(write_descrs_fields) + write_descrs_arrays = frozenset_or_none(write_descrs_arrays) + write_descrs_interiorfields = frozenset_or_none( + write_descrs_interiorfields) + key = (readonly_descrs_fields, + readonly_descrs_arrays, + readonly_descrs_interiorfields, + write_descrs_fields, + write_descrs_arrays, + write_descrs_interiorfields, extraeffect, oopspecindex, can_invalidate) @@ -139,22 +149,34 @@ assert write_descrs_arrays is not None assert write_descrs_interiorfields is not None 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 + # the frozensets "._readonly_xxx" and "._write_xxx" should not be + # translated. + 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_OR_MEMORYERROR or \ extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE: # Ignore the writes. Note that this ignores also writes with # no corresponding reads (rarely the case, but possible). - result.write_descrs_fields = [] - result.write_descrs_arrays = [] - result.write_descrs_interiorfields = [] + result._write_descrs_fields = frozenset() + result._write_descrs_arrays = frozenset() + result._write_descrs_interiorfields = frozenset() else: - result.write_descrs_fields = write_descrs_fields - result.write_descrs_arrays = write_descrs_arrays - result.write_descrs_interiorfields = write_descrs_interiorfields + result._write_descrs_fields = write_descrs_fields + result._write_descrs_arrays = write_descrs_arrays + result._write_descrs_interiorfields = write_descrs_interiorfields + # initialized later, in compute_bitstrings() + # (the goal of this is to make sure we don't build new EffectInfo + # instances after compute_bitstrings() is called) + result.bitstring_readonly_descrs_fields = Ellipsis + result.bitstring_readonly_descrs_arrays = Ellipsis + result.bitstring_readonly_descrs_interiorfields = Ellipsis + result.bitstring_write_descrs_fields = Ellipsis + result.bitstring_write_descrs_arrays = Ellipsis + result.bitstring_write_descrs_interiorfields = Ellipsis + # result.extraeffect = extraeffect result.can_invalidate = can_invalidate result.oopspecindex = oopspecindex @@ -162,9 +184,38 @@ result.call_release_gil_target = call_release_gil_target if result.check_can_raise(ignore_memoryerror=True): assert oopspecindex in cls._OS_CANRAISE + + if (result._write_descrs_arrays is not None and + len(result._write_descrs_arrays) == 1): + # this is used only for ARRAYCOPY operations + [result.single_write_descr_array] = result._write_descrs_arrays + else: + result.single_write_descr_array = None + cls._cache[key] = result return result + def check_readonly_descr_field(self, fielddescr): + return bitstring.bitcheck(self.bitstring_readonly_descrs_fields, + fielddescr.ei_index) + def check_write_descr_field(self, fielddescr): + return bitstring.bitcheck(self.bitstring_write_descrs_fields, + fielddescr.ei_index) + def check_readonly_descr_array(self, arraydescr): + return bitstring.bitcheck(self.bitstring_readonly_descrs_arrays, + arraydescr.ei_index) + def check_write_descr_array(self, arraydescr): + return bitstring.bitcheck(self.bitstring_write_descrs_arrays, + arraydescr.ei_index) + def check_readonly_descr_interiorfield(self, interiorfielddescr): + # NOTE: this is not used so far + return bitstring.bitcheck(self.bitstring_readonly_descrs_interiorfields, + interiorfielddescr.ei_index) + def check_write_descr_interiorfield(self, interiorfielddescr): + # NOTE: this is not used so far + return bitstring.bitcheck(self.bitstring_write_descrs_interiorfields, + interiorfielddescr.ei_index) + def check_can_raise(self, ignore_memoryerror=False): if ignore_memoryerror: return self.extraeffect > self.EF_ELIDABLE_OR_MEMORYERROR @@ -382,3 +433,88 @@ assert funcptr return funcptr funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(1)' + +# ____________________________________________________________ + +def compute_bitstrings(all_descrs): + # Compute the bitstrings in the EffectInfo, + # bitstring_{readonly,write}_descrs_{fieldd,arrays,interiordescrs}, + # and for each FieldDescrs and ArrayDescrs compute 'ei_index'. + # Each bit in the bitstrings says whether this Descr is present in + # this EffectInfo or not. We try to share the value of 'ei_index' + # across multiple Descrs if they always give the same answer (in + # PyPy, it reduces the length of the bitstrings from 4000+ to + # 373). + from rpython.jit.codewriter.policy import log + + log("compute_bitstrings:") + effectinfos = [] + descrs = {'fields': set(), 'arrays': set(), 'interiorfields': set()} + for descr in all_descrs: + if hasattr(descr, 'get_extra_info'): + ei = descr.get_extra_info() + if ei is None: + continue + if ei._readonly_descrs_fields is None: + for key in descrs: + assert getattr(ei, '_readonly_descrs_' + key) is None + assert getattr(ei, '_write_descrs_' + key) is None + setattr(ei, 'bitstring_readonly_descrs_' + key, None) + setattr(ei, 'bitstring_write_descrs_' + key, None) + else: + effectinfos.append(ei) + for key in descrs: + descrs[key].update(getattr(ei, '_readonly_descrs_' + key)) + descrs[key].update(getattr(ei, '_write_descrs_' + key)) + else: + descr.ei_index = sys.maxint + log(" %d effectinfos:" % (len(effectinfos),)) + for key in sorted(descrs): + log(" %d descrs for %s" % (len(descrs[key]), key)) + + seen = set() + for key in descrs: + all_sets = [] + for descr in descrs[key]: + eisetr = [ei for ei in effectinfos + if descr in getattr(ei, '_readonly_descrs_' + key)] + eisetw = [ei for ei in effectinfos + if descr in getattr(ei, '_write_descrs_' + key)] + # these are the set of all ei such that this descr is in + # ei._readonly_descrs or ei._write_descrs + eisetr = frozenset(eisetr) + eisetw = frozenset(eisetw) + all_sets.append((descr, eisetr, eisetw)) + + # heuristic to reduce the total size of the bitstrings: start with + # numbering the descrs that are seen in many EffectInfos. If instead, + # by lack of chance, such a descr had a high number, then all these + # EffectInfos' bitstrings would need to store the same high number. + def size_of_both_sets((d, r, w)): + return len(r) + len(w) + all_sets.sort(key=size_of_both_sets, reverse=True) + + mapping = {} + for (descr, eisetr, eisetw) in all_sets: + assert descr.ei_index == sys.maxint # not modified yet + descr.ei_index = mapping.setdefault((eisetr, eisetw), len(mapping)) + + for ei in effectinfos: + bitstrr = [descr.ei_index + for descr in getattr(ei, '_readonly_descrs_' + key)] + bitstrw = [descr.ei_index + for descr in getattr(ei, '_write_descrs_' + key)] + assert sys.maxint not in bitstrr + assert sys.maxint not in bitstrw + bitstrr = bitstring.make_bitstring(bitstrr) + bitstrw = bitstring.make_bitstring(bitstrw) + setattr(ei, 'bitstring_readonly_descrs_' + key, bitstrr) + setattr(ei, 'bitstring_write_descrs_' + key, bitstrw) + seen.add(bitstrr) + seen.add(bitstrw) + + if seen: + mean_length = float(sum(len(x) for x in seen)) / len(seen) + max_length = max(len(x) for x in seen) + log("-> %d bitstrings, mean length %.1f, max length %d" % ( + len(seen), mean_length, max_length)) diff --git a/rpython/jit/codewriter/test/test_effectinfo.py b/rpython/jit/codewriter/test/test_effectinfo.py --- a/rpython/jit/codewriter/test/test_effectinfo.py +++ b/rpython/jit/codewriter/test/test_effectinfo.py @@ -1,11 +1,12 @@ -import pytest +import pytest, sys from rpython.jit.codewriter.effectinfo import (effectinfo_from_writeanalyze, - EffectInfo, VirtualizableAnalyzer) + EffectInfo, VirtualizableAnalyzer, compute_bitstrings) from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.rclass import OBJECT from rpython.translator.translator import TranslationContext, graphof +from rpython.tool.algo.bitstring import bitcheck class FakeCPU(object): @@ -29,37 +30,39 @@ S = lltype.GcStruct("S", ("a", lltype.Signed)) effects = frozenset([("readstruct", lltype.Ptr(S), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) - assert list(effectinfo.readonly_descrs_fields) == [('fielddescr', S, "a")] - assert not effectinfo.write_descrs_fields - assert not effectinfo.write_descrs_arrays + assert list(effectinfo._readonly_descrs_fields) == [('fielddescr', S, "a")] + assert not effectinfo._write_descrs_fields + assert not effectinfo._write_descrs_arrays + assert effectinfo.single_write_descr_array is None def test_include_write_field(): S = lltype.GcStruct("S", ("a", lltype.Signed)) effects = frozenset([("struct", lltype.Ptr(S), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) - assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] - assert not effectinfo.readonly_descrs_fields - assert not effectinfo.write_descrs_arrays + assert list(effectinfo._write_descrs_fields) == [('fielddescr', S, "a")] + assert not effectinfo._readonly_descrs_fields + assert not effectinfo._write_descrs_arrays def test_include_read_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("readarray", lltype.Ptr(A))]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) - assert not effectinfo.readonly_descrs_fields - assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] - assert not effectinfo.write_descrs_fields - assert not effectinfo.write_descrs_arrays + assert not effectinfo._readonly_descrs_fields + assert list(effectinfo._readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo._write_descrs_fields + assert not effectinfo._write_descrs_arrays def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) - assert not effectinfo.readonly_descrs_fields - assert not effectinfo.write_descrs_fields - assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo._readonly_descrs_fields + assert not effectinfo._write_descrs_fields + assert list(effectinfo._write_descrs_arrays) == [('arraydescr', A)] + assert effectinfo.single_write_descr_array == ('arraydescr', A) def test_dont_include_read_and_write_field(): @@ -67,9 +70,9 @@ effects = frozenset([("readstruct", lltype.Ptr(S), "a"), ("struct", lltype.Ptr(S), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) - assert not effectinfo.readonly_descrs_fields - assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] - assert not effectinfo.write_descrs_arrays + assert not effectinfo._readonly_descrs_fields + assert list(effectinfo._write_descrs_fields) == [('fielddescr', S, "a")] + assert not effectinfo._write_descrs_arrays def test_dont_include_read_and_write_array(): @@ -77,34 +80,34 @@ effects = frozenset([("readarray", lltype.Ptr(A)), ("array", lltype.Ptr(A))]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) - assert not effectinfo.readonly_descrs_fields - assert not effectinfo.readonly_descrs_arrays - assert not effectinfo.write_descrs_fields - assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo._readonly_descrs_fields + assert not effectinfo._readonly_descrs_arrays + assert not effectinfo._write_descrs_fields + assert list(effectinfo._write_descrs_arrays) == [('arraydescr', A)] def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) effectinfo = effectinfo_from_writeanalyze(effects, None) - assert not effectinfo.readonly_descrs_fields - assert not effectinfo.write_descrs_fields - assert not effectinfo.write_descrs_arrays + assert not effectinfo._readonly_descrs_fields + assert not effectinfo._write_descrs_fields + assert not effectinfo._write_descrs_arrays def test_filter_out_array_of_void(): effects = frozenset([("array", lltype.Ptr(lltype.GcArray(lltype.Void)))]) effectinfo = effectinfo_from_writeanalyze(effects, None) - assert not effectinfo.readonly_descrs_fields - assert not effectinfo.write_descrs_fields - assert not effectinfo.write_descrs_arrays + assert not effectinfo._readonly_descrs_fields + assert not effectinfo._write_descrs_fields + assert not effectinfo._write_descrs_arrays def test_filter_out_struct_with_void(): effects = frozenset([("struct", lltype.Ptr(lltype.GcStruct("x", ("a", lltype.Void))), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, None) - assert not effectinfo.readonly_descrs_fields - assert not effectinfo.write_descrs_fields - assert not effectinfo.write_descrs_arrays + assert not effectinfo._readonly_descrs_fields + assert not effectinfo._write_descrs_fields + assert not effectinfo._write_descrs_arrays class TestVirtualizableAnalyzer(object): @@ -138,3 +141,64 @@ res = self.analyze(entry, [int]) assert not res + + +def test_compute_bitstrings(): + class FDescr: + pass + class ADescr: + pass + class CDescr: + def __init__(self, ei): + self._ei = ei + def get_extra_info(self): + return self._ei + + f1descr = FDescr() + f2descr = FDescr() + f3descr = FDescr() + a1descr = ADescr() + a2descr = ADescr() + + ei1 = EffectInfo(None, None, None, None, None, None, + EffectInfo.EF_RANDOM_EFFECTS) + ei2 = EffectInfo([f1descr], [], [], [], [], []) + ei3 = EffectInfo([f1descr], [a1descr, a2descr], [], [f2descr], [], []) + + compute_bitstrings([CDescr(ei1), CDescr(ei2), CDescr(ei3), + f1descr, f2descr, f3descr, a1descr, a2descr]) + + assert f1descr.ei_index in (0, 1) + assert f2descr.ei_index == 1 - f1descr.ei_index + assert f3descr.ei_index == sys.maxint + assert a1descr.ei_index == 0 + assert a2descr.ei_index == 0 + + assert ei1.bitstring_readonly_descrs_fields is None + assert ei1.bitstring_readonly_descrs_arrays is None + assert ei1.bitstring_write_descrs_fields is None + + def expand(bitstr): + return [n for n in range(10) if bitcheck(bitstr, n)] + + assert expand(ei2.bitstring_readonly_descrs_fields) == [f1descr.ei_index] + assert expand(ei2.bitstring_write_descrs_fields) == [] + assert expand(ei2.bitstring_readonly_descrs_arrays) == [] + assert expand(ei2.bitstring_write_descrs_arrays) == [] + + assert expand(ei3.bitstring_readonly_descrs_fields) == [f1descr.ei_index] + assert expand(ei3.bitstring_write_descrs_fields) == [f2descr.ei_index] + assert expand(ei3.bitstring_readonly_descrs_arrays) == [0] #a1descr,a2descr + assert expand(ei3.bitstring_write_descrs_arrays) == [] + + for ei in [ei2, ei3]: + for fdescr in [f1descr, f2descr]: + assert ei.check_readonly_descr_field(fdescr) == ( + fdescr in ei._readonly_descrs_fields) + assert ei.check_write_descr_field(fdescr) == ( + fdescr in ei._write_descrs_fields) + for adescr in [a1descr, a2descr]: + assert ei.check_readonly_descr_array(adescr) == ( + adescr in ei._readonly_descrs_arrays) + assert ei.check_write_descr_array(adescr) == ( + adescr in ei._write_descrs_arrays) diff --git a/rpython/jit/metainterp/heapcache.py b/rpython/jit/metainterp/heapcache.py --- a/rpython/jit/metainterp/heapcache.py +++ b/rpython/jit/metainterp/heapcache.py @@ -209,7 +209,7 @@ isinstance(argboxes[3], ConstInt) and isinstance(argboxes[4], ConstInt) and isinstance(argboxes[5], ConstInt) and - len(descr.get_extra_info().write_descrs_arrays) == 1): + descr.get_extra_info().single_write_descr_array is not None): # ARRAYCOPY with constant starts and constant length doesn't escape # its argument # XXX really? @@ -299,9 +299,9 @@ isinstance(argboxes[3], ConstInt) and isinstance(argboxes[4], ConstInt) and isinstance(argboxes[5], ConstInt) and - len(effectinfo.write_descrs_arrays) == 1 + effectinfo.single_write_descr_array is not None ): - descr = effectinfo.write_descrs_arrays[0] + descr = effectinfo.single_write_descr_array cache = self.heap_array_cache.get(descr, None) srcstart = argboxes[3].getint() dststart = argboxes[4].getint() @@ -328,10 +328,10 @@ idx_cache._clear_cache_on_write(seen_allocation_of_target) return elif ( - len(effectinfo.write_descrs_arrays) == 1 + effectinfo.single_write_descr_array is not None ): # Fish the descr out of the effectinfo - cache = self.heap_array_cache.get(effectinfo.write_descrs_arrays[0], None) + cache = self.heap_array_cache.get(effectinfo.single_write_descr_array, None) if cache is not None: for idx, cache in cache.iteritems(): cache._clear_cache_on_write(seen_allocation_of_target) diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -1,3 +1,4 @@ +import sys from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rlib.objectmodel import we_are_translated, Symbolic @@ -87,9 +88,10 @@ class AbstractDescr(AbstractValue): - __slots__ = ('descr_index',) + __slots__ = ('descr_index', 'ei_index') llopaque = True descr_index = -1 + ei_index = sys.maxint def repr_of_descr(self): return '%r' % (self,) 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 @@ -432,28 +432,35 @@ optimize_GUARD_EXCEPTION = optimize_GUARD_NO_EXCEPTION def force_from_effectinfo(self, effectinfo): - # XXX we can get the wrong complexity here, if the lists - # XXX stored on effectinfo are large - for fielddescr in effectinfo.readonly_descrs_fields: - self.force_lazy_set(fielddescr) - for arraydescr in effectinfo.readonly_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - for fielddescr in effectinfo.write_descrs_fields: - if fielddescr.is_always_pure(): - continue - try: - del self.cached_dict_reads[fielddescr] - except KeyError: - pass - self.force_lazy_set(fielddescr, can_cache=False) - for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr, can_cache=False) - if arraydescr in self.corresponding_array_descrs: - dictdescr = self.corresponding_array_descrs.pop(arraydescr) + # Note: this version of the code handles effectively + # effectinfos that store arbitrarily many descrs, by looping + # on self.cached_{fields, arrayitems} and looking them up in + # the bitstrings stored in the effectinfo. + for fielddescr, cf in self.cached_fields.items(): + if effectinfo.check_readonly_descr_field(fielddescr): + cf.force_lazy_set(self, fielddescr) + if effectinfo.check_write_descr_field(fielddescr): + if fielddescr.is_always_pure(): + continue + try: + del self.cached_dict_reads[fielddescr] + except KeyError: + pass + cf.force_lazy_set(self, fielddescr, can_cache=False) + # + for arraydescr, submap in self.cached_arrayitems.items(): + if effectinfo.check_readonly_descr_array(arraydescr): + self.force_lazy_setarrayitem_submap(submap) + if effectinfo.check_write_descr_array(arraydescr): + self.force_lazy_setarrayitem_submap(submap, can_cache=False) + # + for arraydescr, dictdescr in self.corresponding_array_descrs.items(): + if effectinfo.check_write_descr_array(arraydescr): 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_set(vrefinfo.descr_forced) @@ -476,6 +483,10 @@ if indexb is None or indexb.contains(idx): cf.force_lazy_set(self, None, can_cache) + def force_lazy_setarrayitem_submap(self, submap, can_cache=True): + for cf in submap.itervalues(): + cf.force_lazy_set(self, None, can_cache) + def force_all_lazy_sets(self): items = self.cached_fields.items() if not we_are_translated(): diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -620,10 +620,10 @@ and length and ((dest_info and dest_info.is_virtual()) or length.getint() <= 8) and ((source_info and source_info.is_virtual()) or length.getint() <= 8) - and len(extrainfo.write_descrs_arrays) == 1): # <-sanity check + and extrainfo.single_write_descr_array is not None): #<-sanity check source_start = source_start_box.getint() dest_start = dest_start_box.getint() - arraydescr = extrainfo.write_descrs_arrays[0] + arraydescr = extrainfo.single_write_descr_array if arraydescr.is_array_of_structs(): return False # not supported right now diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py --- a/rpython/jit/metainterp/optimizeopt/test/test_util.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py @@ -10,7 +10,7 @@ from rpython.jit.metainterp.history import (TreeLoop, AbstractDescr, JitCellToken, TargetToken) from rpython.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists -from rpython.jit.codewriter.effectinfo import EffectInfo +from rpython.jit.codewriter.effectinfo import EffectInfo, compute_bitstrings from rpython.jit.metainterp.logger import LogOperations from rpython.jit.tool.oparser import OpParser, pure_parse, convert_loop_to_trace from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr @@ -530,6 +530,7 @@ metainterp_sd.virtualref_info = self.vrefinfo if hasattr(self, 'callinfocollection'): metainterp_sd.callinfocollection = self.callinfocollection + compute_bitstrings(self.cpu.fetch_all_descrs()) # compile_data.enable_opts = self.enable_opts state = optimize_trace(metainterp_sd, None, compile_data) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1838,7 +1838,11 @@ self.cpu.propagate_exception_descr = exc_descr # self.globaldata = MetaInterpGlobalData(self) + + def finish_setup_descrs(self): + from rpython.jit.codewriter import effectinfo self.all_descrs = self.cpu.setup_descrs() + effectinfo.compute_bitstrings(self.all_descrs) def _setup_once(self): """Runtime setup needed by the various components of the JIT.""" diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -132,6 +132,7 @@ metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt) stats.metainterp_sd = metainterp_sd metainterp_sd.finish_setup(cw) + metainterp_sd.finish_setup_descrs() [jitdriver_sd] = metainterp_sd.jitdrivers_sd metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd) diff --git a/rpython/jit/metainterp/test/test_heapcache.py b/rpython/jit/metainterp/test/test_heapcache.py --- a/rpython/jit/metainterp/test/test_heapcache.py +++ b/rpython/jit/metainterp/test/test_heapcache.py @@ -27,8 +27,12 @@ def __init__(self, extraeffect, oopspecindex, write_descrs_fields, write_descrs_arrays): self.extraeffect = extraeffect self.oopspecindex = oopspecindex - self.write_descrs_fields = write_descrs_fields - self.write_descrs_arrays = write_descrs_arrays + self._write_descrs_fields = write_descrs_fields + self._write_descrs_arrays = write_descrs_arrays + if len(write_descrs_arrays) == 1: + [self.single_write_descr_array] = write_descrs_arrays + else: + self.single_write_descr_array = None def has_random_effects(self): return self.extraeffect == self.EF_RANDOM_EFFECTS @@ -37,14 +41,14 @@ def __init__(self, extraeffect, oopspecindex=None, write_descrs_fields=[], write_descrs_arrays=[]): self.extraeffect = extraeffect self.oopspecindex = oopspecindex - self.write_descrs_fields = write_descrs_fields - self.write_descrs_arrays = write_descrs_arrays + self.__write_descrs_fields = write_descrs_fields + self.__write_descrs_arrays = write_descrs_arrays def get_extra_info(self): return FakeEffectinfo( self.extraeffect, self.oopspecindex, - write_descrs_fields=self.write_descrs_fields, - write_descrs_arrays=self.write_descrs_arrays, + write_descrs_fields=self.__write_descrs_fields, + write_descrs_arrays=self.__write_descrs_arrays, ) arraycopydescr1 = FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]) diff --git a/rpython/jit/metainterp/test/test_warmspot.py b/rpython/jit/metainterp/test/test_warmspot.py --- a/rpython/jit/metainterp/test/test_warmspot.py +++ b/rpython/jit/metainterp/test/test_warmspot.py @@ -624,7 +624,7 @@ pass def setup_descrs(self): - pass + return [] def get_latest_descr(self, deadframe): assert isinstance(deadframe, FakeDeadFrame) diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -277,6 +277,7 @@ for vinfo in vinfos: if vinfo is not None: vinfo.finish() + self.metainterp_sd.finish_setup_descrs() if self.cpu.translate_support_code: self.annhelper.finish() diff --git a/rpython/tool/algo/bitstring.py b/rpython/tool/algo/bitstring.py new file mode 100644 --- /dev/null +++ b/rpython/tool/algo/bitstring.py @@ -0,0 +1,23 @@ + + +def make_bitstring(lst): + "NOT_RPYTHON" + if not lst: + return '' + num_bits = max(lst) + 1 + num_bytes = (num_bits + 7) // 8 + entries = [0] * num_bytes + for x in lst: + assert x >= 0 + entries[x >> 3] |= 1 << (x & 7) + return ''.join(map(chr, entries)) + +def bitcheck(bitstring, n): + assert n >= 0 + byte_number = n >> 3 + if byte_number >= len(bitstring): + return False + return (ord(bitstring[byte_number]) & (1 << (n & 7))) != 0 + +def num_bits(bitstring): + return len(bitstring) << 3 diff --git a/rpython/tool/algo/test/test_bitstring.py b/rpython/tool/algo/test/test_bitstring.py new file mode 100644 --- /dev/null +++ b/rpython/tool/algo/test/test_bitstring.py @@ -0,0 +1,25 @@ +from rpython.tool.algo.bitstring import * +from hypothesis import given, strategies + +def test_make(): + assert make_bitstring([]) == '' + assert make_bitstring([0]) == '\x01' + assert make_bitstring([7]) == '\x80' + assert make_bitstring([8]) == '\x00\x01' + assert make_bitstring([2, 4, 20]) == '\x14\x00\x10' + +def test_bitcheck(): + assert bitcheck('\x01', 0) is True + assert bitcheck('\x01', 1) is False + assert bitcheck('\x01', 10) is False + assert [n for n in range(32) if bitcheck('\x14\x00\x10', n)] == [2, 4, 20] + +@given(strategies.lists(strategies.integers(min_value=0, max_value=299))) +def test_random(lst): + bitstring = make_bitstring(lst) + assert set([n for n in range(300) if bitcheck(bitstring, n)]) == set(lst) + +def test_num_bits(): + assert num_bits('') == 0 + assert num_bits('a') == 8 + assert num_bits('bcd') == 24 diff --git a/rpython/translator/backendopt/test/test_writeanalyze.py b/rpython/translator/backendopt/test/test_writeanalyze.py --- a/rpython/translator/backendopt/test/test_writeanalyze.py +++ b/rpython/translator/backendopt/test/test_writeanalyze.py @@ -1,3 +1,4 @@ +import py from rpython.rtyper.lltypesystem import lltype from rpython.translator.translator import TranslationContext, graphof from rpython.translator.backendopt.writeanalyze import WriteAnalyzer, top_set @@ -314,6 +315,7 @@ assert T1 == T2 def test_cutoff(self): + py.test.skip("cutoff: disabled") from rpython.rlib.unroll import unrolling_iterable cutoff = 20 attrs = unrolling_iterable(["s%s" % i for i in range(cutoff + 5)]) 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 @@ -4,10 +4,14 @@ top_set = object() empty_set = frozenset() -CUTOFF = 3000 +# CUTOFF is disabled, as it gave a strangely not-working-any-more effect +# if the size of the result grows past that bound. The main user was +# optimizeopt/heap.py (force_from_effectinfo), which has been rewritten +# to be happy with any size now. +#CUTOFF = 3000 class WriteAnalyzer(graphanalyze.GraphAnalyzer): - cutoff = CUTOFF + #cutoff = CUTOFF def bottom_result(self): return empty_set @@ -25,8 +29,8 @@ if other is top_set: return top_set result.update(other) - if len(result) > self.cutoff: - return top_set + #if len(result) > self.cutoff: + # return top_set return result def finalize_builder(self, result): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit