[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