[pypy-svn] r9752 - in pypy/dist/pypy: annotation interpreter tool translator/test

arigo at codespeak.net arigo at codespeak.net
Sat Mar 12 22:01:53 CET 2005


Author: arigo
Date: Sat Mar 12 22:01:53 2005
New Revision: 9752

Modified:
   pypy/dist/pypy/annotation/bookkeeper.py
   pypy/dist/pypy/annotation/model.py
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/interpreter/gateway.py
   pypy/dist/pypy/interpreter/lazymodule.py
   pypy/dist/pypy/tool/cache.py
   pypy/dist/pypy/translator/test/test_annrpython.py
Log:
Added the _freeze_() protocol to help the annotator decide if something is a pre-built constant or a SomeInstance (i.e. holds mutable state).  The method _freeze_() is also a good place for the objects to perform last-minute initialization, e.g. for LazyModule objects.

Added a test for _freeze_().

New method bookkeeper.warning() for all warning-issuing situations of the annotator.


Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py	(original)
+++ pypy/dist/pypy/annotation/bookkeeper.py	Sat Mar 12 22:01:53 2005
@@ -4,6 +4,7 @@
 
 from types import FunctionType, ClassType, MethodType
 from types import BuiltinMethodType
+from pypy.tool.ansi_print import ansi_print
 from pypy.annotation.model import *
 from pypy.annotation.classdef import ClassDef
 from pypy.interpreter.miscutils import getthreadlocals
@@ -29,6 +30,7 @@
         self.userclasseslist = []# userclasses.keys() in creation order
         self.cachespecializations = {}
         self.pbccache = {}
+        self.pbctypes = {}
         # import ordering hack
         global BUILTIN_ANALYZERS
         from pypy.annotation.builtin import BUILTIN_ANALYZERS
@@ -64,6 +66,9 @@
         try:
             return self.userclasses[cls]
         except KeyError:
+            if cls in self.pbctypes:
+                self.warning("%r gets a ClassDef, but is the type of some PBC"
+                             % (cls,))
             cdef = ClassDef(cls, self)
             self.userclasses[cls] = cdef
             self.userclasseslist.append(cdef)
@@ -94,9 +99,8 @@
         elif callable(x) or isinstance(x, staticmethod): # XXX
             # maybe 'x' is a method bound to a not-yet-frozen cache?
             # fun fun fun.
-            if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache)
-                and not x.im_self.frozen):
-                x.im_self.freeze()
+            if hasattr(x, 'im_self') and hasattr(x.im_self, '_freeze_'):
+                x.im_self._freeze_()
             if hasattr(x, '__self__') and x.__self__ is not None:
                 s_self = self.immutablevalue(x.__self__)
                 try:
@@ -107,9 +111,18 @@
                 return self.getpbc(x)
         elif hasattr(x, '__class__') \
                  and x.__class__.__module__ != '__builtin__':
-            if isinstance(x, Cache) and not x.frozen:
-                x.freeze()
-            return self.getpbc(x)
+            # 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().
+            frozen = hasattr(x, '_freeze_') and x._freeze_()
+            if frozen:
+                return self.getpbc(x)
+            else:
+                clsdef = self.getclassdef(x.__class__)
+                for attr in x.__dict__:
+                    clsdef.add_source_for_attribute(attr, x)
+                return SomeInstance(clsdef)
         elif x is None:
             return self.getpbc(None)
         else:
@@ -124,15 +137,22 @@
             return self.pbccache[x]
         except KeyError:
             result = SomePBC({x: True}) # pre-built inst
-            clsdef = self.getclassdef(new_or_old_class(x))
-            for attr in getattr(x, '__dict__', {}):
-                clsdef.add_source_for_attribute(attr, x)
+            #clsdef = self.getclassdef(new_or_old_class(x))
+            #for attr in getattr(x, '__dict__', {}):
+            #    clsdef.add_source_for_attribute(attr, x)
             self.pbccache[x] = result
+            cls = new_or_old_class(x)
+            if cls not in self.pbctypes:
+                self.pbctypes[cls] = True
+                if cls in self.userclasses:
+                    self.warning("making some PBC of type %r, which has "
+                                 "already got a ClassDef" % (cls,))
             return result
 
     def valueoftype(self, t):
         """The most precise SomeValue instance that contains all
         objects of type t."""
+        assert isinstance(t, (type, ClassType))
         if t is bool:
             return SomeBool()
         elif t is int:
@@ -142,8 +162,7 @@
         elif t is list:
             return SomeList(factories={})
         # can't do dict, tuple
-        elif isinstance(t, (type, ClassType)) and \
-                 t.__module__ != '__builtin__':
+        elif t.__module__ != '__builtin__':
             classdef = self.getclassdef(t)
             return SomeInstance(classdef)
         else:
@@ -246,6 +265,13 @@
     def whereami(self):
         return self.annotator.whereami(self.position_key)
 
+    def warning(self, msg):
+        try:
+            pos = self.whereami()
+        except AttributeError:
+            pos = '?'
+        ansi_print("*** WARNING: [%s] %s" % (pos, msg), esc="31") # RED
+
     def specialize_by_key(self, thing, key, name=None):
         key = thing, key
         try:

Modified: pypy/dist/pypy/annotation/model.py
==============================================================================
--- pypy/dist/pypy/annotation/model.py	(original)
+++ pypy/dist/pypy/annotation/model.py	Sat Mar 12 22:01:53 2005
@@ -32,7 +32,6 @@
 import pypy
 from pypy.annotation.pairtype import pair, extendabletype
 from pypy.objspace.flow.model import Constant
