Author: Carl Friedrich Bolz <cfb...@gmx.de>
Branch: guard-compatible
Changeset: r83142:fa123e6f37d8
Date: 2016-03-18 17:26 +0100
http://bitbucket.org/pypy/pypy/changeset/fa123e6f37d8/

Log:    start using elidable_compatible functions on the map that get stuff
        from the type. The goal is to never have to promote the type in most
        common code paths. somewhat experimental

diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -227,7 +227,7 @@
                    "make instances really small but slow without the JIT",
                    default=False,
                    requires=[("objspace.std.getattributeshortcut", True),
-                             ("objspace.std.withtypeversion", True),
+                             ("objspace.std.withmethodcache", True),
                        ]),
 
         BoolOption("withrangelist",
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -174,6 +174,8 @@
     # hooks that the mapdict implementations needs:
     def _get_mapdict_map(self):
         return None
+    def _get_mapdict_map_no_promote(self):
+        return None
     def _set_mapdict_map(self, map):
         raise NotImplementedError
     def _mapdict_read_storage(self, index):
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -2,6 +2,7 @@
 
 from rpython.rlib import jit, objectmodel, debug, rerased
 from rpython.rlib.rarithmetic import intmask, r_uint
+from rpython.rlib.jit import we_are_jitted
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.objspace.std.dictmultiobject import (
@@ -305,6 +306,36 @@
     def __repr__(self):
         return "<%s>" % (self.__class__.__name__,)
 
+    # ____________________________________________________________
+    # a few things that also interact with the type
+    # the important idea is: don't read self.terminator.w_cls outside of an
+    # elidable_compatible function
+
+    @jit.elidable_compatible(quasi_immut_field_name_for_second_arg="version")
+    def _type_safe_to_do_getattr(self, version):
+        # it's safe if the version is not None and the type does not define its
+        # own __getattribute__
+        if version is None:
+            return False
+        w_type = self.terminator.w_cls
+        return w_type.has_object_getattribute()
+
+    def _type_lookup(self, name):
+        if not self._type_safe_to_do_getattr():
+            return self.getclass_from_terminator().lookup(name)
+        w_descr = self._type_lookup_pure(name)
+        if isinstance(w_descr, MutableCell):
+            w_descr = w_descr.unwrap_cell(self.space)
+        return w_descr
+
+    @jit.elidable_compatible(quasi_immut_field_name_for_second_arg="version")
+    def _type_lookup_pure(self, version, name):
+        assert version is not None
+        w_type = self.terminator.w_cls
+        w_res = w_type._pure_lookup_where_with_method_cache(
+            name, w_cls.version_tag())
+        return w_res
+
 
 class Terminator(AbstractAttribute):
     _immutable_fields_ = ['w_cls', 'version?']
@@ -1097,3 +1128,16 @@
 # XXX fix me: if a function contains a loop with both LOAD_ATTR and
 # XXX LOOKUP_METHOD on the same attribute name, it keeps trashing and
 # XXX rebuilding the cache
+
+
+# ____________________________________________________________
+# various functions that replace objspace implementations
+
+def mapdict_lookup(space, w_obj, name):
+    if we_are_jitted():
+        map = w_obj._get_mapdict_map_no_promote()
+        if map is not None:
+            return map._type_lookup(name)
+    w_type = space.type(w_obj)
+    return w_type.lookup(name)
+
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
@@ -324,6 +324,9 @@
         return w_obj.getclass(self)
 
     def lookup(self, w_obj, name):
+        if self.config.objspace.std.withmapdict:
+            from pypy.objspace.std.mapdict import mapdict_lookup
+            return mapdict_lookup(self, w_obj, name)
         w_type = self.type(w_obj)
         return w_type.lookup(name)
     lookup._annspecialcase_ = 'specialize:lookup'
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -128,7 +128,7 @@
 def promote_string(x):
     return hint(x, promote_string=True)
 
-def elidable_compatible():
+def elidable_compatible(quasi_immut_field_name_for_second_arg=None):
     """ func must be a function of at least one argument. That first argument
     must be pointer-like (XXX for now?) The behaviour of @elidable_compatible
     is as follows:
@@ -151,14 +151,16 @@
     single value res. If func is an injection, there is no reason to not simply
     use a regular promote.
 
-    XXX what happens if the *args are not constant?
     XXX we need a better name
+    XXX document quasi_immut_field_name_for_second_arg
     """
     def decorate(func):
         elidable(func)
         def wrapped_func(x, *args):
             assert x is not None
             x = hint(x, promote_compatible=True)
+            if quasi_immut_field_name_for_second_arg is not None:
+                return func(x, getattr(x, 
quasi_immut_field_name_for_second_arg), *args)
             return func(x, *args)
         return wrapped_func
     return decorate
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to