[pypy-svn] r11933 - in pypy/dist/pypy: annotation tool tool/test

arigo at codespeak.net arigo at codespeak.net
Wed May 4 14:53:49 CEST 2005


Author: arigo
Date: Wed May  4 14:53:49 2005
New Revision: 11933

Modified:
   pypy/dist/pypy/annotation/bookkeeper.py
   pypy/dist/pypy/tool/cache.py
   pypy/dist/pypy/tool/test/test_cache.py
Log:
Trying a _specialize_="memo" function attribute for the annotator...


Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py	(original)
+++ pypy/dist/pypy/annotation/bookkeeper.py	Wed May  4 14:53:49 2005
@@ -2,6 +2,7 @@
 The Bookkeeper class.
 """
 
+from __future__ import generators
 from types import FunctionType, ClassType, MethodType
 from types import BuiltinMethodType
 from pypy.tool.ansi_print import ansi_print
@@ -319,6 +320,16 @@
             elif specialize == "location":
                 # fully specialize: create one version per call position
                 func = self.specialize_by_key(func, self.position_key)
+            elif specialize == "memo":
+                # call the function now, and collect possible results
+                arglist_s, kwds_s = args.unpack()
+                assert not kwds_s, ("no ** args in call to function "
+                                    "marked specialize='concrete'")
+                possible_results = []
+                for arglist in possible_arguments(arglist_s):
+                    result = func(*arglist)
+                    possible_results.append(self.immutablevalue(result))
+                return unionof(*possible_results)
             else:
                 raise Exception, "unsupported specialization type '%s'"%(specialize,)
 
@@ -412,7 +423,7 @@
                 raise Exception, "specializing %r?? why??"%thing
             self.cachespecializations[key] = thing
         return thing
-        
+
 
 def getbookkeeper():
     """Get the current Bookkeeper.
@@ -440,3 +451,24 @@
             name = x.__class__.__name__
         l.append(name)
     return "__".join(l)
+
+def possible_arguments(args):
+    # enumerate all tuples (x1,..xn) of concrete values that are contained
+    # in a tuple args=(s1,..sn) of SomeXxx.  Requires that each s be either
+    # a constant or SomePBC.
+    if not args:
+        yield ()
+        return
+    s = args[0]
+    if s.is_constant():
+        possible_values = [s.const]
+    elif isinstance(s, SomePBC):
+        for value in s.prebuiltinstances.values():
+            assert value is True, ("concrete call with a method bound "
+                                   "on a non-constant instance")
+        possible_values = s.prebuiltinstances.keys()
+    else:
+        raise AssertionError, "concrete call with a non-constant arg %r" % (s,)
+    for tuple_tail in possible_arguments(args[1:]):
+        for value in possible_values:
+            yield (value,) + tuple_tail

Modified: pypy/dist/pypy/tool/cache.py
==============================================================================
--- pypy/dist/pypy/tool/cache.py	(original)
+++ pypy/dist/pypy/tool/cache.py	Wed May  4 14:53:49 2005
@@ -1,41 +1,38 @@
+"""
+Caches that can freeze when the annotator needs it.
+"""
+
+#
+# _freeze_() protocol:
+#     user-defined classes can define a method _freeze_(), which
+#     is called when a prebuilt instance is found.  If the method
+#     returns True, the instance is considered immutable and becomes
+#     a SomePBC().  Otherwise it's just SomeInstance().  The method
+#     should force away any laziness that remains in the instance.
+#
+# Cache class:
+#     a cache meant to map a finite number of keys to values.
+#     It is normally extended lazily, until it contains all possible
+#     keys.  The _specialize_ attribute of the getorbuild() method
+#     forces the annotator to decode the argument's annotations,
+#     which must be constants or SomePBCs, actually call the
+#     method with all possible combinations, and gather the results.
+#     The idea is to completely fill the cache at annotation-time,
+#     using the information collected by the annotator itself about
+#     what the keys can actually be.
+#
 
-# hacks += 1
-class Cache:
-    frozen = True 
 
+class Cache:
     def __init__(self):
         self.content = {}
-        self.frozen = False
-
-    def __hash__(self):
-        if not self.frozen: 
-            #raise TypeError, "cannot get hash of un-frozen cache"
-            self.freeze()
-        return id(self)
-
-    def clear(self):
-        if self.frozen:
-            raise TypeError, "cannot clear frozen cache"
-        self.content.clear()
 
     def getorbuild(self, key, builder, stuff):
         try:
             return self.content[key]
         except KeyError:
-            assert not self.frozen, "cannot build %r, cache already frozen" % key
             result = builder(key, stuff)
             #assert key not in self.content, "things messed up"
             self.content[key] = result
             return result
-    # note to annotator: we want loadfromcache() to be 
-    # specialized for the different cache types 
-    getorbuild._specialize_ = "location"
-
-    def freeze(self):
-        try:
-            del self.frozen
-        except AttributeError:
-            pass
-        return True
-
-    _freeze_ = freeze
+    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	Wed May  4 14:53:49 2005
@@ -6,15 +6,6 @@
         cache = Cache()
         assert cache.getorbuild(1, lambda k,s: 42, None) == 42
         assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 42
-        # XXX   cannot test that any longer:
-        # XXX   hash(cache) now freezes the cache "just-in-time".
-        # XXX      --disabled-- self.assertRaises(TypeError, hash, cache)
-        cache.clear()
-        assert cache.getorbuild(1, lambda k,s: 44, None) == 44
-        assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 44
-        cache.freeze()
-        hash(cache)
-        assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 44
-        raises(TypeError, cache.clear)
-        raises(AssertionError, cache.getorbuild,
-                          2, lambda k,s: self.fail(), 4)
+        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



More information about the Pypy-commit mailing list