[pypy-svn] r7360 - in pypy/trunk/src: goal pypy/annotation pypy/interpreter pypy/interpreter/test pypy/objspace/flow pypy/objspace/std pypy/tool pypy/tool/test

hpk at codespeak.net hpk at codespeak.net
Thu Nov 18 11:18:30 CET 2004


Author: hpk
Date: Thu Nov 18 11:18:30 2004
New Revision: 7360

Added:
   pypy/trunk/src/pypy/tool/cache.py
      - copied, changed from r7351, pypy/trunk/src/pypy/tool/frozendict.py
   pypy/trunk/src/pypy/tool/test/test_cache.py
Removed:
   pypy/trunk/src/pypy/tool/frozendict.py
Modified:
   pypy/trunk/src/goal/buildcache.py
   pypy/trunk/src/goal/translate_pypy.py
   pypy/trunk/src/pypy/annotation/model.py
   pypy/trunk/src/pypy/interpreter/baseobjspace.py
   pypy/trunk/src/pypy/interpreter/gateway.py
   pypy/trunk/src/pypy/interpreter/pycode.py
   pypy/trunk/src/pypy/interpreter/pyopcode.py
   pypy/trunk/src/pypy/interpreter/test/test_code.py
   pypy/trunk/src/pypy/objspace/flow/specialcase.py
   pypy/trunk/src/pypy/objspace/std/fake.py
   pypy/trunk/src/pypy/objspace/std/multimethod.py
   pypy/trunk/src/pypy/objspace/std/objspace.py
Log:

frozendict is dead, long live the freezable Cache class. 

for any code reachable by the annotator/translator you need to/should 
use pypy.tool.cache.Cache().  When the annotator sees such a
cache it calls the "freeze()" method on it after which it cannot be
modified anymore and also becomes hashable as a side effect. 

A Cache has a getorbuild() method where you pass in a key, a builder
and a space. In case the key is not in the cache yet and the cache
is not frozen, builder(key, space) will be called to obtain the 
value. 

Various places now use Cache instead of plain dictionaries. 



Modified: pypy/trunk/src/goal/buildcache.py
==============================================================================
--- pypy/trunk/src/goal/buildcache.py	(original)
+++ pypy/trunk/src/goal/buildcache.py	Thu Nov 18 11:18:30 2004
@@ -1,6 +1,5 @@
 from pypy.tool import option, autopath, testit
 from pypy.interpreter import gateway 
-from pypy.tool.frozendict import frozendict 
 import os
 
 #######################################################
@@ -32,14 +31,21 @@
 gateway.importall(globals())   # app_xxx() -> xxx()
 
 #######################################################
+from pypy.objspace.std import stdtypedef
     
 def buildcache(space): 
     print "triggering cache build for %r" % space 
     triggerall(space) 
     triggerexec(space)
-    space._typecache = frozendict(space._typecache) 
-    space._faketypecache = frozendict(space._faketypecache) 
-    space._gatewaycache = frozendict(space._gatewaycache) 
+    #testit.main(os.path.join(autopath.pypydir, 'objspace', 'std'))
+    #Cache.freeze()
+    #space._typecache = frozendict(space._typecache) 
+    #space._faketypecache = frozendict(space._faketypecache) 
+    #space._gatewaycache = frozendict(space._gatewaycache) 
+    #space = option.objspace('std')
+    #buildcache(space)
+    #for x in  stdtypedef._temp:
+    #    x.cache_table = frozendict(x.cache_table)
     print "cache build finished, caches are 'frozen' now"
 
 if __name__ == '__main__': 

Modified: pypy/trunk/src/goal/translate_pypy.py
==============================================================================
--- pypy/trunk/src/goal/translate_pypy.py	(original)
+++ pypy/trunk/src/goal/translate_pypy.py	Thu Nov 18 11:18:30 2004
@@ -6,9 +6,9 @@
 from pypy.objspace.std.intobject import W_IntObject
 from pypy.translator.translator import Translator
 from pypy.annotation import model as annmodel
+from pypy.tool.cache import Cache
 
-import buildcache 
-
+#from buildcache import buildcache
 # __________  Entry point  __________
 
 def entry_point():
@@ -22,12 +22,13 @@
 def analyse(entry_point=entry_point):
     global t, space
     space = StdObjSpace()
-    buildcache.buildcache(space) 
+    # call the entry_point once to trigger building of all 
+    # caches (as far as analyzing the entry_point is concerned) 
+    entry_point() 
     t = Translator(entry_point, verbose=True, simplifying=True)
     a = t.annotate([])
     a.simplify()
 
