[pypy-svn] r13058 - in pypy/dist/pypy: annotation translator translator/test

pedronis at codespeak.net pedronis at codespeak.net
Sat Jun 4 18:28:53 CEST 2005


Author: pedronis
Date: Sat Jun  4 18:28:53 2005
New Revision: 13058

Modified:
   pypy/dist/pypy/annotation/bookkeeper.py
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/translator/annrpython.py
   pypy/dist/pypy/translator/test/test_annrpython.py
Log:
for less confusion and presision move pbc call sites info computation at fix-point.



Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py	(original)
+++ pypy/dist/pypy/annotation/bookkeeper.py	Sat Jun  4 18:28:53 2005
@@ -64,8 +64,13 @@
         self.argtypes_spec_callsite_results = {}
 
         self.pbc_maximal_access_sets = UnionFind(PBCAccessSet)
-        self.pbc_maximal_call_families = UnionFind(PBCCallFamily)
-        self.pbc_callables = {}
+        # can be precisely computed only at fix-point, see
+        # compute_at_fixpoint
+        self.pbc_maximal_call_families = None
+        self.pbc_callables = None
+        
+        self.pbc_call_sites = {}
+
         
         # import ordering hack
         global BUILTIN_ANALYZERS
@@ -82,6 +87,15 @@
         del TLS.bookkeeper
         del self.position_key
 
+    def compute_at_fixpoint(self):
+        self.pbc_maximal_call_families = UnionFind(PBCCallFamily)
+        self.pbc_callables = {}
+
+        for (fn, block, i), shape in self.pbc_call_sites.iteritems():
+            assert block.operations[i].opname in ('call_args', 'simple_call')
+            pbc = self.annotator.binding(block.operations[i].args[0], extquery=True)
+            self.consider_pbc_call(pbc, shape, position=(fn, block, i))
+
     def getclassdef(self, cls):
         """Get the ClassDef associated with the given user cls."""
         if cls is object:
@@ -298,38 +312,33 @@
                 
         return unionof(*actuals)        
 
-    def mark_callable(self, callable):
-        classdef, func = callable
-        
-        if hasattr(func, 'im_func') and func.im_self is None:
-            # consider unbound methods and the undelying functions as the same
-            func = func.im_func
-
-        self.pbc_callables.setdefault(func,{})[callable] = True
+    def consider_pbc_call(self, pbc, shape, position=None): # computation done at fix-point
+        if not isinstance(pbc, SomePBC):
+            return
 
-    def pbc_call(self, pbc, args):
         nonnullcallables = []
-        patterns = {}
-        results = []
-        # extract args shape
-        shape = args.rawshape()
-        
         for func, classdef in pbc.prebuiltinstances.items():
             if func is None:
                 continue
-            if isclassdef(classdef): 
-                s_self = SomeInstance(classdef)
-                args1 = args.prepend(s_self)
-            else:
+            if not isclassdef(classdef): 
                 classdef = None
-                args1 = args
-            results.append(self.pycall(func, args1))
+
+            # if class => consider __init__ too
+            if isinstance(func, (type, ClassType)) and \
+                    func.__module__ != '__builtin__':
+                assert classdef is None
+                dontcare, s_init = self.get_s_init(func, position=position)
+                if s_init is not None:
+                    init_shape = (shape[0]+1,) + shape[1:]
+                    self.consider_pbc_call(s_init, init_shape) 
 
             callable = (classdef, func)
-            self.mark_callable(callable)
+            if hasattr(func, 'im_func') and func.im_self is None:
+                # consider unbound methods and the undelying functions as the same
+                func = func.im_func
+            self.pbc_callables.setdefault(func,{})[callable] = True
             nonnullcallables.append(callable)
-            patterns[shape] = True
-        
+
         if nonnullcallables:
             call_families = self.pbc_maximal_call_families
 
@@ -337,46 +346,77 @@
             for obj in nonnullcallables:
                     dontcare, rep, callfamily = call_families.union(rep, obj)
 
-            callfamily.patterns.update(patterns)             
+            callfamily.patterns.update({shape: True})
+ 
+    def pbc_call(self, pbc, args, implicit_init):
+        if not implicit_init:
+            fn, block, i = self.position_key
+            assert block.operations[i].opname in ('call_args', 'simple_call')
+            assert self.annotator.binding(block.operations[i].args[0], extquery=True) is pbc
+            
+            # extract shape from args
+            shape = args.rawshape()
+            if self.position_key in self.pbc_call_sites:
+                assert self.pbc_call_sites[self.position_key] == shape
+            else:
+                self.pbc_call_sites[self.position_key] = shape
+
+        results = []        
+        for func, classdef in pbc.prebuiltinstances.items():
+            if func is None:
+                continue
+            if isclassdef(classdef): 
+                s_self = SomeInstance(classdef)
+                args1 = args.prepend(s_self)
+            else:
+                args1 = args
+            results.append(self.pycall(func, args1))
 
         return unionof(*results) 
 
