https://github.com/python/cpython/commit/1b081434666d244d2fa083d47251d90175ac69da
commit: 1b081434666d244d2fa083d47251d90175ac69da
branch: main
author: Pieter Eendebak <[email protected]>
committer: colesbury <[email protected]>
date: 2026-01-29T16:32:09-05:00
summary:
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.
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst
M Objects/longobject.c
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 00000000000000..3a99b3d9e6a1c2
--- /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 74958cb8b9bbb0..7ce5d0535b884e 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));
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]