[pypy-svn] r7337 - in pypy/trunk/src/pypy: annotation interpreter translator

hpk at codespeak.net hpk at codespeak.net
Wed Nov 17 17:03:43 CET 2004


Author: hpk
Date: Wed Nov 17 17:03:42 2004
New Revision: 7337

Modified:
   pypy/trunk/src/pypy/annotation/binaryop.py
   pypy/trunk/src/pypy/annotation/factory.py
   pypy/trunk/src/pypy/annotation/model.py
   pypy/trunk/src/pypy/annotation/unaryop.py
   pypy/trunk/src/pypy/interpreter/baseobjspace.py
   pypy/trunk/src/pypy/translator/annrpython.py
   pypy/trunk/src/pypy/translator/genpyrex.py
Log:

- medium refactoring: unify SomeFunction, SomeClass and SomeMethod 
  to become SomeCallable.  This is meant to prevent the union 
  of e.g. SomeFunction and SomeClass to result in a SomeObject 

- mark loadfromcache() with "specialize = True" to notify 
  the annotator that we want differented "inlined" or specialized 
  versions of this function for the various calling places

- hack genpyrex to continue to pass the tests 

- but translate_pypy.py now fails in a different seemingly 
  unrelated way :-/



Modified: pypy/trunk/src/pypy/annotation/binaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/binaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/binaryop.py	Wed Nov 17 17:03:42 2004
@@ -6,11 +6,11 @@
 from pypy.annotation.model import SomeObject, SomeInteger, SomeBool
 from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
-from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod
+from pypy.annotation.model import SomeInstance, SomeCallable
 from pypy.annotation.model import SomeBuiltin, SomeIterator
 from pypy.annotation.model import SomePrebuiltConstant, immutablevalue
 from pypy.annotation.model import unionof, set, setunion, missing_operation
-from pypy.annotation.factory import generalize
+from pypy.annotation.factory import generalize, isclassdef 
 from pypy.objspace.flow.model import Constant
 
 
@@ -24,6 +24,13 @@
 for opname in BINARY_OPERATIONS:
     missing_operation(pairtype(SomeObject, SomeObject), opname)
 
+#class __extend__(pairtype(SomeFunction, SomeObject)):
+#    def union((obj1, obj2)):
+#        raise TypeError, "generalizing not allowed: %r AND %r" % (obj1, obj2)
+#
+#class __extend__(pairtype(SomeObject, SomeFunction)):
+#    def union((obj1, obj2)):
+#        raise TypeError, "generalizing not allowed: %r AND %r" % (obj2, obj1)
 
 class __extend__(pairtype(SomeObject, SomeObject)):
 
@@ -31,6 +38,11 @@
         if obj1 == obj2:
             return obj1
         else:
+            #if isinstance(obj1, SomeFunction) or \
+            #   isinstance(obj2, SomeFunction): 
+            #   raise TypeError, ("generalizing not allowed:"
+            #                     "%r AND %r" % (obj1, obj2))
+            #    
             result = SomeObject()
             # try to preserve the origin of SomeObjects
             if obj1 == result:
@@ -198,27 +210,19 @@
             s_self = unionof(bltn1.s_self, bltn2.s_self)
             return SomeBuiltin(bltn1.analyser, s_self)
 
+class __extend__(pairtype(SomeCallable, SomeCallable)):
 
