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<fij...@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-com...@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

_______________________________________________
pypy-dev mailing list
pypy-dev@python.org
http://mail.python.org/mailman/listinfo/pypy-dev

Reply via email to