[pypy-commit] pypy default: Don't invalidate already-compiled pieces of JIT code when we only

arigo noreply at buildbot.pypy.org
Wed Jun 25 18:36:40 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r72226:cc99ff68804a
Date: 2014-06-25 18:36 +0200
http://bitbucket.org/pypy/pypy/changeset/cc99ff68804a/

Log:	Don't invalidate already-compiled pieces of JIT code when we only
	*add* new global variables, but only if we *change* old globals.

diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -16,7 +16,7 @@
 
 
 class ModuleCell(W_Root):
-    def __init__(self, w_value=None):
+    def __init__(self, w_value):
         self.w_value = w_value
 
     def __repr__(self):
@@ -49,17 +49,24 @@
         return self.erase({})
 
     def mutated(self):
+        # A mutation means changing an existing key to point to a new value.
+        # A value is either a regular wrapped object, or a ModuleCell if we
+        # detect mutations.  It means that each existing key can only trigger
+        # a mutation at most once.
         self.version = VersionTag()
 
-    def getdictvalue_no_unwrapping(self, w_dict, key):
+    def dictvalue_no_unwrapping(self, w_dict, key):
         # NB: it's important to promote self here, so that self.version is a
         # no-op due to the quasi-immutable field
         self = jit.promote(self)
-        return self._getdictvalue_no_unwrapping_pure(self.version, w_dict, key)
+        return self._dictvalue_no_unwrapping_pure(self.version, w_dict, key)
 
     @jit.elidable_promote('0,1,2')
-    def _getdictvalue_no_unwrapping_pure(self, version, w_dict, key):
-        return self.unerase(w_dict.dstorage).get(key, None)
+    def _dictvalue_no_unwrapping_pure(self, version, w_dict, key):
+        # may raise KeyError.  If it does, then the JIT is prevented from
+        # considering this function as elidable.  This is what lets us add
+        # new keys to the dictionary without changing the version.
+        return self.unerase(w_dict.dstorage)[key]
 
     def setitem(self, w_dict, w_key, w_value):
         space = self.space
@@ -70,17 +77,20 @@
             w_dict.setitem(w_key, w_value)
 
     def setitem_str(self, w_dict, key, w_value):
-        cell = self.getdictvalue_no_unwrapping(w_dict, key)
-        if isinstance(cell, ModuleCell):
-            cell.w_value = w_value
-            return
-        if cell is not None:
+        try:
+            cell = self.dictvalue_no_unwrapping(w_dict, key)
+        except KeyError:
+            pass
+        else:
+            if isinstance(cell, ModuleCell):
+                cell.w_value = w_value
+                return
             # If the new value and the current value are the same, don't
             # create a level of indirection, or mutate the version.
             if self.space.is_w(w_value, cell):
                 return
             w_value = ModuleCell(w_value)
-        self.mutated()
+            self.mutated()
         self.unerase(w_dict.dstorage)[key] = w_value
 
     def setdefault(self, w_dict, w_key, w_default):
@@ -130,7 +140,10 @@
             return w_dict.getitem(w_key)
 
     def getitem_str(self, w_dict, key):
-        cell = self.getdictvalue_no_unwrapping(w_dict, key)
+        try:
+            cell = self.dictvalue_no_unwrapping(w_dict, key)
+        except KeyError:
+            return None
         return unwrap_cell(cell)
 
     def w_keys(self, w_dict):
diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py
--- a/pypy/objspace/std/test/test_celldict.py
+++ b/pypy/objspace/std/test/test_celldict.py
@@ -21,27 +21,27 @@
         w_key = self.FakeString(key)
         d.setitem(w_key, 1)
         v2 = strategy.version
-        assert v1 is not v2
+        assert v1 is v2          # doesn't change when adding new keys
         assert d.getitem(w_key) == 1
-        assert d.strategy.getdictvalue_no_unwrapping(d, key) == 1
+        assert d.strategy.dictvalue_no_unwrapping(d, key) == 1
 
         d.setitem(w_key, 2)
         v3 = strategy.version
         assert v2 is not v3
         assert d.getitem(w_key) == 2
-        assert d.strategy.getdictvalue_no_unwrapping(d, key).w_value == 2
+        assert d.strategy.dictvalue_no_unwrapping(d, key).w_value == 2
 
         d.setitem(w_key, 3)
         v4 = strategy.version
         assert v3 is v4
         assert d.getitem(w_key) == 3
-        assert d.strategy.getdictvalue_no_unwrapping(d, key).w_value == 3
+        assert d.strategy.dictvalue_no_unwrapping(d, key).w_value == 3
 
         d.delitem(w_key)
         v5 = strategy.version
         assert v5 is not v4
         assert d.getitem(w_key) is None
-        assert d.strategy.getdictvalue_no_unwrapping(d, key) is None
+        py.test.raises(KeyError, d.strategy.dictvalue_no_unwrapping, d, key)
 
     def test_same_key_set_twice(self):
         strategy = ModuleDictStrategy(space)
@@ -52,7 +52,7 @@
         x = object()
         d.setitem("a", x)
         v2 = strategy.version
-        assert v1 is not v2
+        assert v1 is v2
         d.setitem("a", x)
         v3 = strategy.version
         assert v2 is v3


More information about the pypy-commit mailing list