-class __extend__(pairtype(SomeFunction, SomeFunction)):
-
-    def union((fun1, fun2)):
-        return SomeFunction(setunion(fun1.funcs, fun2.funcs))
-
-
-class __extend__(pairtype(SomeMethod, SomeMethod)):
-
-    def union((met1, met2)):
-        # the union of the two meths dictionaries is a dictionary
-        #   {func: commonbase(met1[func], met2[func])}
-        # note that this case is probably very rare
-        # (the same Python object found in two different classes)
-        d = met1.meths.copy()
-        for func, classdef in met2.meths.items():
-            if func in d:
-                classdef = classdef.commonbase(d[func])
-            d[func] = classdef
-        return SomeMethod(d)
-
+    def union((cal1, cal2)):
+        d = cal1.callables.copy()
+        for cal, classdef in cal2.callables.items():
+            if cal in d:
+                if bool(isclassdef(classdef)) ^ bool(isclassdef(d[cal])):
+                    raise Exception(
+                        "union failed for %r with classdefs %r and %r" % 
+                        (cal, classdef, d[cal]))
+                classdef = classdef.commonbase(d[cal])
+            d[cal] = classdef
+        return SomeCallable(d)
 
 class __extend__(pairtype(SomeImpossibleValue, SomeObject)):
     def union((imp1, obj2)):
@@ -239,13 +243,11 @@
         # special case for SomePrebuiltConstants that are dictionaries
         # (actually frozendicts)
         possibleresults = []
-        for c_inst in pbc1.prebuiltinstances:
-            assert isinstance(c_inst, Constant)
-            inst = c_inst.value
+        for inst in pbc1.prebuiltinstances:
             if isinstance(inst, dict):
                 possibleresults += inst.values()
-            elif isinstance(inst, list):
-                possibleresults += inst   # maybe
+            #elif isinstance(inst, list):
+            #    possibleresults += inst   # maybe
             else:
                 raise TypeError, "cannot getitem() from %r" % (inst,)
         possibleresults = [immutablevalue(x) for x in possibleresults]

