Author: Manuel Jacob Branch: kill-multimethod Changeset: r69401:fa0cc2a86b87 Date: 2014-02-25 05:59 +0100 http://bitbucket.org/pypy/pypy/changeset/fa0cc2a86b87/
Log: I *think* it's safe to remove builtinshortcut because it seems that it only speeds up multimethods. diff --git a/pypy/objspace/std/builtinshortcut.py b/pypy/objspace/std/builtinshortcut.py deleted file mode 100644 --- a/pypy/objspace/std/builtinshortcut.py +++ /dev/null @@ -1,136 +0,0 @@ -from pypy.interpreter.baseobjspace import ObjSpace -from pypy.interpreter.error import OperationError -from pypy.objspace.descroperation import DescrOperation -from pypy.objspace.std.boolobject import W_BoolObject -from rpython.tool.sourcetools import func_with_new_name - -# ____________________________________________________________ -# -# The sole purpose of this file is performance. -# It speeds up the dispatch of operations between -# built-in objects. -# - -# this is a selection... a few operations are missing because they are -# thought to be very rare or most commonly used with non-builtin types -METHODS_WITH_SHORTCUT = dict.fromkeys( - ['add', 'sub', 'mul', 'truediv', 'floordiv', 'div', - 'mod', 'lshift', 'rshift', 'and_', 'or_', 'xor', 'pow', - 'lt', 'le', 'eq', 'ne', 'gt', 'ge', 'contains', - # unary - 'len', 'nonzero', 'repr', 'str', 'hash', - 'neg', 'invert', 'index', 'iter', 'next', 'buffer', - 'getitem', 'setitem', 'int', - # in-place - 'inplace_add', 'inplace_sub', 'inplace_mul', 'inplace_truediv', - 'inplace_floordiv', 'inplace_div', 'inplace_mod', 'inplace_pow', - 'inplace_lshift', 'inplace_rshift', 'inplace_and', 'inplace_or', - 'inplace_xor', - # other - 'format', - ]) - -KNOWN_MISSING = ['getattr', # mostly non-builtins or optimized by CALL_METHOD - 'setattr', 'delattr', 'userdel', # mostly for non-builtins - 'get', 'set', 'delete', # uncommon (except on functions) - 'getslice', 'setslice', 'delslice', # see below - 'delitem', 'trunc', # rare stuff? - 'abs', 'hex', 'oct', # rare stuff? - 'pos', 'divmod', 'cmp', # rare stuff? - 'float', 'long', 'coerce', # rare stuff? - 'isinstance', 'issubtype', - ] -# We cannot support {get,set,del}slice right now because -# DescrOperation.{get,set,del}slice do a bit more work than just call -# the special methods: they call old_slice_range(). See e.g. -# test_builtinshortcut.AppTestString. - -for _name, _, _, _specialmethods in ObjSpace.MethodTable: - if _specialmethods: - assert _name in METHODS_WITH_SHORTCUT or _name in KNOWN_MISSING, ( - "operation %r should be in METHODS_WITH_SHORTCUT or KNOWN_MISSING" - % (_name,)) - - -def filter_out_conversions(typeorder): - res = {} - for cls, order in typeorder.iteritems(): - res[cls] = [(target_type, converter) for (target_type, converter) in - order if converter is None] - return res - - -def install(space, mm, fallback_mm=None): - """Install a function <name>() on the space instance which invokes - a shortcut for built-in types. Returns the shortcutting multimethod - object or None. - """ - name = mm.name - if name not in METHODS_WITH_SHORTCUT: - return None - - # can be called multiple times without re-installing - if name in space.__dict__: - mm1, shortcut_method = space.__dict__[name].builtinshortcut - assert mm1 is mm - return shortcut_method - - #print 'installing shortcut for:', name - assert hasattr(DescrOperation, name) - - base_method = getattr(space.__class__, name) - - # Basic idea: we first try to dispatch the operation using purely - # the multimethod. If this is done naively, subclassing a built-in - # type like 'int' and overriding a special method like '__add__' - # doesn't work any more, because the multimethod will accept the int - # subclass and compute the result in the built-in way. To avoid - # this issue, we tweak the shortcut multimethods so that these ones - # (and only these ones) never match the interp-level subclasses - # built in pypy.interpreter.typedef.get_unique_interplevel_subclass. - expanded_order = space.model.get_typeorder_with_empty_usersubcls() - if fallback_mm: - mm = mm.merge_with(fallback_mm) - shortcut_method = mm.install_not_sliced(filter_out_conversions(expanded_order)) - - def operate(*args_w): - try: - return shortcut_method(space, *args_w) - except FailedToImplement: - pass - return base_method(space, *args_w) - - operate = func_with_new_name(operate, name) - operate.builtinshortcut = (mm, shortcut_method) - setattr(space, name, operate) - return shortcut_method - - -def install_is_true(space, mm_nonzero, mm_len): - shortcut = install(space, mm_nonzero, fallback_mm = mm_len) - assert 'is_true' not in space.__dict__ - - def is_true(w_obj): - # a bit of duplication of the logic from DescrOperation.is_true... - try: - w_res = shortcut(space, w_obj) - except FailedToImplement: - pass - else: - # the __nonzero__ method of built-in objects should - # always directly return a Bool; however, the __len__ method - # of built-in objects typically returns an unwrappable integer - if isinstance(w_res, W_BoolObject): - return bool(w_res.intval) - try: - return space.int_w(w_res) != 0 - except OperationError: - # I think no OperationError other than w_OverflowError - # could occur here - w_obj = w_res - - # general case fallback - return _DescrOperation_is_true(space, w_obj) - - _DescrOperation_is_true = DescrOperation.is_true.im_func - space.is_true = is_true 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 @@ -4,7 +4,7 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.typedef import get_unique_interplevel_subclass -from pypy.objspace.std import (builtinshortcut, stdtypedef, frame, model, +from pypy.objspace.std import (stdtypedef, frame, model, transparent, callmethod) from pypy.objspace.descroperation import DescrOperation, raiseattrerror from rpython.rlib.objectmodel import instantiate, specialize, is_annotation_constant @@ -485,7 +485,6 @@ def is_true(self, w_obj): # a shortcut for performance - # NOTE! this method is typically overridden by builtinshortcut.py. if type(w_obj) is W_BoolObject: return bool(w_obj.intval) return self._DescrOperation_is_true(w_obj) diff --git a/pypy/objspace/std/test/test_builtinshortcut.py b/pypy/objspace/std/test/test_builtinshortcut.py deleted file mode 100644 --- a/pypy/objspace/std/test/test_builtinshortcut.py +++ /dev/null @@ -1,98 +0,0 @@ -from pypy.objspace.std.test import test_userobject -from pypy.objspace.std.test import test_setobject -from pypy.objspace.std.test import test_bytesobject - -WITH_BUILTINSHORTCUT = {'objspace.std.builtinshortcut': True} - -class AppTestUserObject(test_userobject.AppTestUserObject): - spaceconfig = WITH_BUILTINSHORTCUT - -class AppTestBug: - spaceconfig = WITH_BUILTINSHORTCUT - - def test_frozen_subtype(self): - class S(set): pass - assert set("abc") == S("abc") - assert S("abc") == set("abc") - class F(frozenset): pass - assert frozenset("abc") == F("abc") - assert F("abc") == frozenset("abc") - - assert S("abc") in set([frozenset("abc")]) - assert F("abc") in set([frozenset("abc")]) - - s = set([frozenset("abc")]) - s.discard(S("abc")) - assert not s - - s = set([frozenset("abc")]) - s.discard(F("abc")) - assert not s - - def test_inplace_methods(self): - assert '__iadd__' not in int.__dict__ - assert '__iadd__' not in float.__dict__ - x = 5 - x += 6.5 - assert x == 11.5 - - def test_inplace_user_subclasses(self): - class I(int): pass - class F(float): pass - x = I(5) - x += F(6.5) - assert x == 11.5 - assert type(x) is float - - def test_inplace_override(self): - class I(int): - def __iadd__(self, other): - return 'foo' - x = I(5) - x += 6 - assert x == 'foo' - x = I(5) - x += 6.5 - assert x == 'foo' - assert 5 + 6.5 == 11.5 - - def test_unicode_string_compares(self): - assert u'a' == 'a' - assert 'a' == u'a' - assert not u'a' == 'b' - assert not 'a' == u'b' - assert u'a' != 'b' - assert 'a' != u'b' - assert not (u'a' == 5) - assert u'a' != 5 - assert u'a' < 5 or u'a' > 5 - - s = chr(128) - u = unichr(128) - assert not s == u # UnicodeWarning - assert s != u - assert not u == s - assert u != s - - -class AppTestSet(test_setobject.AppTestAppSetTest): - spaceconfig = WITH_BUILTINSHORTCUT - # this tests tons of funny comparison combinations that can easily go wrong - def setup_class(cls): - w_fakeint = cls.space.appexec([], """(): - class FakeInt(object): - def __init__(self, value): - self.value = value - def __hash__(self): - return hash(self.value) - - def __eq__(self, other): - if other == self.value: - return True - return False - return FakeInt - """) - cls.w_FakeInt = w_fakeint - -class AppTestString(test_bytesobject.AppTestBytesObject): - spaceconfig = WITH_BUILTINSHORTCUT diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py --- a/pypy/objspace/test/test_descroperation.py +++ b/pypy/objspace/test/test_descroperation.py @@ -721,8 +721,3 @@ return CannotConvertToBool() x = X() raises(MyError, "'foo' in x") - - - -class AppTestWithBuiltinShortcut(AppTest_Descroperation): - spaceconfig = {'objspace.std.builtinshortcut': True} _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit