From: Pieter Eendebak Date: Thu, 29 Jan 2026 21:32:09 +0000 (+0100) Subject: gh-143192 Avoid incref/decref pair in long_bitwise (gh-143194) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1b081434666d244d2fa083d47251d90175ac69da;p=thirdparty%2FPython%2Fcpython.git gh-143192 Avoid incref/decref pair in long_bitwise (gh-143194) Remove unnecessary reference count operations in long_bitwise in order to avoid reference count contention in the free-threading build. --- diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst new file mode 100644 index 000000000000..3a99b3d9e6a1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst @@ -0,0 +1 @@ +Improve performance of bitwise operations on multi-digit ints. diff --git a/Objects/longobject.c b/Objects/longobject.c index 74958cb8b9bb..7ce5d0535b88 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5589,46 +5589,45 @@ long_bitwise(PyLongObject *a, Py_ssize_t size_a, size_b, size_z, i; PyLongObject *z; + PyLongObject *new_a = NULL; + PyLongObject *new_b = NULL; + /* Bitwise operations for negative numbers operate as though on a two's complement representation. So convert arguments from sign-magnitude to two's complement, and convert the result back to sign-magnitude at the end. */ - /* If a is negative, replace it by its two's complement. */ size_a = _PyLong_DigitCount(a); + size_b = _PyLong_DigitCount(b); + /* Swap a and b if necessary to ensure size_a >= size_b. */ + if (size_a < size_b) { + z = a; a = b; b = z; + size_z = size_a; size_a = size_b; size_b = size_z; + } + + /* If a is negative, replace it by its two's complement. */ nega = _PyLong_IsNegative(a); if (nega) { z = long_alloc(size_a); if (z == NULL) return NULL; v_complement(z->long_value.ob_digit, a->long_value.ob_digit, size_a); + new_a = z; // reference to decrement instead of a itself a = z; } - else - /* Keep reference count consistent. */ - Py_INCREF(a); /* Same for b. */ - size_b = _PyLong_DigitCount(b); negb = _PyLong_IsNegative(b); if (negb) { z = long_alloc(size_b); if (z == NULL) { - Py_DECREF(a); + Py_XDECREF(new_a); return NULL; } v_complement(z->long_value.ob_digit, b->long_value.ob_digit, size_b); + new_b = z; // reference to decrement instead of b itself b = z; } - else - Py_INCREF(b); - - /* Swap a and b if necessary to ensure size_a >= size_b. */ - if (size_a < size_b) { - z = a; a = b; b = z; - size_z = size_a; size_a = size_b; size_b = size_z; - negz = nega; nega = negb; negb = negz; - } /* JRH: The original logic here was to allocate the result value (z) as the longer of the two operands. However, there are some cases @@ -5658,8 +5657,8 @@ long_bitwise(PyLongObject *a, the final two's complement of z doesn't overflow. */ z = long_alloc(size_z + negz); if (z == NULL) { - Py_DECREF(a); - Py_DECREF(b); + Py_XDECREF(new_a); + Py_XDECREF(new_b); return NULL; } @@ -5696,8 +5695,8 @@ long_bitwise(PyLongObject *a, v_complement(z->long_value.ob_digit, z->long_value.ob_digit, size_z+1); } - Py_DECREF(a); - Py_DECREF(b); + Py_XDECREF(new_a); + Py_XDECREF(new_b); return (PyObject *)maybe_small_long(long_normalize(z)); }