Author: Carl Friedrich Bolz <[email protected]>
Branch: typed-cells
Changeset: r75497:bb52cf0f8734
Date: 2015-01-23 00:47 +0100
http://bitbucket.org/pypy/pypy/changeset/bb52cf0f8734/

Log:    keep a flag on PlainAttributes that indicates whether we need to
        check for a MutableCell

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
@@ -41,8 +41,8 @@
             result = self._pure_mapdict_read_storage(obj, attr.storageindex)
             assert not isinstance(result, MutableCell)
         else:
-            result = unwrap_cell(
-                attr.space, obj._mapdict_read_storage(attr.storageindex))
+            result = attr._read_cell(
+                obj._mapdict_read_storage(attr.storageindex))
         return result
 
     @jit.elidable
@@ -58,7 +58,7 @@
         # introduce cells only on the second write, to make immutability for
         # int fields still work
         cell = obj._mapdict_read_storage(attr.storageindex)
-        w_value = attr._write_cell(attr.space, cell, w_value)
+        w_value = attr._write_cell(cell, w_value)
         if w_value is not None:
             obj._mapdict_write_storage(attr.storageindex, w_value)
         return True
@@ -283,7 +283,8 @@
         return Terminator.set_terminator(self, obj, terminator)
 
 class PlainAttribute(AbstractAttribute):
-    _immutable_fields_ = ['selector', 'storageindex', 'back', 'ever_mutated?']
+    _immutable_fields_ = ['selector', 'storageindex', 'back',
+                          'ever_mutated?', 'can_contain_mutable_cell?']
 
     def __init__(self, selector, back):
         AbstractAttribute.__init__(self, back.space, back.terminator)
@@ -292,6 +293,16 @@
         self.back = back
         self._size_estimate = self.length() * NUM_DIGITS_POW2
         self.ever_mutated = False
+        # this flag means: at some point there was an instance that used a
+        # derivative of this map that had a MutableCell stored into the
+        # corresponding field.
+        # if the flag is False, we don't need to unbox the attribute.
+        self.can_contain_mutable_cell = False
+
+    def _read_cell(self, w_cell):
+        if not self.can_contain_mutable_cell:
+            return w_cell
+        return unwrap_cell(self.space, w_cell)
 
     def _write_cell(self, w_cell, w_value):
         from pypy.objspace.std.intobject import W_IntObject
@@ -300,6 +311,8 @@
             w_cell.intvalue = w_value.intval
             return None
         if type(w_value) is W_IntObject:
+            if not self.can_contain_mutable_cell:
+                self.can_contain_mutable_cell = True
             return IntMutableCell(w_value.intval)
         return w_value
 
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
@@ -169,11 +169,28 @@
     assert mutcell1.intvalue == 6
 
     obj.setdictvalue(space, "a", W_IntObject(7))
-    assert obj.getdictvalue(space, "a") == 7 # because of the FakeSpace :-(
+    assert obj.getdictvalue(space, "a") == 7 # FakeSpace again
     mutcell2 = obj._mapdict_read_storage(0)
     assert mutcell2.intvalue == 7
     assert mutcell2 is mutcell1
 
+
+def test_mutcell_unwrap_only_if_needed():
+    from pypy.objspace.std.intobject import W_IntObject
+    cls = Class()
+    obj = cls.instantiate()
+    obj.setdictvalue(space, "a", "foo")
+    assert not obj._get_mapdict_map().can_contain_mutable_cell
+    obj.setdictvalue(space, "a", W_IntObject(6))
+    obj.setdictvalue(space, "a", W_IntObject(6))
+    assert obj._get_mapdict_map().can_contain_mutable_cell
+
+    obj._get_mapdict_map().can_contain_mutable_cell = False
+    mutcell = IntMutableCell(1)
+    obj._mapdict_write_storage(0, mutcell)
+    assert obj.getdictvalue(space, "a") is mutcell # not unwrapped
+
+
 def test_delete():
     for i, dattr in enumerate(["a", "b", "c"]):
         c = Class()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to