Author: Carl Friedrich Bolz <[email protected]>
Branch: global-cell-cache
Changeset: r75731:b9b462fe9ada
Date: 2015-02-06 01:07 +0100
http://bitbucket.org/pypy/pypy/changeset/b9b462fe9ada/

Log:    cache global cells when interpreting

        makes non-jitted richards 7% faster, but needs tests

diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -123,6 +123,9 @@
         if self.space.config.objspace.std.withmapdict:
             from pypy.objspace.std.mapdict import init_mapdict_cache
             init_mapdict_cache(self)
+        if self.space.config.objspace.std.withcelldict:
+            from pypy.objspace.std.celldict import init_celldict_cache
+            init_celldict_cache(self)
 
     def _cleanup_(self):
         if (self.magic == cpython_magic and
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -872,8 +872,12 @@
         self.space.delattr(w_obj, w_attributename)
 
     def STORE_GLOBAL(self, nameindex, next_instr):
+        w_newvalue = self.popvalue()
+        if self.space.config.objspace.std.withcelldict and jit.we_are_jitted():
+            from pypy.objspace.std.celldict import STORE_GLOBAL_celldict
+            STORE_GLOBAL_celldict(self.space, self, nameindex, w_newvalue)
+            return
         varname = self.getname_u(nameindex)
-        w_newvalue = self.popvalue()
         self.space.setitem_str(self.w_globals, varname, w_newvalue)
 
     def DELETE_GLOBAL(self, nameindex, next_instr):
@@ -905,7 +909,12 @@
     _load_global_failed._dont_inline_ = True
 
     def LOAD_GLOBAL(self, nameindex, next_instr):
-        self.pushvalue(self._load_global(self.getname_u(nameindex)))
+        if self.space.config.objspace.std.withcelldict and jit.we_are_jitted():
+            from pypy.objspace.std.celldict import LOAD_GLOBAL_celldict
+            w_result = LOAD_GLOBAL_celldict(self.space, self, nameindex)
+        else:
+            w_result = self._load_global(self.getname_u(nameindex))
+        self.pushvalue(w_result)
     LOAD_GLOBAL._always_inline_ = True
 
     def DELETE_FAST(self, varindex, next_instr):
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
@@ -172,3 +172,79 @@
 
 
 create_iterator_classes(ModuleDictStrategy)
+
+class CelldictCache(object):
+    def __init__(self):
+        self.version = None
+        self.value = None
+        self.builtin_version = None
+        self.builtin_value = None
+INVALID_CACHE_ENTRY = CelldictCache()
+
+def init_celldict_cache(pycode):
+    num_entries = len(pycode.co_names_w)
+    pycode._celldict_cache = [INVALID_CACHE_ENTRY] * num_entries
+
+def _finditem_with_cache(space, frame, nameindex, pycode, w_dict, 
entry_version, entry_value, builtin=False):
+    from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+    if (isinstance(w_dict, W_DictMultiObject) and
+            not w_dict.user_overridden_class):
+        strategy = w_dict.strategy
+        if isinstance(strategy, ModuleDictStrategy):
+            # it's enough to check that the version is the same
+            # if the version is the same, that means that both the same globals
+            # object is used, and that that object did not change
+            version = strategy.version
+            if version is entry_version:
+                result = entry_value
+            else:
+                # need to fill the cache
+                result = strategy.getitem_str(
+                        w_dict, frame.getname_u(nameindex))
+                entry = pycode._celldict_cache[nameindex]
+                if entry is INVALID_CACHE_ENTRY:
+                    entry = pycode._celldict_cache[nameindex] = CelldictCache()
+                if builtin:
+                    entry.builtin_version = version
+                    entry.builtin_value = result
+                else:
+                    entry.version = version
+                    entry.value = result
+            return result
+    return space.finditem_str(w_dict, frame.getname_u(nameindex))
+
+def LOAD_GLOBAL_celldict(space, frame, nameindex):
+    from pypy.interpreter.mixedmodule import MixedModule
+    pycode = frame.getcode()
+    w_globals = frame.w_globals
+    entry = pycode._celldict_cache[nameindex]
+    cell = _finditem_with_cache(space, frame, nameindex, pycode, w_globals,
+                                  entry.version, entry.value)
+    if cell is None:
+        assert not space.config.objspace.honor__builtins__
+        # not in the globals, now look in the built-ins
+        builtin = frame.get_builtin()
+        assert isinstance(builtin, MixedModule)
+        cell = _finditem_with_cache(space, frame, nameindex, pycode, 
builtin.w_dict,
+                                      entry.builtin_version, 
entry.builtin_value,
+                                      builtin=True)
+        if cell is None and builtin.lazy:
+            w_result = builtin._load_lazily(space, frame.getname_u(nameindex))
+        else:
+            w_result = unwrap_cell(space, cell)
+        if w_result is None:
+            frame._load_global_failed(frame.getname_u(nameindex))
+    else:
+        w_result = unwrap_cell(space, cell)
+    return w_result
+
+def STORE_GLOBAL_celldict(space, frame, nameindex, w_value):
+    pycode = frame.getcode()
+    w_globals = frame.w_globals
+    entry = pycode._celldict_cache[nameindex]
+    cell = _finditem_with_cache(space, frame, nameindex, pycode, w_globals,
+                                entry.version, entry.value)
+    w_newvalue = write_cell(space, cell, w_value)
+    if w_newvalue is None:
+        return
+    space.setitem_str(w_globals, frame.getname_u(nameindex), w_value)
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -45,6 +45,7 @@
 
 def write_cell(space, w_cell, w_value):
     from pypy.objspace.std.intobject import W_IntObject
+    assert w_value is not None
     if w_cell is None:
         # attribute does not exist at all, write it without a cell first
         return w_value
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to