[pypy-svn] r65360 - in pypy/branch/speedup-global2/pypy: config interpreter objspace objspace/fake objspace/std objspace/std/test translator/microbench

cfbolz at codespeak.net cfbolz at codespeak.net
Fri May 22 18:53:15 CEST 2009


Author: cfbolz
Date: Fri May 22 18:53:13 2009
New Revision: 65360

Added:
   pypy/branch/speedup-global2/pypy/objspace/std/celldict.py   (contents, props changed)
   pypy/branch/speedup-global2/pypy/objspace/std/test/test_celldict.py   (contents, props changed)
Modified:
   pypy/branch/speedup-global2/pypy/config/pypyoption.py
   pypy/branch/speedup-global2/pypy/interpreter/module.py
   pypy/branch/speedup-global2/pypy/interpreter/pycode.py
   pypy/branch/speedup-global2/pypy/objspace/fake/objspace.py
   pypy/branch/speedup-global2/pypy/objspace/reflective.py
   pypy/branch/speedup-global2/pypy/objspace/std/dictmultiobject.py
   pypy/branch/speedup-global2/pypy/objspace/std/objspace.py
   pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictmultiobject.py
   pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictobject.py
   pypy/branch/speedup-global2/pypy/translator/microbench/test_count1.py
Log:
Port over changes from old speedup-globals branch:

    ------------------------------------------------------------------------
    r62765 | cfbolz | 2009-03-09 17:53:28 +0100 (Mon, 09 Mar 2009) | 3 lines
    Changed paths:                                                          
       A /pypy/branch/speedup-globals (from /pypy/trunk:62764)              

    A branch to try Armin's and mine newest idea about how to speed up global
    lookups.                                                                 

    ------------------------------------------------------------------------
    r62773 | cfbolz | 2009-03-09 19:02:50 +0100 (Mon, 09 Mar 2009) | 5 lines
    Changed paths:                                                          
       M /pypy/branch/speedup-globals/pypy/config/pypyoption.py             
       M /pypy/branch/speedup-globals/pypy/interpreter/module.py            
       M /pypy/branch/speedup-globals/pypy/objspace/fake/objspace.py        
       M /pypy/branch/speedup-globals/pypy/objspace/reflective.py           
       M /pypy/branch/speedup-globals/pypy/objspace/std/dictmultiobject.py  
       M /pypy/branch/speedup-globals/pypy/objspace/std/objspace.py         
       M /pypy/branch/speedup-globals/pypy/objspace/std/test/test_dictmultiobject.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/test/test_dictobject.py     

    First step to make global lookups faster: Introduce a special dict
    implementation for modules, where every value in the RPython-level dict is a
    cell that contains the real value. As long as the "valid" flag on such a cell is
    set, it is safe to store the cell somewhere else.                               

    ------------------------------------------------------------------------
    r62811 | cfbolz | 2009-03-10 16:00:52 +0100 (Tue, 10 Mar 2009) | 2 lines
    Changed paths:                                                          
       A /pypy/branch/speedup-globals/pypy/objspace/std/celldict.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/dictmultiobject.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/objspace.py
       A /pypy/branch/speedup-globals/pypy/objspace/std/test/test_celldict.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/test/test_dictmultiobject.py

    Actually use the cell-dict stuff to cache global lookups in frames.

    ------------------------------------------------------------------------
    r62816 | cfbolz | 2009-03-10 16:34:17 +0100 (Tue, 10 Mar 2009) | 2 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/objspace/std/celldict.py

    help flow space

    ------------------------------------------------------------------------
    r62819 | cfbolz | 2009-03-10 17:54:44 +0100 (Tue, 10 Mar 2009) | 2 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/translator/benchmark/benchmarks.py

    fix typo

    ------------------------------------------------------------------------
    r62823 | cfbolz | 2009-03-10 17:57:56 +0100 (Tue, 10 Mar 2009) | 2 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/translator/benchmark/benchmarks.py

    fix gadfly

    ------------------------------------------------------------------------
    r62827 | cfbolz | 2009-03-10 19:07:12 +0100 (Tue, 10 Mar 2009) | 4 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/interpreter/pycode.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/celldict.py

    It turns out that using one additional dict lookup per call negates many of the
    benefits of this optimization. Therefore, attach the cache to the code object
    directly.

    ------------------------------------------------------------------------
    r62830 | cfbolz | 2009-03-10 20:38:30 +0100 (Tue, 10 Mar 2009) | 2 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/translator/microbench/test_count1.py

    two more microbenchmarks

    ------------------------------------------------------------------------
    r62845 | cfbolz | 2009-03-11 11:54:45 +0100 (Wed, 11 Mar 2009) | 2 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/objspace/std/celldict.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/test/test_celldict.py

    get rid of invalid flag

    ------------------------------------------------------------------------
    r62856 | cfbolz | 2009-03-11 13:16:33 +0100 (Wed, 11 Mar 2009) | 2 lines
    Changed paths:
       M /pypy/branch/speedup-globals/pypy/objspace/std/celldict.py
       M /pypy/branch/speedup-globals/pypy/objspace/std/test/test_celldict.py

    fix a corner-case

    ------------------------------------------------------------------------


