[pypy-svn] r11949 - in pypy/dist/pypy: interpreter module/sys2 objspace/flow objspace/std tool tool/test

arigo at codespeak.net arigo at codespeak.net
Thu May 5 00:07:31 CEST 2005


Author: arigo
Date: Thu May  5 00:07:31 2005
New Revision: 11949

Modified:
   pypy/dist/pypy/interpreter/baseobjspace.py
   pypy/dist/pypy/interpreter/gateway.py
   pypy/dist/pypy/interpreter/lazymodule.py
   pypy/dist/pypy/interpreter/typedef.py
   pypy/dist/pypy/module/sys2/state.py
   pypy/dist/pypy/objspace/flow/objspace.py
   pypy/dist/pypy/objspace/std/fake.py
   pypy/dist/pypy/objspace/std/objspace.py
   pypy/dist/pypy/objspace/std/stdtypedef.py
   pypy/dist/pypy/tool/cache.py
   pypy/dist/pypy/tool/test/test_cache.py
Log:
Changed the annotator-related behavior of Cache.  It doesn't really make sense
to forcibly freeze caches.  What we really want is that the annotator figures
out all the keys that can be used with a given cache (as SomePBCs), and build
the corresponding values and add them to the cache.

This change required a bit of refactoring in all places using the Cache class.  
(Some of these places didn't actually need to use the now-a-bit-obscure Cache
machinery, and were changed into plain dict manipulations.)



Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py	Thu May  5 00:07:31 2005
@@ -51,6 +51,31 @@
     """Same as BaseWrappable, just new-style instead."""
 
 
+class InternalSpaceCache(Cache):
+    """A generic cache for an object space.  Arbitrary information can
+    be attached to the space by defining a function or class 'f' which
+    can be called as 'f(space)'.  Its result is stored in this
+    ObjSpaceCache.
+    """
+    def __init__(self, space):
+        Cache.__init__(self)
+        self.space = space
+    def _build(self, callable):
+        return callable(self.space)
+
+class SpaceCache(Cache):
+    """A base class for all our concrete caches."""
+    def __init__(self, space):
+        Cache.__init__(self)
+        self.space = space
+    def _build(self, key):
+        val = self.space.enter_cache_building_mode()
+        try:
+            return self.build(key)
+        finally:
+            self.space.leave_cache_building_mode(val)
+
+
 class ObjSpace(object):
     """Base class for the interpreter-level implementations of object spaces.
     http://codespeak.net/moin/pypy/moin.cgi/ObjectSpace"""
@@ -59,8 +84,7 @@
 
     def __init__(self):
         "NOT_RPYTHON: Basic initialization of objects."
-        self._gatewaycache = Cache()
-        self._codecache = Cache()
+        self.fromcache = InternalSpaceCache(self).getorbuild
         # set recursion limit
         # sets all the internal descriptors
         self.initialize()
@@ -112,10 +136,10 @@
         """NOT_RPYTHON: Abstract method that should put some minimal
         content into the w_builtins."""
 
-    def loadfromcache(self, key, builder, cache):
-        return cache.getorbuild(key, builder, self) 
-    loadfromcache._specialize_ = "location" 
-
+    def enter_cache_building_mode(self):
+        "hook for the flow object space"
+    def leave_cache_building_mode(self, val):
+        "hook for the flow object space"
 
     def get_ec_state_dict(self):
         "Return the 'state dict' from the active execution context."
