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
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;
}
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));
}