-
 if __name__ == '__main__':
 
     def about(x):

Modified: pypy/trunk/src/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/model.py	(original)
+++ pypy/trunk/src/pypy/annotation/model.py	Thu Nov 18 11:18:30 2004
@@ -33,6 +33,7 @@
 import pypy
 from pypy.annotation.pairtype import pair, extendabletype
 from pypy.objspace.flow.model import Constant
+from pypy.tool.cache import Cache 
 
 class SomeObject:
     """The set of all objects.  Each instance stands
@@ -215,6 +216,8 @@
         else:
             result = SomeCallable({x : True})
     elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__':
+        if isinstance(x, Cache) and not x.frozen:
+            x.freeze()
         result = SomePrebuiltConstant({x: True}) # pre-built inst:
     else:
         result = SomeObject()

Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/src/pypy/interpreter/baseobjspace.py	Thu Nov 18 11:18:30 2004
@@ -2,7 +2,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.miscutils import getthreadlocals
 from pypy.interpreter.argument import Arguments
-from pypy.tool.frozendict import frozendict 
+from pypy.tool.cache import Cache 
 
 __all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'BaseWrappable',
            'W_Root']
@@ -33,21 +33,10 @@
 
     def __init__(self):
         "Basic initialization of objects."
-        self._gatewaycache = {}
+        self._gatewaycache = Cache()
         # sets all the internal descriptors
         self.initialize()
 
-    def loadfromcache(self, key, builder, cache):
-        try:
-            return cache[key]
-        except KeyError:
-            assert not isinstance(cache, frozendict)
-            #print "building for key %r" % key 
-            return cache.setdefault(key, builder(key, self))
-    # note to annotator: we want loadfromcache() to be 
-    # specialized for the different cache types 
-    loadfromcache.specialize = True 
-
     def make_builtins(self, for_builtins):
         # initializing builtins may require creating a frame which in
         # turn already accesses space.w_builtins, provide a dummy one ...
@@ -101,6 +90,10 @@
         """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 = True 
+
     def getexecutioncontext(self):
         "Return what we consider to be the active execution context."
         ec = getthreadlocals().executioncontext

Modified: pypy/trunk/src/pypy/interpreter/gateway.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/gateway.py	(original)
+++ pypy/trunk/src/pypy/interpreter/gateway.py	Thu Nov 18 11:18:30 2004
@@ -15,7 +15,7 @@
 from pypy.interpreter.function import Function, Method
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.argument import Arguments
-
+from pypy.tool.cache import Cache 
 
 class BuiltinCode(eval.Code):
     "The code object implementing a built-in (interpreter-level) hook."
@@ -358,10 +358,10 @@
 # temporary/initialization purposes 
 class app2interp_temp(app2interp): 
     def getcache(self, space): 
-        return self.__dict__.setdefault(space, {}) 
+        return self.__dict__.setdefault(space, Cache())
         #                               ^^^^^
         #                          armin suggested this 
      
 class interp2app_temp(interp2app): 
     def getcache(self, space): 
-        return self.__dict__.setdefault(space, {}) 
+        return self.__dict__.setdefault(space, Cache())

Modified: pypy/trunk/src/pypy/interpreter/pycode.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pycode.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pycode.py	Thu Nov 18 11:18:30 2004
@@ -6,6 +6,7 @@
 
 import dis
 from pypy.interpreter import eval
+from pypy.tool.cache import Cache 
 
 # code object contants, for co_flags below
 CO_OPTIMIZED    = 0x0001
@@ -130,7 +131,7 @@
             code.co_cellvars = space.unwrap(w_cellvars)
         return space.wrap(code)
 
-def enhanceclass(baseclass, newclass, cache={}):
+def enhanceclass(baseclass, newclass, cache=Cache()):
     # this is a bit too dynamic for RPython, but it looks nice
     # and I assume that we can easily change it into a static
     # pre-computed table
@@ -140,20 +141,8 @@
         try:
             return cache[baseclass, newclass]
         except KeyError:
+            assert not cache.frozen 
             class Mixed(newclass, baseclass):
                 pass
             cache[baseclass, newclass] = Mixed
             return Mixed
