[pypy-svn] r13088 - in pypy/dist/pypy: annotation interpreter module/sys objspace/std tool translator translator/goal translator/test
pedronis at codespeak.net
pedronis at codespeak.net
Mon Jun 6 05:09:00 CEST 2005
Author: pedronis
Date: Mon Jun 6 05:08:52 2005
New Revision: 13088
Added:
pypy/dist/pypy/annotation/policy.py (contents, props changed)
pypy/dist/pypy/annotation/specialize.py (contents, props changed)
Modified:
pypy/dist/pypy/annotation/bookkeeper.py
pypy/dist/pypy/annotation/unaryop.py
pypy/dist/pypy/interpreter/compiler.py
pypy/dist/pypy/interpreter/error.py
pypy/dist/pypy/interpreter/miscutils.py
pypy/dist/pypy/interpreter/pyframe.py
pypy/dist/pypy/interpreter/typedef.py
pypy/dist/pypy/module/sys/state.py
pypy/dist/pypy/objspace/std/fake.py
pypy/dist/pypy/objspace/std/objspace.py
pypy/dist/pypy/tool/cache.py
pypy/dist/pypy/translator/ann_override.py
pypy/dist/pypy/translator/annrpython.py
pypy/dist/pypy/translator/goal/translate_pypy.py
pypy/dist/pypy/translator/test/snippet.py
pypy/dist/pypy/translator/test/test_annrpython.py
pypy/dist/pypy/translator/translator.py
Log:
Revised specialization, see annotation/specialize.py and changes in bookkeeper;
now annotator can receive a policy object to specify both overrides and specializations through the methods
specialize and override
a base class version is defined in annotation/policy.py, it will use methods of the form specialize__xxx or override__xxx
chosen by attaching to the callable in user-code the attribute _annspecialcase_ with values:
"specialize:xxx"
"override:xxx"
respectively.
ann_override now defines such a policy class which is used by translate_pypy,
(Notice: if a policy is not passed to the annotator an even more basic policy without any overrides nor specializations is used.)
- 'override' methods take the policy and inputcells
- 'specialize' methods take the policy and a bookkeeper, the involved spaceop, the involved callable func,
an Arguments object with SomeObjects and a mono flag whether just one statically known callable is involved;
they should normally return a _tuple_ key to identify the specialized version (which if absent will be created), or None meaning no
specialization
the policy can define a default_specialize that is always invoked, the version in the base class does the specializion for *arg
functions
There's no general 'location' specialization anymore, for classes there's "specialize:ctr_location" which is implemented
in specialize.py and exposed by the base policy class.
Now phases successive to annotation can query whether a call space op involves specialized callables:
bookkeeper.query_spaceop_callable(spaceop) can be called with a call spaceop that has the called obj annotated as some PBC
it will return possibly a new PBC with the specialized version effectively considered by the annotator for the callable
(it also returns a flag which is normally false unless, in the only case (for now), the callable involved was marked
"specialize:memo")
the call site families and tables now refer to specialized versions of callables, not the original ones.
Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py (original)
+++ pypy/dist/pypy/annotation/bookkeeper.py Mon Jun 6 05:08:52 2005
@@ -11,14 +11,12 @@
from pypy.annotation.classdef import ClassDef, isclassdef
from pypy.annotation.listdef import ListDef, MOST_GENERAL_LISTDEF
from pypy.annotation.dictdef import DictDef, MOST_GENERAL_DICTDEF
-from pypy.tool.sourcetools import func_with_new_name, valid_identifier
-from pypy.interpreter.pycode import CO_VARARGS
from pypy.interpreter.pycode import cpython_code_signature
-from pypy.interpreter.argument import ArgErr
+from pypy.interpreter.argument import Arguments, ArgErr
from pypy.rpython.rarithmetic import r_uint
from pypy.tool.unionfind import UnionFind
-import inspect, new
+from pypy.annotation.specialize import decide_callable
class PBCAccessSet:
def __init__(self, obj):
@@ -59,9 +57,8 @@
self.listdefs = {} # map position_keys to ListDefs
self.dictdefs = {} # map position_keys to DictDefs
- # mapping position -> most general result, for call sites calling
- # argtypes specialized functions
- self.argtypes_spec_callsite_results = {}
+ # mapping position -> key, prev_result for specializations
+ self.spec_callsite_keys_results = {}
self.pbc_maximal_access_sets = UnionFind(PBCAccessSet)
# can be precisely computed only at fix-point, see
@@ -92,9 +89,10 @@
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))
+ spaceop = block.operations[i]
+ assert spaceop.opname in ('call_args', 'simple_call')
+ pbc = self.annotator.binding(spaceop.args[0], extquery=True)
+ self.consider_pbc_call(pbc, shape, spaceop)
def getclassdef(self, cls):
"""Get the ClassDef associated with the given user cls."""
@@ -312,9 +310,18 @@
return unionof(*actuals)
- def consider_pbc_call(self, pbc, shape, position=None): # computation done at fix-point
+ def consider_pbc_call(self, pbc, shape, spaceop=None, implicit_init=None): # computation done at fix-point
if not isinstance(pbc, SomePBC):
return
+
+ if implicit_init:
+ implicit_init = pbc, implicit_init
+ shape = (shape[0]+1,) + shape[1:]
+ else:
+ implicit_init = None
+
+ pbc, dontcarememo = self.query_spaceop_callable(spaceop,
+ implicit_init=implicit_init)
nonnullcallables = []
for func, classdef in pbc.prebuiltinstances.items():
@@ -327,10 +334,9 @@
if isinstance(func, (type, ClassType)) and \
func.__module__ != '__builtin__':
assert classdef is None
- dontcare, s_init = self.get_s_init(func, position=position)
+ init_classdef, s_init = self.get_s_init(func)
if s_init is not None:
- init_shape = (shape[0]+1,) + shape[1:]
- self.consider_pbc_call(s_init, init_shape)
+ self.consider_pbc_call(s_init, shape, spaceop, implicit_init=init_classdef)
callable = (classdef, func)
if hasattr(func, 'im_func') and func.im_self is None:
@@ -376,21 +382,52 @@
return unionof(*results)
# decide_callable(position, func, args, mono) -> callb, key
- # query_spaceop_callable(spaceop) -> pbc
+ # query_spaceop_callable(spaceop) -> pbc, memo
# get_s_init(decided_cls) -> classdef, s_undecided_init
- def get_s_init(self, cls, position=None, mono=True):
- specialize = getattr(cls, "_specialize_", False)
- if specialize:
- if specialize == "location":
- assert mono, "not-static construction of specialized class %s" % cls
- cls = self.specialize_by_key(cls, position,
- name="%s__At_%s" % (cls.__name__,
- position_name(position)))
+ def query_spaceop_callable(self, spaceop, implicit_init=None): # -> s_pbc, memo
+ self.enter(None)
+ try:
+ if implicit_init is None:
+ assert spaceop.opname in ("simple_call", "call_args")
+ obj = spaceop.args[0]
+ s_obj = self.annotator.binding(obj, extquery=True)
+ init_classdef = None
else:
- raise Exception, \
- "unsupported specialization type '%s'"%(specialize,)
+ s_obj, init_classdef = implicit_init
+
+ assert isinstance(s_obj, SomePBC)
+ if len(s_obj.prebuiltinstances) > 1: # no specialization expected
+ return s_obj, False
+
+ argsvars = spaceop.args[1:]
+ args_s = [self.annotator.binding(v) for v in argsvars]
+ args = self.build_args(spaceop.opname, args_s)
+ if init_classdef:
+ args = args.prepend(SomeInstance(init_classdef))
+
+ func, classdef = s_obj.prebuiltinstances.items()[0]
+ func, key = decide_callable(self, spaceop, func, args, mono=True)
+
+ if key is None:
+ return s_obj, False
+
+ if func is None: # specialisation computes annotation direclty
+ return s_obj, True
+
+ return SomePBC({func: classdef}), False
+ finally:
+ self.leave()
+
+ def build_args(self, op, args_s):
+ space = RPythonCallsSpace()
+ if op == "simple_call":
+ return Arguments(space, args_s)
+ elif op == "call_args":
+ return Arguments.fromshape(space, args_s[0].const, # shape
+ args_s[1:])
+ def get_s_init(self, cls):
classdef = self.getclassdef(cls)
init = getattr(cls, '__init__', None)
if init is not None and init != object.__init__:
@@ -409,9 +446,20 @@
def pycall(self, func, args, mono):
if func is None: # consider None as a NULL function pointer
return SomeImpossibleValue()
+
+ # decide and pick if necessary a specialized version
+ base_func = func
+ func, key = decide_callable(self, self.position_key, func, args, mono, unpacked=True)
+
+ if func is None:
+ assert isinstance(key, SomeObject)
+ return key
+
+ func, args = func # method unpacking done by decide_callable
+
if isinstance(func, (type, ClassType)) and \
func.__module__ != '__builtin__':
- classdef, s_init = self.get_s_init(func, position=self.position_key, mono=mono)
+ classdef, s_init = self.get_s_init(func)
s_instance = SomeInstance(classdef)
# flow into __init__() if the class has got one
if s_init is not None:
@@ -423,60 +471,7 @@
raise Exception, "no __init__ found in %r" % (cls,)
return s_instance
- if hasattr(func, 'im_func'):
- if func.im_self is not None:
- s_self = self.immutablevalue(func.im_self)
- args = args.prepend(s_self)
- # for debugging only, but useful to keep anyway:
- try:
- func.im_func.class_ = func.im_class
- except AttributeError:
- # probably a builtin function, we don't care to preserve
- # class information then
- pass
- func = func.im_func
assert isinstance(func, FunctionType), "[%s] expected function, got %r" % (self.whereami(), func)
- # do we need to specialize this function in several versions?
- specialize = getattr(func, '_specialize_', False)
-
- if specialize:
- assert mono, "not-static call to specialized %s" % func
- base_func = func
- if specialize == 'argtypes':
- key = short_type_name(args)
- func = self.specialize_by_key(func, key,
- func.__name__+'__'+key)
- elif specialize == "location":
- # fully specialize: create one version per call position
- func = self.specialize_by_key(func, self.position_key,
- name="%s__At_%s" % (func.__name__,
- position_name(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,)
-
- elif func.func_code.co_flags & CO_VARARGS:
- # calls to *arg functions: create one version per number of args
- assert mono, "not-static call to *arg function %s" % func
- assert not args.has_keywords(), (
- "keyword forbidden in calls to *arg functions")
- nbargs = len(args.arguments_w)
- if args.w_stararg is not None:
- s_len = args.w_stararg.len()
- assert s_len.is_constant(), "calls require known number of args"
- nbargs += s_len.const
- func = self.specialize_by_key(func, nbargs,
- name='%s__%d' % (func.func_name,
- nbargs))
# parse the arguments according to the function we are calling
signature = cpython_code_signature(func.func_code)
@@ -492,19 +487,21 @@
r = self.annotator.recursivecall(func, self.position_key, inputcells)
- # in the case of argtypes specialisation we may have been calling a
- # different function for the site which could also be just partially analysed,
- # we need to force unifying all past and present results for the site
- # in order to guarantee the more general results invariant.
- if specialize == 'argtypes':
- key = (base_func, self.position_key)
- prev_r = self.argtypes_spec_callsite_results.get(key)
- if prev_r is not None:
- r = unionof(prev_r, r)
- self.argtypes_spec_callsite_results[key] = r
+ # if we got different specializations keys for a same site, mix previous results for stability
+ if key is not None:
+ occurence = (base_func, self.position_key)
+ try:
+ prev_key, prev_r = self.spec_callsite_keys_results[occurence]
+ except KeyError:
+ self.spec_callsite_keys_results[occurence] = key, r
+ else:
+ if prev_key != key:
+ r = unionof(r, prev_r)
+ prev_key = None
+ self.spec_callsite_keys_results[occurence] = prev_key, r
+
return r
-
def whereami(self):
return self.annotator.whereami(self.position_key)
@@ -516,48 +513,39 @@
pos = '?'
ansi_print("*** WARNING: [%s] %s" % (pos, msg), esc="31") # RED
- def specialize_by_key(self, thing, key, name=None):
- key = thing, key
- try:
- thing = self.cachespecializations[key]
- except KeyError:
- if isinstance(thing, FunctionType):
- # XXX XXX XXX HAAAAAAAAAAAACK
- # xxx we need a way to let know subsequent phases (the
- # generator) about the specialized function.
- # The caller flowgraph, as it is, doesn't know.
- # This line just avoids that the flowgraph of the original
- # function (which is what will be considered and compiled for
- # now) will be computed during generation itself.
- self.annotator.translator.getflowgraph(thing)
- #
- thing = func_with_new_name(thing, name or thing.func_name)
- elif isinstance(thing, (type, ClassType)):
- superclasses = iter(inspect.getmro(thing))
- superclasses.next() # skip thing itself
- for cls in superclasses:
- assert not hasattr(cls, "_specialize_"), "for now specialization only for leaf classes"
-
- newdict = {}
- for attrname,val in thing.__dict__.iteritems():
- if attrname == '_specialize_': # don't copy the marker
- continue
- if isinstance(val, FunctionType):
- fname = val.func_name
- if name:
- fname = "%s_for_%s" % (fname, name)
- newval = func_with_new_name(val, fname)
- # xxx more special cases
- else:
- newval = val
- newdict[attrname] = newval
- thing = type(thing)(name or thing.__name__, (thing,), newdict)
- else:
- raise Exception, "specializing %r?? why??"%thing
- self.cachespecializations[key] = thing
- return thing
+def ishashable(x):
+ try:
+ hash(x)
+ except TypeError:
+ return False
+ else:
+ return True
+
+# for parsing call arguments
+class RPythonCallsSpace:
+ """Pseudo Object Space providing almost no real operation.
+ For the Arguments class: if it really needs other operations, it means
+ that the call pattern is too complex for R-Python.
+ """
+ def newtuple(self, items_s):
+ return SomeTuple(items_s)
+
+ def newdict(self, stuff):
+ raise CallPatternTooComplex, "'**' argument"
+
+ def unpackiterable(self, s_obj, expected_length=None):
+ if isinstance(s_obj, SomeTuple):
+ if (expected_length is not None and
+ expected_length != len(s_obj.items)):
+ raise ValueError
+ return s_obj.items
+ raise CallPatternTooComplex, "'*' argument must be SomeTuple"
+class CallPatternTooComplex(Exception):
+ pass
+
+# get current bookkeeper
def getbookkeeper():
"""Get the current Bookkeeper.
@@ -566,50 +554,3 @@
return TLS.bookkeeper
except AttributeError:
return None
-
-def ishashable(x):
- try:
- hash(x)
- except TypeError:
- return False
- else:
- return True
-
-def short_type_name(args):
- l = []
- shape, args_w = args.flatten()
- for x in args_w:
- if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'):
- name = "SI_" + x.knowntype.__name__
- else:
- name = x.__class__.__name__
- l.append(name)
- return "__".join(l)
-
-def position_name((fn, block, i)):
- mod = valid_identifier(getattr(fn, '__module__', 'SYNTH'))
- name = valid_identifier(getattr(fn, '__name__', 'UNKNOWN'))
- return "%s_%s_Giving_%s" % (mod, name, block.operations[i].result)
-
-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()
- elif isinstance(s, SomeBool):
- possible_values = [False, True]
- 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
Added: pypy/dist/pypy/annotation/policy.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/annotation/policy.py Mon Jun 6 05:08:52 2005
@@ -0,0 +1,46 @@
+# base annotation policy for overrides and specialization
+from pypy.annotation.specialize import memo, ctr_location, default_specialize as default
+
+class AnnotatorPolicy:
+ """
+ Possibly subclass and pass an instance to the annotator to control special casing during annotation
+ """
+
+ def getspecialcase(pol, kind, obj):
+ if hasattr(obj, '_annspecialcase_'):
+ sc = obj._annspecialcase_.split(':')
+ assert len(sc) ==2, "_annspecialcase_ should have the form kind:tag"
+ if sc[0] == kind:
+ return sc[1]
+ assert sc[0] in ('override', 'specialize'), "_annspecialcase_ kinds are only 'override', 'specialize'"
+ return None
+
+ def override(pol, func, inputcells):
+ tag = pol.getspecialcase('override', func)
+ if tag is None:
+ return None
+ try:
+ override = getattr(pol, 'override__%s' % tag)
+ except AttributeError:
+ raise AttributeError, "%s override tag found in user program but not defined in annotation policy %s" % (tag, pol)
+
+ return override(*inputcells)
+
+ def specialize(pol, bookkeeper, spaceop, func, args, mono):
+ tag = pol.getspecialcase('specialize', func)
+ if tag is None:
+ return pol.default_specialize(bookkeeper, spaceop, func, args, mono)
+
+ try:
+ specialize = getattr(pol, 'specialize__%s' % tag)
+ except AttributeError:
+ raise AttributeError, "%s specialize tag found in user program but not defined in annotation policy %s" % (tag, pol)
+
+ return specialize(bookkeeper, spaceop, func, args, mono)
+
+
+ # common specializations
+
+ default_specialize = staticmethod(default)
+ specialize__memo = staticmethod(memo)
+ specialize__ctr_location = staticmethod(ctr_location)
Added: pypy/dist/pypy/annotation/specialize.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/annotation/specialize.py Mon Jun 6 05:08:52 2005
@@ -0,0 +1,199 @@
+# specialization support
+import types, inspect, new
+
+from pypy.tool.sourcetools import valid_identifier, func_with_new_name
+
+def decide_callable(bookkeeper, position, func, args, mono=True, unpacked=False):
+ from pypy.objspace.flow.model import SpaceOperation
+ from pypy.annotation.model import SomeObject
+
+ key = None
+ ismeth, im_class, im_self, func, args = unpack_method(bookkeeper, func, args)
+
+
+ if position is None or isinstance(position, SpaceOperation):
+ spaceop = position
+ else:
+ fn, block, i = position
+ spaceop = block.operations[i]
+
+ key = bookkeeper.annotator.policy.specialize(bookkeeper, spaceop, func, args, mono)
+ if key is not None:
+ assert mono, "not-static call to specialized %s" % func
+ if isinstance(key, SomeObject):
+ # direct computation
+ return None, key
+ if isinstance(key, tuple):
+ # cache specialization
+ try:
+ func = bookkeeper.cachespecializations[key]
+ except KeyError:
+ postfix = key
+ if postfix[0] is func:
+ postfix = postfix[1:]
+ func = bookkeeper.cachespecializations[key] = clone(func, postfix)
+ elif isinstance(key, str):
+ # specialization explicit in operation annotation
+ postfix = key
+ func = clone(func, postfix)
+ else:
+ # specialization already retrieved
+ func = key
+
+ if unpacked:
+ func = func, args
+ else:
+ func = repack_method(ismeth, im_class, im_self, func)
+
+ return func, key
+
+def default_specialize(bookkeeper, spaceop, func, args, mono):
+ from pypy.interpreter.pycode import CO_VARARGS
+ if isinstance(func, types.FunctionType) and func.func_code.co_flags & CO_VARARGS:
+ # calls to *arg functions: create one version per number of args
+ assert mono, "not-static call to *arg function %s" % func
+ assert not args.has_keywords(), (
+ "keyword forbidden in calls to *arg functions")
+ nbargs = len(args.arguments_w)
+ if args.w_stararg is not None:
+ s_len = args.w_stararg.len()
+ assert s_len.is_constant(), "calls require known number of args"
+ nbargs += s_len.const
+ return (func, nbargs)
+ return None # no specialization
+
+# helpers
+
+def unpack_method(bookkeeper, func, args):
+ if not hasattr(func, 'im_func'):
+ return False, None, None, func, args
+ if func.im_self is not None:
+ s_self = bookkeeper.immutablevalue(func.im_self)
+ args = args.prepend(s_self)
+ # for debugging only, but useful to keep anyway:
+ try:
+ func.im_func.class_ = func.im_class
+ except AttributeError:
+ # probably a builtin function, we don't care to preserve
+ # class information then
+ pass
+ return True, func.im_class, func.im_self, func.im_func, args
+
+def repack_method(ismeth, im_class, im_self, func):
+ if not ismeth:
+ return func
+ return new.instancemethod(func, im_self, im_class)
+
+
+def clone(callb, postfix):
+ if not isinstance(postfix, str):
+ postfix = '_'.join([getattr(comp, '__name__', str(comp)) for comp in postfix])
+
+ name = valid_identifier(callb.__name__ + "__" + postfix)
+
+ if isinstance(callb, types.FunctionType):
+ newcallb = func_with_new_name(callb, name)
+ elif isinstance(callb, (type, types.ClassType)):
+ superclasses = iter(inspect.getmro(callb))
+ superclasses.next() # skip callb itself
+ for cls in superclasses:
+ assert not hasattr(cls, "_annspecialcase_"), "for now specialization only for leaf classes"
+
+ newdict = {}
+ for attrname,val in callb.__dict__.iteritems():
+ if attrname == '_annspecialcase_': # don't copy the marker
+ continue
+ if isinstance(val, types.FunctionType):
+ fname = val.func_name
+ fname = "%s_for_%s" % (fname, name)
+ newval = func_with_new_name(val, fname)
+ # xxx more special cases
+ else:
+ newval = val
+ newdict[attrname] = newval
+
+ newcallb = type(callb)(name or callb.__name__, (callb,), newdict)
+ else:
+ raise Exception, "specializing %r?? why??" % callb
+
+ return newcallb
+
+# ____________________________________________________________________________
+# specializations
+
+def memo(bookkeeper, spaceop, func, args, mono):
+ """NOT_RPYTHON"""
+ from pypy.annotation.model import unionof
+ # 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(bookkeeper.immutablevalue(result))
+ return unionof(*possible_results)
+
+def possible_arguments(args):
+ from pypy.annotation.model import SomeBool, SomePBC
+ # 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()
+ elif isinstance(s, SomeBool):
+ possible_values = [False, True]
+ 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
+
+#def argtypes(bookkeeper, spaceop, func, args, mono):
+# """NOT_RPYTHON"""
+# from pypy.annotation.model import SomeInstance
+# l = []
+# shape, args_w = args.flatten()
+# for x in args_w:
+# if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'):
+# name = "SI_" + x.knowntype.__name__
+# else:
+# name = x.__class__.__name__
+# l.append(name)
+# return func, "__".join(l)
+
+def ctr_location(bookkeeper, spaceop, orig_cls, args, mono):
+ """NOT_RPYTHON"""
+ from pypy.annotation.model import SomeInstance
+ v = spaceop.result
+ s_ins = bookkeeper.annotator.binding(v, extquery=True)
+ if s_ins is None:
+ return "Giving_"+v.name
+ else:
+ assert isinstance(s_ins, SomeInstance)
+ cls = s_ins.classdef.cls
+ assert issubclass(cls, orig_cls)
+ return cls
+
+def argvalue(i):
+ def specialize_argvalue(bookkeeper, spaceop, func, args, mono):
+ """NOT_RPYTHON"""
+ ignore, args_w = args.flatten()
+ return func, args_w[i].const
+ return specialize_argvalue
+
+def argtype(i):
+ def specialize_argtype(bookkeeper, spaceop, func, args, mono):
+ """NOT_RPYTHON"""
+ ignore, args_w = args.flatten()
+ return func, args_w[i].knowntype
+ return specialize_argtype
Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py (original)
+++ pypy/dist/pypy/annotation/unaryop.py Mon Jun 6 05:08:52 2005
@@ -12,7 +12,7 @@
from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeFloat
from pypy.annotation.model import SomeIterator, SomePBC, new_or_old_class
from pypy.annotation.model import unionof, set, setunion, missing_operation
-from pypy.annotation.bookkeeper import getbookkeeper
+from pypy.annotation.bookkeeper import getbookkeeper, RPythonCallsSpace
from pypy.annotation.classdef import isclassdef
from pypy.annotation import builtin
@@ -131,12 +131,10 @@
return obj # default unbound __get__ implementation
def simple_call(obj, *args_s):
- space = RPythonCallsSpace()
- return obj.call(Arguments(space, args_s))
+ return obj.call(getbookkeeper().build_args("simple_call", args_s))
- def call_args(obj, s_shape, *args_s):
- space = RPythonCallsSpace()
- return obj.call(Arguments.fromshape(space, s_shape.const, args_s))
+ def call_args(obj, *args_s):
+ return obj.call(getbookkeeper().build_args("call_args", args_s))
def call(obj, args, implicit_init=False):
#raise Exception, "cannot follow call_args%r" % ((obj, args),)
@@ -428,28 +426,6 @@
return immutablevalue(outcome)
-class RPythonCallsSpace:
- """Pseudo Object Space providing almost no real operation.
- For the Arguments class: if it really needs other operations, it means
- that the call pattern is too complex for R-Python.
- """
- def newtuple(self, items_s):
- return SomeTuple(items_s)
-
- def newdict(self, stuff):
- raise CallPatternTooComplex, "'**' argument"
-
- def unpackiterable(self, s_obj, expected_length=None):
- if isinstance(s_obj, SomeTuple):
- if (expected_length is not None and
- expected_length != len(s_obj.items)):
- raise ValueError
- return s_obj.items
- raise CallPatternTooComplex, "'*' argument must be SomeTuple"
-
-class CallPatternTooComplex(Exception):
- pass
-
# annotation of low-level types
from pypy.annotation.model import SomePtr, ll_to_annotation, annotation_to_lltype
class __extend__(SomePtr):
Modified: pypy/dist/pypy/interpreter/compiler.py
==============================================================================
--- pypy/dist/pypy/interpreter/compiler.py (original)
+++ pypy/dist/pypy/interpreter/compiler.py Mon Jun 6 05:08:52 2005
@@ -112,6 +112,7 @@
raise OperationError(space.w_TypeError,space.wrap(str(e)))
from pypy.interpreter.pycode import PyCode
return space.wrap(PyCode(space)._from_code(c))
+ compile._annspecialcase_ = "override:cpy_compile"
def getcodeflags(self, code):
from pypy.interpreter.pycode import PyCode
Modified: pypy/dist/pypy/interpreter/error.py
==============================================================================
--- pypy/dist/pypy/interpreter/error.py (original)
+++ pypy/dist/pypy/interpreter/error.py Mon Jun 6 05:08:52 2005
@@ -70,6 +70,7 @@
application."""
if RECORD_INTERPLEVEL_TRACEBACK:
self.debug_excs.append(sys.exc_info())
+ record_interpreter_traceback._annspecialcase_ = "override:ignore"
def print_application_traceback(self, space, file=None):
"NOT_RPYTHON: Dump a standard application-level traceback."
Modified: pypy/dist/pypy/interpreter/miscutils.py
==============================================================================
--- pypy/dist/pypy/interpreter/miscutils.py (original)
+++ pypy/dist/pypy/interpreter/miscutils.py Mon Jun 6 05:08:52 2005
@@ -8,7 +8,7 @@
class Stack:
"""Utility class implementing a stack."""
- _specialize_ = 'location' # polymorphic
+ _annspecialcase_ = "specialize:ctr_location" # polymorphic
def __init__(self):
self.items = []
Modified: pypy/dist/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyframe.py (original)
+++ pypy/dist/pypy/interpreter/pyframe.py Mon Jun 6 05:08:52 2005
@@ -19,6 +19,7 @@
"""NOT_RPYTHON"""
import sys
return sys.exc_info()[2]
+cpython_tb._annspecialcase_ = "override:ignore"
class PyFrame(eval.Frame):
"""Represents a frame for a regular Python function
Modified: pypy/dist/pypy/interpreter/typedef.py
==============================================================================
--- pypy/dist/pypy/interpreter/typedef.py (original)
+++ pypy/dist/pypy/interpreter/typedef.py Mon Jun 6 05:08:52 2005
@@ -33,7 +33,7 @@
subcls = _buildusercls(cls, hasdict, wants_slots)
subclass_cache[key] = subcls
return subcls
-get_unique_interplevel_subclass._specialize_ = "memo"
+get_unique_interplevel_subclass._annspecialcase_ = "specialize:memo"
def _buildusercls(cls, hasdict, wants_slots):
"NOT_RPYTHON: initialization-time only"
@@ -109,6 +109,7 @@
return object.__new__(cls)
else:
return new.instance(cls)
+instantiate._annspecialcase_ = "override:instantiate"
def make_descr_typecheck_wrapper(func, extraargs=(), cls=None):
if func is None:
Modified: pypy/dist/pypy/module/sys/state.py
==============================================================================
--- pypy/dist/pypy/module/sys/state.py (original)
+++ pypy/dist/pypy/module/sys/state.py Mon Jun 6 05:08:52 2005
@@ -80,6 +80,7 @@
"""NOT_RPYTHON"""
from pypy.tool.udir import udir
return space.wrap(str(udir))
+pypy_getudir._annspecialcase_ = "override:ignore"
def getdefaultencoding(space):
return space.wrap(sys.getdefaultencoding())
Modified: pypy/dist/pypy/objspace/std/fake.py
==============================================================================
--- pypy/dist/pypy/objspace/std/fake.py (original)
+++ pypy/dist/pypy/objspace/std/fake.py Mon Jun 6 05:08:52 2005
@@ -17,7 +17,7 @@
return space.gettypeobject(ft.typedef)
ft = fake_type(type(x))
return ft(space, x)
-
+fake_object._annspecialcase_ = "override:fake_object"
import sys
@@ -43,6 +43,7 @@
w_exc = space.wrap(exc)
w_value = space.wrap(value)
raise OperationError, OperationError(w_exc, w_value), tb
+wrap_exception._annspecialcase_ = "override:ignore"
def fake_type(cpy_type):
assert type(cpy_type) is type
Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py (original)
+++ pypy/dist/pypy/objspace/std/objspace.py Mon Jun 6 05:08:52 2005
@@ -238,7 +238,7 @@
from fake import fake_object
return fake_object(self, x)
- wrap._specialize_ = "argtypes"
+ wrap._annspecialcase_ = "specialize:argtype1"
def wrap_exception_cls(self, x):
"""NOT_RPYTHON"""
@@ -246,6 +246,7 @@
w_result = getattr(self, 'w_' + x.__name__)
return w_result
return None
+ wrap_exception_cls._annspecialcase_ = "override:wrap_exception_cls"
def unwrap(self, w_obj):
if isinstance(w_obj, BaseWrappable):
@@ -324,8 +325,7 @@
instance.user_setup(self, w_subtype, w_subtype.nslots)
assert isinstance(instance, cls)
return instance
- allocate_instance._specialize_ = "location"
-
+ allocate_instance._annspecialcase_ = "specialize:arg1"
def unpacktuple(self, w_tuple, expected_length=-1):
assert isinstance(w_tuple, W_TupleObject)
Modified: pypy/dist/pypy/tool/cache.py
==============================================================================
--- pypy/dist/pypy/tool/cache.py (original)
+++ pypy/dist/pypy/tool/cache.py Mon Jun 6 05:08:52 2005
@@ -37,7 +37,7 @@
result = self._build(key)
self.content[key] = result
return result
- getorbuild._specialize_ = "memo"
+ getorbuild._annspecialcase_ = "specialize:memo"
def _freeze_(self):
# needs to be SomePBC, but otherwise we can't really freeze the
Modified: pypy/dist/pypy/translator/ann_override.py
==============================================================================
--- pypy/dist/pypy/translator/ann_override.py (original)
+++ pypy/dist/pypy/translator/ann_override.py Mon Jun 6 05:08:52 2005
@@ -1,55 +1,39 @@
# overrides for annotation specific to PyPy codebase
+from pypy.annotation.policy import AnnotatorPolicy
from pypy.annotation.bookkeeper import getbookkeeper
from pypy.annotation import model as annmodel
+from pypy.annotation import specialize
-from pypy.interpreter import error
-from pypy.interpreter import pyframe
-from pypy.objspace.std import fake
-from pypy.module.sys import state as sys_state
-import pypy.interpreter.typedef as itypedef
-import pypy.interpreter.pycode as pycode
-import pypy.interpreter.compiler as icompiler
-from pypy.objspace.std.objspace import StdObjSpace
-
-def ignore(*args):
- bk = getbookkeeper()
- return bk.immutablevalue(None)
-
-def instantiate(clspbc):
- assert isinstance(clspbc, annmodel.SomePBC)
- clsdef = None
- for cls, v in clspbc.prebuiltinstances.items():
- if not clsdef:
- clsdef = getbookkeeper().getclassdef(cls)
- else:
- clsdef = clsdef.commonbase(getbookkeeper().getclassdef(cls))
- return annmodel.SomeInstance(clsdef)
-
-def wrap_exception_cls(space, x):
- import pypy.objspace.std.typeobject as typeobject
- clsdef = getbookkeeper().getclassdef(typeobject.W_TypeObject)
- return annmodel.SomeInstance(clsdef, can_be_None=True)
-
-def fake_object(space, x):
- clsdef = getbookkeeper().getclassdef(itypedef.W_Root)
- return annmodel.SomeInstance(clsdef)
-
-def cpy_compile(self, source, filename, mode, flags):
- clsdef = getbookkeeper().getclassdef(pycode.PyCode)
- return annmodel.SomeInstance(clsdef)
-
-pypy_overrides = {}
-
-def install(tgt, override):
- if hasattr(tgt, 'im_func'):
- tgt = tgt.im_func
- pypy_overrides[tgt] = override
-
-install(pyframe.cpython_tb, ignore)
-install(error.OperationError.record_interpreter_traceback, ignore)
-install(sys_state.pypy_getudir, ignore)
-install(fake.wrap_exception, ignore)
-install(fake.fake_object, fake_object)
-install(itypedef.instantiate, instantiate)
-install(StdObjSpace.wrap_exception_cls, wrap_exception_cls)
-install(icompiler.CPythonCompiler.compile, cpy_compile)
+class PyPyAnnotatorPolicy(AnnotatorPolicy):
+
+ def override__ignore(pol, *args):
+ bk = getbookkeeper()
+ return bk.immutablevalue(None)
+
+ def override__instantiate(pol, clspbc):
+ assert isinstance(clspbc, annmodel.SomePBC)
+ clsdef = None
+ for cls, v in clspbc.prebuiltinstances.items():
+ if not clsdef:
+ clsdef = getbookkeeper().getclassdef(cls)
+ else:
+ clsdef = clsdef.commonbase(getbookkeeper().getclassdef(cls))
+ return annmodel.SomeInstance(clsdef)
+
+ def override__wrap_exception_cls(pol, space, x):
+ import pypy.objspace.std.typeobject as typeobject
+ clsdef = getbookkeeper().getclassdef(typeobject.W_TypeObject)
+ return annmodel.SomeInstance(clsdef, can_be_None=True)
+
+ def override__fake_object(pol, space, x):
+ from pypy.interpreter import typedef
+ clsdef = getbookkeeper().getclassdef(typedef.W_Root)
+ return annmodel.SomeInstance(clsdef)
+
+ def override__cpy_compile(pol, self, source, filename, mode, flags):
+ from pypy.interpreter import pycode
+ clsdef = getbookkeeper().getclassdef(pycode.PyCode)
+ return annmodel.SomeInstance(clsdef)
+
+ specialize__arg1 = staticmethod(specialize.argvalue(1))
+ specialize__argtype1 = staticmethod(specialize.argtype(1))
Modified: pypy/dist/pypy/translator/annrpython.py
==============================================================================
--- pypy/dist/pypy/translator/annrpython.py (original)
+++ pypy/dist/pypy/translator/annrpython.py Mon Jun 6 05:08:52 2005
@@ -12,12 +12,18 @@
class AnnotatorError(Exception):
pass
+class NullAnnotatorPolicy:
+ def override(pol, func, inputcells):
+ return None
+
+ def specialize(pol, bookkeeper, spaceop, func, args, mono):
+ return None
class RPythonAnnotator:
"""Block annotator for RPython.
See description in doc/translation/annotation.txt."""
- def __init__(self, translator=None, overrides={}):
+ def __init__(self, translator=None, policy = None):
self.translator = translator
self.pendingblocks = {} # map {block: function}
self.bindings = {} # map Variables to SomeValues
@@ -42,21 +48,20 @@
# --- end of debugging information ---
self.bookkeeper = Bookkeeper(self)
# user-supplied annotation logic for functions we don't want to flow into
- self.overrides = overrides
+ if policy is None:
+ self.policy = NullAnnotatorPolicy()
+ else:
+ self.policy = policy
def __getstate__(self):
attrs = """translator pendingblocks bindings annotated links_followed
- notify bookkeeper overrides""".split()
+ notify bookkeeper policy""".split()
ret = self.__dict__.copy()
for key, value in ret.items():
if key not in attrs:
assert type(value) is dict, ("please update %s.__getstate__" %
self.__class__.__name__)
ret[key] = {}
- # special case: clean up the overrides which would trigger bad imports
- overrides = ret['overrides'] = {}
- for key in self.overrides:
- overrides[key] = None
return ret
def _register_returnvar(self, flowgraph, func):
@@ -232,9 +237,9 @@
#___ interface for annotator.bookkeeper _______
def recursivecall(self, func, position_key, inputcells):
- override = self.overrides.get(func, None)
- if override is not None:
- return override(*inputcells)
+ overriden = self.policy.override(func, inputcells)
+ if overriden is not None:
+ return overriden
parent_fn, parent_block, parent_index = position_key
graph = self.getflowgraph(func, parent_fn, position_key)
# self.notify[graph.returnblock] is a dictionary of call
Modified: pypy/dist/pypy/translator/goal/translate_pypy.py
==============================================================================
--- pypy/dist/pypy/translator/goal/translate_pypy.py (original)
+++ pypy/dist/pypy/translator/goal/translate_pypy.py Mon Jun 6 05:08:52 2005
@@ -59,7 +59,7 @@
import threading, pdb
from pypy.translator.translator import Translator
-from pypy.translator.ann_override import pypy_overrides
+from pypy.translator.ann_override import PyPyAnnotatorPolicy
from pypy.annotation import model as annmodel
from pypy.tool.cache import Cache
from pypy.annotation.model import SomeObject
@@ -85,7 +85,7 @@
if listen_port:
run_async_server()
if not options['-no-a']:
- a = t.annotate(inputtypes, overrides=pypy_overrides)
+ a = t.annotate(inputtypes, policy=PyPyAnnotatorPolicy())
sanity_check_exceptblocks(t)
worstblocks_topten(a)
if not options['-no-s']:
Modified: pypy/dist/pypy/translator/test/snippet.py
==============================================================================
--- pypy/dist/pypy/translator/test/snippet.py (original)
+++ pypy/dist/pypy/translator/test/snippet.py Mon Jun 6 05:08:52 2005
@@ -1136,7 +1136,7 @@
# class specialization
class PolyStk:
- _specialize_ = 'location'
+ _annspecialcase_ = "specialize:ctr_location"
def __init__(self):
self.itms = []
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 Mon Jun 6 05:08:52 2005
@@ -5,6 +5,8 @@
from pypy.translator.annrpython import annmodel
from pypy.translator.translator import Translator
+from pypy.annotation import policy
+from pypy.annotation import specialize
from pypy.annotation.listdef import ListDef
from pypy.annotation.dictdef import DictDef
from pypy.objspace.flow.model import *
@@ -589,7 +591,7 @@
assert s == a.bookkeeper.immutablevalue(42)
def test_class_spec(self):
- a = self.RPythonAnnotator()
+ a = self.RPythonAnnotator(policy=policy.AnnotatorPolicy())
s = a.build_types(snippet.class_spec, [])
assert s.items[0].knowntype == int
assert s.items[1].knowntype == str
@@ -668,6 +670,7 @@
def record_exc(e):
"""NOT_RPYTHON"""
excs.append(sys.exc_info)
+ record_exc._annspecialcase_ = "override:record_exc"
def g():
pass
def f():
@@ -675,9 +678,12 @@
g()
except Exception, e:
record_exc(e)
- def ann_record_exc(s_e):
- return a.bookkeeper.immutablevalue(None)
- a = self.RPythonAnnotator(overrides={record_exc: ann_record_exc})
+ class MyAnnotatorPolicy(policy.AnnotatorPolicy):
+
+ def override__record_exc(pol, s_e):
+ return a.bookkeeper.immutablevalue(None)
+
+ a = self.RPythonAnnotator(policy=MyAnnotatorPolicy())
s = a.build_types(f, [])
assert s.const is None
@@ -925,17 +931,37 @@
i = inst(cls)
assert isinstance(i, cls)
return i
- alloc._specialize_ = "location"
+ alloc._annspecialcase_ = "specialize:arg0"
def f():
c1 = alloc(C1)
c2 = alloc(C2)
return c1,c2
- a = self.RPythonAnnotator()
+
+ class MyAnnotatorPolicy(policy.AnnotatorPolicy):
+
+ specialize__arg0 = staticmethod(specialize.argvalue(0))
+
+ a = self.RPythonAnnotator(policy=MyAnnotatorPolicy())
s = a.build_types(f, [])
assert s.items[0].knowntype == C1
assert s.items[1].knowntype == C2
+ callb = a.getpbccallables()
+ assert alloc not in callb
+ def visit(block):
+ if isinstance(block, Block):
+ for spaceop in block.operations:
+ if spaceop.opname == "simple_call" and spaceop.args[0] == Constant(alloc):
+ spec_alloc, memo = a.bookkeeper.query_spaceop_callable(spaceop)
+ assert not memo
+ spec_alloc = spec_alloc.const
+ assert spec_alloc in callb
+ assert callb[spec_alloc] == {(None, spec_alloc): True}
+ assert (a.binding(a.translator.getflowgraph(spec_alloc).getreturnvar()).knowntype
+ == spaceop.args[1].value)
+ traverse(visit, a.translator.getflowgraph(f))
+
def test_assert_list_doesnt_lose_info(self):
class T(object):
pass
Modified: pypy/dist/pypy/translator/translator.py
==============================================================================
--- pypy/dist/pypy/translator/translator.py (original)
+++ pypy/dist/pypy/translator/translator.py Mon Jun 6 05:08:52 2005
@@ -114,14 +114,14 @@
graph = self.getflowgraph(func)
simplify_graph(graph, passes)
- def annotate(self, input_args_types, func=None, overrides={}):
+ def annotate(self, input_args_types, func=None, policy=None):
"""annotate(self, input_arg_types[, func]) -> Annotator
Provides type information of arguments. Returns annotator.
"""
func = func or self.entrypoint
if self.annotator is None:
- self.annotator = RPythonAnnotator(self, overrides=overrides)
+ self.annotator = RPythonAnnotator(self, policy=policy)
graph = self.getflowgraph(func)
self.annotator.build_types(graph, input_args_types, func)
return self.annotator
More information about the Pypy-commit
mailing list