[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:58 CEST 2011
Hi Maciek,
The objspace part of this merge 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