-
-def keys():
-    from pypy.interpreter.pyopcode import PyInterpFrame as Frame
-    from pypy.interpreter.nestedscope import PyNestedScopeFrame
-    from pypy.interpreter.generator import GeneratorFrame 
-
-    return [
-         (Frame, PyNestedScopeFrame), 
-         (Frame, GeneratorFrame), 
-         (enhanceclass(Frame, PyNestedScopeFrame), GeneratorFrame), 
-        ]
-
-enhanceclass.keys = keys 

Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pyopcode.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pyopcode.py	Thu Nov 18 11:18:30 2004
@@ -342,7 +342,7 @@
         w_globals = f.valuestack.pop()
         w_prog    = f.valuestack.pop()
         w_resulttuple = f.prepare_exec(w_prog, w_globals, w_locals)
-        w_prog, w_globals, w_locals = f.space.unpacktuple(w_resulttuple)
+        w_prog, w_globals, w_locals = f.space.unpacktuple(w_resulttuple, 3)
 
         plain = f.space.is_true(f.space.is_(w_locals, f.w_locals))
         if plain:

Modified: pypy/trunk/src/pypy/interpreter/test/test_code.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/test/test_code.py	(original)
+++ pypy/trunk/src/pypy/interpreter/test/test_code.py	Thu Nov 18 11:18:30 2004
@@ -92,15 +92,5 @@
         exec co in d
         self.assertEquals(d['c'], 3)
 
-class TestCodeEnhanceClass(testit.IntTestCase):
-    def test_enhanceclass_for_translator(self):
-        from pypy.interpreter.pycode import enhanceclass
-        assert hasattr(enhanceclass, 'keys')
-        arglist = enhanceclass.keys() 
-        for args in arglist: 
-            enhanceclass(*args)
-        
-        
-
 if __name__ == '__main__':
     testit.main()

Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/specialcase.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/specialcase.py	Thu Nov 18 11:18:30 2004
@@ -43,15 +43,6 @@
     # this function returns a real tuple that can be handled
     # by FlowObjSpace.unpacktuple()
 
-def loadfromcache(space, args):
-    # XXX need some way to know how to fully initialize the cache
-    print space, args
-    assert len(args.args_w) == 2 and args.kwds_w == {}
-    w_key, w_builder = args.args_w
-    w_cache = Constant('space_cache')   # temporary
-    return space.do_operation('getitem', w_cache, w_key)
-
-
 def import_(space, args):
     assert len(args.args_w) == 4 and args.kwds_w == {}
     unwrapped_args = []
@@ -63,6 +54,4 @@
 def setup(space):
     fn = pyframe.normalize_exception.get_function(space)
     space.specialcases[fn] = normalize_exception
-    fn = baseobjspace.ObjSpace.loadfromcache.im_func
-    space.specialcases[fn] = loadfromcache
     space.specialcases[__import__] = import_

Modified: pypy/trunk/src/pypy/objspace/std/fake.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/fake.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/fake.py	Thu Nov 18 11:18:30 2004
@@ -4,6 +4,7 @@
 from pypy.objspace.std.stdtypedef import *
 from pypy.objspace.std.objspace import W_Object, StdObjSpace
 from pypy.objspace.std.default 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
@@ -11,7 +12,7 @@
 
 import sys
 
-_fake_type_cache = {}
+_fake_type_cache = Cache()
 
 # real-to-wrapped exceptions
 def wrap_exception(space):
@@ -35,6 +36,7 @@
     assert type(cpy_type) is type
     if cpy_type in _fake_type_cache:
         return _fake_type_cache[cpy_type]
+    assert not _fake_type_cache.frozen 
     print 'faking %r'%(cpy_type,)
     kw = {}
     for s, v in cpy_type.__dict__.items():

Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/multimethod.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/multimethod.py	Thu Nov 18 11:18:30 2004
@@ -1,6 +1,5 @@
 from pypy.interpreter.baseobjspace import OperationError
-from pypy.tool.frozendict import frozendict
-
+from pypy.tool.cache import Cache 
 
 class FailedToImplement(Exception):
     "Signals the dispatcher to try harder."
@@ -43,7 +42,7 @@
         self.arity = arity
         self.operatorsymbol = operatorsymbol
         self.dispatch_table = {}
-        self.cache_table = {}
+        self.cache_table = Cache()
         self.cache_delegator_key = None
         self.dispatch_arity = 0
 
@@ -76,7 +75,7 @@
         try:
             return self.cache_table[argclasses]
         except KeyError:
-            assert not isinstance(self.cache_table, frozendict)
+            assert not self.cache_table.frozen 
             calllist = []
             self.internal_buildcalllist(argclasses, delegate, calllist)
             result = self.internal_compilecalllist(argclasses, calllist)

