[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