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