Modified: pypy/trunk/src/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/objspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/objspace.py	Thu Nov 18 11:18:30 2004
@@ -2,6 +2,7 @@
 from pypy.interpreter.baseobjspace import *
 from pypy.interpreter.typedef import get_unique_interplevel_subclass
 from pypy.interpreter.typedef import instantiate
+from pypy.tool.cache import Cache 
 from pypy.objspace.std.multimethod import *
 from pypy.objspace.descroperation import DescrOperation
 from pypy.objspace.std import stdtypedef
@@ -135,8 +136,8 @@
         return done
                             
     def initialize(self):
-        self._typecache = {}
-        self._faketypecache = {}
+        self._typecache = Cache()
+        self._faketypecache = Cache()
 
         # The object implementations that we want to 'link' into PyPy must be
         # imported here.  This registers them into the multimethod tables,

Copied: pypy/trunk/src/pypy/tool/cache.py (from r7351, pypy/trunk/src/pypy/tool/frozendict.py)
==============================================================================
--- pypy/trunk/src/pypy/tool/frozendict.py	(original)
+++ pypy/trunk/src/pypy/tool/cache.py	Thu Nov 18 11:18:30 2004
@@ -1,16 +1,36 @@
 
+class basecache(dict): 
+    pass
+
 # hacks += 1
-class frozendict(dict):
-    _hash_cache = None
-    def __setitem__(self, *args):
-        raise TypeError, "this dict is already frozen, you are too late!" 
-    __delitem__ = setdefault = update = pop = popitem = clear = __setitem__
+class Cache(dict):
+    frozen = True 
+
+    def __init__(self, *args):  
+        self.frozen = False
+        dict.__init__(self, *args) 
 
+    for x in ('__setitem__', '__delitem__', 'setdefault', 'update',
+              'pop', 'popitem', 'clear'):
+        l=["def %s(self, *args):",
+           "   assert not self.frozen, 'cache already frozen'",
+           "   return dict.%s(self, *args)"]
+        exec "\n".join(l) % (x,x)
+         
     def __hash__(self):
-        rval = self._hash_cache
-        if rval is None:
-            dct = self.items()
-            dct.sort()
-            rval = self._hash_cache = hash(tuple(dct)) ^ 0x18293742
-        return rval
+        if not self.frozen: 
+            raise TypeError, "cannot get hash of un-frozen cache"
+        return id(self) 
+
+    def getorbuild(self, key, builder, space):
+        try:
+            return self[key]
+        except KeyError:
+            assert not self.frozen, "cannot build %r, cache already frozen" % key
+            return self.setdefault(key, builder(key, space))
+    # note to annotator: we want loadfromcache() to be 
+    # specialized for the different cache types 
+    getorbuild.specialize = True 
 
+    def freeze(self):
+        del self.frozen 

Deleted: /pypy/trunk/src/pypy/tool/frozendict.py
==============================================================================
--- /pypy/trunk/src/pypy/tool/frozendict.py	Thu Nov 18 11:18:30 2004
+++ (empty file)
@@ -1,16 +0,0 @@
-
-# hacks += 1
-class frozendict(dict):
-    _hash_cache = None
-    def __setitem__(self, *args):
-        raise TypeError, "this dict is already frozen, you are too late!" 
-    __delitem__ = setdefault = update = pop = popitem = clear = __setitem__
-
-    def __hash__(self):
-        rval = self._hash_cache
-        if rval is None:
-            dct = self.items()
-            dct.sort()
-            rval = self._hash_cache = hash(tuple(dct)) ^ 0x18293742
-        return rval
-

Added: pypy/trunk/src/pypy/tool/test/test_cache.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/tool/test/test_cache.py	Thu Nov 18 11:18:30 2004
@@ -0,0 +1,17 @@
+import autopath
+import unittest
+from pypy.tool.cache import Cache 
+
+class TestCache(unittest.TestCase): 
+    def test_getorbuild(self):
+        cache = Cache()
+        cache.getorbuild(1, lambda k,s: 42, None)
+        assert 1 in cache 
+        assert cache[1] == 42 
+        assert cache.getorbuild(1, lambda k,s: 44, None) == 42 
+        self.assertRaises(TypeError, hash, cache)
+        cache.freeze()
+        hash(cache) 
+   
+if __name__ == '__main__':
+    unittest.main() 



More information about the Pypy-commit mailing list