Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: value-profiling Changeset: r79952:70119492d559 Date: 2015-10-03 15:36 +0200 http://bitbucket.org/pypy/pypy/changeset/70119492d559/
Log: not necessary to do a write when overwriting a known constant attribute diff --git a/pypy/interpreter/test/test_valueprof.py b/pypy/interpreter/test/test_valueprof.py --- a/pypy/interpreter/test/test_valueprof.py +++ b/pypy/interpreter/test/test_valueprof.py @@ -124,3 +124,37 @@ v.see_write(OtherValue()) assert v._vprof_status == SEEN_TOO_MUCH +def test_write_not_necessary_int(): + v = ValueProf() + assert v._vprof_status == SEEN_NOTHING + res = v.see_write(ValueInt(1)) + assert not res + res = v.see_write(ValueInt(1)) + assert res + res = v.see_write(ValueInt(1)) + assert res + res = v.see_write(ValueInt(2)) + assert not res + res = v.see_write(ValueInt(2)) + assert not res + res = v.see_write(Value()) + assert not res + +def test_write_not_necessary_obj(): + v = ValueProf() + assert v._vprof_status == SEEN_NOTHING + val = Value() + res = v.see_write(val) + assert not res + res = v.see_write(val) + assert res + res = v.see_write(val) + assert res + res = v.see_write(ValueInt(1)) + assert not res + res = v.see_write(ValueInt(2)) + assert not res + res = v.see_write(ValueInt(2)) + assert not res + res = v.see_write(Value()) + assert not res diff --git a/pypy/interpreter/valueprof.py b/pypy/interpreter/valueprof.py --- a/pypy/interpreter/valueprof.py +++ b/pypy/interpreter/valueprof.py @@ -29,13 +29,17 @@ raise NotImplementedError("abstract base") def see_write(self, w_value): + """ inform the value profiler of a write. returns False, unless the + value is known to be a constant, and w_value that constant (in that + case the caller can elide the write to the actual object, if that + object already stores a value). """ status = self._vprof_status if status == SEEN_TOO_MUCH: - return + return False if w_value is None: self._vprof_status = SEEN_TOO_MUCH - return + return False if status == SEEN_NOTHING: if self.is_int(w_value): @@ -55,6 +59,8 @@ if self.read_constant_int() != self.get_int_val(w_value): self._vprof_status = SEEN_CONSTANT_CLASS self._vprof_const_cls = w_value.__class__ + else: + return True else: self._vprof_status = SEEN_TOO_MUCH elif status == SEEN_CONSTANT_OBJ: @@ -66,10 +72,13 @@ self._vprof_status = SEEN_CONSTANT_CLASS else: self._vprof_status = SEEN_TOO_MUCH + else: + return True elif status == SEEN_CONSTANT_CLASS: cls = self.read_constant_cls() if cls is not w_value.__class__: self._vprof_status = SEEN_TOO_MUCH + return False def can_fold_read_int(self): return self._vprof_status == SEEN_CONSTANT_INT diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -63,10 +63,14 @@ attr = self.find_map_attr(selector) if attr is None: return self.terminator._write_terminator(obj, selector, w_value) - attr.see_write(w_value) + write_unnecessary = attr.see_write(w_value) if not attr.ever_mutated: attr.ever_mutated = True - obj._mapdict_write_storage(attr.storageindex, w_value) + # if this path is taken, the storage is already filled from the time we + # did the map transition. Therefore, if the value profiler says so, we + # can not do the write + if not write_unnecessary: + obj._mapdict_write_storage(attr.storageindex, w_value) return True def delete(self, obj, selector): diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -397,6 +397,25 @@ assert obj.getdictvalue(space, "a") == a assert seen == [(a, Value), (a, Value)] + +def test_value_profiling_elide_write(monkeypatch): + monkeypatch.setattr(jit, "we_are_jitted", lambda : True) + class Value(object): + pass + a = Value() + cls = Class() + obj = cls.instantiate() + a1 = Value() + obj.setdictvalue(space, "a", a1) + obj = cls.instantiate() + obj.setdictvalue(space, "a", a1) + storage = obj.storage + # replace storage, both reads and writes of a1 should still work + obj.storage = None + assert obj.getdictvalue(space, "a") is a1 + obj.setdictvalue(space, "a", a1) + assert obj.getdictvalue(space, "a") is a1 + # ___________________________________________________________ # dict tests _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit