Author: Alex Gaynor <alex.gay...@gmail.com>
Branch: detect-immutable-fields
Changeset: r68870:7244e2ea0430
Date: 2014-01-23 13:32 -0600
http://bitbucket.org/pypy/pypy/changeset/7244e2ea0430/

Log:    Initial re-organization to allow detecting immutable fields in
        mapdicts

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
@@ -19,7 +19,7 @@
 # we want to propagate knowledge that the result cannot be negative
 
 class AbstractAttribute(object):
-    _immutable_fields_ = ['terminator']
+    _immutable_fields_ = ['terminator', 'ever_mutated?']
     cache_attrs = None
     _size_estimate = 0
 
@@ -27,18 +27,21 @@
         self.space = space
         assert isinstance(terminator, Terminator)
         self.terminator = terminator
+        self.ever_mutated = False
 
     def read(self, obj, selector):
         index = self.index(selector)
-        if index < 0:
+        if index is None:
             return self.terminator._read_terminator(obj, selector)
-        return obj._mapdict_read_storage(index)
+        return obj._mapdict_read_storage(index.position, pure=not 
self.ever_mutated)
 
     def write(self, obj, selector, w_value):
         index = self.index(selector)
-        if index < 0:
+        if index is None:
             return self.terminator._write_terminator(obj, selector, w_value)
-        obj._mapdict_write_storage(index, w_value)
+        obj._mapdict_write_storage(index.position, w_value)
+        if not index.ever_mutated:
+            index.ever_mutated = True
         return True
 
     def delete(self, obj, selector):
@@ -97,9 +100,9 @@
     def _index(self, selector):
         while isinstance(self, PlainAttribute):
             if selector == self.selector:
-                return self.position
+                return self
             self = self.back
-        return -1
+        return None
 
     def copy(self, obj):
         raise NotImplementedError("abstract base class")
@@ -330,7 +333,7 @@
         self.attrs = [None] * SIZE
         self._empty_selector = (None, INVALID)
         self.selectors = [self._empty_selector] * SIZE
-        self.indices = [0] * SIZE
+        self.indices = [None] * SIZE
         if space.config.objspace.std.withmethodcachecounter:
             self.hits = {}
             self.misses = {}
@@ -460,9 +463,10 @@
         self.map = map
         self.storage = make_sure_not_resized([None] * map.size_estimate())
 
-    def _mapdict_read_storage(self, index):
+    def _mapdict_read_storage(self, index, pure=False):
         assert index >= 0
         return self.storage[index]
+
     def _mapdict_write_storage(self, index, value):
         self.storage[index] = value
     def _mapdict_storage_length(self):
@@ -519,7 +523,6 @@
     rangenmin1 = unroll.unrolling_iterable(range(nmin1))
     class subcls(BaseMapdictObject, supercls):
         def _init_empty(self, map):
-            from rpython.rlib.debug import make_sure_not_resized
             for i in rangen:
                 setattr(self, "_value%s" % i, erase_item(None))
             self.map = map
@@ -531,7 +534,7 @@
             erased = getattr(self, "_value%s" % nmin1)
             return unerase_list(erased)
 
-        def _mapdict_read_storage(self, index):
+        def _mapdict_read_storage(self, index, pure=False):
             assert index >= 0
             if index < nmin1:
                 for i in rangenmin1:
@@ -879,11 +882,11 @@
             #
             if selector[1] != INVALID:
                 index = map.index(selector)
-                if index >= 0:
+                if index is not None:
                     # Note that if map.terminator is a DevolvedDictTerminator,
                     # map.index() will always return -1 if selector[1]==DICT.
-                    _fill_cache(pycode, nameindex, map, version_tag, index)
-                    return w_obj._mapdict_read_storage(index)
+                    _fill_cache(pycode, nameindex, map, version_tag, 
index.position)
+                    return w_obj._mapdict_read_storage(index.position)
     if space.config.objspace.std.withmethodcachecounter:
         INVALID_CACHE_ENTRY.failure_counter += 1
     return space.getattr(w_obj, w_name)
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
@@ -64,7 +64,7 @@
     current = Terminator(space, "cls")
     for i in range(20000):
         current = PlainAttribute((str(i), DICT), current)
-    assert current.index(("0", DICT)) == 0
+    assert current.index(("0", DICT)).position == 0
 
 
 def test_search():
@@ -231,7 +231,6 @@
     obj = cls.instantiate()
     a = 0
     b = 1
-    c = 2
     obj.setslotvalue(a, 50)
     obj.setslotvalue(b, 60)
     assert obj.getslotvalue(a) == 50
@@ -648,7 +647,7 @@
     def test_delete_slot(self):
         class A(object):
             __slots__ = ['x']
-        
+
         a = A()
         a.x = 42
         del a.x
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to