Modified: pypy/trunk/src/pypy/annotation/factory.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py	(original)
+++ pypy/trunk/src/pypy/annotation/factory.py	Wed Nov 17 17:03:42 2004
@@ -7,7 +7,7 @@
 """
 
 from __future__ import generators
-from types import FunctionType
+from types import FunctionType, ClassType, MethodType
 from pypy.annotation.model import SomeImpossibleValue, SomeList, SomeDict
 from pypy.annotation.model import SomeObject, SomeInstance
 from pypy.annotation.model import unionof, immutablevalue
@@ -94,6 +94,8 @@
             factory.bookkeeper.annotator.reflowfromposition(factory.position_key)
         raise BlockedInference   # reflow now
 
+def isclassdef(x):
+    return isinstance(x, ClassDef) 
 
 class ListFactory:
     s_item = SomeImpossibleValue()
@@ -133,26 +135,42 @@
             return False
 
 
-class FuncCallFactory:
-
+class CallableFactory: 
     def pycall(self, func, *args):
+        if isinstance(func, (type, ClassType)) and \
+            func.__module__ != '__builtin__':
+            cls = func 
+            classdef = self.bookkeeper.getclassdef(cls)
+            classdef.instancefactories[self] = True
+            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__:
+                self.pycall(init, s_instance, *args)
+            else:
+                assert not args, "no __init__ found in %r" % (cls,)
+            return s_instance
+        if hasattr(func, '__call__') and \
+           isinstance(func.__call__, MethodType): 
+            func = func.__call__
+        if hasattr(func, 'im_func'):
+            if func.im_self is not None:
+                s_self = immutablevalue(func.im_self)
+                args = [s_self] + list(args)
+            func = func.im_func
         return self.bookkeeper.annotator.recursivecall(func, self, *args)
 
-
-class InstanceFactory(FuncCallFactory):
-
-    def create(self, cls, *args):
-        classdef = self.bookkeeper.getclassdef(cls)
-        classdef.instancefactories[self] = True
-        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__:
-            self.pycall(init, s_instance, *args)
-        else:
-            assert not args, "no __init__ found in %r" % (cls,)
-        return s_instance
-
+        #if hasattr(func, 'specialize'):
+        #    key = func, factory.position_key 
+        #    try:
+        #        func = self._cachespecializedfunctions[key]
+        #    except KeyError:
+        #        func = new.function(func.func_code, 
+        #                            func.func_globals, 
+        #                            func.func_name, 
+        #                            func.func_defaults, 
+        #                            func.func_closure)
+        #        self._cachespecializedfunctions[key] = func 
 
 class ClassDef:
     "Wraps a user class."
@@ -184,7 +202,7 @@
             # the following might still invalidate some blocks if it
             # generalizes existing values in parent classes
             s_value = immutablevalue(value)
-            s_value = s_value.classattribute(self)
+            s_value = s_value.bindcallables(self)
             self.generalize(name, s_value, bookkeeper)
 
     def __repr__(self):
@@ -240,3 +258,5 @@
         if bookkeeper:
             for factory in self.getallfactories():
                 bookkeeper.annotator.reflowfromposition(factory.position_key)
+
+from pypy.annotation.builtin  import BUILTIN_FUNCTIONS

Modified: pypy/trunk/src/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/model.py	(original)
+++ pypy/trunk/src/pypy/annotation/model.py	Wed Nov 17 17:03:42 2004
@@ -117,12 +117,12 @@
     def __init__(self, s_item=SomeObject()):
         self.s_item = s_item
 
-class SomeClass(SomeObject):
-    "Stands for a user-defined class object."
-    # only used when the class object is loaded in a variable
-    knowntype = ClassType
-    def __init__(self, cls):
-        self.cls = cls
+#class SomeClass(SomeObject):
+#    "Stands for a user-defined class object."
+#    # only used when the class object is loaded in a variable
+#    knowntype = ClassType
+#    def __init__(self, cls):
+#        self.cls = cls
 
 class SomeInstance(SomeObject):
     "Stands for an instance of a (user-defined) class."
@@ -131,35 +131,48 @@
         self.knowntype = classdef.cls
         self.revision = classdef.revision
 
-class SomeBuiltin(SomeObject):
+class SomeCallable(SomeObject):
+    """Stands for a (callable) function, method, 
+    prebuiltconstant or class"""
+    def __init__(self, callables):
+        # callables is a dictionary containing concrete python 
+        # callable objects as keys and - in the case of a method - 
+        # the value contains the classdef (see SomeMethod above) 
+        self.callables = callables 
+        if len(callables) == 1:
+            self.const, = callables
+
+class SomeBuiltin(SomeCallable):
     "Stands for a built-in function or method with special-cased analysis."
     knowntype = BuiltinFunctionType  # == BuiltinMethodType
     def __init__(self, analyser, s_self=None):
         self.analyser = analyser
         self.s_self = s_self
 
-class SomeFunction(SomeObject):
-    """Stands for a Python function (or some function out of a list).
-    Alternatively, it can be a constant bound or unbound method."""
-    knowntype = FunctionType
-    def __init__(self, funcs):
-        self.funcs = funcs   # set of functions that this one may be
-        if len(funcs) == 1:
-            self.const, = funcs
-
-class SomeMethod(SomeObject):
-    "Stands for a bound Python method (or some method out of a list)."
-    knowntype = MethodType
-    def __init__(self, meths):
-        self.meths = meths   # map {python_function: classdef}
+#class SomeFunction(SomeObject):
+#    """Stands for a Python function (or some function out of a list).
+#    Alternatively, it can be a constant bound or unbound method."""
+#    knowntype = FunctionType
+#    def __init__(self, funcs):
+#        self.funcs = funcs   # set of functions that this one may be
+#        if len(funcs) == 1:
+#            self.const, = funcs
+
+#class SomeMethod(SomeObject):
+#    "Stands for a bound Python method (or some method out of a list)."
+#    knowntype = MethodType
+#    def __init__(self, meths):
+#        self.meths = meths   # map {python_function: classdef}
+
 
 class SomePrebuiltConstant(SomeObject):
     """Stands for a global user instance, built prior to the analysis,
     or a set of such instances."""
     def __init__(self, prebuiltinstances):
