[pypy-commit] pypy value-profiling: proper integration between a field being known an instance of W_IntObject or

cfbolz pypy.commits at gmail.com
Tue Jan 19 14:06:04 EST 2016


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: value-profiling
Changeset: r81863:703d8c63a5f6
Date: 2016-01-16 07:20 +0100
http://bitbucket.org/pypy/pypy/changeset/703d8c63a5f6/

Log:	proper integration between a field being known an instance of
	W_IntObject or W_FloatObject

diff --git a/pypy/interpreter/valueprof.py b/pypy/interpreter/valueprof.py
--- a/pypy/interpreter/valueprof.py
+++ b/pypy/interpreter/valueprof.py
@@ -28,6 +28,22 @@
     def get_int_val(self, w_obj):
         raise NotImplementedError("abstract base")
 
+    def write_necessary(self, w_value):
+        status = self._vprof_status
+        if status == SEEN_TOO_MUCH:
+            return True
+        # we must have seen something already, because it only makes sense to
+        # call write_necessary if there is already a value there
+        assert not status == SEEN_NOTHING
+        if status == SEEN_CONSTANT_INT:
+            return (self.is_int(w_value) and
+                self.read_constant_int() != self.get_int_val(w_value))
+        elif status == SEEN_CONSTANT_OBJ:
+            prev_obj = self.try_read_constant_obj()
+            return prev_obj is not w_value
+        return True
+
+
     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
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
@@ -34,6 +34,7 @@
 
     def read(self, obj, selector):
         from pypy.objspace.std.intobject import W_IntObject
+        from pypy.objspace.std.floatobject import W_FloatObject
         attr = self.find_map_attr(selector)
         if attr is None:
             return self.terminator._read_terminator(obj, selector)
@@ -54,21 +55,30 @@
         else:
             result = obj._mapdict_read_storage(attr.storageindex)
             if jit.we_are_jitted() and attr.class_is_known():
-                jit.record_exact_class(result, attr.read_constant_cls())
+                cls = attr.read_constant_cls()
+                if cls is W_IntObject:
+                    # this means that the class stored in the storage is an
+                    # IntMutableCell
+                    return W_IntObject(result.intvalue)
+                if cls is W_FloatObject:
+                    # ditto
+                    return W_FloatObject(result.floatvalue)
+                jit.record_exact_class(result, cls)
             return attr._read_cell(result)
 
     def write(self, obj, selector, w_value):
         attr = self.find_map_attr(selector)
         if attr is None:
             return self.terminator._write_terminator(obj, selector, w_value)
-        write_unnecessary = attr.see_write(w_value)
+        # if the write is not necessary, 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
+        write_necessary = attr.write_necessary(w_value)
+        if not write_necessary:
+            return True
         if not attr.ever_mutated:
             attr.ever_mutated = True
-        # if write_unnecessary, 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 write_unnecessary:
-            return True
+        self.see_write(w_value)
         cell = obj._mapdict_read_storage(attr.storageindex)
         w_value = attr._write_cell(cell, w_value)
         if w_value is not None:
@@ -173,7 +183,6 @@
     def add_attr(self, obj, selector, w_value):
         # grumble, jit needs this
         attr = self._get_new_attr(selector[0], selector[1])
-        w_value = attr._write_cell(None, w_value)
         oldattr = obj._get_mapdict_map()
         if not jit.we_are_jitted():
             size_est = (oldattr._size_estimate + attr.size_estimate()
@@ -190,10 +199,11 @@
         # the order is important here: first change the map, then the storage,
         # for the benefit of the special subclasses
         obj._set_mapdict_map(attr)
+        # important to see the write of the original value, not the cell
+        attr.see_write(w_value)
         w_value = attr._write_cell(None, w_value)
         assert w_value is not None
         obj._mapdict_write_storage(attr.storageindex, w_value)
-        attr.see_write(w_value)
 
     def materialize_r_dict(self, space, obj, dict_w):
         raise NotImplementedError("abstract base class")
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
@@ -512,6 +512,29 @@
     assert obj.getdictvalue(space, "a") == a
     assert seen == [(a, Value), (a, Value)]
 
+def test_value_profiling_known_cls_mutcells(monkeypatch):
+    from pypy.objspace.std.intobject import W_IntObject
+    from pypy.objspace.std.floatobject import W_FloatObject
+    for cls, mutcls, val, attrname in [
+            (W_IntObject, IntMutableCell, 0, "intval"),
+            (W_FloatObject, FloatMutableCell, 0.0, "floatval")]:
+        a = cls(val)
+        a1 = cls(val + 1)
+        cls = Class()
+        obj = cls.instantiate()
+        obj.setdictvalue(space, "a", a1)
+        obj = cls.instantiate()
+        obj.setdictvalue(space, "a", a1)
+        obj.setdictvalue(space, "a", a)
+
+        def f(obj, cls):
+            assert False, "unreachable"
+        monkeypatch.setattr(jit, "we_are_jitted", lambda : True)
+        monkeypatch.setattr(jit, "record_exact_class", f)
+
+        assert getattr(obj.getdictvalue(space, "a"), attrname) == val
+        assert getattr(obj.getdictvalue(space, "a"), attrname) == val
+
 
 def test_value_profiling_elide_write(monkeypatch):
     monkeypatch.setattr(jit, "we_are_jitted", lambda : True)


More information about the pypy-commit mailing list