Modified: pypy/branch/speedup-global2/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/config/pypyoption.py	(original)
+++ pypy/branch/speedup-global2/pypy/config/pypyoption.py	Fri May 22 18:53:13 2009
@@ -228,6 +228,13 @@
                    "use dictionaries optimized for flexibility",
                    default=False),
 
+        BoolOption("withcelldict",
+                   "use dictionaries that are opimized for being used as module dicts",
+                   default=False,
+                   requires=[("objspace.std.withmultidict", True),
+                             ("objspace.opcodes.CALL_LIKELY_BUILTIN", False),
+                             ("objspace.honor__builtins__", False)]),
+
         BoolOption("withsharingdict",
                    "use dictionaries that share the keys part",
                    default=False,

Modified: pypy/branch/speedup-global2/pypy/interpreter/module.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/interpreter/module.py	(original)
+++ pypy/branch/speedup-global2/pypy/interpreter/module.py	Fri May 22 18:53:13 2009
@@ -11,7 +11,7 @@
     def __init__(self, space, w_name, w_dict=None):
         self.space = space
         if w_dict is None: 
-            w_dict = space.newdict(track_builtin_shadowing=True)
+            w_dict = space.newdict(module=True)
         self.w_dict = w_dict 
         self.w_name = w_name 
         if w_name is not None:

Modified: pypy/branch/speedup-global2/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/interpreter/pycode.py	(original)
+++ pypy/branch/speedup-global2/pypy/interpreter/pycode.py	Fri May 22 18:53:13 2009
@@ -111,6 +111,10 @@
 
         self._compute_flatcall()
 
+        if space.config.objspace.std.withcelldict:
+            from pypy.objspace.std.celldict import init_code
+            init_code(self)
+
     co_names = property(lambda self: [self.space.unwrap(w_name) for w_name in self.co_names_w]) # for trace
 
     def signature(self):

Modified: pypy/branch/speedup-global2/pypy/objspace/fake/objspace.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/objspace/fake/objspace.py	(original)
+++ pypy/branch/speedup-global2/pypy/objspace/fake/objspace.py	Fri May 22 18:53:13 2009
@@ -93,7 +93,7 @@
     newint            = make_dummy()
     newlong           = make_dummy()
     newfloat          = make_dummy()
-    def newdict(self, track_builtin_shadowing=False):
+    def newdict(self, module=False):
         return self.newfloat()
     newlist           = make_dummy()
     emptylist         = make_dummy()

Modified: pypy/branch/speedup-global2/pypy/objspace/reflective.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/objspace/reflective.py	(original)
+++ pypy/branch/speedup-global2/pypy/objspace/reflective.py	Fri May 22 18:53:13 2009
@@ -137,8 +137,8 @@
         return None
 
     if opname == "newdict": # grr grr kwargs
-        def fn(track_builtin_shadowing=False):
-            w_obj = parentfn(track_builtin_shadowing)
+        def fn(module=False):
+            w_obj = parentfn(module)
             w_newobj = user_hook(w_obj)
             if w_newobj is not None:
                 return w_newobj

Added: pypy/branch/speedup-global2/pypy/objspace/std/celldict.py
==============================================================================
--- (empty file)
+++ pypy/branch/speedup-global2/pypy/objspace/std/celldict.py	Fri May 22 18:53:13 2009
@@ -0,0 +1,248 @@
+from pypy.objspace.std.dictmultiobject import DictImplementation
+from pypy.objspace.std.dictmultiobject import IteratorImplementation
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash
+
+class ModuleCell(object):
+    def __init__(self, w_value=None):
+        self.w_value = w_value
+
+    def invalidate(self):
+        w_value = self.w_value
+        self.w_value = None
+        return w_value
+
+    def __repr__(self):
+        return "<ModuleCell: %s>" % (self.w_value, )
+
+class ModuleDictImplementation(DictImplementation):
+    def __init__(self, space):
+        self.space = space
+        self.content = {}
+        self.unshadowed_builtins = {}
+
+    def getcell(self, key, make_new=True):
+        try:
+            return self.content[key]
+        except KeyError:
+            if not make_new:
+                raise
+            result = self.content[key] = ModuleCell()
+            return result
+
+    def add_unshadowed_builtin(self, name, builtin_impl):
+        assert isinstance(builtin_impl, ModuleDictImplementation)
+        self.unshadowed_builtins[name] = builtin_impl
+
+    def invalidate_unshadowed_builtin(self, name):
+        impl = self.unshadowed_builtins[name]
+        try:
+            cell = impl.content[name]
+        except KeyError:
+            pass
+        else:
+            w_value = cell.invalidate()
+            cell = impl.content[name] = ModuleCell(w_value)
+
+    def setitem(self, w_key, w_value):
+        space = self.space
+        if space.is_w(space.type(w_key), space.w_str):
+            return self.setitem_str(w_key, w_value)
+        else:
+            return self._as_rdict().setitem(w_key, w_value)
+
+    def setitem_str(self, w_key, w_value, shadows_type=True):
+        name = self.space.str_w(w_key)
+        self.getcell(name).w_value = w_value
+        
+        if name in self.unshadowed_builtins:
+            self.invalidate_unshadowed_builtin(name)
+            del self.unshadowed_builtins[name]
+
+        return self
+
+    def delitem(self, w_key):
+        space = self.space
+        w_key_type = space.type(w_key)
+        if space.is_w(w_key_type, space.w_str):
+            key = space.str_w(w_key)
+            cell = self.getcell(key, False)
+            cell.invalidate()
+            del self.content[key]
+            return self
+        elif _is_sane_hash(space, w_key_type):
+            raise KeyError
+        else:
+            return self._as_rdict().delitem(w_key)
+        
+    def length(self):
+        return len(self.content)
+
+    def get(self, w_lookup):
+        space = self.space
+        w_lookup_type = space.type(w_lookup)
+        if space.is_w(w_lookup_type, space.w_str):
+            try:
+                return self.getcell(space.str_w(w_lookup), False).w_value
+            except KeyError:
+                return None
+        elif _is_sane_hash(space, w_lookup_type):
+            return None
+        else:
+            return self._as_rdict().get(w_lookup)
+
+    def iteritems(self):
+        return ModuleDictItemIteratorImplementation(self.space, self)
+
+    def iterkeys(self):
+        return ModuleDictKeyIteratorImplementation(self.space, self)
+
+    def itervalues(self):
+        return ModuleDictValueIteratorImplementation(self.space, self)
+
+    def keys(self):
+        space = self.space
+        return [space.wrap(key) for key in self.content.iterkeys()]
+
+    def values(self):
+        return [cell.w_value for cell in self.content.itervalues()]
+
+    def items(self):
+        space = self.space
+        return [space.newtuple([space.wrap(key), cell.w_value])
+                    for (key, cell) in self.content.iteritems()]
+
+    def _as_rdict(self):
+        newimpl = self.space.DefaultDictImpl(self.space)
+        for k, cell in self.content.iteritems():
+            newimpl.setitem(self.space.wrap(k), cell.w_value)
+            cell.invalidate()
+        for k in self.unshadowed_builtins:
+            self.invalidate_unshadowed_builtin(k)
+        return newimpl
+
+# grrrrr. just a copy-paste from StrKeyIteratorImplementation in dictmultiobject
+class ModuleDictKeyIteratorImplementation(IteratorImplementation):
+    def __init__(self, space, dictimplementation):
+        IteratorImplementation.__init__(self, space, dictimplementation)
+        self.iterator = dictimplementation.content.iterkeys()
+
+    def next_entry(self):
+        # note that this 'for' loop only runs once, at most
+        for key in self.iterator:
+            return self.space.wrap(key)
+        else:
+            return None
+
+class ModuleDictValueIteratorImplementation(IteratorImplementation):
+    def __init__(self, space, dictimplementation):
+        IteratorImplementation.__init__(self, space, dictimplementation)
+        self.iterator = dictimplementation.content.itervalues()
+
+    def next_entry(self):
+        # note that this 'for' loop only runs once, at most
+        for cell in self.iterator:
+            return cell.w_value
+        else:
+            return None
+
+class ModuleDictItemIteratorImplementation(IteratorImplementation):
+    def __init__(self, space, dictimplementation):
+        IteratorImplementation.__init__(self, space, dictimplementation)
+        self.iterator = dictimplementation.content.iteritems()
+
+    def next_entry(self):
+        # note that this 'for' loop only runs once, at most
+        for key, cell in self.iterator:
+            return self.space.newtuple([self.space.wrap(key), cell.w_value])
+        else:
+            return None
+
+
+
+
+
+
+
+class State(object):
+    def __init__(self, space):
+        self.space = space
+        self.invalidcell = ModuleCell()
+        self.always_invalid_cache = []
+        self.neverused_dictimpl = ModuleDictImplementation(space)
+
+class GlobalCacheHolder(object):
+    def __init__(self, space):
+        self.cache = None
+        state = space.fromcache(State)
+        self.dictimpl = state.neverused_dictimpl
+
+    def getcache(self, space, code, w_globals):
+        implementation = getimplementation(w_globals)
+        if self.dictimpl is implementation:
+            return self.cache
+        return self.getcache_slow(space, code, w_globals, implementation)
+    getcache._always_inline_ = True
+
+    def getcache_slow(self, space, code, w_globals, implementation):
+        state = space.fromcache(State)
+        if not isinstance(implementation, ModuleDictImplementation):
+            missing_length = max(len(code.co_names_w) - len(state.always_invalid_cache), 0)
+            state.always_invalid_cache.extend([state.invalidcell] * missing_length)
+            cache = state.always_invalid_cache
+        else:
+            cache = [state.invalidcell] * len(code.co_names_w)
+        self.cache = cache
+        self.dictimpl = implementation
+        return cache
+    getcache_slow._dont_inline_ = True
+
+def init_code(code):
+    code.globalcacheholder = GlobalCacheHolder(code.space)
+
+
+def get_global_cache(space, code, w_globals):
+    from pypy.interpreter.pycode import PyCode
+    if not isinstance(code, PyCode):
+        return []
+    holder = code.globalcacheholder
+    return holder.getcache(space, code, w_globals)
+
+def getimplementation(w_dict):
+    if type(w_dict) is W_DictMultiObject:
+        return w_dict.implementation
+    else:
+        return None
+
+def LOAD_GLOBAL(f, nameindex, *ignored):
+    cell = f.cache_for_globals[nameindex]
+    w_value = cell.w_value
+    if w_value is None:
+        # slow path
+        w_value = load_global_fill_cache(f, nameindex)
+    f.pushvalue(w_value)
+LOAD_GLOBAL._always_inline_ = True
+
+def find_cell_from_dict(implementation, name):
+    if isinstance(implementation, ModuleDictImplementation):
+        try:
+            return implementation.getcell(name, False)
+        except KeyError:
+            return None
+    return None
+
+def load_global_fill_cache(f, nameindex):
+    name = f.space.str_w(f.getname_w(nameindex))
+    implementation = getimplementation(f.w_globals)
+    if isinstance(implementation, ModuleDictImplementation):
+        cell = find_cell_from_dict(implementation, name)
+        if cell is None:
+            builtin_impl = getimplementation(f.get_builtin().getdict())
+            cell = find_cell_from_dict(builtin_impl, name)
+            if cell is not None:
+                implementation.add_unshadowed_builtin(name, builtin_impl)
+            
+        if cell is not None:
+            f.cache_for_globals[nameindex] = cell
+            return cell.w_value
+    return f._load_global(f.getname_w(nameindex))
+load_global_fill_cache._dont_inline_ = True

Modified: pypy/branch/speedup-global2/pypy/objspace/std/dictmultiobject.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/objspace/std/dictmultiobject.py	(original)
+++ pypy/branch/speedup-global2/pypy/objspace/std/dictmultiobject.py	Fri May 22 18:53:13 2009
@@ -865,7 +865,6 @@
         else:
             return None
 
-
 import time, py
 
 class DictInfo(object):
@@ -1038,8 +1037,11 @@
 class W_DictMultiObject(W_Object):
     from pypy.objspace.std.dicttype import dict_typedef as typedef
 
-    def __init__(w_self, space, wary=False, sharing=False):
-        if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and wary:
+    def __init__(w_self, space, wary=False, sharing=False, module=False):
+        if space.config.objspace.std.withcelldict and wary:
+            from pypy.objspace.std.celldict import ModuleDictImplementation
+            w_self.implementation = ModuleDictImplementation(space)
+        elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and wary:
             w_self.implementation = WaryDictImplementation(space)
         elif space.config.objspace.std.withdictmeasurement:
             w_self.implementation = MeasuringDictImplementation(space)

Modified: pypy/branch/speedup-global2/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/objspace/std/objspace.py	(original)
+++ pypy/branch/speedup-global2/pypy/objspace/std/objspace.py	Fri May 22 18:53:13 2009
@@ -72,7 +72,16 @@
         # Import all the object types and implementations
         self.model = StdTypeModel(self.config)
 
+        from pypy.objspace.std.celldict import get_global_cache
+
         class StdObjSpaceFrame(pyframe.PyFrame):
+            if self.config.objspace.std.withcelldict:
+                def __init__(self, space, code, w_globals, closure):
+                    pyframe.PyFrame.__init__(self, space, code, w_globals, closure)
+                    self.cache_for_globals = get_global_cache(space, code, w_globals)
+
+                from pypy.objspace.std.celldict import LOAD_GLOBAL
+
             if self.config.objspace.std.optimized_int_add:
                 if self.config.objspace.std.withsmallint:
                     def BINARY_ADD(f, oparg, *ignored):
@@ -580,8 +589,8 @@
             from pypy.objspace.std.listobject import W_ListObject
             return W_ListObject(list_w)
 
-    def newdict(self, track_builtin_shadowing=False):
-        if self.config.objspace.opcodes.CALL_LIKELY_BUILTIN and track_builtin_shadowing:
+    def newdict(self, module=False):
+        if self.config.objspace.std.withmultidict and module:
             from pypy.objspace.std.dictmultiobject import W_DictMultiObject
             return W_DictMultiObject(self, wary=True)
         return self.DictObjectCls(self)

Added: pypy/branch/speedup-global2/pypy/objspace/std/test/test_celldict.py
==============================================================================
--- (empty file)
+++ pypy/branch/speedup-global2/pypy/objspace/std/test/test_celldict.py	Fri May 22 18:53:13 2009
@@ -0,0 +1,259 @@
+from pypy.conftest import gettestobjspace
+from pypy.objspace.std.celldict import get_global_cache, ModuleCell, ModuleDictImplementation
+from pypy.interpreter import gateway
+
+# this file tests mostly the effects of caching global lookup. The dict
+# implementation itself is tested in test_dictmultiobject.py
+
+
+class AppTestCellDict(object):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withcelldict": True})
+        cls.w_impl_used = cls.space.appexec([], """():
+            import __pypy__
+            def impl_used(obj):
+                assert "ModuleDictImplementation" in __pypy__.internal_repr(obj)
+            return impl_used
+        """)
+        def is_in_cache(space, w_code, w_globals, w_name):
+            name = space.str_w(w_name)
+            cache = get_global_cache(space, w_code, w_globals)
+            index = [space.str_w(w_n) for w_n in w_code.co_names_w].index(name)
+            return space.wrap(cache[index].w_value is not None)
+        is_in_cache = gateway.interp2app(is_in_cache)
+        cls.w_is_in_cache = cls.space.wrap(is_in_cache) 
+        stored_builtins = []
+        def rescue_builtins(space):
+            w_dict = space.builtin.getdict()
+            content = {}
+            for key, cell in w_dict.implementation.content.iteritems():
+                newcell = ModuleCell()
+                newcell.w_value = cell.w_value
+                content[key] = newcell
+            stored_builtins.append(content)
+        rescue_builtins = gateway.interp2app(rescue_builtins)
+        cls.w_rescue_builtins = cls.space.wrap(rescue_builtins) 
+        def restore_builtins(space):
+            w_dict = space.builtin.getdict()
+            if not isinstance(w_dict.implementation, ModuleDictImplementation):
+                w_dict.implementation = ModuleDictImplementation(space)
+            w_dict.implementation.content = stored_builtins.pop()
+        restore_builtins = gateway.interp2app(restore_builtins)
+        cls.w_restore_builtins = cls.space.wrap(restore_builtins) 
+
+    def test_same_code_in_different_modules(self):
+        import sys
+        mod1 = type(sys)("abc")
+        self.impl_used(mod1.__dict__)
+        glob1 = mod1.__dict__
+        mod2 = type(sys)("abc")
+        self.impl_used(mod2.__dict__)
+        glob2 = mod2.__dict__
+        def f():
+            return x + 1
+        code = f.func_code
+        f1 = type(f)(code, glob1)
+        mod1.x = 1
+        assert not self.is_in_cache(code, glob1, "x")
+        assert f1() == 2
+        assert self.is_in_cache(code, glob1, "x")
+        assert f1() == 2
+        assert self.is_in_cache(code, glob1, "x")
+        mod1.x = 2
+        assert f1() == 3
+        assert self.is_in_cache(code, glob1, "x")
+        assert f1() == 3
+        assert self.is_in_cache(code, glob1, "x")
+        f2 = type(f)(code, glob2)
+        mod2.x = 5
+        assert not self.is_in_cache(code, glob2, "x")
+        assert f2() == 6
+        assert self.is_in_cache(code, glob2, "x")
+        assert f2() == 6
+        assert self.is_in_cache(code, glob2, "x")
+        mod2.x = 7
+        assert f2() == 8
+        assert self.is_in_cache(code, glob2, "x")
+        assert f2() == 8
+        assert self.is_in_cache(code, glob2, "x")
+
+    def test_override_builtins(self):
+        import sys, __builtin__
+        mod1 = type(sys)("abc")
+        glob1 = mod1.__dict__
+        self.impl_used(mod1.__dict__)
+        def f():
+            return len(x)
+        code = f.func_code
+        f1 = type(f)(f.func_code, glob1)
+        mod1.x = []
+        assert not self.is_in_cache(code, glob1, "len")
+        assert not self.is_in_cache(code, glob1, "x")
+        assert f1() == 0
+        assert self.is_in_cache(code, glob1, "len")
+        assert self.is_in_cache(code, glob1, "x")
+        assert f1() == 0
+        mod1.x.append(1)
+        assert f1() == 1
+        assert self.is_in_cache(code, glob1, "len")
+        assert self.is_in_cache(code, glob1, "x")
+        mod1.len = lambda x: 15
+        assert not self.is_in_cache(code, glob1, "len")
+        mod1.x.append(1)
+        assert f1() == 15
+        assert self.is_in_cache(code, glob1, "len")
+        assert f1() == 15
+        assert self.is_in_cache(code, glob1, "len")
+        del mod1.len
+        mod1.x.append(1)
+        assert not self.is_in_cache(code, glob1, "len")
+        assert f1() == 3
+        assert self.is_in_cache(code, glob1, "len")
+        assert f1() == 3
+        assert self.is_in_cache(code, glob1, "len")
+        orig_len = __builtins__.len
+        try:
+            __builtins__.len = lambda x: 12
+            mod1.x.append(1)
+            assert self.is_in_cache(code, glob1, "len")
+            assert f1() == 12
+            assert self.is_in_cache(code, glob1, "len")
+            assert f1() == 12
+            assert self.is_in_cache(code, glob1, "len")
+        finally:
+            __builtins__.len = orig_len
+
+    def test_override_builtins2(self):
+        import sys, __builtin__
+        mod1 = type(sys)("abc")
+        glob1 = mod1.__dict__
+        self.impl_used(mod1.__dict__)
+        def f():
+            return l(x)
+        code = f.func_code
+        f1 = type(f)(f.func_code, glob1)
+        mod1.x = []
+        __builtin__.l = len
+        try:
+            assert not self.is_in_cache(code, glob1, "l")
+            assert not self.is_in_cache(code, glob1, "x")
+            assert f1() == 0
+            assert self.is_in_cache(code, glob1, "l")
+            assert self.is_in_cache(code, glob1, "x")
+            assert f1() == 0
+            mod1.x.append(1)
+            assert f1() == 1
+            assert self.is_in_cache(code, glob1, "l")
+            assert self.is_in_cache(code, glob1, "x")
+            del __builtin__.l
+            mod1.l = len
+            mod1.x.append(1)
+            assert not self.is_in_cache(code, glob1, "l")
+            assert f1() == 2
+            assert self.is_in_cache(code, glob1, "l")
+            assert self.is_in_cache(code, glob1, "x")
+        finally:
+            if hasattr(__builtins__, "l"):
+                del __builtins__.l
+
+    def test_generator(self):
+        import sys, __builtin__
+        mod1 = type(sys)("abc")
+        glob1 = mod1.__dict__
+        self.impl_used(mod1.__dict__)
+        def f():
+            yield 1
+            yield x
+            yield len(x)
+        code = f.func_code
+        f1 = type(f)(f.func_code, glob1)
+        mod1.x = []
+        gen = f1()
+        assert not self.is_in_cache(code, glob1, "len")
+        assert not self.is_in_cache(code, glob1, "x")
+        v = gen.next()
+        assert v == 1
+        assert not self.is_in_cache(code, glob1, "len")
+        assert not self.is_in_cache(code, glob1, "x")
+        v = gen.next()
+        assert v is mod1.x
+        assert not self.is_in_cache(code, glob1, "len")
+        assert self.is_in_cache(code, glob1, "x")
+        v = gen.next()
+        assert v == 0
+        assert self.is_in_cache(code, glob1, "len")
+        assert self.is_in_cache(code, glob1, "x")
+
+    def test_degenerate_to_rdict(self):
+        import sys
+        mod1 = type(sys)("abc")
+        self.impl_used(mod1.__dict__)
+        glob1 = mod1.__dict__
+        def f():
+            return x + 1
+        code = f.func_code
+        f1 = type(f)(code, glob1)
+        mod1.x = 1
+        assert not self.is_in_cache(code, glob1, "x")
+        assert f1() == 2
+        assert self.is_in_cache(code, glob1, "x")
+        glob1[1] = 2
+        assert not self.is_in_cache(code, glob1, "x")
+        assert f1() == 2
+        assert not self.is_in_cache(code, glob1, "x")
+
+    def test_degenerate_builtin_to_rdict(self):
+        import sys, __builtin__
+        mod1 = type(sys)("abc")
+        self.impl_used(mod1.__dict__)
+        glob1 = mod1.__dict__
+        def f():
+            return len(x)
+        code = f.func_code
+        f1 = type(f)(code, glob1)
+        mod1.x = [1, 2]
+        assert not self.is_in_cache(code, glob1, "x")
+        assert not self.is_in_cache(code, glob1, "len")
+        assert f1() == 2
+        assert self.is_in_cache(code, glob1, "x")
+        assert self.is_in_cache(code, glob1, "len")
+        self.rescue_builtins()
+        try:
+            __builtin__.__dict__[1] = 2
+            assert not self.is_in_cache(code, glob1, "len")
+            assert f1() == 2
+            assert not self.is_in_cache(code, glob1, "len")
+        finally:
+            self.restore_builtins()
+
+    def test_mapping_as_locals(self):
+        import sys
+        if sys.version_info < (2,5) or not hasattr(sys, 'pypy_objspaceclass'):
+            skip("need CPython 2.5 or PyPy for non-dictionaries in exec statements")
+        class M(object):
+            def __getitem__(self, key):
+                return key
+            def __setitem__(self, key, value):
+                self.result[key] = value
+        m = M()
+        m.result = {}
+        exec "x=m" in {}, m
+        assert m.result == {'x': 'm'}
+        exec "y=n" in m   # NOTE: this doesn't work in CPython 2.4
+        assert m.result == {'x': 'm', 'y': 'n'}
+
+    def test_subclass_of_dict_as_locals(self):
+        import sys
+        if sys.version_info < (2,5) or not hasattr(sys, 'pypy_objspaceclass'):
+            skip("need CPython 2.5 or PyPy for non-dictionaries in exec statements")
+        class M(dict):
+            def __getitem__(self, key):
+                return key
+            def __setitem__(self, key, value):
+                dict.__setitem__(self, key, value)
+        m = M()
+        exec "x=m" in {}, m
+        assert m == {'x': 'm'}
+        exec "y=n" in m   # NOTE: this doesn't work in CPython 2.4
+        assert m == {'x': 'm', 'y': 'n'}
+

Modified: pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictmultiobject.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictmultiobject.py	(original)
+++ pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictmultiobject.py	Fri May 22 18:53:13 2009
@@ -3,6 +3,8 @@
      W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \
      EmptyDictImplementation, RDictImplementation, StrDictImplementation, \
      SmallDictImplementation, SmallStrDictImplementation, MeasuringDictImplementation
+
+from pypy.objspace.std.celldict import ModuleDictImplementation
 from pypy.conftest import gettestobjspace
 from pypy.objspace.std.test import test_dictobject
 
@@ -58,6 +60,26 @@
         a.__dict__.items() == [("abc", 12)]
 
 
+class AppTestModuleDict(object):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withcelldict": True})
+        cls.w_impl_used = cls.space.appexec([], """():
+            import __pypy__
+            def impl_used(obj):
+                assert "ModuleDictImplementation" in __pypy__.internal_repr(obj)
+            return impl_used
+        """)
+
+
+    def test_check_module_uses_module_dict(self):
+        m = type(__builtins__)("abc")
+        self.impl_used(m.__dict__)
+
+    def test_key_not_there(self):
+        d = type(__builtins__)("abc").__dict__
+        raises(KeyError, "d['def']")
+
+
 
 class TestW_DictSmall(test_dictobject.TestW_DictObject):
     def setup_class(cls):
@@ -233,3 +255,15 @@
 
     def get_impl(self):
         return self.ImplementionClass(self.space, self.string, self.string2)
+
+class TestModuleDictImplementation(TestRDictImplementation):
+    ImplementionClass = ModuleDictImplementation
+    EmptyClass = ModuleDictImplementation
+
+class TestModuleDictImplementationWithBuiltinNames(TestRDictImplementation):
+    ImplementionClass = ModuleDictImplementation
+    EmptyClass = ModuleDictImplementation
+
+    string = "int"
+    string2 = "isinstance"
+

Modified: pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictobject.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictobject.py	(original)
+++ pypy/branch/speedup-global2/pypy/objspace/std/test/test_dictobject.py	Fri May 22 18:53:13 2009
@@ -489,6 +489,7 @@
 FakeSpace.config.objspace.std.withdictmeasurement = False
 FakeSpace.config.objspace.std.withsharingdict = False
 FakeSpace.config.objspace.std.withsmalldicts = False
+FakeSpace.config.objspace.std.withcelldict = False
 FakeSpace.config.objspace.opcodes = Config()
 FakeSpace.config.objspace.opcodes.CALL_LIKELY_BUILTIN = False
 

Modified: pypy/branch/speedup-global2/pypy/translator/microbench/test_count1.py
==============================================================================
--- pypy/branch/speedup-global2/pypy/translator/microbench/test_count1.py	(original)
+++ pypy/branch/speedup-global2/pypy/translator/microbench/test_count1.py	Fri May 22 18:53:13 2009
@@ -201,3 +201,15 @@
         y = y + 1
         c += 1
     
+def test_count_with_True():
+    x = 0
+    n = N
+    while x < n:
+        x = x + True
+
+increment = 1
+def test_count_with_global_increment():
+    x = 0
+    n = N
+    while x < n:
+        x = x + increment



More information about the Pypy-commit mailing list