+    def get_s_init(self, cls, position=None):
+        specialize = getattr(cls, "_specialize_", False)
+        if specialize:
+            if specialize == "location":
+                cls = self.specialize_by_key(cls, position, 
+                                             name="%s__At_%s" % (cls.__name__, 
+                                                                 position_name(position)))
+            else:
+                raise Exception, \
+                      "unsupported specialization type '%s'"%(specialize,)
+
+        classdef = self.getclassdef(cls)
+        init = getattr(cls, '__init__', None)
+        if init is not None and init != object.__init__:
+            # don't record the access of __init__ on the classdef
+            # because it is not a dynamic attribute look-up, but
+            # merely a static function call
+            if hasattr(init, 'im_func'):
+                init = init.im_func
+            else:
+                assert isinstance(init, BuiltinMethodType)
+            s_init = self.immutablevalue(init)
+            return classdef, s_init
+        else:
+            return classdef, None
+ 
     def pycall(self, func, args):
         if func is None:   # consider None as a NULL function pointer
             return SomeImpossibleValue()
         if isinstance(func, (type, ClassType)) and \
             func.__module__ != '__builtin__':
-            cls = func
-            specialize = getattr(cls, "_specialize_", False)
-            if specialize:
-                if specialize == "location":
-                    cls = self.specialize_by_key(cls, self.position_key, 
-                                                 name="%s__At_%s" % (cls.__name__, 
-                                                                     position_name(self.position_key)))
-                else:
-                    raise Exception, \
-                          "unsupported specialization type '%s'"%(specialize,)
-
-            classdef = self.getclassdef(cls)
+            classdef, s_init = self.get_s_init(func, position=self.position_key)
             s_instance = SomeInstance(classdef)
             # flow into __init__() if the class has got one
-            init = getattr(cls, '__init__', None)
-            if init is not None and init != object.__init__:
-                # don't record the access of __init__ on the classdef
-                # because it is not a dynamic attribute look-up, but
-                # merely a static function call
-                if hasattr(init, 'im_func'):
-                    init = init.im_func
-                else:
-                    assert isinstance(init, BuiltinMethodType)
-                s_init = self.immutablevalue(init)
-                s_init.call(args.prepend(s_instance))
+            if s_init is not None:
+                s_init.call(args.prepend(s_instance), implicit_init=True)
             else:
                 try:
                     args.fixedunpack(0)
                 except ValueError:
                     raise Exception, "no __init__ found in %r" % (cls,)
             return s_instance
+
         if hasattr(func, '__call__') and \
            isinstance(func.__call__, MethodType):
             func = func.__call__

Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Sat Jun  4 18:28:53 2005
@@ -138,7 +138,7 @@
         space = RPythonCallsSpace()
         return obj.call(Arguments.fromshape(space, s_shape.const, args_s))
 
-    def call(obj, args):
+    def call(obj, args, implicit_init=False):
         #raise Exception, "cannot follow call_args%r" % ((obj, args),)
         getbookkeeper().warning("cannot follow call(%r, %r)" % (obj, args))
         return SomeObject()
@@ -367,7 +367,7 @@
         else:
             return bltn.analyser(*args)
 
-    def call(bltn, args):
+    def call(bltn, args, implicit_init=False):
         args, kw = args.unpack()
         assert not kw, "don't call builtins with keywords arguments"
         if bltn.s_self is not None:
@@ -385,9 +385,9 @@
     def setattr(pbc, s_attr, s_value):
         getbookkeeper().warning("setattr not wanted on %r" % (pbc,))
 
-    def call(pbc, args):
+    def call(pbc, args, implicit_init=False):
         bookkeeper = getbookkeeper()
-        return bookkeeper.pbc_call(pbc, args)
+        return bookkeeper.pbc_call(pbc, args, implicit_init=implicit_init)
 
         #bookkeeper = getbookkeeper()
         #results = []

Modified: pypy/dist/pypy/translator/annrpython.py
==============================================================================
--- pypy/dist/pypy/translator/annrpython.py	(original)
+++ pypy/dist/pypy/translator/annrpython.py	Sat Jun  4 18:28:53 2005
@@ -169,6 +169,7 @@
                 print "++-" * 20
             raise AnnotatorError('%d blocks are still blocked' %
                                  self.annotated.values().count(False))
+        self.bookkeeper.compute_at_fixpoint()
 
     def binding(self, arg, extquery=False):
         "Gives the SomeValue corresponding to the given Variable or Constant."

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 Jun  4 18:28:53 2005
@@ -859,6 +859,8 @@
             def n(self):
                 pass
         class C(A):
+            def __init__(self):
+                pass
             def m(self):
                 pass
         def f(x):
@@ -882,11 +884,12 @@
         fc = lambda x: {(None, x): True}
         mc = lambda x: {(clsdef(x.im_class), x.im_func): True}
 
-        assert len(callables) == 5
-        assert callables == { B: fc(B), C: fc(C),
-                             A.m.im_func: mc(A.m),
-                             C.m.im_func: mc(C.m),
-                             B.n.im_func: mc(B.n) }
+        assert len(callables) == 6
+        assert callables == { B: fc(B), C: fc(C), 
+                              C.__init__.im_func: fc(C.__init__.im_func),
+                              A.m.im_func: mc(A.m),
+                              C.m.im_func: mc(C.m),
+                              B.n.im_func: mc(B.n) }
         
         ign, repA_m, famA_m = call_families.find((clsdef(A), A.m.im_func))
         ign, repC_m, famC_m = call_families.find((clsdef(C), C.m.im_func))
@@ -900,6 +903,9 @@
 
         assert famB_n.patterns == {(0, (), False, False): True }
         assert famA_m.patterns == {(0, (), False, False): True }
+
+        ign, repCinit, famCinit = call_families.find((None, C.__init__.im_func))
+        assert famCinit.patterns == {(1, (), False, False): True }
         
     def test_isinstance_usigned(self):
         def f(x):



More information about the Pypy-commit mailing list