-from pypy.tool.cache import Cache 
 import inspect
 
 

Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Sat Mar 12 22:01:53 2005
@@ -3,7 +3,6 @@
 """
 
 from types import FunctionType
-from pypy.tool.ansi_print import ansi_print
 from pypy.interpreter.argument import Arguments
 from pypy.annotation.pairtype import pair
 from pypy.annotation.model import SomeObject, SomeInteger, SomeBool
@@ -90,8 +89,7 @@
 
     def call(obj, args):
         #raise Exception, "cannot follow call_args%r" % ((obj, args),)
-        ansi_print("*** WARNING: [%s] cannot follow call(%r, %r)" %
-                   (getbookkeeper().whereami(), obj, args), esc="31") # RED
+        getbookkeeper().warning("cannot follow call(%r, %r)" % (obj, args))
         return SomeObject()
 
 class __extend__(SomeInteger):
@@ -238,17 +236,14 @@
         for c in pbc.prebuiltinstances:
             if hasattr(c, attr):
                 # force the attribute to be considered on the class
-                classdef = bookkeeper.getclassdef(new_or_old_class(c))
-                classdef.find_attribute(attr).getvalue()
+                ##classdef = bookkeeper.getclassdef(new_or_old_class(c))
+                ##classdef.find_attribute(attr).getvalue()
                 # but only return the more precise result getattr(c, attr)
                 actuals.append(immutablevalue(getattr(c, attr)))
         return unionof(*actuals)
 
     def setattr(pbc, s_attr, s_value):
-        #raise Exception, "oops!"
-        ansi_print("*** WARNING: [%s] setattr not wanted on %r" %
-                   (getbookkeeper().whereami(), pbc), esc="31") # RED
-        pass
+        getbookkeeper().warning("setattr not wanted on %r" % (pbc,))
 
     def call(pbc, args):
         bookkeeper = getbookkeeper()
@@ -269,9 +264,9 @@
         d = {}
         for func, value in pbc.prebuiltinstances.items():
             if isinstance(func, FunctionType): 
-                if isclassdef(value): 
-                    print ("!!! rebinding an already bound"
-                           " method %r with %r" % (func, value))
+                if isclassdef(value):
+                    getbookkeeper().warning("rebinding an already bound "
+                                            "method %r with %r" % (func, value))
                 d[func] = classdef
             elif isinstance(func, staticmethod):
                 d[func.__get__(43)] = value

Modified: pypy/dist/pypy/interpreter/gateway.py
==============================================================================
--- pypy/dist/pypy/interpreter/gateway.py	(original)
+++ pypy/dist/pypy/interpreter/gateway.py	Sat Mar 12 22:01:53 2005
@@ -522,6 +522,9 @@
         appcaller.get_function = get_function
         return appcaller
 
+    def _freeze_(self):
+        return True  # hint for the annotator: applevel instances are constants
+
 ## XXX experimental code using geninterplevel
 
 class applevelinterp(applevel):

Modified: pypy/dist/pypy/interpreter/lazymodule.py
==============================================================================
--- pypy/dist/pypy/interpreter/lazymodule.py	(original)
+++ pypy/dist/pypy/interpreter/lazymodule.py	Sat Mar 12 22:01:53 2005
@@ -54,6 +54,12 @@
             self.lazy = False 
         return self.w_dict 
 
+    def _freeze_(self):
+        self.getdict()
+        # hint for the annotator: Modules can hold state, so they are
+        # not constant
+        return False
+
     def buildloaders(cls): 
         """ NOT_RPYTHON """ 
         if not hasattr(cls, 'loaders'): 

Modified: pypy/dist/pypy/tool/cache.py
==============================================================================
--- pypy/dist/pypy/tool/cache.py	(original)
+++ pypy/dist/pypy/tool/cache.py	Sat Mar 12 22:01:53 2005
@@ -32,4 +32,10 @@
     getorbuild._specialize_ = "location"
 
     def freeze(self):
-        del self.frozen 
+        try:
+            del self.frozen
+        except AttributeError:
+            pass
+        return True
+
+    _freeze_ = freeze

Modified: pypy/dist/pypy/translator/test/test_annrpython.py
==============================================================================
--- pypy/dist/pypy/translator/test/test_annrpython.py	(original)
+++ pypy/dist/pypy/translator/test/test_annrpython.py	Sat Mar 12 22:01:53 2005
@@ -594,6 +594,25 @@
         assert isinstance(s, annmodel.SomeInstance)
         assert s.knowntype is snippet.Exc
 
+    def test_freeze_protocol(self):
+        class Stuff:
+            def __init__(self, flag):
+                self.called = False
+                self.flag = flag
+            def _freeze_(self):
+                self.called = True
+                return self.flag
+        myobj = Stuff(True)
+        a = RPythonAnnotator()
+        s = a.build_types(lambda: myobj, [])
+        assert myobj.called
+        assert s == annmodel.SomePBC({myobj: True})
+        myobj = Stuff(False)
+        a = RPythonAnnotator()
+        s = a.build_types(lambda: myobj, [])
+        assert myobj.called
+        assert s == annmodel.SomeInstance(a.bookkeeper.getclassdef(Stuff))
+
 
 def g(n):
     return [0,1,2,n]



More information about the Pypy-commit mailing list