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

fijal noreply at buildbot.pypy.org
Thu Sep 29 04:40:41 CEST 2011


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]
-
     


More information about the pypy-commit mailing list