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