@@ -334,21 +358,23 @@
                        return result
                '''
         """
-        w_func = self.loadfromcache(source, buildappexecfunc, self._codecache)
+        w_func = self.fromcache(AppExecCache).getorbuild(source)
         args = Arguments(self, posargs_w)
         return self.call_args(w_func, args)
 
-def buildappexecfunc(source, space):
-    """ NOT_RPYTHON """ 
-    # XXX will change once we have our own compiler 
-    from pypy.interpreter.pycode import PyCode
-    from pypy.tool.getpy import py  # aehem
-    source = source.lstrip()
-    assert source.startswith('('), "incorrect header in:\n%s" % (source,)
-    source = py.code.Source("def anonymous%s\n" % source)
-    w_glob = space.newdict([])
-    space.exec_(source.compile(), w_glob, w_glob)
-    return space.getitem(w_glob, space.wrap('anonymous'))
+class AppExecCache(SpaceCache):
+    def build(cache, source):
+        """ NOT_RPYTHON """
+        space = cache.space
+        # XXX will change once we have our own compiler 
+        from pypy.interpreter.pycode import PyCode
+        from pypy.tool.getpy import py  # aehem
+        source = source.lstrip()
+        assert source.startswith('('), "incorrect header in:\n%s" % (source,)
+        source = py.code.Source("def anonymous%s\n" % source)
+        w_glob = space.newdict([])
+        space.exec_(source.compile(), w_glob, w_glob)
+        return space.getitem(w_glob, space.wrap('anonymous'))
 
 ## Table describing the regular part of the interface of object spaces,
 ## namely all methods which only take w_ arguments and return a w_ result

Modified: pypy/dist/pypy/interpreter/gateway.py
==============================================================================
--- pypy/dist/pypy/interpreter/gateway.py	(original)
+++ pypy/dist/pypy/interpreter/gateway.py	Thu May  5 00:07:31 2005
@@ -15,9 +15,9 @@
 from pypy.interpreter.error import OperationError 
 from pypy.interpreter import eval
 from pypy.interpreter.function import Function, Method
-from pypy.interpreter.baseobjspace import W_Root, ObjSpace, BaseWrappable, Wrappable
+from pypy.interpreter.baseobjspace import W_Root, ObjSpace, BaseWrappable
+from pypy.interpreter.baseobjspace import Wrappable, SpaceCache
 from pypy.interpreter.argument import Arguments
-from pypy.tool.cache import Cache 
 from pypy.tool.compile import compile2
 from pypy.tool.sourcetools import NiceCompile
 
@@ -457,12 +457,10 @@
         return self.get_function(space)
 
     def get_function(self, space):
-        return space.loadfromcache(self, 
-                                   interp2app.build_function, 
-                                   self.getcache(space))
+        return self.getcache(space).getorbuild(self)
 
     def getcache(self, space):
-        return space._gatewaycache 
+        return space.fromcache(GatewayCache)
 
     def get_method(self, obj):
         # to bind this as a method out of an instance, we build a
@@ -479,17 +477,15 @@
                       w_obj, space.type(w_obj))
 
 
-    def build_function(self, space):
+class GatewayCache(SpaceCache):
+    def build(cache, gateway):
         "NOT_RPYTHON"
-        cache = self.getcache(space) 
-        try: 
-            return cache.content[self] 
-        except KeyError: 
-            defs = self._getdefaults(space)  # needs to be implemented by subclass
-            code = self._code
-            fn = Function(space, code, None, defs, forcename = self.name)
-            cache.content[self] = fn 
-            return fn
+        space = cache.space
+        defs = gateway._getdefaults(space) # needs to be implemented by subclass
+        code = gateway._code
+        fn = Function(space, code, None, defs, forcename = gateway.name)
+        return fn
+
 
 # 
 # the next gateways are to be used only for 
@@ -498,7 +494,7 @@
 class interp2app_temp(interp2app): 
     "NOT_RPYTHON"
     def getcache(self, space): 
-        return self.__dict__.setdefault(space, Cache())
+        return self.__dict__.setdefault(space, GatewayCache(space))
 
 
 # and now for something completely different ... 
@@ -521,8 +517,7 @@
             self.code = NiceCompile(filename)(source)
         
     def getwdict(self, space):
-        return space.loadfromcache(self, self.__class__._builddict,
-                                   space._gatewaycache)
+        return space.fromcache(ApplevelCache).getorbuild(self)
 
     def buildmodule(self, space, name='applevel'):
         from pypy.interpreter.module import Module
@@ -564,6 +559,10 @@
     def _freeze_(self):
         return True  # hint for the annotator: applevel instances are constants
 
+class ApplevelCache(SpaceCache):
+    def build(cache, app):
+        return app._builddict(cache.space)
+
 class ApplevelInterpClass(ApplevelClass):
     """ similar to applevel, but using translation to interp-level.
         This version maintains a cache folder with single files.

Modified: pypy/dist/pypy/interpreter/lazymodule.py
==============================================================================
--- pypy/dist/pypy/interpreter/lazymodule.py	(original)
+++ pypy/dist/pypy/interpreter/lazymodule.py	Thu May  5 00:07:31 2005
@@ -1,6 +1,5 @@
 from pypy.interpreter.module import Module
 from pypy.interpreter.function import Function, BuiltinFunction
-from pypy.tool.cache import Cache
 from pypy.interpreter import gateway 
 from pypy.interpreter.error import OperationError 
 
@@ -106,7 +105,7 @@
                 return value 
     return ifileloader 
         
-applevelcache = Cache()
+applevelcache = {}
 def getappfileloader(pkgroot, spec):
     """ NOT_RPYTHON """ 
     # hum, it's a bit more involved, because we usually 
@@ -114,15 +113,16 @@
     modname, attrname = spec.split('.')
     impbase = pkgroot + '.' + modname 
     mod = __import__(impbase, None, None, ['attrname'])
-    app = applevelcache.getorbuild(mod, buildapplevelfrommodule, None)
+    try:
+        app = applevelcache[mod]
+    except KeyError:
+        source = inspect.getsource(mod) 
+        fn = mod.__file__
+        if fn.endswith('.pyc') or fn.endswith('.pyo'):
+            fn = fn[:-1]
+        app = gateway.applevel(source, filename=fn)
+        applevelcache[mod] = app
+
     def afileloader(space): 
         return app.wget(space, attrname)
     return afileloader 
-
-def buildapplevelfrommodule(mod, _):
-    """ NOT_RPYTHON """ 
-    source = inspect.getsource(mod) 
-    fn = mod.__file__
-    if fn.endswith('.pyc'): 
-        fn = fn[:-1]
-    return gateway.applevel(source, filename=fn) 

Modified: pypy/dist/pypy/interpreter/typedef.py
==============================================================================
--- pypy/dist/pypy/interpreter/typedef.py	(original)
+++ pypy/dist/pypy/interpreter/typedef.py	Thu May  5 00:07:31 2005
@@ -24,11 +24,18 @@
         # hint for the annotator: track individual constant instances of TypeDef
         return True
 
-unique_interplevel_subclass_cache = Cache()
+subclass_cache = {}
 def get_unique_interplevel_subclass(cls, hasdict, wants_slots):
-    return unique_interplevel_subclass_cache.getorbuild((cls, hasdict, wants_slots), _buildusercls, None)
+    key = (cls, hasdict, wants_slots)
+    try:
+        return subclass_cache[key]
+    except KeyError:
+        subcls = _buildusercls(cls, hasdict, wants_slots)
+        subclass_cache[key] = subcls
+        return subcls
+get_unique_interplevel_subclass._specialize_ = "memo"
 
-def _buildusercls((cls, hasdict, wants_slots), ignored):
+def _buildusercls(cls, hasdict, wants_slots):
     "NOT_RPYTHON: initialization-time only"
     typedef = cls.typedef
     name = ['User']

Modified: pypy/dist/pypy/module/sys2/state.py
==============================================================================
--- pypy/dist/pypy/module/sys2/state.py	(original)
+++ pypy/dist/pypy/module/sys2/state.py	Thu May  5 00:07:31 2005
@@ -3,7 +3,6 @@
 """
 #from pypy.interpreter.module import Module
 from pypy.interpreter.error import OperationError
-from pypy.tool.cache import Cache
 
 import sys, os 
 
@@ -41,7 +40,7 @@
 builtin_module_names.sort() 
 
 class State: 
-    def __init__(self, space, stuff=None): 
+    def __init__(self, space): 
         self.space = space 
         self.w_builtin_module_names = space.newtuple(
             [space.wrap(fn) for fn in builtin_module_names])
@@ -71,9 +70,8 @@
                                ] +
                                [space.wrap(p) for p in sys.path if p!= srcdir])
 
-statecache = Cache()
 def get(space): 
-    return space.loadfromcache(space, State, statecache) 
+    return space.fromcache(State)
 
 def pypy_getudir(space):
     """NOT_RPYTHON"""

Modified: pypy/dist/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/objspace.py	(original)
+++ pypy/dist/pypy/objspace/flow/objspace.py	Thu May  5 00:07:31 2005
@@ -63,20 +63,18 @@
         #self.make_builtins()
         #self.make_sys()
 
-    def loadfromcache(self, key, builder, cache):
+    def enter_cache_building_mode(self):
         # when populating the caches, the flow space switches to
         # "concrete mode".  In this mode, only Constants are allowed
         # and no SpaceOperation is recorded.
-        def my_builder(key, stuff):
-            previous_recorder = self.executioncontext.recorder
-            self.executioncontext.recorder = flowcontext.ConcreteNoOp()
-            self.concrete_mode += 1
-            try:
-                return builder(key, stuff)
-            finally:
-                self.executioncontext.recorder = previous_recorder
-                self.concrete_mode -= 1
-        return super(FlowObjSpace, self).loadfromcache(key, my_builder, cache)
+        previous_recorder = self.executioncontext.recorder
+        self.executioncontext.recorder = flowcontext.ConcreteNoOp()
+        self.concrete_mode += 1
+        return previous_recorder
+
+    def leave_cache_building_mode(self, previous_recorder):
+        self.executioncontext.recorder = previous_recorder
+        self.concrete_mode -= 1
 
     def newdict(self, items_w):
         if self.concrete_mode:

Modified: pypy/dist/pypy/objspace/std/fake.py
==============================================================================
--- pypy/dist/pypy/objspace/std/fake.py	(original)
+++ pypy/dist/pypy/objspace/std/fake.py	Thu May  5 00:07:31 2005
@@ -5,7 +5,6 @@
 from pypy.objspace.std.stdtypedef import *
 from pypy.objspace.std.objspace import W_Object, StdObjSpace
 from pypy.objspace.std.model import UnwrapError
-from pypy.tool.cache import Cache 
 
 # this file automatically generates non-reimplementations of CPython
 # types that we do not yet implement in the standard object space
@@ -22,7 +21,7 @@
 
 import sys
 
-_fake_type_cache = Cache()
+_fake_type_cache = {}
 
 # real-to-wrapped exceptions
 def wrap_exception(space):
@@ -47,9 +46,14 @@
 
 def fake_type(cpy_type):
     assert type(cpy_type) is type
-    return _fake_type_cache.getorbuild(cpy_type, really_build_fake_type, None)
+    try:
+        return _fake_type_cache[cpy_type]
+    except KeyError:
+        faked_type = really_build_fake_type(cpy_type)
+        _fake_type_cache[cpy_type] = faked_type
+        return faked_type
 
-def really_build_fake_type(cpy_type, ignored):
+def really_build_fake_type(cpy_type):
     "NOT_RPYTHON (not remotely so!)."
     debug_print('faking %r'%(cpy_type,))
     kw = {}
@@ -160,9 +164,9 @@
         func = BuiltinFunction(func)
     return func
 
-_fake_type_cache.content[type(len)] = fake_builtin_function
-_fake_type_cache.content[type(list.append)] = fake_builtin_callable
-_fake_type_cache.content[type(type(None).__repr__)] = fake_builtin_callable
+_fake_type_cache[type(len)] = fake_builtin_function
+_fake_type_cache[type(list.append)] = fake_builtin_callable
+_fake_type_cache[type(type(None).__repr__)] = fake_builtin_callable
 
 
 from pypy.interpreter.baseobjspace import Wrappable
@@ -212,5 +216,5 @@
         __delete__ = interp2app(descr_descriptor_del),
         )
 
-_fake_type_cache.content[type(file.softspace)] = W_FakeDescriptor
-_fake_type_cache.content[type(type.__dict__['__dict__'])] = W_FakeDescriptor
+_fake_type_cache[type(file.softspace)] = W_FakeDescriptor
+_fake_type_cache[type(type.__dict__['__dict__'])] = W_FakeDescriptor

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Thu May  5 00:07:31 2005
@@ -168,9 +168,7 @@
     def gettypeobject(self, typedef):
         # types_w maps each StdTypeDef instance to its
         # unique-for-this-space W_TypeObject instance
-        return self.loadfromcache(typedef, 
-                                  stdtypedef.buildtypeobject,
-                                  self._typecache)
+        return self.fromcache(stdtypedef.TypeCache).getorbuild(typedef)
 
     def wrap(self, x):
         "Wraps the Python value 'x' into one of the wrapper classes."

Modified: pypy/dist/pypy/objspace/std/stdtypedef.py
==============================================================================
--- pypy/dist/pypy/objspace/std/stdtypedef.py	(original)
+++ pypy/dist/pypy/objspace/std/stdtypedef.py	Thu May  5 00:07:31 2005
@@ -1,6 +1,7 @@
 from pypy.interpreter import eval, function, gateway
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.typedef import TypeDef, GetSetProperty, Member
+from pypy.interpreter.baseobjspace import SpaceCache
 from pypy.objspace.std.model import MultiMethod, FailedToImplement
 from pypy.tool.compile import compile2
 
@@ -51,43 +52,45 @@
 # the descriptors to put into the W_TypeObjects.
 #
 
-def buildtypeobject(typedef, space):
-    "NOT_RPYTHON: initialization-time only."
-    # build a W_TypeObject from this StdTypeDef
-    from pypy.objspace.std.typeobject import W_TypeObject
-    from pypy.objspace.std.objecttype import object_typedef
-
-    w = space.wrap
-    rawdict = typedef.rawdict
-    lazyloaders = {}
-
-    if isinstance(typedef, StdTypeDef):
-        # get all the sliced multimethods
-        multimethods = slicemultimethods(space, typedef)
-        for name, loader in multimethods.items():
-            if name in rawdict:
-                # the name specified in the rawdict has priority
-                continue
-            assert name not in lazyloaders, (
-                'name clash: %s in %s.lazyloaders' % (name, typedef.name))
-            lazyloaders[name] = loader
-
-    # compute the bases
-    if typedef is object_typedef:
-        bases_w = []
-    else:
-        base = typedef.base or object_typedef
-        bases_w = [space.gettypeobject(base)]
-
-    # wrap everything
-    dict_w = {}
-    for descrname, descrvalue in rawdict.items():
-        dict_w[descrname] = w(descrvalue)
-
-    w_type = W_TypeObject(space, typedef.name, bases_w, dict_w,
-                          overridetypedef=typedef)
-    w_type.lazyloaders = lazyloaders
-    return w_type
+class TypeCache(SpaceCache):
+    def build(cache, typedef):
+        "NOT_RPYTHON: initialization-time only."
+        # build a W_TypeObject from this StdTypeDef
+        from pypy.objspace.std.typeobject import W_TypeObject
+        from pypy.objspace.std.objecttype import object_typedef
+
+        space = cache.space
+        w = space.wrap
+        rawdict = typedef.rawdict
+        lazyloaders = {}
+
+        if isinstance(typedef, StdTypeDef):
+            # get all the sliced multimethods
+            multimethods = slicemultimethods(space, typedef)
+            for name, loader in multimethods.items():
+                if name in rawdict:
+                    # the name specified in the rawdict has priority
+                    continue
+                assert name not in lazyloaders, (
+                    'name clash: %s in %s.lazyloaders' % (name, typedef.name))
+                lazyloaders[name] = loader
+
+        # compute the bases
+        if typedef is object_typedef:
+            bases_w = []
+        else:
+            base = typedef.base or object_typedef
+            bases_w = [space.gettypeobject(base)]
+
+        # wrap everything
+        dict_w = {}
+        for descrname, descrvalue in rawdict.items():
+            dict_w[descrname] = w(descrvalue)
+
+        w_type = W_TypeObject(space, typedef.name, bases_w, dict_w,
+                              overridetypedef=typedef)
+        w_type.lazyloaders = lazyloaders
+        return w_type
 
 def hack_out_multimethods(ns):
     "NOT_RPYTHON: initialization-time only."

Modified: pypy/dist/pypy/tool/cache.py
==============================================================================
--- pypy/dist/pypy/tool/cache.py	(original)
+++ pypy/dist/pypy/tool/cache.py	Thu May  5 00:07:31 2005
@@ -21,18 +21,20 @@
 #     using the information collected by the annotator itself about
 #     what the keys can actually be.
 #
+#     Cache must be subclassed, and a _build() method provided.
+#     Be sure to call the parent __init__() if you override it.
+#
 
 
-class Cache:
+class Cache(object):
     def __init__(self):
         self.content = {}
 
-    def getorbuild(self, key, builder, stuff):
+    def getorbuild(self, key):
         try:
             return self.content[key]
         except KeyError:
-            result = builder(key, stuff)
-            #assert key not in self.content, "things messed up"
+            result = self._build(key)
             self.content[key] = result
             return result
     getorbuild._specialize_ = "memo"

Modified: pypy/dist/pypy/tool/test/test_cache.py
==============================================================================
--- pypy/dist/pypy/tool/test/test_cache.py	(original)
+++ pypy/dist/pypy/tool/test/test_cache.py	Thu May  5 00:07:31 2005
@@ -1,11 +1,22 @@
 import autopath
 from pypy.tool.cache import Cache 
 
+class MyCache(Cache):
+    counter = 0
+    def _build(self, key):
+        self.counter += 1
+        return key*7
+
 class TestCache: 
     def test_getorbuild(self):
-        cache = Cache()
-        assert cache.getorbuild(1, lambda k,s: 42, None) == 42
-        assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 42
-        assert cache.getorbuild(2, lambda k,s: 24, None) == 24
-        assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 42
-        assert cache.getorbuild(2, lambda k,s: self.fail(), None) == 24
+        cache = MyCache()
+        assert cache.getorbuild(1) == 7
+        assert cache.counter == 1
+        assert cache.getorbuild(1) == 7
+        assert cache.counter == 1
+        assert cache.getorbuild(3) == 21
+        assert cache.counter == 2
+        assert cache.getorbuild(1) == 7
+        assert cache.counter == 2
+        assert cache.getorbuild(3) == 21
+        assert cache.counter == 2



More information about the Pypy-commit mailing list