[pypy-commit] pypy remove-intlong-smm: improve interpreted (non-jit) perf:

pjenvey noreply at buildbot.pypy.org
Fri Feb 14 21:12:33 CET 2014


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: remove-intlong-smm
Changeset: r69138:13c6b40389d3
Date: 2014-02-14 12:02 -0800
http://bitbucket.org/pypy/pypy/changeset/13c6b40389d3/

Log:	improve interpreted (non-jit) perf: o specialize W_IntObject methods
	w/ import_from_mixin o try to fastpath pure int binops

diff --git a/pypy/objspace/std/boolobject.py b/pypy/objspace/std/boolobject.py
--- a/pypy/objspace/std/boolobject.py
+++ b/pypy/objspace/std/boolobject.py
@@ -1,15 +1,17 @@
 import operator
 
+from rpython.rlib.objectmodel import import_from_mixin
 from rpython.rlib.rarithmetic import r_uint
 from rpython.rlib.rbigint import rbigint
 from rpython.tool.sourcetools import func_renamer, func_with_new_name
 
 from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
-from pypy.objspace.std.intobject import W_AbstractIntObject
+from pypy.objspace.std.intobject import IntMethods, W_AbstractIntObject
 from pypy.objspace.std.stdtypedef import StdTypeDef
 
 
 class W_BoolObject(W_AbstractIntObject):
+    import_from_mixin(IntMethods)
 
     _immutable_fields_ = ['boolval']
 
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -9,7 +9,7 @@
 import sys
 
 from rpython.rlib import jit
-from rpython.rlib.objectmodel import instantiate, specialize
+from rpython.rlib.objectmodel import instantiate, import_from_mixin, specialize
 from rpython.rlib.rarithmetic import (
     LONG_BIT, is_valid_int, ovfcheck, r_uint, string_to_int)
 from rpython.rlib.rbigint import rbigint
@@ -29,27 +29,197 @@
 from pypy.objspace.std.stdtypedef import StdTypeDef
 
 
+SENTINEL = object()
+
+
 class W_AbstractIntObject(W_Root):
 
     __slots__ = ()
 
     def int(self, space):
         """x.__int__() <==> int(x)"""
-        raise NotImplementedError
+
+    def descr_format(self, space, w_format_spec):
+        pass
 
     def descr_coerce(self, space, w_other):
         """x.__coerce__(y) <==> coerce(x, y)"""
