[pypy-svn] r79018 - in pypy/branch/mapdict-without-jit/pypy/objspace/std: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Thu Nov 11 23:52:10 CET 2010
Author: cfbolz
Date: Thu Nov 11 23:52:08 2010
New Revision: 79018
Modified:
pypy/branch/mapdict-without-jit/pypy/objspace/std/callmethod.py
pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py
pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py
Log:
Also use the local mapdict cache in the CALLMETHOD bytecode. I think it all can
be generalized a bit more, but I first want to see if this helps.
Modified: pypy/branch/mapdict-without-jit/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/objspace/std/callmethod.py (original)
+++ pypy/branch/mapdict-without-jit/pypy/objspace/std/callmethod.py Thu Nov 11 23:52:08 2010
@@ -13,6 +13,9 @@
from pypy.interpreter import function
from pypy.objspace.descroperation import object_getattribute
from pypy.rlib import jit, rstack # for resume points
+from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \
+ LOOKUP_METHOD_mapdict_fill_cache_method
+
# This module exports two extra methods for StdObjSpaceFrame implementing
# the LOOKUP_METHOD and CALL_METHOD opcodes in an efficient way, as well
@@ -30,6 +33,13 @@
#
space = f.space
w_obj = f.popvalue()
+
+ if space.config.objspace.std.withmapdict:
+ # mapdict has an extra-fast version of this function
+ from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict
+ if LOOKUP_METHOD_mapdict(f, nameindex, w_obj):
+ return
+
w_name = f.getname_w(nameindex)
w_value = None
@@ -50,6 +60,10 @@
# nothing in the instance
f.pushvalue(w_descr)
f.pushvalue(w_obj)
+ if space.config.objspace.std.withmapdict:
+ # let mapdict cache stuff
+ LOOKUP_METHOD_mapdict_fill_cache_method(
+ f.getcode(), nameindex, w_obj, w_type, w_descr)
return
if w_value is None:
w_value = space.getattr(w_obj, w_name)
Modified: pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py (original)
+++ pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py Thu Nov 11 23:52:08 2010
@@ -659,30 +659,54 @@
map = None
version_tag = None
index = 0
+ w_method = None # for callmethod
success_counter = 0
failure_counter = 0
+ def is_valid_for_obj(self, w_obj):
+ map = w_obj._get_mapdict_map()
+ return self.is_valid_for_map(map)
+
+ def is_valid_for_map(self, map):
+ if map is self.map:
+ version_tag = map.terminator.w_cls.version_tag()
+ if version_tag is self.version_tag:
+ # everything matches, it's incredibly fast
+ if map.space.config.objspace.std.withmethodcachecounter:
+ self.success_counter += 1
+ return True
+ return False
+
INVALID_CACHE_ENTRY = CacheEntry()
INVALID_CACHE_ENTRY.map = objectmodel.instantiate(AbstractAttribute)
# different from any real map ^^^
INVALID_CACHE_ENTRY.map.terminator = None
+
def init_mapdict_cache(pycode):
num_entries = len(pycode.co_names_w)
pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries
+def _fill_cache(pycode, nameindex, map, version_tag, index, w_method=None):
+ entry = pycode._mapdict_caches[nameindex]
+ if entry is INVALID_CACHE_ENTRY:
+ entry = CacheEntry()
+ pycode._mapdict_caches[nameindex] = entry
+ entry.map = map
+ entry.version_tag = version_tag
+ entry.index = index
+ entry.w_method = w_method
+ if pycode.space.config.objspace.std.withmethodcachecounter:
+ entry.failure_counter += 1
+
def LOAD_ATTR_caching(pycode, w_obj, nameindex):
# this whole mess is to make the interpreter quite a bit faster; it's not
# used if we_are_jitted().
entry = pycode._mapdict_caches[nameindex]
map = w_obj._get_mapdict_map()
- if map is entry.map:
- version_tag = map.terminator.w_cls.version_tag()
- if version_tag is entry.version_tag:
- # everything matches, it's incredibly fast
- if pycode.space.config.objspace.std.withmethodcachecounter:
- entry.success_counter += 1
- return w_obj._mapdict_read_storage(entry.index)
+ if entry.is_valid_for_map(map):
+ # everything matches, it's incredibly fast
+ return w_obj._mapdict_read_storage(entry.index)
return LOAD_ATTR_slowpath(pycode, w_obj, nameindex, map)
LOAD_ATTR_caching._always_inline_ = True
@@ -710,17 +734,30 @@
if selector[1] != INVALID:
index = map.index(selector)
if index >= 0:
- entry = pycode._mapdict_caches[nameindex]
- if entry is INVALID_CACHE_ENTRY:
- entry = CacheEntry()
- pycode._mapdict_caches[nameindex] = entry
- entry.map = map
- entry.version_tag = version_tag
- entry.index = index
- if space.config.objspace.std.withmethodcachecounter:
- entry.failure_counter += 1
+ _fill_cache(pycode, nameindex, map, version_tag, index)
return w_obj._mapdict_read_storage(index)
if space.config.objspace.std.withmethodcachecounter:
INVALID_CACHE_ENTRY.failure_counter += 1
return space.getattr(w_obj, w_name)
LOAD_ATTR_slowpath._dont_inline_ = True
+
+def LOOKUP_METHOD_mapdict(f, nameindex, w_obj):
+ space = f.space
+ pycode = f.getcode()
+ entry = pycode._mapdict_caches[nameindex]
+ if entry.is_valid_for_obj(w_obj):
+ w_method = entry.w_method
+ if w_method is not None:
+ f.pushvalue(w_method)
+ f.pushvalue(w_obj)
+ return True
+ return False
+
+def LOOKUP_METHOD_mapdict_fill_cache_method(pycode, nameindex, w_obj, w_type, w_method):
+ version_tag = w_type.version_tag()
+ if version_tag is None:
+ return
+ map = w_obj._get_mapdict_map()
+ if map is None:
+ return
+ _fill_cache(pycode, nameindex, map, version_tag, -1, w_method)
Modified: pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py (original)
+++ pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py Thu Nov 11 23:52:08 2010
@@ -597,7 +597,8 @@
from pypy.interpreter import gateway
cls.space = gettestobjspace(
**{"objspace.std.withmapdict": True,
- "objspace.std.withmethodcachecounter": True})
+ "objspace.std.withmethodcachecounter": True,
+ "objspace.opcodes.CALL_METHOD": True})
#
def check(space, w_func, name):
w_code = space.getattr(w_func, space.wrap('func_code'))
@@ -778,6 +779,58 @@
res = self.check(f, 'x')
assert res == (0, 0, 1)
+ def test_call_method_uses_cache(self):
+ # bit sucky
+ global C
+
+ class C(object):
+ def m(*args):
+ return args
+ C.sm = staticmethod(C.m.im_func)
+ C.cm = classmethod(C.m.im_func)
+
+ exec """if 1:
+
+ def f():
+ c = C()
+ res = c.m(1)
+ assert res == (c, 1)
+ return 42
+
+ def g():
+ c = C()
+ res = c.sm(1)
+ assert res == (1, )
+ return 42
+
+ def h():
+ c = C()
+ res = c.cm(1)
+ assert res == (C, 1)
+ return 42
+ """
+ res = self.check(f, 'm')
+ assert res == (1, 0, 0)
+ res = self.check(f, 'm')
+ assert res == (0, 1, 0)
+ res = self.check(f, 'm')
+ assert res == (0, 1, 0)
+ res = self.check(f, 'm')
+ assert res == (0, 1, 0)
+
+ # static methods are not cached
+ res = self.check(g, 'sm')
+ assert res == (0, 0, 0)
+ res = self.check(g, 'sm')
+ assert res == (0, 0, 0)
+
+ # neither are class methods
+ res = self.check(h, 'cm')
+ assert res == (0, 0, 0)
+ res = self.check(h, 'cm')
+ assert res == (0, 0, 0)
+
+
class AppTestGlobalCaching(AppTestWithMapDict):
def setup_class(cls):
cls.space = gettestobjspace(
More information about the Pypy-commit
mailing list