-        self.prebuiltinstances = prebuiltinstances  # set of Constants
-        self.knowntype = reduce(commonbase, [x.value.__class__
-                                             for x in prebuiltinstances])
+        self.prebuiltinstances = prebuiltinstances  
+        self.knowntype = reduce(commonbase, 
+                                [x.__class__ for x in prebuiltinstances])
+        
 
 class SomeImpossibleValue(SomeObject):
     """The empty set.  Instances are placeholders for objects that
@@ -194,12 +207,10 @@
         result = SomeTuple(items = [immutablevalue(e) for e in x])
     elif ishashable(x) and x in BUILTIN_FUNCTIONS:
         result = SomeBuiltin(BUILTIN_FUNCTIONS[x])
-    elif isinstance(x, (type, ClassType)) and x.__module__ != '__builtin__':
-        result = SomeClass(x)
-    elif isinstance(x, (FunctionType, MethodType)):
-        result = SomeFunction({x: True})
+    elif callable(x): 
+        result = SomeCallable({x : True}) 
     elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__':
-        result = SomePrebuiltConstant({Constant(x): True}) # pre-built instances
+        result = SomePrebuiltConstant({x: True}) # pre-built inst:
     else:
         result = SomeObject()
     result.const = x

Modified: pypy/trunk/src/pypy/annotation/unaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/unaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/unaryop.py	Wed Nov 17 17:03:42 2004
@@ -7,13 +7,13 @@
 from pypy.annotation.model import SomeObject, SomeInteger, SomeBool
 from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
-from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass
-from pypy.annotation.model import SomeFunction, SomeMethod, SomeIterator
+from pypy.annotation.model import SomeInstance, SomeBuiltin 
+from pypy.annotation.model import SomeCallable, SomeIterator
 from pypy.annotation.model import SomePrebuiltConstant
 from pypy.annotation.model import immutablevalue
 from pypy.annotation.model import unionof, set, setunion, missing_operation
 from pypy.annotation.factory import BlockedInference, getbookkeeper
-from pypy.annotation.factory import InstanceFactory, FuncCallFactory
+from pypy.annotation.factory import CallableFactory, isclassdef 
 
 
 UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'simple_call',
@@ -51,7 +51,7 @@
                 return immutablevalue(getattr(obj.const, attr))
         return SomeObject()
 
-    def classattribute(obj, classdef):
+    def bindcallables(obj, classdef):
         return obj   # default unbound __get__ implementation
 
 
@@ -135,51 +135,46 @@
             raise BlockedInference
         return SomeObject()
 
-
 class __extend__(SomeBuiltin):
-
     def simple_call(bltn, *args):
         if bltn.s_self is not None:
             return bltn.analyser(bltn.s_self, *args)
         else:
             return bltn.analyser(*args)
 
+class __extend__(SomeCallable):
+    def simple_call(cal, *args):
+        factory = getbookkeeper().getfactory(CallableFactory) 
+        results = []
+        for func, classdef in cal.callables.items():
+            if isclassdef(classdef): 
+                # create s_self and record the creation in the factory
+                s_self = SomeInstance(classdef)
+                classdef.instancefactories[factory] = True
+                results.append(factory.pycall(func, s_self, *args))
+            else:
+                results.append(factory.pycall(func, *args))
+        return unionof(*results) 
 
-class __extend__(SomeClass):
-
-    def simple_call(cls, *args):
-        factory = getbookkeeper().getfactory(InstanceFactory)
-        return factory.create(cls.cls, *args)
-
-
-class __extend__(SomeFunction):
-
-    def simple_call(fun, *args):
-        factory = getbookkeeper().getfactory(FuncCallFactory)
-        results = [factory.pycall(func, *args) for func in fun.funcs]
-        return unionof(*results)
-
-    def classattribute(fun, classdef):   # function -> unbound method
+    def bindcallables(cal, classdef):   
+        """ turn the callables in the given SomeCallable 'cal' 
+            into bound versions.
+        """
         d = {}
-        for func in fun.funcs:
-            assert isinstance(func, FunctionType), (
-                "%r should not be read out of class %r" % (func, classdef))
-            d[func] = classdef
-        return SomeMethod(d)
-
-
-class __extend__(SomeMethod):
-
-    def simple_call(met, *args):
-        factory = getbookkeeper().getfactory(FuncCallFactory)
-        results = []
-        for func, classdef in met.meths.items():
-            # create s_self and record the creation in the factory
-            s_self = SomeInstance(classdef)
-            classdef.instancefactories[factory] = True
-            # call func(s_self, *arglist)
-            results.append(factory.pycall(func, s_self, *args))
-        return unionof(*results)
+        for func, value in cal.callables.items():
+            if isinstance(func, FunctionType): 
+                if isclassdef(value): 
+                    print ("!!! rebinding an already bound"
+                           " method %r with %r" % (func, value))
+                d[func] = classdef
+            else:
+                d[func] = value 
+        return SomeCallable(d)
+                
+    #def simple_call(fun, *args):
+    #    factory = getbookkeeper().getfactory(CallableFactory)
+    #    results = [factory.pycall(func, *args) for func in fun.funcs]
+    #    return unionof(*results)
 
 
 class __extend__(SomePrebuiltConstant):
@@ -191,8 +186,8 @@
         actuals = []
         for c in pbc.prebuiltinstances:
             bookkeeper.attrs_read_from_constants.setdefault(c, {})[attr] = True
-            if hasattr(c.value, attr):
-                actuals.append(immutablevalue(getattr(c.value, attr)))
+            if hasattr(c, attr):
+                actuals.append(immutablevalue(getattr(c, attr)))
         return unionof(*actuals)
 
     def setattr(pbc, s_attr, s_value):

Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/src/pypy/interpreter/baseobjspace.py	Wed Nov 17 17:03:42 2004
@@ -44,6 +44,9 @@
             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

Modified: pypy/trunk/src/pypy/translator/annrpython.py
==============================================================================
--- pypy/trunk/src/pypy/translator/annrpython.py	(original)
+++ pypy/trunk/src/pypy/translator/annrpython.py	Wed Nov 17 17:03:42 2004
@@ -158,12 +158,6 @@
     #___ interface for annotator.factory _______
 
     def recursivecall(self, func, factory, *args):
-        # calls to methods: expand the argument
-        if hasattr(func, 'im_func'):
-            if func.im_self is not None:
-                s_self = annmodel.immutablevalue(func.im_self)
-                args = [s_self] + list(args)
-            func = func.im_func
         parent_fn, parent_block, parent_index = factory.position_key
         graph = self.translator.getflowgraph(func, parent_fn,
                                              factory.position_key)

Modified: pypy/trunk/src/pypy/translator/genpyrex.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genpyrex.py	(original)
+++ pypy/trunk/src/pypy/translator/genpyrex.py	Wed Nov 17 17:03:42 2004
@@ -6,7 +6,8 @@
 from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant
 from pypy.objspace.flow.model import mkentrymap
 from pypy.translator.annrpython import RPythonAnnotator
-from pypy.annotation.model import SomeMethod
+from pypy.annotation.model import SomeCallable
+from pypy.annotation.factory import isclassdef
 import inspect
 
 class Op:
@@ -397,8 +398,10 @@
                 self.indent += 1
                 empty = True
                 for attr,s_value in cls.attrs.items():
-                    if isinstance(s_value,SomeMethod):
-                        for py_fun,fun_class in s_value.meths.items():
+                    if isinstance(s_value, SomeCallable):
+                        for py_fun,fun_class in s_value.callables.items():
+                            assert isclassdef(fun_class), (
+                                "%r must have a classdef" % py_fun)
                             delay_methods.setdefault(fun_class,[]).append(py_fun)                          
                     else:
                         vartype=self._gettypename(s_value.knowntype)



More information about the Pypy-commit mailing list