+
+    def descr_pow(self, space, w_exponent, w_modulus=None):
+        """x.__pow__(y[, z]) <==> pow(x, y[, z])"""
+    descr_rpow = func_with_new_name(descr_pow, 'descr_rpow')
+    descr_rpow.__doc__ = "y.__rpow__(x[, z]) <==> pow(x, y[, z])"
+
+    def _abstract_unaryop(opname, doc=SENTINEL):
+        if doc is SENTINEL:
+            doc = 'x.__%s__() <==> %s(x)' % (opname, opname)
+        @func_renamer('descr_' + opname)
+        def descr_unaryop(self, space):
+            pass
+        descr_unaryop.__doc__ = doc
+        return descr_unaryop
+
+    descr_repr = _abstract_unaryop('repr')
+    descr_str = _abstract_unaryop('str')
+
+    descr_conjugate = _abstract_unaryop(
+        'conjugate', "Returns self, the complex conjugate of any int.")
+    descr_bit_length = _abstract_unaryop('bit_length', """\
+        int.bit_length() -> int
+
+        Number of bits necessary to represent self in binary.
+        >>> bin(37)
+        '0b100101'
+        >>> (37).bit_length()
+        6""")
+    descr_hash = _abstract_unaryop('hash')
+    descr_oct = _abstract_unaryop('oct')
+    descr_hex = _abstract_unaryop('hex')
+    descr_getnewargs = _abstract_unaryop('getnewargs', None)
+
+    descr_long = _abstract_unaryop('long')
+    descr_index = _abstract_unaryop(
+        'index', "x[y:z] <==> x[y.__index__():z.__index__()]")
+    descr_trunc = _abstract_unaryop('trunc',
+                                    "Truncating an Integral returns itself.")
+    descr_float = _abstract_unaryop('float')
+
+    descr_pos = _abstract_unaryop('pos', "x.__pos__() <==> +x")
+    descr_neg = _abstract_unaryop('neg', "x.__neg__() <==> -x")
+    descr_abs = _abstract_unaryop('abs')
+    descr_nonzero = _abstract_unaryop('nonzero', "x.__nonzero__() <==> x != 0")
+    descr_invert = _abstract_unaryop('invert', "x.__invert__() <==> ~x")
+
+    def _abstract_cmpop(opname):
+        @func_renamer('descr_' + opname)
+        def descr_cmp(self, space, w_other):
+            pass
+        descr_cmp.__doc__ = 'x.__%s__(y) <==> x%sy' % (opname, CMP_OPS[opname])
+        return descr_cmp
+
+    descr_lt = _abstract_cmpop('lt')
+    descr_le = _abstract_cmpop('le')
+    descr_eq = _abstract_cmpop('eq')
+    descr_ne = _abstract_cmpop('ne')
+    descr_gt = _abstract_cmpop('gt')
+    descr_ge = _abstract_cmpop('ge')
+
+    def _abstract_binop(opname):
+        oper = BINARY_OPS.get(opname)
+        if oper == '%':
+            oper = '%%'
+        oper = '%s(%%s, %%s)' % opname if not oper else '%%s%s%%s' % oper
+        @func_renamer('descr_' + opname)
+        def descr_binop(self, space, w_other):
+            pass
+        descr_binop.__doc__ = "x.__%s__(y) <==> %s" % (opname,
+                                                       oper % ('x', 'y'))
+        descr_rbinop = func_with_new_name(descr_binop, 'descr_r' + opname)
+        descr_rbinop.__doc__ = "x.__r%s__(y) <==> %s" % (opname,
+                                                         oper % ('y', 'x'))
+        return descr_binop, descr_rbinop
+
+    descr_add, descr_radd = _abstract_binop('add')
+    descr_sub, descr_rsub = _abstract_binop('sub')
+    descr_mul, descr_rmul = _abstract_binop('mul')
+
+    descr_and, descr_rand = _abstract_binop('and')
+    descr_or, descr_ror = _abstract_binop('or')
+    descr_xor, descr_rxor = _abstract_binop('xor')
+
+    descr_lshift, descr_rlshift = _abstract_binop('lshift')
+    descr_rshift, descr_rrshift = _abstract_binop('rshift')
+
+    descr_floordiv, descr_rfloordiv = _abstract_binop('floordiv')
+    descr_div, descr_rdiv = _abstract_binop('div')
+    descr_truediv, descr_rtruediv = _abstract_binop('truediv')
+    descr_mod, descr_rmod = _abstract_binop('mod')
+    descr_divmod, descr_rdivmod = _abstract_binop('divmod')
+
+    def descr_get_numerator(self, space):
+        return self.int(space)
+    descr_get_real = descr_get_numerator
+
+    def descr_get_denominator(self, space):
+        return wrapint(space, 1)
+
+    def descr_get_imag(self, space):
+        return wrapint(space, 0)
+
+
+def _floordiv(space, x, y):
+    try:
+        z = ovfcheck(x // y)
+    except ZeroDivisionError:
+        raise oefmt(space.w_ZeroDivisionError, "integer division by zero")
+    return wrapint(space, z)
+_div = _floordiv
+
+
+def _truediv(space, x, y):
+    a = float(x)
+    b = float(y)
+    if b == 0.0:
+        raise oefmt(space.w_ZeroDivisionError, "division by zero")
+    return space.wrap(a / b)
+
+
+def _mod(space, x, y):
+    try:
+        z = ovfcheck(x % y)
+    except ZeroDivisionError:
+        raise oefmt(space.w_ZeroDivisionError, "integer modulo by zero")
+    return wrapint(space, z)
+
+
+def _divmod(space, x, y):
+    try:
+        z = ovfcheck(x // y)
+    except ZeroDivisionError:
+        raise oefmt(space.w_ZeroDivisionError, "integer divmod by zero")
+    # no overflow possible
+    m = x % y
+    w = space.wrap
+    return space.newtuple([w(z), w(m)])
+
+
+def _lshift(space, a, b):
+    if r_uint(b) < LONG_BIT: # 0 <= b < LONG_BIT
+        c = ovfcheck(a << b)
+        return wrapint(space, c)
+    if b < 0:
+        raise oefmt(space.w_ValueError, "negative shift count")
+    # b >= LONG_BIT
+    if a == 0:
+        return wrapint(space, a)
+    raise OverflowError
+
+
+def _rshift(space, a, b):
+    if r_uint(b) >= LONG_BIT: # not (0 <= b < LONG_BIT)
+        if b < 0:
+            raise oefmt(space.w_ValueError, "negative shift count")
+        # b >= LONG_BIT
+        if a == 0:
+            return wrapint(space, a)
+        a = -1 if a < 0 else 0
+    else:
+        a = a >> b
+    return wrapint(space, a)
+
+
+class IntMethods(object):
+
+    def descr_coerce(self, space, w_other):
         if not isinstance(w_other, W_AbstractIntObject):
             return space.w_NotImplemented
         return space.newtuple([self, w_other])
 
     def descr_long(self, space):
-        """x.__long__() <==> long(x)"""
         from pypy.objspace.std.longobject import W_LongObject
         return W_LongObject.fromint(space, self.int_w(space))
 
     def descr_hash(self, space):
-        """x.__hash__() <==> hash(x)"""
         # unlike CPython, we don't special-case the value -1 in most of
         # our hash functions, so there is not much sense special-casing
         # it here either.  Make sure this is consistent with the hash of
@@ -57,22 +227,17 @@
         return self.int(space)
 
     def descr_nonzero(self, space):
-        """x.__nonzero__() <==> x != 0"""
-        return space.newbool(space.int_w(self) != 0)
+        return space.newbool(self.int_w(space) != 0)
 
     def descr_invert(self, space):
-        """x.__invert__() <==> ~x"""
-        return wrapint(space, ~space.int_w(self))
+        return wrapint(space, ~self.int_w(space))
 
     def descr_pos(self, space):
-        """x.__pos__() <==> +x"""
         return self.int(space)
-    descr_trunc = func_with_new_name(descr_pos, 'descr_trunc')
-    descr_trunc.__doc__ = 'Truncating an Integral returns itself.'
+    descr_trunc = descr_pos # XX: descr_index/conjugate
 
     def descr_neg(self, space):
-        """x.__neg__() <==> -x"""
-        a = space.int_w(self)
+        a = self.int_w(space)
         try:
             x = ovfcheck(-a)
         except OverflowError:
@@ -83,45 +248,31 @@
         return wrapint(space, x)
 
     def descr_abs(self, space):
-        """x.__abs__() <==> abs(x)"""
-        pos = space.int_w(self) >= 0
+        pos = self.int_w(space) >= 0
         return self.int(space) if pos else self.descr_neg(space)
 
     def descr_index(self, space):
-        """x[y:z] <==> x[y.__index__():z.__index__()]"""
         return self.int(space)
 
     def descr_float(self, space):
-        """x.__float__() <==> float(x)"""
-        a = space.int_w(self)
+        a = self.int_w(space)
         x = float(a)
         return space.newfloat(x)
 
     def descr_oct(self, space):
-        """x.__oct__() <==> oct(x)"""
-        return space.wrap(oct(space.int_w(self)))
+        return space.wrap(oct(self.int_w(space)))
 
     def descr_hex(self, space):
-        """x.__hex__() <==> hex(x)"""
-        return space.wrap(hex(space.int_w(self)))
+        return space.wrap(hex(self.int_w(space)))
 
     def descr_getnewargs(self, space):
-        return space.newtuple([wrapint(space, space.int_w(self))])
+        return space.newtuple([wrapint(space, self.int_w(space))])
 
     def descr_conjugate(self, space):
-        """Returns self, the complex conjugate of any int."""
-        return space.int(self)
+        return self.int(space)
 
     def descr_bit_length(self, space):
-        """int.bit_length() -> int
-
-        Number of bits necessary to represent self in binary.
-        >>> bin(37)
-        '0b100101'
-        >>> (37).bit_length()
-        6
-        """
-        val = space.int_w(self)
+        val = self.int_w(space)
         if val < 0:
             val = -val
         bits = 0
@@ -131,35 +282,24 @@
         return space.wrap(bits)
 
     def descr_repr(self, space):
-        """x.__repr__() <==> repr(x)"""
         res = str(self.int_w(space))
         return space.wrap(res)
-    descr_str = func_with_new_name(descr_repr, 'descr_str')
-    descr_str.__doc__ = "x.__str__() <==> str(x)"
+    descr_str = descr_repr
 
     def descr_format(self, space, w_format_spec):
         return newformat.run_formatter(space, w_format_spec,
                                        "format_int_or_long", self,
                                        newformat.INT_KIND)
 
-    def descr_get_denominator(self, space):
-        return space.wrap(1)
-
-    def descr_get_imag(self, space):
-        return space.wrap(0)
-
-    descr_get_numerator = descr_get_real = descr_conjugate
-
     @unwrap_spec(w_modulus=WrappedDefault(None))
     def descr_pow(self, space, w_exponent, w_modulus=None):
-        """x.__pow__(y[, z]) <==> pow(x, y[, z])"""
         if not isinstance(w_exponent, W_AbstractIntObject):
             return space.w_NotImplemented
 
         if space.is_none(w_modulus):
             z = 0
         elif isinstance(w_modulus, W_AbstractIntObject):
-            z = space.int_w(w_modulus)
+            z = w_modulus.int_w(space)
             if z == 0:
                 raise oefmt(space.w_ValueError,
                             "pow() 3rd argument cannot be 0")
@@ -169,8 +309,8 @@
             # handle it ourselves
             return self._ovfpow2long(space, w_exponent, w_modulus)
 
-        x = space.int_w(self)
-        y = space.int_w(w_exponent)
+        x = self.int_w(space)
+        y = w_exponent.int_w(space)
         try:
             result = _pow_impl(space, x, y, z)
         except (OverflowError, ValueError):
@@ -179,7 +319,6 @@
 
     @unwrap_spec(w_modulus=WrappedDefault(None))
     def descr_rpow(self, space, w_base, w_modulus=None):
-        """y.__rpow__(x[, z]) <==> pow(x, y[, z])"""
         if not isinstance(w_base, W_AbstractIntObject):
             return space.w_NotImplemented
         return w_base.descr_pow(space, self, w_modulus)
@@ -195,12 +334,14 @@
         op = getattr(operator, opname)
         @func_renamer('descr_' + opname)
         def descr_cmp(self, space, w_other):
-            if not isinstance(w_other, W_AbstractIntObject):
+            i = self.int_w(space)
+            if isinstance(w_other, W_IntObject):
+                j = w_other.intval
+            elif isinstance(w_other, W_AbstractIntObject):
+                j = w_other.int_w(space)
+            else:
                 return space.w_NotImplemented
-            i = space.int_w(self)
-            j = space.int_w(w_other)
             return space.newbool(op(i, j))
-        descr_cmp.__doc__ = 'x.__%s__(y) <==> x%sy' % (opname, CMP_OPS[opname])
         return descr_cmp
 
     descr_lt = _make_descr_cmp('lt')
@@ -213,17 +354,16 @@
     def _make_generic_descr_binop(opname, ovf=True):
         op = getattr(operator,
                      opname + '_' if opname in ('and', 'or') else opname)
-        oper = BINARY_OPS.get(opname)
-        doc = "x.__%s__(y) <==> x%sy" % (opname, oper)
-        rdoc = "x.__r%s__(y) <==> y%sx" % (opname, oper)
 
         @func_renamer('descr_' + opname)
         def descr_binop(self, space, w_other):
-            if not isinstance(w_other, W_AbstractIntObject):
+            x = self.int_w(space)
+            if isinstance(w_other, W_IntObject):
+                y = w_other.intval
+            elif isinstance(w_other, W_AbstractIntObject):
+                y = w_other.int_w(space)
+            else:
                 return space.w_NotImplemented
-
-            x = space.int_w(self)
-            y = space.int_w(w_other)
             if ovf:
                 try:
                     z = ovfcheck(op(x, y))
@@ -232,27 +372,28 @@
             else:
                 z = op(x, y)
             return wrapint(space, z)
-        descr_binop.__doc__ = doc
 
         if opname in COMMUTATIVE_OPS:
-            descr_rbinop = func_with_new_name(descr_binop, 'descr_r' + opname)
-        else:
-            @func_renamer('descr_r' + opname)
-            def descr_rbinop(self, space, w_other):
-                if not isinstance(w_other, W_AbstractIntObject):
-                    return space.w_NotImplemented
+            return descr_binop, func_with_new_name(descr_binop,
+                                                   'descr_r' + opname)
 
-                x = space.int_w(self)
-                y = space.int_w(w_other)
-                if ovf:
-                    try:
-                        z = ovfcheck(op(y, x))
-                    except OverflowError:
-                        return _ovf2long(space, opname, w_other, self)
-                else:
-                    z = op(y, x)
-                return wrapint(space, z)
-        descr_rbinop.__doc__ = rdoc
+        @func_renamer('descr_r' + opname)
+        def descr_rbinop(self, space, w_other):
+            x = self.int_w(space)
+            if isinstance(w_other, W_IntObject):
+                y = w_other.intval
+            elif isinstance(w_other, W_AbstractIntObject):
+                y = w_other.int_w(space)
+            else:
+                return space.w_NotImplemented
+            if ovf:
+                try:
+                    z = ovfcheck(op(y, x))
+                except OverflowError:
+                    return _ovf2long(space, opname, w_other, self)
+            else:
+                z = op(y, x)
+            return wrapint(space, z)
 
         return descr_binop, descr_rbinop
 
@@ -266,116 +407,53 @@
 
     def _make_descr_binop(func, ovf=True):
         opname = func.__name__[1:]
-        oper = BINARY_OPS.get(opname)
-        if oper == '%':
-            oper = '%%'
-        oper = '%s(%%s, %%s)' % opname if not oper else '%%s%s%%s' % oper
 
         @func_renamer('descr_' + opname)
         def descr_binop(self, space, w_other):
-            if not isinstance(w_other, W_AbstractIntObject):
+            x = self.int_w(space)
+            if isinstance(w_other, W_IntObject):
+                y = w_other.intval
+            elif isinstance(w_other, W_AbstractIntObject):
+                y = w_other.int_w(space)
+            else:
                 return space.w_NotImplemented
             if ovf:
                 try:
-                    return func(self, space, w_other)
+                    return func(space, x, y)
                 except OverflowError:
                     return _ovf2long(space, opname, self, w_other)
             else:
-                return func(self, space, w_other)
-        descr_binop.__doc__ = "x.__%s__(y) <==> %s" % (opname,
-                                                       oper % ('x', 'y'))
+                return func(space, x, y)
 
         @func_renamer('descr_r' + opname)
         def descr_rbinop(self, space, w_other):
-            if not isinstance(w_other, W_AbstractIntObject):
+            x = self.int_w(space)
+            if isinstance(w_other, W_IntObject):
+                y = w_other.intval
+            elif isinstance(w_other, W_AbstractIntObject):
+                y = w_other.int_w(space)
+            else:
                 return space.w_NotImplemented
             if ovf:
                 try:
-                    return func(w_other, space, self)
+                    return func(space, y, x)
                 except OverflowError:
                     return _ovf2long(space, opname, w_other, self)
             else:
-                return func(w_other, space, self)
-        descr_rbinop.__doc__ = "x.__r%s__(y) <==> %s" % (opname,
-                                                         oper % ('y', 'x'))
-
+                return func(space, y, x)
         return descr_binop, descr_rbinop
 
-    def _floordiv(self, space, w_other):
-        x = space.int_w(self)
-        y = space.int_w(w_other)
-        try:
-            z = ovfcheck(x // y)
-        except ZeroDivisionError:
-            raise oefmt(space.w_ZeroDivisionError, "integer division by zero")
-        return wrapint(space, z)
     descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv)
-
-    _div = func_with_new_name(_floordiv, '_div')
     descr_div, descr_rdiv = _make_descr_binop(_div)
-
-    def _truediv(self, space, w_other):
-        x = float(space.int_w(self))
-        y = float(space.int_w(w_other))
-        if y == 0.0:
-            raise oefmt(space.w_ZeroDivisionError, "division by zero")
-        return space.wrap(x / y)
     descr_truediv, descr_rtruediv = _make_descr_binop(_truediv, ovf=False)
-
-    def _mod(self, space, w_other):
-        x = space.int_w(self)
-        y = space.int_w(w_other)
-        try:
-            z = ovfcheck(x % y)
-        except ZeroDivisionError:
-            raise oefmt(space.w_ZeroDivisionError, "integer modulo by zero")
-        return wrapint(space, z)
     descr_mod, descr_rmod = _make_descr_binop(_mod)
-
-    def _divmod(self, space, w_other):
-        x = space.int_w(self)
-        y = space.int_w(w_other)
-        try:
-            z = ovfcheck(x // y)
-        except ZeroDivisionError:
-            raise oefmt(space.w_ZeroDivisionError, "integer divmod by zero")
-        # no overflow possible
-        m = x % y
-        w = space.wrap
-        return space.newtuple([w(z), w(m)])
     descr_divmod, descr_rdivmod = _make_descr_binop(_divmod)
-
-    def _lshift(self, space, w_other):
-        a = space.int_w(self)
-        b = space.int_w(w_other)
-        if r_uint(b) < LONG_BIT: # 0 <= b < LONG_BIT
-            c = ovfcheck(a << b)
-            return wrapint(space, c)
-        if b < 0:
-            raise oefmt(space.w_ValueError, "negative shift count")
-        # b >= LONG_BIT
-        if a == 0:
-            return self.int(space)
-        raise OverflowError
     descr_lshift, descr_rlshift = _make_descr_binop(_lshift)
-
-    def _rshift(self, space, w_other):
-        a = space.int_w(self)
-        b = space.int_w(w_other)
-        if r_uint(b) >= LONG_BIT: # not (0 <= b < LONG_BIT)
-            if b < 0:
-                raise oefmt(space.w_ValueError, "negative shift count")
-            # b >= LONG_BIT
-            if a == 0:
-                return self.int(space)
-            a = -1 if a < 0 else 0
-        else:
-            a = a >> b
-        return wrapint(space, a)
     descr_rshift, descr_rrshift = _make_descr_binop(_rshift, ovf=False)
 
 
 class W_IntObject(W_AbstractIntObject):
+    import_from_mixin(IntMethods)
 
     __slots__ = 'intval'
     _immutable_fields_ = ['intval']
@@ -393,7 +471,7 @@
             return False
         if self.user_overridden_class or w_other.user_overridden_class:
             return self is w_other
-        return space.int_w(self) == space.int_w(w_other)
+        return self.int_w(space) == w_other.int_w(space)
 
     def immutable_unique_id(self, space):
         if self.user_overridden_class:
@@ -634,8 +712,8 @@
         W_AbstractIntObject.descr_get_imag,
         doc="the imaginary part of a complex number"),
 
-    __repr__ = interp2app(W_AbstractIntObject.descr_repr),
-    __str__ = interp2app(W_AbstractIntObject.descr_str),
+    __repr__ = interpindirect2app(W_AbstractIntObject.descr_repr),
+    __str__ = interpindirect2app(W_AbstractIntObject.descr_str),
 
     conjugate = interpindirect2app(W_AbstractIntObject.descr_conjugate),
     bit_length = interpindirect2app(W_AbstractIntObject.descr_bit_length),


More information about the pypy-commit mailing list