Author: Carl Friedrich Bolz <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit