[pypy-dev] [pypy-commit] pypy default: Merge a branch that makes space.isinstance(w_obj, <a constant>) do a fastpath

Carl Friedrich Bolz cfbolz at gmx.de
Thu Sep 29 10:33:47 CEST 2011


Hi Maciek,

The objspace part of this test really needs tests! You should write 
tests that the .interplevel_cls attribute is set, and that calling 
isinstance_w actually goes through the fast path.

Cheers,

Carl Friedrich

On 09/29/2011 04:40 AM, fijal wrote:
> Author: Maciej Fijalkowski<fijall at gmail.com>
> Branch:
> Changeset: r47667:ffbf1bcf89d6
> Date: 2011-09-28 23:39 -0300
> http://bitbucket.org/pypy/pypy/changeset/ffbf1bcf89d6/
>
> Log:	Merge a branch that makes space.isinstance(w_obj,<a constant>) do a
> 	fastpath with isinstance(w_obj,<an RPython class representing the
> 	constant>)
>
> diff --git a/pypy/annotation/policy.py b/pypy/annotation/policy.py
> --- a/pypy/annotation/policy.py
> +++ b/pypy/annotation/policy.py
> @@ -1,6 +1,6 @@
>   # base annotation policy for specialization
>   from pypy.annotation.specialize import default_specialize as default
> -from pypy.annotation.specialize import specialize_argvalue, specialize_argtype, specialize_arglistitemtype
> +from pypy.annotation.specialize import specialize_argvalue, specialize_argtype, specialize_arglistitemtype, specialize_arg_or_var
>   from pypy.annotation.specialize import memo, specialize_call_location
>   # for some reason, model must be imported first,
>   # or we create a cycle.
> @@ -73,6 +73,7 @@
>       default_specialize = staticmethod(default)
>       specialize__memo = staticmethod(memo)
>       specialize__arg = staticmethod(specialize_argvalue) # specialize:arg(N)
> +    specialize__arg_or_var = staticmethod(specialize_arg_or_var)
>       specialize__argtype = staticmethod(specialize_argtype) # specialize:argtype(N)
>       specialize__arglistitemtype = staticmethod(specialize_arglistitemtype)
>       specialize__call_location = staticmethod(specialize_call_location)
> diff --git a/pypy/annotation/specialize.py b/pypy/annotation/specialize.py
> --- a/pypy/annotation/specialize.py
> +++ b/pypy/annotation/specialize.py
> @@ -353,6 +353,16 @@
>       key = tuple(key)
>       return maybe_star_args(funcdesc, key, args_s)
>
> +def specialize_arg_or_var(funcdesc, args_s, *argindices):
> +    for argno in argindices:
> +        if not args_s[argno].is_constant():
> +            break
> +    else:
> +        # all constant
> +        return specialize_argvalue(funcdesc, args_s, *argindices)
> +    # some not constant
> +    return maybe_star_args(funcdesc, None, args_s)
> +
>   def specialize_argtype(funcdesc, args_s, *argindices):
>       key = tuple([args_s[i].knowntype for i in argindices])
>       for cls in key:
> diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
> --- a/pypy/annotation/test/test_annrpython.py
> +++ b/pypy/annotation/test/test_annrpython.py
> @@ -1194,6 +1194,20 @@
>           assert len(executedesc._cache[(0, 'star', 2)].startblock.inputargs) == 4
>           assert len(executedesc._cache[(1, 'star', 3)].startblock.inputargs) == 5
>
> +    def test_specialize_arg_or_var(self):
> +        def f(a):
> +            return 1
> +        f._annspecialcase_ = 'specialize:arg_or_var(0)'
> +
> +        def fn(a):
> +            return f(3) + f(a)
> +
> +        a = self.RPythonAnnotator()
> +        a.build_types(fn, [int])
> +        executedesc = a.bookkeeper.getdesc(f)
> +        assert sorted(executedesc._cache.keys()) == [None, (3,)]
> +        # we got two different special
> +
>       def test_specialize_call_location(self):
>           def g(a):
>               return a
> diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
> --- a/pypy/objspace/descroperation.py
> +++ b/pypy/objspace/descroperation.py
> @@ -6,6 +6,7 @@
>   from pypy.interpreter.typedef import default_identity_hash
>   from pypy.tool.sourcetools import compile2, func_with_new_name
>   from pypy.module.__builtin__.interp_classobj import W_InstanceObject
> +from pypy.rlib.objectmodel import specialize
>
>   def object_getattribute(space):
>       "Utility that returns the app-level descriptor object.__getattribute__."
> @@ -507,6 +508,7 @@
>       def issubtype(space, w_sub, w_type):
>           return space._type_issubtype(w_sub, w_type)
>
> +    @specialize.arg_or_var(2)
>       def isinstance(space, w_inst, w_type):
>           return space.wrap(space._type_isinstance(w_inst, w_type))
>
> diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
> --- a/pypy/objspace/std/objspace.py
> +++ b/pypy/objspace/std/objspace.py
> @@ -7,7 +7,7 @@
>   from pypy.objspace.std import (builtinshortcut, stdtypedef, frame, model,
>                                  transparent, callmethod, proxyobject)
>   from pypy.objspace.descroperation import DescrOperation, raiseattrerror
> -from pypy.rlib.objectmodel import instantiate, r_dict, specialize
> +from pypy.rlib.objectmodel import instantiate, r_dict, specialize, is_constant
>   from pypy.rlib.debug import make_sure_not_resized
>   from pypy.rlib.rarithmetic import base_int, widen
>   from pypy.rlib.objectmodel import we_are_translated
> @@ -83,6 +83,12 @@
>           if self.config.objspace.std.withtproxy:
>               transparent.setup(self)
>
> +        for type, classes in self.model.typeorder.iteritems():
> +            if len(classes) == 3:
> +                # W_Root, AnyXxx and actual object
> +                self.gettypefor(type).interplevel_cls = classes[0][0]
> +
> +
>       def get_builtin_types(self):
>           return self.builtin_types
>
> @@ -567,10 +573,19 @@
>               return self.wrap(w_sub.issubtype(w_type))
>           raise OperationError(self.w_TypeError, self.wrap("need type objects"))
>
> +    @specialize.arg_or_var(2)
>       def _type_isinstance(self, w_inst, w_type):
> -        if isinstance(w_type, W_TypeObject):
> -            return self.type(w_inst).issubtype(w_type)
> -        raise OperationError(self.w_TypeError, self.wrap("need type object"))
> +        if not isinstance(w_type, W_TypeObject):
> +            raise OperationError(self.w_TypeError,
> +                                 self.wrap("need type object"))
> +        if is_constant(w_type):
> +            cls = w_type.interplevel_cls
> +            if cls is not None:
> +                assert w_inst is not None
> +                if isinstance(w_inst, cls):
> +                    return True
> +        return self.type(w_inst).issubtype(w_type)
>
> +    @specialize.arg_or_var(2)
>       def isinstance_w(space, w_inst, w_type):
>           return space._type_isinstance(w_inst, w_type)
> diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
> --- a/pypy/objspace/std/typeobject.py
> +++ b/pypy/objspace/std/typeobject.py
> @@ -115,6 +115,9 @@
>       # of the __new__ is an instance of the type
>       w_bltin_new = None
>
> +    interplevel_cls = None # not None for prebuilt instances of
> +                           # interpreter-level types
> +
>       @dont_look_inside
>       def __init__(w_self, space, name, bases_w, dict_w,
>                    overridetypedef=None):
> diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
> --- a/pypy/rlib/objectmodel.py
> +++ b/pypy/rlib/objectmodel.py
> @@ -46,6 +46,17 @@
>
>           return decorated_func
>
> +    def arg_or_var(self, *args):
> +        """ Same as arg, but additionally allow for a 'variable' annotation,
> +        that would simply be a situation where designated arg is not
> +        a constant
> +        """
> +        def decorated_func(func):
> +            func._annspecialcase_ = 'specialize:arg_or_var' + self._wrap(args)
> +            return func
> +
> +        return decorated_func
> +
>       def argtype(self, *args):
>           """ Specialize function based on types of arguments on given positions.
>
> @@ -165,6 +176,22 @@
>   def keepalive_until_here(*values):
>       pass
>
> +def is_constant(thing):
> +    return True
> +
> +class Entry(ExtRegistryEntry):
> +    _about_ = is_constant
> +
> +    def compute_result_annotation(self, s_arg):
> +        from pypy.annotation import model
> +        r = model.SomeBool()
> +        r.const = s_arg.is_constant()
> +        return r
> +
> +    def specialize_call(self, hop):
> +        from pypy.rpython.lltypesystem import lltype
> +        return hop.inputconst(lltype.Bool, hop.s_result.const)
> +
>   # ____________________________________________________________
>
>   class FREED_OBJECT(object):
> diff --git a/pypy/rlib/test/test_objectmodel.py b/pypy/rlib/test/test_objectmodel.py
> --- a/pypy/rlib/test/test_objectmodel.py
> +++ b/pypy/rlib/test/test_objectmodel.py
> @@ -339,6 +339,19 @@
>           res = self.interpret(f, [42])
>           assert res == 84
>
> +    def test_isconstant(self):
> +        from pypy.rlib.objectmodel import is_constant, specialize
> +
> +        @specialize.arg_or_var(0)
> +        def f(arg):
> +            if is_constant(arg):
> +                return 1
> +            return 10
> +
> +        def fn(arg):
> +            return f(arg) + f(3)
> +
> +        assert self.interpret(fn, [15]) == 11
>
>   class TestLLtype(BaseTestObjectModel, LLRtypeMixin):
>
> @@ -451,5 +464,4 @@
>           if llop.opname == 'malloc_varsize':
>               break
>       assert llop.args[2] is graph.startblock.inputargs[0]
> -
>
> _______________________________________________
> pypy-commit mailing list
> pypy-commit at python.org
> http://mail.python.org/mailman/listinfo/pypy-commit



More information about the pypy-dev mailing list